super_module 1.1.1 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9bd0e7f146de1366ca97c760ab283ca3f3623c44
4
- data.tar.gz: ce3dad2bf81e80135bfaaea2fbdf2e305359e8b6
3
+ metadata.gz: 2417fe4ac87bcf7e975d971de2f86caa01f1f357
4
+ data.tar.gz: 305eda58e8250ce45e24af27325ba09f2f34c9f1
5
5
  SHA512:
6
- metadata.gz: 6f28bdb35c1cf93c1a0b4a98d3f22726ca95e02e1f95458b1965fa2d097f6497da7c2359ae6dcb656db49c0443f5f8fe0c1f270efffee6a5ee0da91571247547
7
- data.tar.gz: d698ce744051e84c772eb32c38fed978e8b4711e846012a2c6cd8b3cc3058f8a95de27f2a28b01cdb7ca3ef01f44c5f249f282086d6187830adfbff7a6e96c8b
6
+ metadata.gz: f4eea83f2a17b20dd8c40ab3f5e710f702c501936fea5782dbfb8295ee5c3a8a7889479d742777bbfa6151d8aa6ccfdc71ab4fdbd9431e2a13dbd4f0986f1f1a
7
+ data.tar.gz: 071b746e0e94003c5716724e9b51744986bd28c388492ed55284d9c65f8c445393d2688e2e8be0046b101bbb6bccaed75a97a472c2356c4b748012541efbad2a
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # <img src="https://raw.githubusercontent.com/AndyObtiva/super_module/master/SuperModule.jpg" alt="SuperModule" align="left" height="50" /> &nbsp; SuperModule v1.1.1 [2015-04-09]
1
+ # <img src="https://raw.githubusercontent.com/AndyObtiva/super_module/master/SuperModule.jpg" alt="SuperModule" align="left" height="50" /> &nbsp; SuperModule 2 Beta (1.2.0)
2
2
  [![Gem Version](https://badge.fury.io/rb/super_module.svg)](http://badge.fury.io/rb/super_module)
3
3
  [![Build Status](https://api.travis-ci.org/AndyObtiva/super_module.svg?branch=master)](https://travis-ci.org/AndyObtiva/super_module)
4
4
  [![Coverage Status](https://coveralls.io/repos/AndyObtiva/super_module/badge.svg?branch=master)](https://coveralls.io/r/AndyObtiva/super_module?branch=master)
@@ -8,7 +8,7 @@ Calling [Ruby](https://www.ruby-lang.org/en/)'s [`Module#include`](http://ruby-d
8
8
 
9
9
  [`ActiveSupport::Concern`](http://api.rubyonrails.org/classes/ActiveSupport/Concern.html) is a popular Rails library that attempts to ease some of the boilerplate pain by offering a [DSL](http://www.infoq.com/news/2007/06/dsl-or-not) layer on top of [`Module.included(base)`](http://ruby-doc.org/core-2.2.1/Module.html#method-i-included). Unfortunately, while it improves the readability of the code needed to include class methods, it supports the same boilerplate idiom, thus feeling no more than putting a band-aid on the problem.
10
10
 
11
- Fortunately, [SuperModule](https://rubygems.org/gems/super_module) comes to the rescue. Including `SuperModule` at the top of a Ruby module's body automatically ensures inclusion of class methods whenever a developer mixes it in via [`Module#include`](http://ruby-doc.org/core-2.2.1/Module.html#method-i-include).
11
+ Fortunately, [SuperModule](https://rubygems.org/gems/super_module) comes to the rescue. By declaring your module as a `super_module`, it will automatically include class methods whenever it is mixed into a class or another module via [`Module#include`](http://ruby-doc.org/core-2.2.1/Module.html#method-i-include).
12
12
 
13
13
  ## Introductory Comparison
14
14
 
@@ -72,8 +72,7 @@ A step forward that addresses the boiler-plate repetitive code concern, but is o
72
72
  #### 3) [SuperModule](https://github.com/AndyObtiva/super_module)
73
73
 
74
74
  ```ruby
75
- module UserIdentifiable
76
- include SuperModule
75
+ super_module :UserIdentifiable do
77
76
  include ActiveModel::Model
78
77
 
79
78
  belongs_to :user
@@ -88,13 +87,21 @@ module UserIdentifiable
88
87
  end
89
88
  end
90
89
  ```
90
+ Using `super_module`, developers can directly add class method invocations and definitions inside the module's body, and [`SuperModule`](https://github.com/AndyObtiva/super_module) takes care of automatically mixing them into classes that include the module.
91
91
 
92
- With `include SuperModule` declared on top, developers can directly add class method invocations and definitions inside the module's body, and [`SuperModule`](https://github.com/AndyObtiva/super_module) takes care of automatically mixing them into classes that include the module.
93
-
94
- As a result, [SuperModule](https://rubygems.org/gems/super_module) collapses the difference between extending a super class and including a super module, thus encouraging developers to write simpler code while making better Object-Oriented Design decisions.
92
+ As a result, [SuperModule](https://rubygems.org/gems/super_module) collapses the difference between extending a super class and including a super module, thus encouraging developers to write simpler code while making better Object-Oriented Design decisions.
95
93
 
96
94
  In other words, [SuperModule](https://rubygems.org/gems/super_module) furthers Ruby's goal of making programmers happy.
97
95
 
96
+ By the way, SuperModule 2 Beta supports an alternate syntax as well:
97
+
98
+ ```ruby
99
+ UserIdentifiable = super_module do
100
+ end
101
+ ```
102
+
103
+
104
+
98
105
  ## Instructions
99
106
 
100
107
  #### 1) Install and require gem
@@ -115,11 +122,10 @@ Run the following command: <pre>gem install super_module</pre>
115
122
 
116
123
  Add the following at the top of your [Ruby](https://www.ruby-lang.org/en/) file: <pre>require 'super_module'</pre>
117
124
 
118
- #### 2) Include [`SuperModule`](https://rubygems.org/gems/super_module) at the top of the module
125
+ #### 2) Call `super_module(name)` and pass it the super module body in a block
119
126
 
120
127
  ```ruby
121
- module UserIdentifiable
122
- include SuperModule
128
+ super_module :UserIdentifiable do
123
129
  include ActiveModel::Model
124
130
 
125
131
  belongs_to :user
@@ -144,8 +150,7 @@ end
144
150
  class CourseEnrollment < ActiveRecord::Base
145
151
  include UserIdentifiable
146
152
  end
147
- module Accountable
148
- include SuperModule
153
+ super_module :Accountable do
149
154
  include UserIdentifiable
150
155
  end
151
156
  class Activity < ActiveRecord::Base
@@ -188,8 +193,7 @@ Create a ruby file called super_module_irb_example.rb with the following content
188
193
  require 'rubygems' # to be backwards compatible with Ruby 1.8.7
189
194
  require 'super_module'
190
195
 
191
- module RequiresAttributes
192
- include SuperModule
196
+ super_module :RequiresAttributes do
193
197
 
194
198
  def self.requires(*attributes)
195
199
  attributes.each {|attribute| required_attributes << attribute}
@@ -255,85 +259,20 @@ media_authorization.requirements_satisfied?
255
259
 
256
260
  ## How Does It Work?
257
261
 
258
- Here is the general algorithm from the implementation:
259
-
260
- ```ruby
261
- def included(base)
262
- __define_super_module_class_methods(base)
263
- __invoke_super_module_class_method_calls(base)
264
- end
265
- ```
266
-
267
- #### 1) Defines super module class methods on the including base class
268
-
269
- For example, suppose we have a super module called Addressable:
270
-
271
- ```ruby
272
- module Addressable
273
- include SuperModule
274
-
275
- include Locatable
276
- validates :city, presence: true, length: { maximum: 255 }
277
- validates :state, presence: true, length: { is: 2 }
278
-
279
- def self.merge_duplicates
280
- # 1. Look through all Addressable instances in the database
281
- # 2. Identify duplicates
282
- # 3. Merge duplicate addressables
283
- end
284
- end
285
-
286
- class Contact < ActiveRecord::Base
287
- include Addressable
288
- # … more code follows
289
- end
290
- ```
291
-
292
- This step ensures that <code>merge_duplicates</code> is included in Contact as a class method, allowing the call <code>Contact.merge_duplicates</code>
293
-
294
- It does so by recording every class method defined using the Ruby [`self.singleton_method_added(method_name)`](http://ruby-doc.org/core-2.2.1/BasicObject.html#method-i-singleton_method_added) hook, reading class method sources using the [method_source](https://rubygems.org/gems/method_source/) gem, and finally upon invocation of `self.included(base)`, `class_eval`ing the recorded class methods on the including base class (or module).
295
-
296
- In order to avoid interference with existing class method definitions, there is an exception list for what not to record, such as <code>:included_super_modules, :class_eval, :singleton_method_added</code> and any other "__" prefixed class methods defined in [SuperModule](https://rubygems.org/gems/super_module), such as <code>__super_module_class_method_calls</code>.
297
-
298
- Also, the recorded class method sources are altered to handle recording of method calls as well, which is used in the second step explained next.
299
-
300
- #### 2) Invoke super module class method calls on the including base class (or module).
301
-
302
- For example, suppose we have a super module called `Locatable`:
303
-
304
- ```ruby
305
- module Locatable
306
- include SuperModule
307
-
308
- validates :x_coordinate, numericality: true
309
- validates :y_coordinate, numericality: true
310
-
311
- def move(x, y)
312
- self.x_coordinate += x
313
- self.y_coordinate += y
314
- end
315
- end
316
-
317
- class Vehicle < ActiveRecord::Base
318
- include Locatable
319
- # … more code follows
320
- end
321
- ```
262
+ V2 has a much simpler algorithm than V1 that goes as follows:
322
263
 
323
- This step guarantees invocation of the two `Locatable` <code>validates</code> method calls on the `Vehicle` object class.
324
-
325
- It does so by relying on an interally defined method `__record_method_call(method_name, *args, &block)` to record every class method call that happens in the super module class body, and later replaying those calls on the including base class during `self.included(base)` by using Ruby's `send(method_name, *args, &block)` method introspection.
264
+ 1. Handle invocation of `super_module(name, &super_module_body)` method anywhere in the Ruby code where the block it receives represents the super module body, including instance methods, and class methods, and class body invocations.
265
+ 2. Clone `SuperModule` and store in it the passed in `super_module_body` block
266
+ 3. Assign the cloned `SuperModule` to a new constant as defined by name (e.g. 'Utilities::Printer') under a class, module, or the top-level Ruby scope
267
+ 4. When calling `include` on the module later on, its stored super_module_body attribute is retrieved and run in the including class or module body via `class_eval`
326
268
 
327
269
  ## Limitations and Caveats
328
270
 
329
- * [SuperModule](https://rubygems.org/gems/super_module) has been designed to be used only in the code definition of a module, not to be mixed in at run-time.
330
-
331
- * Initial Ruby runtime load of a class or module mixing in [SuperModule](https://rubygems.org/gems/super_module) will incur a very marginal performance hit (in the order of nano-to-milliseconds). However, class usage (instantiation and method invocation) will not incur any performance hit, running as fast as any other Ruby class.
271
+ * [SuperModule](https://rubygems.org/gems/super_module) has been designed to be used only in the initial code definition of a module (not supporting later re-opening of the module.)
332
272
 
333
273
  * Given [SuperModule](https://rubygems.org/gems/super_module)'s implementation relies on `self.included(base)`, if an including super module (or a super module including another super module) must hook into <code>self.included(base)</code> for meta-programming cases that require it, such as conditional `include` statements or method definitions, it would have to alias <code>self.included(base)</code> and then invoke the aliased version in every super module that needs it like in this example:
334
274
  ```ruby
335
- module AdminIdentifiable
336
- include SuperModule
275
+ super_module :AdminIdentifiable do
337
276
  include UserIdentifiable
338
277
 
339
278
  class << self
@@ -345,11 +284,19 @@ module AdminIdentifiable
345
284
  # or conditional definition of methods
346
285
  end
347
286
  end
287
+ end
348
288
  ```
349
289
  In the future, [SuperModule](https://rubygems.org/gems/super_module) could perhaps provide robust built-in facilities for allowing super modules to easily hook into <code>self.included(base)</code> without interfering with [SuperModule](https://rubygems.org/gems/super_module) behavior.
350
290
 
351
291
  ## What's New?
352
292
 
293
+ ### v2 Beta (v1.2.0)
294
+
295
+ * New `super_module(name)` syntax
296
+ * Much simpler implementation with guaranteed correctness and no performance hit
297
+ * Less memory footprint by not requiring method_source Ruby gem for v2 syntax
298
+ * Backwards compatibility with v1 syntax
299
+
353
300
  ### v1.1.1
354
301
 
355
302
  * Added support for private and protected methods
@@ -378,5 +325,5 @@ The library is quite new and can use all the feedback and help it can get. So, p
378
325
 
379
326
  ## Copyright
380
327
 
381
- Copyright (c) 2014-2015 Andy Maleh. See LICENSE.txt for
328
+ Copyright (c) 2014-2016 Andy Maleh. See LICENSE.txt for
382
329
  further details.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.1.1
1
+ 1.2.0
@@ -1,7 +1,6 @@
1
1
  require_relative '../../../lib/super_module'
2
2
 
3
- module Foo
4
- include SuperModule
3
+ super_module :Foo
5
4
  def self.hello
6
5
  self
7
6
  end
@@ -7,35 +7,50 @@
7
7
  # This module allows defining class methods and method invocations the same way a super class does without using def included(base).
8
8
 
9
9
  # Avoiding require_relative for backwards compatibility with Ruby 1.8.7
10
- require File.expand_path(File.join(File.dirname(__FILE__), 'super_module', 'module_body_method_call_recorder'))
11
- require File.expand_path(File.join(File.dirname(__FILE__), 'super_module', 'singleton_method_definition_store'))
12
10
 
13
11
  module SuperModule
14
- def self.included(original_base)
15
- original_base.class_eval do
16
- extend SuperModule::ModuleBodyMethodCallRecorder
17
- extend SuperModule::SingletonMethodDefinitionStore
18
-
19
- class << self
20
- def __define_super_module_singleton_methods(base)
21
- __super_module_singleton_methods.each do |method_name, method_body|
22
- # The following is needed for cases where a method is declared public/protected/private after it was added
23
- refreshed_access_level_method_body = method_body.sub(/class << self\n(public|protected|private)\n/, "class << self\n#{__singleton_method_access_level(method_name)}\n")
24
- base.class_eval(refreshed_access_level_method_body)
25
- end
26
- end
27
-
28
- def __invoke_module_body_method_calls(base)
29
- __all_module_body_method_calls_in_definition_order.each do |method_name, args, block|
30
- base.send(method_name, *args, &block)
31
- end
32
- end
33
-
34
- def included(base)
35
- __define_super_module_singleton_methods(base)
36
- __invoke_module_body_method_calls(base)
37
- end
12
+ class << self
13
+ V1_LIBRARY = File.expand_path(File.join(File.dirname(__FILE__), 'super_module', 'v1'))
14
+
15
+ attr_accessor :super_module_body
16
+
17
+ def define(&super_module_body)
18
+ clone.tap { |super_module| super_module.super_module_body = super_module_body }
19
+ end
20
+
21
+ def included(original_base)
22
+ if super_module_body
23
+ original_base.class_eval(&super_module_body)
24
+ else
25
+ require V1_LIBRARY
26
+ original_base.send(:include, SuperModule::V1)
27
+ end
28
+ end
29
+
30
+ def __super_module_parent(name, ancestor)
31
+ name_tokens = name.to_s.split('::')
32
+ name_token_count = name_tokens.size
33
+ if name_token_count == 1
34
+ ancestor
35
+ else
36
+ top_ancestor = ancestor.const_get(name_tokens.first)
37
+ sub_module_name = name_tokens[1, name_token_count].join('::')
38
+ __super_module_parent(sub_module_name, top_ancestor)
38
39
  end
39
40
  end
41
+
42
+ end
43
+
44
+ end
45
+
46
+ def super_module(name=nil, &super_module_body)
47
+ initial_ancestor = self.class == Object ? Object : self
48
+ SuperModule.define(&super_module_body).tap do |new_super_module|
49
+ if name
50
+ parent = SuperModule.__super_module_parent(name, initial_ancestor)
51
+ module_name = name.to_s.split('::').last
52
+ parent.const_set(module_name, new_super_module)
53
+ end
40
54
  end
41
55
  end
56
+
@@ -0,0 +1,37 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), 'v1', 'module_body_method_call_recorder'))
2
+ require File.expand_path(File.join(File.dirname(__FILE__), 'v1', 'singleton_method_definition_store'))
3
+
4
+ module SuperModule
5
+ module V1
6
+ class << self
7
+ def included(original_base)
8
+ original_base.class_eval do
9
+ extend SuperModule::V1::ModuleBodyMethodCallRecorder
10
+ extend SuperModule::V1::SingletonMethodDefinitionStore
11
+
12
+ class << self
13
+ def __define_super_module_singleton_methods(base)
14
+ __super_module_singleton_methods.each do |method_name, method_body|
15
+ # The following is needed for cases where a method is declared public/protected/private after it was added
16
+ refreshed_access_level_method_body = method_body.sub(/class << self\n(public|protected|private)\n/, "class << self\n#{__singleton_method_access_level(method_name)}\n")
17
+ base.class_eval(refreshed_access_level_method_body)
18
+ end
19
+ end
20
+
21
+ def __invoke_module_body_method_calls(base)
22
+ __all_module_body_method_calls_in_definition_order.each do |method_name, args, block|
23
+ base.send(method_name, *args, &block)
24
+ end
25
+ end
26
+
27
+ def included(base)
28
+ __define_super_module_singleton_methods(base)
29
+ __invoke_module_body_method_calls(base)
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+
@@ -0,0 +1,42 @@
1
+ module SuperModule
2
+ module V1
3
+ module ModuleBodyMethodCallRecorder
4
+ def __super_module_singleton_methods_excluded_from_call_recording
5
+ @__super_module_singleton_methods_excluded_from_call_recording ||= [
6
+ :__record_method_call,
7
+ :__method_signature
8
+ ]
9
+ end
10
+
11
+ def __module_body_method_calls
12
+ @__module_body_method_calls ||= []
13
+ end
14
+
15
+ def __method_signature(method_name, args)
16
+ "#{method_name}(#{args.to_a.map(&:to_s).join(",")})"
17
+ end
18
+
19
+ #TODO handle case of a method call being passed a block (e.g. validates do custom validator end )
20
+ def __record_method_call(method_name, *args, &block)
21
+ return if self.is_a?(Class)
22
+ __module_body_method_calls << [method_name, args, block]
23
+ end
24
+
25
+ def __all_module_body_method_calls_in_definition_order
26
+ ancestor_module_body_method_calls = included_super_modules.map(&:__module_body_method_calls).flatten(1)
27
+ all_module_body_method_calls = __module_body_method_calls + ancestor_module_body_method_calls
28
+ all_module_body_method_calls.reverse
29
+ end
30
+
31
+ def __singleton_method_call_recorder(method_name, method_args)
32
+ unless __super_module_singleton_methods_excluded_from_call_recording.include?(method_name)
33
+ method_call_recorder_args = "'#{method_name}'"
34
+ method_call_recorder_args << ", #{method_args}" unless method_args.to_s.strip == ''
35
+ "self.__record_method_call(#{method_call_recorder_args})"
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+
42
+
@@ -0,0 +1,106 @@
1
+ require 'method_source'
2
+ require File.expand_path(File.join(File.dirname(__FILE__), 'module_body_method_call_recorder')) # backwards compatible with Ruby 1.8.7
3
+
4
+ module SuperModule
5
+ module V1
6
+ module SingletonMethodDefinitionStore
7
+ # excluded list of singleton methods to define (perhaps give a better name)
8
+ def __super_module_singleton_methods_excluded_from_base_definition
9
+ @__super_module_singleton_methods_excluded_from_base_definition ||= [
10
+ :__all_module_body_method_calls_in_definition_order,
11
+ :__build_singleton_method_body_source,
12
+ :__define_super_module_singleton_methods,
13
+ :__invoke_module_body_method_calls,
14
+ :__module_body_method_calls,
15
+ :__overwrite_singleton_method_from_current_super_module,
16
+ :__singleton_method_args,
17
+ :__singleton_method_body,
18
+ :__singleton_method_body_for,
19
+ :__singleton_method_call_recorder,
20
+ :__singleton_method_definition_regex,
21
+ :__super_module_having_method,
22
+ :__super_module_singleton_methods,
23
+ :__super_module_singleton_methods_excluded_from_base_definition,
24
+ :__super_module_singleton_methods_excluded_from_call_recording,
25
+ :class_eval,
26
+ :dbg_print, #debugger library friendly exclusion
27
+ :dbg_puts, #debugger library friendly exclusion
28
+ :define,
29
+ :included,
30
+ :included_super_modules,
31
+ :singleton_method_added,
32
+ :super_module_body
33
+ ]
34
+ end
35
+
36
+ def __super_module_singleton_methods
37
+ @__super_module_singleton_methods ||= []
38
+ end
39
+
40
+ def __singleton_method_body_for(super_module, method_name)
41
+ super_module.__super_module_singleton_methods.detect {|sm_method_name, sm_method_body| sm_method_name == method_name}[1]
42
+ end
43
+
44
+ def included_super_modules
45
+ included_modules.select {|m| m.include?(SuperModule)}
46
+ end
47
+
48
+ def __all_methods(object)
49
+ object.public_methods + object.protected_methods + object.private_methods
50
+ end
51
+
52
+ def __super_module_having_method(method_name)
53
+ included_super_modules.detect {|included_super_module| __all_methods(included_super_module).map(&:to_s).include?(method_name.to_s)}
54
+ end
55
+
56
+ def __singleton_method_definition_regex(method_name)
57
+ /(public|protected|private)?(send)?[ \t(:"']*def(ine_method)?[ \t,:"']+(self\.)?#{method_name}\)?[ \tdo{(|]*([^\n)|;]*)?[ \t)|;]*/m
58
+ end
59
+
60
+ def __singleton_method_args(method_name, method_body)
61
+ method_arg_match = method_body.match(__singleton_method_definition_regex(method_name)).to_a[5]
62
+ end
63
+
64
+ def __singleton_method_access_level(method_name)
65
+ %w(private protected public).detect do |method_access|
66
+ method_group = "#{method_access}_methods"
67
+ send(method_group).map(&:to_s).include?(method_name.to_s)
68
+ end
69
+ end
70
+
71
+ def __build_singleton_method_body_source(method_name)
72
+ method_body = self.method(method_name).source
73
+ method_args = __singleton_method_args(method_name, method_body)
74
+ method_body = "def #{method_name}\n#{method_body}\nend" if method_args.nil?
75
+ class_self_method_def_enclosure = "class << self\n#{__singleton_method_access_level(method_name)}\ndef #{method_name}(#{method_args})\n#{__singleton_method_call_recorder(method_name, method_args)}\n"
76
+ method_body.sub(__singleton_method_definition_regex(method_name), class_self_method_def_enclosure) + "\nend\n"
77
+ end
78
+
79
+ def __singleton_method_body(method_name)
80
+ super_module_having_method = __super_module_having_method(method_name)
81
+ super_module_having_method ? __singleton_method_body_for(super_module_having_method, method_name) : __build_singleton_method_body_source(method_name)
82
+ end
83
+
84
+ def __overwrite_singleton_method_from_current_super_module(method_name, method_body)
85
+ if __super_module_having_method(method_name).nil?
86
+ __super_module_singleton_methods_excluded_from_base_definition << method_name
87
+ class_eval(method_body)
88
+ end
89
+ end
90
+
91
+ def singleton_method_added(method_name)
92
+ unless __super_module_singleton_methods_excluded_from_base_definition.include?(method_name)
93
+ method_body = __singleton_method_body(method_name)
94
+ __super_module_singleton_methods << [method_name, method_body]
95
+ __overwrite_singleton_method_from_current_super_module(method_name, method_body)
96
+ end
97
+ end
98
+
99
+ def self.extended(base)
100
+ base.extend(SuperModule::ModuleBodyMethodCallRecorder) unless base.respond_to?(:__record_method_call)
101
+ base.singleton_method_added(:__method_signature)
102
+ base.singleton_method_added(:__record_method_call)
103
+ end
104
+ end
105
+ end
106
+ end