topoisomerase 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/ChangeLog +4 -0
- data/README.md +23 -1
- data/lib/topoisomerase.rb +66 -21
- data/lib/topoisomerase/comment_adder.rb +40 -0
- data/lib/topoisomerase/stub_template.rb.erb +5 -6
- data/lib/topoisomerase/template/page_object.rb +69 -0
- data/lib/topoisomerase/version.rb +2 -1
- data/todo.md +4 -0
- metadata +6 -4
- data/Gemfile.lock +0 -93
- data/lib/topoisomerase/override_define.rb +0 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cf5043b7dcc2f4ba70d7a034d42683de8975d67a0d2a92d51cab289b4f0b1996
|
4
|
+
data.tar.gz: 8d3ceca3787dbb577e9fb3e994a4180e5d5706c7cbc7ffd37c8238a7249131ab
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b8b8ad151f546440ee8d9a64122680d0a4177fec31536d944f1c4cbefb76d4f7e79f8c2d7fe2735768dccb6c3d9867893b5d9fc3e37d704e56e2253a9eb11bff
|
7
|
+
data.tar.gz: f3ed5723e43bb23279e084f5efec789c6352fb610bad3eb6b6024ea730e0798ceba8df0f1738e8c6bdb8ebff059a2be836a501bd5a152770c5900b8fe291cd3e
|
data/.gitignore
CHANGED
data/ChangeLog
ADDED
data/README.md
CHANGED
@@ -34,7 +34,29 @@ Or install it yourself as:
|
|
34
34
|
|
35
35
|
## Usage
|
36
36
|
|
37
|
-
|
37
|
+
To create a stub file for a class, call the `create_stubs_for` passing that class.
|
38
|
+
|
39
|
+
E.g:
|
40
|
+
```ruby
|
41
|
+
Topoisomerase.create_stubs_for BasicClass
|
42
|
+
```
|
43
|
+
|
44
|
+
By default stubs will be created in the `stubs` folder.
|
45
|
+
This can be changed by setting the `stub_folder` variable.
|
46
|
+
|
47
|
+
```ruby
|
48
|
+
Topoisomerase.stub_folder = 'custom_folder'
|
49
|
+
```
|
50
|
+
|
51
|
+
Note that this will by default attempt to instantiate the class with ClassName.new. If parameters are
|
52
|
+
needed pass a block to the `create_stubs_for` as shown below. The result of the block will be the
|
53
|
+
instance of the class used in creating stubs.
|
54
|
+
|
55
|
+
```ruby
|
56
|
+
Topoisomerase.create_stubs_for ParameterizedClass do
|
57
|
+
ParameterizedClass.new 5
|
58
|
+
end
|
59
|
+
```
|
38
60
|
|
39
61
|
## Development
|
40
62
|
|
data/lib/topoisomerase.rb
CHANGED
@@ -2,49 +2,92 @@ require 'topoisomerase/version'
|
|
2
2
|
require 'method_source'
|
3
3
|
require 'fileutils'
|
4
4
|
require 'topoisomerase/core_ext/string'
|
5
|
+
require 'topoisomerase/comment_adder'
|
5
6
|
|
6
|
-
#
|
7
|
+
# Module for parsing and creating stubs for dynamic methods
|
7
8
|
module Topoisomerase
|
8
9
|
@stub_folder = 'stub'
|
10
|
+
@comments_added = {}
|
11
|
+
# @return [Object] Class to create stubs for
|
12
|
+
@class_name = nil
|
9
13
|
|
14
|
+
# For errors raised related to Topoisomerase
|
10
15
|
class Error < StandardError; end
|
11
|
-
# Your code goes here...
|
12
16
|
class << self
|
13
17
|
# @return [String] Folder where stubs are stored
|
14
18
|
attr_accessor :stub_folder
|
19
|
+
# @todo Use custom object for this
|
20
|
+
# @return [Hash] Comments added to stubs generated grouped by inheriting class and then by
|
21
|
+
# message, matcher patterns
|
22
|
+
attr_accessor :comments_added
|
15
23
|
|
24
|
+
# @todo This is only covering 'define_method'. More methods will be added later
|
25
|
+
# @return [Boolean] Whether method is defined dynamically
|
16
26
|
def dynamic_method?(method)
|
17
27
|
source_code = method.source
|
18
28
|
source_code.strip.start_with? 'define_method'
|
19
29
|
end
|
20
30
|
|
21
31
|
# @param [Object] class_name Class to retrieve dynamic methods for
|
22
|
-
# @return [Hash]
|
32
|
+
# @return [Hash] Hash with dynamic methods as keys and values being the source, comment
|
33
|
+
# and location
|
23
34
|
def dynamic_instance_methods(class_name)
|
24
|
-
class_instance =
|
25
|
-
yield
|
26
|
-
else
|
27
|
-
class_name.new
|
28
|
-
end
|
35
|
+
class_instance = block_given? ? yield(class_name) : class_name.new
|
29
36
|
methods_hash = {}
|
30
37
|
(class_instance.public_methods - Object.public_methods).each do |method|
|
31
38
|
method_obj = class_instance.method(method)
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
39
|
+
next unless dynamic_method? class_instance.method(method)
|
40
|
+
|
41
|
+
methods_hash.merge!(method => { source: method_obj.source, comment: method_obj.comment,
|
42
|
+
location: method_obj.source_location,
|
43
|
+
parameters: method_obj.parameters.collect { |p| p.last.to_s } })
|
44
|
+
# TODO: May be worth checking required parameters and documenting non-required differently
|
45
|
+
# receiver - Shows object that will call method
|
46
|
+
# owner - shows class from which method belongs to
|
47
|
+
# parameters - Array with params and :req
|
36
48
|
end
|
37
|
-
# methods.each do |method|
|
38
|
-
# method_obj = class_instance.method(method)
|
39
|
-
# methods_hash.merge(method => { source: method_obj.source, comment: method_obj.comment,
|
40
|
-
# location: method_obj.source_location })
|
41
|
-
# end
|
42
49
|
methods_hash
|
43
50
|
end
|
44
51
|
|
52
|
+
# @return [String] Comment extracted from dynamic element
|
53
|
+
def extracted_comment(method_data)
|
54
|
+
method_data[:comment].strip.empty? ? '' : "Extracted comment #{method_data[:comment].strip}"
|
55
|
+
end
|
56
|
+
|
57
|
+
# @return [Boolean]
|
58
|
+
def match?(value_to_test, matcher_value)
|
59
|
+
value_to_test = value_to_test.to_s
|
60
|
+
case matcher_value
|
61
|
+
when Regexp then !value_to_test[matcher_value].nil?
|
62
|
+
when String then value_to_test == matcher_value
|
63
|
+
else
|
64
|
+
raise "Unknown matcher type for #{value_to_test}, value of #{matcher_value}"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# Reads from 'comments_added' variable if no comment added above dynamic method
|
69
|
+
# @return [String] Comment defined by 'comments_added'
|
70
|
+
def comment_for(method_to_stub, method_data)
|
71
|
+
return extracted_comment(method_data) unless comments_added[@inheriting_class]
|
72
|
+
|
73
|
+
comments_added[@inheriting_class].each do |comment_matcher|
|
74
|
+
matchers = comment_matcher[:matchers]
|
75
|
+
return ERB.new(comment_matcher[:message]).result(binding) if matchers.all? do |matcher_type, matcher_value|
|
76
|
+
extracted_match = case matcher_type
|
77
|
+
when :method_name then match?(method_to_stub, matcher_value)
|
78
|
+
when :source then match? method_data[:source], matcher_value
|
79
|
+
else
|
80
|
+
raise Topoisomerase::Error, "Undefined matcher #{matcher_type}"
|
81
|
+
end
|
82
|
+
extracted_match
|
83
|
+
end
|
84
|
+
end
|
85
|
+
''
|
86
|
+
end
|
87
|
+
|
45
88
|
# Create stub file for passed in class
|
46
89
|
# @param [Object] class_name Object to create stub file for
|
47
|
-
def create_stubs_for(class_name)
|
90
|
+
def create_stubs_for(class_name, inner_folder = nil)
|
48
91
|
template = File.join(File.dirname(__FILE__), 'topoisomerase', 'stub_template.rb.erb')
|
49
92
|
@class_name = class_name
|
50
93
|
@class_instance = if block_given?
|
@@ -55,8 +98,9 @@ module Topoisomerase
|
|
55
98
|
@dynamic_methods = dynamic_instance_methods(class_name) do
|
56
99
|
@class_instance
|
57
100
|
end
|
58
|
-
|
59
|
-
|
101
|
+
class_folder = inner_folder ? File.join(stub_folder, inner_folder) : stub_folder
|
102
|
+
FileUtils.mkdir_p class_folder
|
103
|
+
filename = File.join(class_folder, "#{class_name.to_s.snakecase}.rb")
|
60
104
|
IO.write filename, ERB.new(File.read(template)).result(binding)
|
61
105
|
`rubocop -a #{filename}`
|
62
106
|
end
|
@@ -64,12 +108,13 @@ module Topoisomerase
|
|
64
108
|
# Create stub files for each class that inherits from passed in class
|
65
109
|
# @param [Object] inheriting_class Object to check for inheriting classes for
|
66
110
|
def create_stubs_based_on(inheriting_class)
|
111
|
+
@inheriting_class = inheriting_class
|
67
112
|
classes = ObjectSpace.each_object(Class).select { |class_name| class_name < inheriting_class }.reject do |class_name|
|
68
113
|
class_name.to_s.split(':')[0] == inheriting_class.to_s
|
69
114
|
end
|
70
115
|
classes.each do |class_name|
|
71
116
|
@class_instance = block_given? ? yield(class_name) : class_name.new
|
72
|
-
create_stubs_for(class_name) { @class_instance }
|
117
|
+
create_stubs_for(class_name, inheriting_class.to_s.snakecase) { @class_instance }
|
73
118
|
end
|
74
119
|
end
|
75
120
|
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Topoisomerase
|
2
|
+
# Class to set up comments that will be added to stubs for dynamic methods
|
3
|
+
class Comments
|
4
|
+
class << self
|
5
|
+
# @return [Object] Class for which stubs will be created from and for
|
6
|
+
# which rules to add comments for are defined
|
7
|
+
attr_accessor :inheriting_class
|
8
|
+
|
9
|
+
# Add a comment that is returned if ALL matchers are true
|
10
|
+
# @example Match a method ending with '_element' and include it's name without the '_element'
|
11
|
+
# comment "@return [Object] The '<%= method_to_stub.to_s.gsub('_element', '') %>' element",
|
12
|
+
# method_name: /_element$/
|
13
|
+
# @param [String] comment Comment to add above class
|
14
|
+
def comment(comment, matchers)
|
15
|
+
Topoisomerase.comments_added[inheriting_class] << {
|
16
|
+
message: comment,
|
17
|
+
matchers: matchers
|
18
|
+
}
|
19
|
+
end
|
20
|
+
|
21
|
+
# Add comments according to matchers for an inheriting class
|
22
|
+
#
|
23
|
+
# The order in which they are added is the order in which matching will occur.
|
24
|
+
# The first comment that has a match will be used.
|
25
|
+
# If several matchers are used on 1 comment, all must be true to be considered a match
|
26
|
+
#
|
27
|
+
# @example Add a comment where method name ends with '=' and source contains '.text'
|
28
|
+
# Comments.add_for_class PageObject do
|
29
|
+
# comment 'Comment to add', method_name: /=$/, source: /.text/
|
30
|
+
# end
|
31
|
+
#
|
32
|
+
# @param [Object] inheriting_class Class for which stubs will be created from and for
|
33
|
+
# which rules to add comments for are defined
|
34
|
+
def add_for_class(inheriting_class, &script)
|
35
|
+
self.inheriting_class = inheriting_class
|
36
|
+
instance_eval(&script)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -2,13 +2,12 @@ require 'topoisomerase'
|
|
2
2
|
# Stub for <%= @class_name %> created by 'topoisomerase'
|
3
3
|
class <%= @class_name %>
|
4
4
|
<% @dynamic_methods.each do |method_to_stub, method_data| %>
|
5
|
-
#
|
6
|
-
|
7
|
-
|
8
|
-
raise Topoisomerase::Error, "Method '<%= method_to_stub %>' called when it
|
5
|
+
# <%= comment_for(method_to_stub, method_data) %>
|
6
|
+
def <%= method_to_stub %> <%= method_data[:parameters].join(',') %>
|
7
|
+
# Defined at <%= method_data[:location] %>
|
8
|
+
raise Topoisomerase::Error, "Method '<%= method_to_stub %>' called with when it
|
9
9
|
should not have been. Don't require stub files"
|
10
|
-
# This is merely a stub
|
11
|
-
# Contents is below
|
10
|
+
# This is merely a stub. Contents is below
|
12
11
|
<%= method_data[:source] %>
|
13
12
|
end
|
14
13
|
<% end %>
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# Load comments for page_object and create stubs for classes inheriting from it
|
2
|
+
|
3
|
+
# This blocks shows the manual addition of comments to the comments_added accessor
|
4
|
+
# Preferred way is to Topoisomerase::Comments.add_for_class
|
5
|
+
#
|
6
|
+
# Topoisomerase.comments_added[PageObject] = [
|
7
|
+
# {
|
8
|
+
# message: "@return [PageObject::Elements::Element] An object representing the '<%= method_to_stub.to_s.gsub('_element', '') %>' element",
|
9
|
+
# matchers: { method_name: /_element$/ } # If either matcher matches, result returned
|
10
|
+
# },
|
11
|
+
# {
|
12
|
+
# message: "@return [Boolean] Whether the '<%= method_to_stub.to_s.gsub('?', '') %>' element is present",
|
13
|
+
# matchers: { method_name: /\?$/ }
|
14
|
+
# },
|
15
|
+
# # Testing whether 2 matchers use AND
|
16
|
+
# {
|
17
|
+
# message: "Set the text of the '<%= method_to_stub.to_s.gsub('?', '') %>' text field\n # @param [String] _value Value to set",
|
18
|
+
# matchers: { method_name: /=$/, source: /text_field_value_set/ }
|
19
|
+
# },
|
20
|
+
# {
|
21
|
+
# message: "Set the value of '<%= method_to_stub.to_s.gsub('?', '') %>' element\n # @param [String] _value Value to set",
|
22
|
+
# matchers: { method_name: /=$/ }
|
23
|
+
# },
|
24
|
+
# {
|
25
|
+
# message: "@return [String] The text of the '<%= method_to_stub.to_s.gsub('?', '') %>' element",
|
26
|
+
# matchers: { source: /\.text/ }
|
27
|
+
# },
|
28
|
+
# {
|
29
|
+
# message: "Click the '<%= method_to_stub.to_s.gsub('?', '') %>' element",
|
30
|
+
# matchers: { source: /\.click/ }
|
31
|
+
# }
|
32
|
+
# ]
|
33
|
+
|
34
|
+
|
35
|
+
# message: "@return [Watir::Elements::Element] An object representing the '<%= method_to_stub.to_s.gsub('_element', '') %>' element",
|
36
|
+
# matchers: { method_name: /_element$/ } # If either matcher matches, result returned
|
37
|
+
# },
|
38
|
+
|
39
|
+
Topoisomerase::Comments.add_for_class PageObject do
|
40
|
+
comment "Url of the page. Used by 'goto' method and when using 'visit'", method_name: 'page_url_value'
|
41
|
+
comment 'Open the page on the browser', method_name: 'goto'
|
42
|
+
comment "@return [PageObject::Elements::Element] An object representing the '<%= method_to_stub.to_s.gsub('_element', '') %>' element",
|
43
|
+
method_name: /_element$/
|
44
|
+
end
|
45
|
+
|
46
|
+
# This block demonstrates how a real browser could be used to create stubs.
|
47
|
+
# This however should not be necessary and be resorted to only if the MockBrowser does not
|
48
|
+
# work
|
49
|
+
#
|
50
|
+
# @return [Array] List of Selenium options
|
51
|
+
# def options
|
52
|
+
# [args: %w[--disable-popup-blocking
|
53
|
+
# --no-sandbox --disable-dev-shm-usage],
|
54
|
+
# headless: true]
|
55
|
+
# end
|
56
|
+
#
|
57
|
+
# require 'watir'
|
58
|
+
# browser = Watir::Browser.new :chrome, *options
|
59
|
+
# browser.close
|
60
|
+
|
61
|
+
# Mock class just to make instantiating a page object with a browser happy
|
62
|
+
class MockBrowser
|
63
|
+
# Called by PageObject though not needed for documentation
|
64
|
+
def bridge; end
|
65
|
+
end
|
66
|
+
|
67
|
+
Topoisomerase.create_stubs_based_on PageObject do |inheriting_class|
|
68
|
+
inheriting_class.new(MockBrowser.new, false)
|
69
|
+
end
|
data/todo.md
ADDED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: topoisomerase
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Samuel Garratt
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-05-
|
11
|
+
date: 2019-05-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: method_source
|
@@ -135,8 +135,8 @@ files:
|
|
135
135
|
- ".rspec"
|
136
136
|
- ".rubocop.yml"
|
137
137
|
- CODE_OF_CONDUCT.md
|
138
|
+
- ChangeLog
|
138
139
|
- Gemfile
|
139
|
-
- Gemfile.lock
|
140
140
|
- LICENSE.txt
|
141
141
|
- README.md
|
142
142
|
- Rakefile
|
@@ -144,10 +144,12 @@ files:
|
|
144
144
|
- bin/setup
|
145
145
|
- exe/topoisomerase
|
146
146
|
- lib/topoisomerase.rb
|
147
|
+
- lib/topoisomerase/comment_adder.rb
|
147
148
|
- lib/topoisomerase/core_ext/string.rb
|
148
|
-
- lib/topoisomerase/override_define.rb
|
149
149
|
- lib/topoisomerase/stub_template.rb.erb
|
150
|
+
- lib/topoisomerase/template/page_object.rb
|
150
151
|
- lib/topoisomerase/version.rb
|
152
|
+
- todo.md
|
151
153
|
- topoisomerase.gemspec
|
152
154
|
homepage: https://gitlab.com/samuel-garratt/topoisomerase
|
153
155
|
licenses:
|
data/Gemfile.lock
DELETED
@@ -1,93 +0,0 @@
|
|
1
|
-
PATH
|
2
|
-
remote: .
|
3
|
-
specs:
|
4
|
-
topoisomerase (0.1.0)
|
5
|
-
method_source
|
6
|
-
rubocop
|
7
|
-
|
8
|
-
GEM
|
9
|
-
remote: https://rubygems.org/
|
10
|
-
specs:
|
11
|
-
ast (2.4.0)
|
12
|
-
childprocess (1.0.1)
|
13
|
-
rake (< 13.0)
|
14
|
-
concurrent-ruby (1.1.5)
|
15
|
-
data_magic (1.2)
|
16
|
-
faker (>= 1.1.2)
|
17
|
-
yml_reader (>= 0.6)
|
18
|
-
diff-lcs (1.3)
|
19
|
-
faker (1.9.3)
|
20
|
-
i18n (>= 0.7)
|
21
|
-
i18n (1.6.0)
|
22
|
-
concurrent-ruby (~> 1.0)
|
23
|
-
jaro_winkler (1.5.2)
|
24
|
-
method_source (0.9.2)
|
25
|
-
mini_portile2 (2.4.0)
|
26
|
-
nokogiri (1.10.3)
|
27
|
-
mini_portile2 (~> 2.4.0)
|
28
|
-
page-object (2.2.5)
|
29
|
-
page_navigation (>= 0.10)
|
30
|
-
selenium-webdriver (~> 3.0)
|
31
|
-
watir (~> 6.8)
|
32
|
-
page_navigation (0.10)
|
33
|
-
data_magic (>= 0.22)
|
34
|
-
parallel (1.17.0)
|
35
|
-
parser (2.6.0.0)
|
36
|
-
ast (~> 2.4.0)
|
37
|
-
powerpack (0.1.2)
|
38
|
-
psych (3.1.0)
|
39
|
-
rainbow (3.0.0)
|
40
|
-
rake (10.5.0)
|
41
|
-
regexp_parser (1.3.0)
|
42
|
-
rspec (3.8.0)
|
43
|
-
rspec-core (~> 3.8.0)
|
44
|
-
rspec-expectations (~> 3.8.0)
|
45
|
-
rspec-mocks (~> 3.8.0)
|
46
|
-
rspec-core (3.8.0)
|
47
|
-
rspec-support (~> 3.8.0)
|
48
|
-
rspec-expectations (3.8.3)
|
49
|
-
diff-lcs (>= 1.2.0, < 2.0)
|
50
|
-
rspec-support (~> 3.8.0)
|
51
|
-
rspec-mocks (3.8.0)
|
52
|
-
diff-lcs (>= 1.2.0, < 2.0)
|
53
|
-
rspec-support (~> 3.8.0)
|
54
|
-
rspec-support (3.8.0)
|
55
|
-
rubocop (0.65.0)
|
56
|
-
jaro_winkler (~> 1.5.1)
|
57
|
-
parallel (~> 1.10)
|
58
|
-
parser (>= 2.5, != 2.5.1.1)
|
59
|
-
powerpack (~> 0.1)
|
60
|
-
psych (>= 3.1.0)
|
61
|
-
rainbow (>= 2.2.2, < 4.0)
|
62
|
-
ruby-progressbar (~> 1.7)
|
63
|
-
unicode-display_width (~> 1.4.0)
|
64
|
-
ruby-progressbar (1.10.0)
|
65
|
-
rubyzip (1.2.2)
|
66
|
-
selenium-webdriver (3.142.0)
|
67
|
-
childprocess (>= 0.5, < 2.0)
|
68
|
-
rubyzip (~> 1.2, >= 1.2.2)
|
69
|
-
unicode-display_width (1.4.1)
|
70
|
-
watir (6.16.5)
|
71
|
-
regexp_parser (~> 1.2)
|
72
|
-
selenium-webdriver (~> 3.6)
|
73
|
-
webdrivers (3.8.0)
|
74
|
-
nokogiri (~> 1.6)
|
75
|
-
rubyzip (~> 1.0)
|
76
|
-
selenium-webdriver (~> 3.0)
|
77
|
-
yard (0.9.19)
|
78
|
-
yml_reader (0.7)
|
79
|
-
|
80
|
-
PLATFORMS
|
81
|
-
ruby
|
82
|
-
|
83
|
-
DEPENDENCIES
|
84
|
-
bundler (~> 2.0)
|
85
|
-
page-object
|
86
|
-
rake
|
87
|
-
rspec (~> 3.0)
|
88
|
-
topoisomerase!
|
89
|
-
webdrivers
|
90
|
-
yard
|
91
|
-
|
92
|
-
BUNDLED WITH
|
93
|
-
2.0.1
|
@@ -1,13 +0,0 @@
|
|
1
|
-
# This is very dangerous. Overriding define_method.
|
2
|
-
# Only to be used for specific task of documenting dynamic methods used
|
3
|
-
class Object
|
4
|
-
def self.define_method(method_name)
|
5
|
-
Topoisomerase.dynamic_methods[self] = method_name
|
6
|
-
end
|
7
|
-
|
8
|
-
# I don't think I should include this. Safer and makes sense
|
9
|
-
# just to focus on definitions in custom classes
|
10
|
-
# def define_method(method_name)
|
11
|
-
# Topoisomerase.dynamic_methods[self] = method_name
|
12
|
-
# end
|
13
|
-
end
|