rbs 0.5.0 → 0.6.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.
@@ -125,6 +125,49 @@ module RBS
125
125
  end
126
126
  end
127
127
 
128
+ class NoSuperclassFoundError < StandardError
129
+ attr_reader :type_name
130
+ attr_reader :location
131
+
132
+ def initialize(type_name:, location:)
133
+ @type_name = type_name
134
+ @location = location
135
+
136
+ super "#{Location.to_string location}: Could not find super class: #{type_name}"
137
+ end
138
+
139
+ def self.check!(type_name, env:, location:)
140
+ env.class_decls.key?(type_name) or raise new(type_name: type_name, location: location)
141
+ end
142
+ end
143
+
144
+ class NoMixinFoundError < StandardError
145
+ attr_reader :type_name
146
+ attr_reader :member
147
+
148
+ def initialize(type_name:, member:)
149
+ @type_name = type_name
150
+ @member = member
151
+
152
+ super "#{Location.to_string location}: Could not find mixin: #{type_name}"
153
+ end
154
+
155
+ def location
156
+ member.location
157
+ end
158
+
159
+ def self.check!(type_name, env:, member:)
160
+ dic = case
161
+ when type_name.class?
162
+ env.class_decls
163
+ when type_name.interface?
164
+ env.interface_decls
165
+ end
166
+
167
+ dic.key?(type_name) or raise new(type_name: type_name, member: member)
168
+ end
169
+ end
170
+
128
171
  class DuplicatedMethodDefinitionError < StandardError
129
172
  attr_reader :decl
130
173
  attr_reader :location
@@ -187,17 +230,6 @@ module RBS
187
230
  end
188
231
  end
189
232
 
190
- class MixedClassModuleDeclarationError < StandardError
191
- attr_reader :name
192
- attr_reader :decl
193
-
194
- def initialize(name:, decl:)
195
- @name = name
196
- @decl = decl
197
- super "#{Location.to_string decl.location}: Both class and module declarations: #{name}"
198
- end
199
- end
200
-
201
233
  class SuperclassMismatchError < StandardError
202
234
  attr_reader :name
203
235
  attr_reader :entry
@@ -209,20 +241,6 @@ module RBS
209
241
  end
210
242
  end
211
243
 
212
- class ModuleSelfTypeMismatchError < StandardError
213
- attr_reader :name
214
- attr_reader :entry
215
- attr_reader :location
216
-
217
- def initialize(name:, entry:, location:)
218
- @name = name
219
- @entry = entry
220
- @location = location
221
-
222
- super "#{Location.to_string location}: Module self type mismatch: #{name}"
223
- end
224
- end
225
-
226
244
  class InconsistentMethodVisibilityError < StandardError
227
245
  attr_reader :type_name
228
246
  attr_reader :method_name
@@ -0,0 +1,14 @@
1
+ module RBS
2
+ class Factory
3
+ def type_name(string)
4
+ absolute = string.start_with?("::")
5
+
6
+ *path, name = string.delete_prefix("::").split("::").map(&:to_sym)
7
+
8
+ TypeName.new(
9
+ name: name,
10
+ namespace: Namespace.new(path: path, absolute: absolute)
11
+ )
12
+ end
13
+ end
14
+ end
@@ -106,28 +106,28 @@ rule
106
106
  }
107
107
 
108
108
  module_decl:
109
- annotations kMODULE start_new_scope class_name module_type_params module_self_type class_members kEND {
109
+ annotations kMODULE start_new_scope class_name module_type_params colon_module_self_types class_members kEND {
110
110
  reset_variable_scope
111
111
 
112
112
  location = val[1].location + val[7].location
113
113
  result = Declarations::Module.new(
114
114
  name: val[3].value,
115
115
  type_params: val[4]&.value || Declarations::ModuleTypeParams.empty,
116
- self_type: val[5],
116
+ self_types: val[5],
117
117
  members: val[6],
118
118
  annotations: val[0],
119
119
  location: location,
120
120
  comment: leading_comment(val[0].first&.location || location)
121
121
  )
122
122
  }
123
- | annotations kMODULE start_new_scope tUKEYWORD type class_members kEND {
123
+ | annotations kMODULE start_new_scope tUKEYWORD module_self_types class_members kEND {
124
124
  reset_variable_scope
125
125
 
126
126
  location = val[1].location + val[6].location
127
127
  result = Declarations::Module.new(
128
128
  name: val[3].value,
129
129
  type_params: Declarations::ModuleTypeParams.empty,
130
- self_type: val[4],
130
+ self_types: val[4],
131
131
  members: val[5],
132
132
  annotations: val[0],
133
133
  location: location,
@@ -135,12 +135,50 @@ rule
135
135
  )
136
136
  }
137
137
 
138
- module_self_type:
139
- { result = nil }
140
- | kCOLON type {
138
+ colon_module_self_types:
139
+ { result = [] }
140
+ | kCOLON module_self_types {
141
141
  result = val[1]
142
142
  }
143
143
 
144
+ module_self_types:
145
+ module_self_type {
146
+ result = [val[0]]
147
+ }
148
+ | module_self_types kCOMMA module_self_type {
149
+ result = val[0].push(val[2])
150
+ }
151
+
152
+ module_self_type:
153
+ qualified_name kLBRACKET type_list kRBRACKET {
154
+ name = val[0].value
155
+ args = val[2]
156
+ location = val[0].location + val[3].location
157
+
158
+ case
159
+ when name.class?
160
+ result = Declarations::Module::Self.new(name: name, args: args, location: location)
161
+ when name.interface?
162
+ result = Declarations::Module::Self.new(name: name, args: args, location: location)
163
+ else
164
+ raise SemanticsError.new("Module self type should be instance or interface", subject: val[0], location: val[0].location)
165
+ end
166
+ }
167
+ | qualified_name {
168
+ name = val[0].value
169
+ args = []
170
+ location = val[0].location
171
+
172
+ case
173
+ when name.class?
174
+ result = Declarations::Module::Self.new(name: name, args: args, location: location)
175
+ when name.interface?
176
+ result = Declarations::Module::Self.new(name: name, args: args, location: location)
177
+ else
178
+ raise SemanticsError.new("Module self type should be instance or interface", subject: val[0], location: val[0].location)
179
+ end
180
+ }
181
+
144
182
  class_members:
145
183
  { result = [] }
146
184
  | class_members class_member {
@@ -1030,6 +1068,7 @@ def initialize(type, buffer:, eof_re:)
1030
1068
  @eof = false
1031
1069
  @bound_variables_stack = []
1032
1070
  @comments = {}
1071
+ @ascii_only = buffer.content.ascii_only?
1033
1072
  end
1034
1073
 
1035
1074
  def start_merged_variables_scope
@@ -1123,8 +1162,9 @@ def push_comment(string, location)
1123
1162
  end
1124
1163
 
1125
1164
  def new_token(type, value = input.matched)
1126
- start_index = input.charpos - input.matched.size
1127
- end_index = input.charpos
1165
+ charpos = charpos(input)
1166
+ start_index = charpos - input.matched.size
1167
+ end_index = charpos
1128
1168
 
1129
1169
  location = RBS::Location.new(buffer: buffer,
1130
1170
  start_pos: start_index,
@@ -1133,6 +1173,14 @@ def new_token(type, value = input.matched)
1133
1173
  [type, LocatedValue.new(location: location, value: value)]
1134
1174
  end
1135
1175
 
1176
+ def charpos(scanner)
1177
+ if @ascii_only
1178
+ scanner.pos
1179
+ else
1180
+ scanner.charpos
1181
+ end
1182
+ end
1183
+
1136
1184
  def empty_params_result
1137
1185
  [
1138
1186
  [],
@@ -1250,8 +1298,9 @@ def next_token
1250
1298
  when input.scan(/\s+/)
1251
1299
  # skip
1252
1300
  when input.scan(/#(( *)|( ?(?<string>.*)))\n/)
1253
- start_index = input.charpos - input.matched.size
1254
- end_index = input.charpos-1
1301
+ charpos = charpos(input)
1302
+ start_index = charpos - input.matched.size
1303
+ end_index = charpos-1
1255
1304
 
1256
1305
  location = RBS::Location.new(buffer: buffer,
1257
1306
  start_pos: start_index,
@@ -81,7 +81,7 @@ module RBS
81
81
  mod = AST::Declarations::Module.new(
82
82
  name: const_to_name(module_name),
83
83
  type_params: AST::Declarations::ModuleTypeParams.empty,
84
- self_type: nil,
84
+ self_types: [],
85
85
  members: [],
86
86
  annotations: [],
87
87
  location: nil,
@@ -69,7 +69,7 @@ module RBS
69
69
  members: [],
70
70
  annotations: [],
71
71
  location: nil,
72
- self_type: nil,
72
+ self_types: [],
73
73
  comment: comment
74
74
  )
75
75
 
@@ -370,7 +370,7 @@ module RBS
370
370
  decl = AST::Declarations::Module.new(
371
371
  name: type_name,
372
372
  type_params: AST::Declarations::ModuleTypeParams.empty,
373
- self_type: nil,
373
+ self_types: [],
374
374
  members: [],
375
375
  annotations: [],
376
376
  location: nil,
@@ -1,6 +1,9 @@
1
+ require "securerandom"
2
+ require "rbs/test/observer"
1
3
  require "rbs/test/spy"
2
4
  require "rbs/test/errors"
3
5
  require "rbs/test/type_check"
6
+ require "rbs/test/tester"
4
7
  require "rbs/test/hook"
5
8
 
6
9
  module RBS
@@ -16,11 +19,86 @@ module RBS
16
19
  INSPECT = Kernel.instance_method(:inspect)
17
20
  METHODS = Kernel.instance_method(:methods)
18
21
 
19
- ArgumentsReturn = Struct.new(:arguments, :return_value, :exception, keyword_init: true)
22
+ class ArgumentsReturn
23
+ attr_reader :arguments
24
+ attr_reader :exit_value
25
+ attr_reader :exit_type
26
+
27
+ def initialize(arguments:, exit_value:, exit_type:)
28
+ @arguments = arguments
29
+ @exit_value = exit_value
30
+ @exit_type = exit_type
31
+ end
32
+
33
+ def self.return(arguments:, value:)
34
+ new(arguments: arguments, exit_value: value, exit_type: :return)
35
+ end
36
+
37
+ def self.exception(arguments:, exception:)
38
+ new(arguments: arguments, exit_value: exception, exit_type: :exception)
39
+ end
40
+
41
+ def self.break(arguments:)
42
+ new(arguments: arguments, exit_value: nil, exit_type: :break)
43
+ end
44
+
45
+ def return_value
46
+ raise unless exit_type == :return
47
+ exit_value
48
+ end
49
+
50
+ def exception
51
+ raise unless exit_type == :exception
52
+ exit_value
53
+ end
54
+
55
+ def return?
56
+ exit_type == :return
57
+ end
58
+
59
+ def exception?
60
+ exit_type == :exception
61
+ end
62
+
63
+ def break?
64
+ exit_type == :break
65
+ end
66
+ end
67
+
20
68
  CallTrace = Struct.new(:method_name, :method_call, :block_calls, :block_given, keyword_init: true)
21
69
 
22
- def self.call(receiver, method, *args, **kwargs, &block)
23
- method.bind_call(receiver, *args, **kwargs, &block)
70
+ class <<self
71
+ attr_accessor :suffix
72
+
73
+ def reset_suffix
74
+ self.suffix = "RBS_TEST_#{SecureRandom.hex(3)}"
75
+ end
76
+ end
77
+
78
+ reset_suffix
79
+
80
+ if ::UnboundMethod.instance_methods.include?(:bind_call)
81
+ def self.call(receiver, method, *args, &block)
82
+ method.bind_call(receiver, *args, &block)
83
+ end
84
+ else
85
+ def self.call(receiver, method, *args, &block)
86
+ method.bind(receiver).call(*args, &block)
87
+ end
24
88
  end
25
89
  end
26
90
  end
91
+
92
+ unless ::Module.private_instance_methods.include?(:ruby2_keywords)
93
+ class Module
94
+ private
95
+ def ruby2_keywords(*)
96
+ end
97
+ end
98
+ end
99
+
100
+ unless ::Proc.instance_methods.include?(:ruby2_keywords)
101
+ class Proc
102
+ def ruby2_keywords; end
103
+ end
104
+ end
@@ -28,7 +28,7 @@ module RBS
28
28
  end
29
29
 
30
30
  def self.inspect_(obj)
31
- Hook.inspect_(obj)
31
+ Test::INSPECT.bind(obj).call
32
32
  end
33
33
 
34
34
  def self.to_string(error)
@@ -3,291 +3,165 @@ require "pp"
3
3
 
4
4
  module RBS
5
5
  module Test
6
- class Hook
7
- class Error < Exception
8
- attr_reader :errors
9
-
10
- def initialize(errors)
11
- @errors = errors
12
- super "Type error detected: [#{errors.map {|e| Errors.to_string(e) }.join(", ")}]"
13
- end
14
- end
15
-
16
- attr_reader :env
17
- attr_reader :logger
18
-
19
- attr_reader :instance_module
20
- attr_reader :instance_methods
21
- attr_reader :singleton_module
22
- attr_reader :singleton_methods
23
-
24
- attr_reader :klass
25
- attr_reader :errors
26
-
27
- def builder
28
- @builder ||= DefinitionBuilder.new(env: env)
29
- end
30
-
31
- def typecheck
32
- @typecheck ||= TypeCheck.new(self_class: klass, builder: builder)
33
- end
34
-
35
- def initialize(env, klass, logger:, raise_on_error: false)
36
- @env = env
37
- @logger = logger
38
- @klass = klass
39
-
40
- @instance_module = Module.new
41
- @instance_methods = []
42
-
43
- @singleton_module = Module.new
44
- @singleton_methods = []
45
-
46
- @errors = []
47
-
48
- @raise_on_error = raise_on_error
49
- end
50
-
51
- def raise_on_error!(error = true)
52
- @raise_on_error = error
53
- self
54
- end
55
-
56
- def raise_on_error?
57
- @raise_on_error
58
- end
59
-
60
- def prepend!
61
- klass.prepend @instance_module
62
- klass.singleton_class.prepend @singleton_module
6
+ module Hook
7
+ OPERATORS = {
8
+ :== => "eqeq",
9
+ :=== => "eqeqeq",
10
+ :+ => "plus",
11
+ :- => "minus",
12
+ :* => "star",
13
+ :/ => "slash",
14
+ :> => "gt",
15
+ :>= => "gteq",
16
+ :< => "lt",
17
+ :<= => "lteq",
18
+ :<=> => "ufo",
19
+ :& => "amp",
20
+ :| => "vbar",
21
+ :^ => "hat",
22
+ :! => "not",
23
+ :<< => "lshift",
24
+ :>> => "rshift",
25
+ :~ => "tilda"
26
+ }
27
+ def self.alias_names(target)
28
+ case target
29
+ when *OPERATORS.keys
30
+ name = OPERATORS[target]
31
+ [
32
+ "#{name}____with__#{Test.suffix}",
33
+ "#{name}____without__#{Test.suffix}"
34
+ ]
35
+ else
36
+ aliased_target, punctuation = target.to_s.sub(/([?!=])$/, ''), $1
63
37
 
64
- if block_given?
65
- yield
66
- disable
38
+ [
39
+ "#{aliased_target}__with__#{Test.suffix}#{punctuation}",
40
+ "#{aliased_target}__without__#{Test.suffix}#{punctuation}"
41
+ ]
67
42
  end
68
-
69
- self
70
43
  end
71
44
 
72
- def self.install(env, klass, logger:)
73
- new(env, klass, logger: logger).prepend!
74
- end
75
-
76
- def refinement
77
- klass = self.klass
78
- instance_module = self.instance_module
79
- singleton_module = self.singleton_module
80
-
81
- Module.new do
82
- refine klass do
83
- prepend instance_module
84
- end
85
-
86
- refine klass.singleton_class do
87
- prepend singleton_module
88
- end
89
- end
90
- end
45
+ def self.setup_alias_method_chain(klass, target)
46
+ with_method, without_method = alias_names(target)
91
47
 
92
- def verify_all
93
- type_name = Namespace.parse(klass.name).to_type_name.absolute!
48
+ RBS.logger.debug "alias name: #{target}, #{with_method}, #{without_method}"
94
49
 
95
- builder.build_instance(type_name).tap do |definition|
96
- definition.methods.each do |name, method|
97
- if method.defined_in == type_name
98
- unless method.annotations.any? {|a| a.string == "rbs:test:skip" }
99
- logger.info "Installing a hook on #{type_name}##{name}: #{method.method_types.join(" | ")}"
100
- verify instance_method: name, types: method.method_types
101
- else
102
- logger.info "Skipping test of #{type_name}##{name}"
103
- end
104
- end
105
- end
106
- end
50
+ klass.instance_eval do
51
+ alias_method without_method, target
52
+ alias_method target, with_method
107
53
 
108
- builder.build_singleton(type_name).tap do |definition|
109
- definition.methods.each do |name, method|
110
- if method.defined_in == type_name || name == :new
111
- unless method.annotations.any? {|a| a.string == "rbs:test:skip" }
112
- logger.info "Installing a hook on #{type_name}.#{name}: #{method.method_types.join(" | ")}"
113
- verify singleton_method: name, types: method.method_types
114
- else
115
- logger.info "Skipping test of #{type_name}.#{name}"
116
- end
117
- end
54
+ case
55
+ when public_method_defined?(without_method)
56
+ public target
57
+ when protected_method_defined?(without_method)
58
+ protected target
59
+ when private_method_defined?(without_method)
60
+ private target
118
61
  end
119
62
  end
120
-
121
- self
122
- end
123
-
124
- def delegation(name, method_types, method_name)
125
- hook = self
126
-
127
- -> (*args, &block) do
128
- hook.logger.debug { "#{method_name} receives arguments: #{hook.inspect_(args)}" }
129
-
130
- block_calls = []
131
-
132
- if block
133
- original_block = block
134
-
135
- block = hook.call(Object.new, INSTANCE_EVAL) do |fresh_obj|
136
- ->(*as) do
137
- hook.logger.debug { "#{method_name} receives block arguments: #{hook.inspect_(as)}" }
138
-
139
- ret = if self.equal?(fresh_obj)
140
- original_block[*as]
141
- else
142
- hook.call(self, INSTANCE_EXEC, *as, &original_block)
143
- end
144
-
145
- block_calls << ArgumentsReturn.new(
146
- arguments: as,
147
- return_value: ret,
148
- exception: nil
149
- )
150
-
151
- hook.logger.debug { "#{method_name} returns from block: #{hook.inspect_(ret)}" }
152
-
153
- ret
154
- end.ruby2_keywords
155
- end
156
- end
157
-
158
- method = hook.call(self, METHOD, name)
159
- klass = hook.call(self, CLASS)
160
- singleton_klass = begin
161
- hook.call(self, SINGLETON_CLASS)
162
- rescue TypeError
163
- nil
164
- end
165
- prepended = klass.ancestors.include?(hook.instance_module) || singleton_klass&.ancestors&.include?(hook.singleton_module)
166
- exception = nil
167
- result = begin
168
- if prepended
169
- method.super_method.call(*args, &block)
170
- else
171
- # Using refinement
172
- method.call(*args, &block)
173
- end
174
- rescue Exception => e
175
- exception = e
176
- nil
177
- end
178
-
179
- hook.logger.debug { "#{method_name} returns: #{hook.inspect_(result)}" }
180
-
181
- call = CallTrace.new(method_call: ArgumentsReturn.new(arguments: args, return_value: result, exception: exception),
182
- block_calls: block_calls,
183
- block_given: block != nil)
184
-
185
- method_type_errors = method_types.map do |method_type|
186
- hook.typecheck.method_call(method_name, method_type, call, errors: [])
187
- end
188
-
189
- new_errors = []
190
-
191
- if method_type_errors.none?(&:empty?)
192
- if (best_errors = hook.find_best_errors(method_type_errors))
193
- new_errors.push(*best_errors)
194
- else
195
- new_errors << Errors::UnresolvedOverloadingError.new(
196
- klass: hook.klass,
197
- method_name: method_name,
198
- method_types: method_types
199
- )
200
- end
201
- end
202
-
203
- unless new_errors.empty?
204
- new_errors.each do |error|
205
- hook.logger.error Errors.to_string(error)
206
- end
207
-
208
- hook.errors.push(*new_errors)
209
-
210
- if hook.raise_on_error?
211
- raise Error.new(new_errors)
212
- end
213
- end
214
-
215
- result
216
- end.ruby2_keywords
217
63
  end
218
64
 
219
- def verify(instance_method: nil, singleton_method: nil, types:)
220
- method_types = types.map do |type|
221
- case type
222
- when String
223
- Parser.parse_method_type(type)
65
+ def self.hook_method_source(prefix, method_name, key)
66
+ with_name, without_name = alias_names(method_name)
67
+ full_method_name = "#{prefix}#{method_name}"
68
+
69
+ [__LINE__ + 1, <<RUBY]
70
+ def #{with_name}(*args)
71
+ ::RBS.logger.debug { "#{full_method_name} with arguments: [" + args.map(&:inspect).join(", ") + "]" }
72
+
73
+ begin
74
+ return_from_call = false
75
+ block_calls = []
76
+
77
+ if block_given?
78
+ result = __send__(:"#{without_name}", *args) do |*block_args|
79
+ return_from_block = false
80
+
81
+ begin
82
+ block_result = yield(*block_args)
83
+ return_from_block = true
84
+ ensure
85
+ exn = $!
86
+
87
+ case
88
+ when return_from_block
89
+ # Returned from yield
90
+ block_calls << ::RBS::Test::ArgumentsReturn.return(
91
+ arguments: block_args,
92
+ value: block_result
93
+ )
94
+ when exn
95
+ # Exception
96
+ block_calls << ::RBS::Test::ArgumentsReturn.exception(
97
+ arguments: block_args,
98
+ exception: exn
99
+ )
224
100
  else
225
- type
101
+ # break?
102
+ block_calls << ::RBS::Test::ArgumentsReturn.break(
103
+ arguments: block_args
104
+ )
226
105
  end
227
106
  end
228
107
 
229
- case
230
- when instance_method
231
- instance_methods << instance_method
232
- call(self.instance_module, DEFINE_METHOD, instance_method, &delegation(instance_method, method_types, "##{instance_method}"))
233
- when singleton_method
234
- call(self.singleton_module, DEFINE_METHOD, singleton_method, &delegation(singleton_method, method_types, ".#{singleton_method}"))
235
- end
236
-
237
- self
108
+ block_result
238
109
  end
110
+ else
111
+ result = __send__(:"#{without_name}", *args)
112
+ end
113
+ return_from_call = true
114
+ result
115
+ ensure
116
+ exn = $!
117
+
118
+ case
119
+ when return_from_call
120
+ ::RBS.logger.debug { "#{full_method_name} return with value: " + result.inspect }
121
+ method_call = ::RBS::Test::ArgumentsReturn.return(
122
+ arguments: args,
123
+ value: result
124
+ )
125
+ when exn
126
+ ::RBS.logger.debug { "#{full_method_name} exit with exception: " + exn.inspect }
127
+ method_call = ::RBS::Test::ArgumentsReturn.exception(
128
+ arguments: args,
129
+ exception: exn
130
+ )
131
+ else
132
+ ::RBS.logger.debug { "#{full_method_name} exit with jump" }
133
+ method_call = ::RBS::Test::ArgumentsReturn.break(arguments: args)
134
+ end
239
135
 
240
- def find_best_errors(errorss)
241
- if errorss.size == 1
242
- errorss[0]
243
- else
244
- no_arity_errors = errorss.select do |errors|
245
- errors.none? do |error|
246
- error.is_a?(Errors::ArgumentError) ||
247
- error.is_a?(Errors::BlockArgumentError) ||
248
- error.is_a?(Errors::MissingBlockError) ||
249
- error.is_a?(Errors::UnexpectedBlockError)
250
- end
251
- end
136
+ trace = ::RBS::Test::CallTrace.new(
137
+ method_name: #{method_name.inspect},
138
+ method_call: method_call,
139
+ block_calls: block_calls,
140
+ block_given: block_given?,
141
+ )
252
142
 
253
- unless no_arity_errors.empty?
254
- # Choose a error set which doesn't include arity error
255
- return no_arity_errors[0] if no_arity_errors.size == 1
256
- end
257
- end
258
- end
143
+ ::RBS::Test::Observer.notify(#{key.inspect}, self, trace)
144
+ end
259
145
 
260
- def self.backtrace(skip: 2)
261
- raise
262
- rescue => exn
263
- exn.backtrace.drop(skip)
264
- end
146
+ result
147
+ end
265
148
 
266
- def run
267
- yield
268
- self
269
- ensure
270
- disable
149
+ ruby2_keywords :#{with_name}
150
+ RUBY
271
151
  end
272
152
 
273
- def call(receiver, method, *args, &block)
274
- method.bind(receiver).call(*args, &block)
275
- end
153
+ def self.hook_instance_method(klass, method, key:)
154
+ line, source = hook_method_source("#{klass}#", method, key)
276
155
 
277
- def inspect_(obj)
278
- Hook.inspect_(obj)
156
+ klass.module_eval(source, __FILE__, line)
157
+ setup_alias_method_chain klass, method
279
158
  end
280
159
 
281
- def self.inspect_(obj)
282
- obj.inspect
283
- rescue
284
- INSPECT.bind(obj).call()
285
- end
160
+ def self.hook_singleton_method(klass, method, key:)
161
+ line, source = hook_method_source("#{klass}.",method, key)
286
162
 
287
- def disable
288
- self.instance_module.remove_method(*instance_methods)
289
- self.singleton_module.remove_method(*singleton_methods)
290
- self
163
+ klass.singleton_class.module_eval(source, __FILE__, line)
164
+ setup_alias_method_chain klass.singleton_class, method
291
165
  end
292
166
  end
293
167
  end