steep 0.14.0 → 0.15.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (190) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +5 -0
  3. data/exe/rbs +1 -1
  4. data/lib/steep/annotation_parser.rb +4 -4
  5. data/lib/steep/ast/buffer.rb +11 -7
  6. data/lib/steep/ast/builtin.rb +8 -0
  7. data/lib/steep/ast/types/factory.rb +55 -55
  8. data/lib/steep/drivers/check.rb +20 -4
  9. data/lib/steep/drivers/langserver.rb +6 -1
  10. data/lib/steep/drivers/vendor.rb +2 -2
  11. data/lib/steep/project/completion_provider.rb +5 -11
  12. data/lib/steep/project/dsl.rb +14 -0
  13. data/lib/steep/project/file.rb +42 -46
  14. data/lib/steep/project/hover_content.rb +11 -5
  15. data/lib/steep/project/options.rb +25 -3
  16. data/lib/steep/project/target.rb +10 -4
  17. data/lib/steep/signature/errors.rb +1 -1
  18. data/lib/steep/signature/validator.rb +8 -8
  19. data/lib/steep/source.rb +1 -1
  20. data/lib/steep/type_construction.rb +987 -711
  21. data/lib/steep/type_inference/constant_env.rb +1 -1
  22. data/lib/steep/type_inference/context.rb +7 -3
  23. data/lib/steep/type_inference/context_array.rb +111 -0
  24. data/lib/steep/type_inference/local_variable_type_env.rb +226 -0
  25. data/lib/steep/type_inference/logic.rb +130 -0
  26. data/lib/steep/type_inference/type_env.rb +5 -69
  27. data/lib/steep/typing.rb +79 -22
  28. data/lib/steep/version.rb +1 -1
  29. data/lib/steep.rb +6 -1
  30. data/smoke/alias/Steepfile +1 -0
  31. data/smoke/and/Steepfile +1 -0
  32. data/smoke/array/Steepfile +1 -0
  33. data/smoke/array/b.rb +0 -2
  34. data/smoke/block/Steepfile +1 -0
  35. data/smoke/case/Steepfile +1 -0
  36. data/smoke/class/Steepfile +1 -0
  37. data/smoke/const/Steepfile +1 -0
  38. data/smoke/dstr/Steepfile +1 -0
  39. data/smoke/ensure/Steepfile +1 -0
  40. data/smoke/enumerator/Steepfile +1 -0
  41. data/smoke/extension/Steepfile +1 -0
  42. data/smoke/extension/c.rb +1 -0
  43. data/smoke/hash/Steepfile +1 -0
  44. data/smoke/hello/Steepfile +1 -0
  45. data/smoke/if/Steepfile +1 -0
  46. data/smoke/if/a.rb +1 -1
  47. data/smoke/implements/Steepfile +1 -0
  48. data/smoke/initialize/Steepfile +1 -0
  49. data/smoke/integer/Steepfile +1 -0
  50. data/smoke/interface/Steepfile +1 -0
  51. data/smoke/kwbegin/Steepfile +1 -0
  52. data/smoke/lambda/Steepfile +1 -0
  53. data/smoke/literal/Steepfile +1 -0
  54. data/smoke/map/Steepfile +1 -0
  55. data/smoke/method/Steepfile +1 -0
  56. data/smoke/module/Steepfile +1 -0
  57. data/smoke/regexp/Steepfile +1 -0
  58. data/smoke/regression/Steepfile +1 -0
  59. data/smoke/rescue/Steepfile +1 -0
  60. data/smoke/rescue/a.rb +1 -1
  61. data/smoke/self/Steepfile +1 -0
  62. data/smoke/skip/Steepfile +1 -0
  63. data/smoke/stdout/Steepfile +1 -0
  64. data/smoke/super/Steepfile +1 -0
  65. data/smoke/type_case/Steepfile +1 -0
  66. data/smoke/yield/Steepfile +1 -0
  67. data/steep.gemspec +1 -1
  68. data/vendor/ruby-signature/.gitignore +2 -2
  69. data/vendor/ruby-signature/README.md +2 -2
  70. data/vendor/ruby-signature/Rakefile +2 -2
  71. data/vendor/ruby-signature/bin/annotate-with-rdoc +14 -13
  72. data/vendor/ruby-signature/bin/console +1 -1
  73. data/vendor/ruby-signature/bin/sort +7 -6
  74. data/vendor/ruby-signature/bin/test_runner.rb +0 -1
  75. data/vendor/ruby-signature/docs/CONTRIBUTING.md +1 -1
  76. data/vendor/ruby-signature/docs/sigs.md +3 -3
  77. data/vendor/ruby-signature/docs/stdlib.md +1 -1
  78. data/vendor/ruby-signature/docs/syntax.md +9 -9
  79. data/vendor/ruby-signature/exe/rbs +5 -1
  80. data/vendor/ruby-signature/lib/rbs/ast/annotation.rb +27 -0
  81. data/vendor/ruby-signature/lib/rbs/ast/comment.rb +27 -0
  82. data/vendor/ruby-signature/lib/rbs/ast/declarations.rb +395 -0
  83. data/vendor/ruby-signature/lib/rbs/ast/members.rb +362 -0
  84. data/vendor/ruby-signature/lib/rbs/buffer.rb +50 -0
  85. data/vendor/ruby-signature/lib/rbs/builtin_names.rb +55 -0
  86. data/vendor/ruby-signature/lib/rbs/cli.rb +558 -0
  87. data/vendor/ruby-signature/lib/rbs/constant.rb +26 -0
  88. data/vendor/ruby-signature/lib/rbs/constant_table.rb +150 -0
  89. data/vendor/ruby-signature/lib/rbs/definition.rb +170 -0
  90. data/vendor/ruby-signature/lib/rbs/definition_builder.rb +919 -0
  91. data/vendor/ruby-signature/lib/rbs/environment.rb +281 -0
  92. data/vendor/ruby-signature/lib/rbs/environment_loader.rb +136 -0
  93. data/vendor/ruby-signature/lib/rbs/environment_walker.rb +124 -0
  94. data/vendor/ruby-signature/lib/rbs/errors.rb +187 -0
  95. data/vendor/ruby-signature/lib/rbs/location.rb +102 -0
  96. data/vendor/ruby-signature/lib/rbs/method_type.rb +123 -0
  97. data/vendor/ruby-signature/lib/rbs/namespace.rb +91 -0
  98. data/vendor/ruby-signature/lib/{ruby/signature → rbs}/parser.rb +21 -23
  99. data/vendor/ruby-signature/lib/{ruby/signature → rbs}/parser.y +18 -18
  100. data/vendor/ruby-signature/lib/rbs/prototype/rb.rb +553 -0
  101. data/vendor/ruby-signature/lib/rbs/prototype/rbi.rb +587 -0
  102. data/vendor/ruby-signature/lib/rbs/prototype/runtime.rb +381 -0
  103. data/vendor/ruby-signature/lib/rbs/substitution.rb +46 -0
  104. data/vendor/ruby-signature/lib/rbs/test/errors.rb +61 -0
  105. data/vendor/ruby-signature/lib/rbs/test/hook.rb +294 -0
  106. data/vendor/ruby-signature/lib/{ruby/signature → rbs}/test/setup.rb +7 -7
  107. data/vendor/ruby-signature/lib/rbs/test/spy.rb +325 -0
  108. data/vendor/ruby-signature/lib/rbs/test/test_helper.rb +183 -0
  109. data/vendor/ruby-signature/lib/rbs/test/type_check.rb +254 -0
  110. data/vendor/ruby-signature/lib/rbs/test.rb +26 -0
  111. data/vendor/ruby-signature/lib/rbs/type_name.rb +70 -0
  112. data/vendor/ruby-signature/lib/rbs/types.rb +936 -0
  113. data/vendor/ruby-signature/lib/rbs/variance_calculator.rb +138 -0
  114. data/vendor/ruby-signature/lib/rbs/vendorer.rb +47 -0
  115. data/vendor/ruby-signature/lib/rbs/version.rb +3 -0
  116. data/vendor/ruby-signature/lib/rbs/writer.rb +269 -0
  117. data/vendor/ruby-signature/lib/rbs.rb +64 -0
  118. data/vendor/ruby-signature/lib/ruby/signature.rb +4 -61
  119. data/vendor/ruby-signature/{ruby-signature.gemspec → rbs.gemspec} +4 -4
  120. data/vendor/ruby-signature/stdlib/abbrev/abbrev.rbs +58 -1
  121. data/vendor/ruby-signature/stdlib/base64/base64.rbs +69 -13
  122. data/vendor/ruby-signature/stdlib/benchmark/benchmark.rbs +372 -0
  123. data/vendor/ruby-signature/stdlib/builtin/builtin.rbs +9 -0
  124. data/vendor/ruby-signature/stdlib/builtin/dir.rbs +1 -7
  125. data/vendor/ruby-signature/stdlib/builtin/encoding.rbs +2 -1
  126. data/vendor/ruby-signature/stdlib/builtin/exception.rbs +3 -2
  127. data/vendor/ruby-signature/stdlib/builtin/file.rbs +902 -302
  128. data/vendor/ruby-signature/stdlib/builtin/gc.rbs +190 -68
  129. data/vendor/ruby-signature/stdlib/builtin/integer.rbs +3 -6
  130. data/vendor/ruby-signature/stdlib/builtin/kernel.rbs +6 -4
  131. data/vendor/ruby-signature/stdlib/builtin/marshal.rbs +146 -120
  132. data/vendor/ruby-signature/stdlib/builtin/math.rbs +310 -7
  133. data/vendor/ruby-signature/stdlib/builtin/method.rbs +11 -8
  134. data/vendor/ruby-signature/stdlib/builtin/module.rbs +959 -103
  135. data/vendor/ruby-signature/stdlib/builtin/proc.rbs +3 -0
  136. data/vendor/ruby-signature/stdlib/builtin/process.rbs +981 -108
  137. data/vendor/ruby-signature/stdlib/builtin/random.rbs +215 -41
  138. data/vendor/ruby-signature/stdlib/builtin/rb_config.rbs +47 -0
  139. data/vendor/ruby-signature/stdlib/builtin/string.rbs +9 -2
  140. data/vendor/ruby-signature/stdlib/builtin/string_io.rbs +282 -11
  141. data/vendor/ruby-signature/stdlib/builtin/symbol.rbs +11 -13
  142. data/vendor/ruby-signature/stdlib/builtin/thread.rbs +25 -29
  143. data/vendor/ruby-signature/stdlib/builtin/thread_group.rbs +1 -1
  144. data/vendor/ruby-signature/stdlib/builtin/time.rbs +875 -567
  145. data/vendor/ruby-signature/stdlib/builtin/trace_point.rbs +243 -44
  146. data/vendor/ruby-signature/stdlib/builtin/unbound_method.rbs +103 -109
  147. data/vendor/ruby-signature/stdlib/coverage/coverage.rbs +62 -0
  148. data/vendor/ruby-signature/stdlib/csv/csv.rbs +773 -0
  149. data/vendor/ruby-signature/stdlib/erb/erb.rbs +375 -1
  150. data/vendor/ruby-signature/stdlib/find/find.rbs +0 -4
  151. data/vendor/ruby-signature/stdlib/ipaddr/ipaddr.rbs +247 -0
  152. data/vendor/ruby-signature/stdlib/pathname/pathname.rbs +1088 -16
  153. data/vendor/ruby-signature/stdlib/set/set.rbs +251 -27
  154. metadata +49 -44
  155. data/exe/ruby-signature +0 -3
  156. data/vendor/ruby-signature/exe/ruby-signature +0 -7
  157. data/vendor/ruby-signature/lib/ruby/signature/ast/annotation.rb +0 -29
  158. data/vendor/ruby-signature/lib/ruby/signature/ast/comment.rb +0 -29
  159. data/vendor/ruby-signature/lib/ruby/signature/ast/declarations.rb +0 -391
  160. data/vendor/ruby-signature/lib/ruby/signature/ast/members.rb +0 -364
  161. data/vendor/ruby-signature/lib/ruby/signature/buffer.rb +0 -52
  162. data/vendor/ruby-signature/lib/ruby/signature/builtin_names.rb +0 -54
  163. data/vendor/ruby-signature/lib/ruby/signature/cli.rb +0 -555
  164. data/vendor/ruby-signature/lib/ruby/signature/constant.rb +0 -28
  165. data/vendor/ruby-signature/lib/ruby/signature/constant_table.rb +0 -152
  166. data/vendor/ruby-signature/lib/ruby/signature/definition.rb +0 -172
  167. data/vendor/ruby-signature/lib/ruby/signature/definition_builder.rb +0 -921
  168. data/vendor/ruby-signature/lib/ruby/signature/environment.rb +0 -283
  169. data/vendor/ruby-signature/lib/ruby/signature/environment_loader.rb +0 -138
  170. data/vendor/ruby-signature/lib/ruby/signature/environment_walker.rb +0 -126
  171. data/vendor/ruby-signature/lib/ruby/signature/errors.rb +0 -189
  172. data/vendor/ruby-signature/lib/ruby/signature/location.rb +0 -104
  173. data/vendor/ruby-signature/lib/ruby/signature/method_type.rb +0 -125
  174. data/vendor/ruby-signature/lib/ruby/signature/namespace.rb +0 -93
  175. data/vendor/ruby-signature/lib/ruby/signature/prototype/rb.rb +0 -444
  176. data/vendor/ruby-signature/lib/ruby/signature/prototype/rbi.rb +0 -579
  177. data/vendor/ruby-signature/lib/ruby/signature/prototype/runtime.rb +0 -383
  178. data/vendor/ruby-signature/lib/ruby/signature/substitution.rb +0 -48
  179. data/vendor/ruby-signature/lib/ruby/signature/test/errors.rb +0 -63
  180. data/vendor/ruby-signature/lib/ruby/signature/test/hook.rb +0 -290
  181. data/vendor/ruby-signature/lib/ruby/signature/test/spy.rb +0 -327
  182. data/vendor/ruby-signature/lib/ruby/signature/test/test_helper.rb +0 -185
  183. data/vendor/ruby-signature/lib/ruby/signature/test/type_check.rb +0 -256
  184. data/vendor/ruby-signature/lib/ruby/signature/test.rb +0 -28
  185. data/vendor/ruby-signature/lib/ruby/signature/type_name.rb +0 -72
  186. data/vendor/ruby-signature/lib/ruby/signature/types.rb +0 -932
  187. data/vendor/ruby-signature/lib/ruby/signature/variance_calculator.rb +0 -140
  188. data/vendor/ruby-signature/lib/ruby/signature/vendorer.rb +0 -49
  189. data/vendor/ruby-signature/lib/ruby/signature/version.rb +0 -5
  190. data/vendor/ruby-signature/lib/ruby/signature/writer.rb +0 -271
@@ -0,0 +1,294 @@
1
+ require "rbs"
2
+ require "pp"
3
+
4
+ module RBS
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
63
+
64
+ if block_given?
65
+ yield
66
+ disable
67
+ end
68
+
69
+ self
70
+ end
71
+
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
91
+
92
+ def verify_all
93
+ type_name = Namespace.parse(klass.name).to_type_name.absolute!
94
+
95
+ builder.build_instance(type_name).tap do |definition|
96
+ definition.methods.each do |name, method|
97
+ if method.defined_in.name.absolute! == 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
107
+
108
+ builder.build_singleton(type_name).tap do |definition|
109
+ definition.methods.each do |name, method|
110
+ if method.defined_in&.name&.absolute! == 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
118
+ end
119
+ 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
+ end
218
+
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)
224
+ else
225
+ type
226
+ end
227
+ end
228
+
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
238
+ end
239
+
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
252
+
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
259
+
260
+ def self.backtrace(skip: 2)
261
+ raise
262
+ rescue => exn
263
+ exn.backtrace.drop(skip)
264
+ end
265
+
266
+ def run
267
+ yield
268
+ self
269
+ ensure
270
+ disable
271
+ end
272
+
273
+ def call(receiver, method, *args, &block)
274
+ method.bind(receiver).call(*args, &block)
275
+ end
276
+
277
+ def inspect_(obj)
278
+ Hook.inspect_(obj)
279
+ end
280
+
281
+ def self.inspect_(obj)
282
+ obj.inspect
283
+ rescue
284
+ INSPECT.bind(obj).call()
285
+ end
286
+
287
+ def disable
288
+ self.instance_module.remove_method(*instance_methods)
289
+ self.singleton_module.remove_method(*singleton_methods)
290
+ self
291
+ end
292
+ end
293
+ end
294
+ end
@@ -1,5 +1,5 @@
1
- require "ruby/signature"
2
- require "ruby/signature/test"
1
+ require "rbs"
2
+ require "rbs/test"
3
3
 
4
4
  require "optparse"
5
5
  require "shellwords"
@@ -13,7 +13,7 @@ begin
13
13
  logger.level = (ENV["RBS_TEST_LOGLEVEL"] || "info")
14
14
  raise_on_error = ENV["RBS_TEST_RAISE"]
15
15
  rescue
16
- STDERR.puts "ruby/signature/test/setup handles the following environment variables:"
16
+ STDERR.puts "rbs/test/setup handles the following environment variables:"
17
17
  STDERR.puts " [REQUIRED] RBS_TEST_TARGET: test target class name, `Foo::Bar,Foo::Baz` for each class or `Foo::*` for all classes under `Foo`"
18
18
  STDERR.puts " [OPTIONAL] RBS_TEST_SKIP: skip testing classes"
19
19
  STDERR.puts " [OPTIONAL] RBS_TEST_OPT: options for signatures (`-r` for libraries or `-I` for signatures)"
@@ -24,9 +24,9 @@ end
24
24
 
25
25
  hooks = []
26
26
 
27
- env = Ruby::Signature::Environment.new
27
+ env = RBS::Environment.new
28
28
 
29
- loader = Ruby::Signature::EnvironmentLoader.new
29
+ loader = RBS::EnvironmentLoader.new
30
30
  OptionParser.new do |opts|
31
31
  opts.on("-r [LIB]") do |name| loader.add(library: name) end
32
32
  opts.on("-I [DIR]") do |dir| loader.add(path: Pathname(dir)) end
@@ -46,11 +46,11 @@ TracePoint.trace :end do |tp|
46
46
 
47
47
  if class_name
48
48
  if filter.any? {|f| match(f, class_name) } && skips.none? {|f| match(f, class_name) }
49
- type_name = Ruby::Signature::Namespace.parse(class_name).absolute!.to_type_name
49
+ type_name = RBS::Namespace.parse(class_name).absolute!.to_type_name
50
50
  if hooks.none? {|hook| hook.klass == tp.self }
51
51
  if env.find_class(type_name)
52
52
  logger.info "Setting up hooks for #{class_name}"
53
- hooks << Ruby::Signature::Test::Hook.install(env, tp.self, logger: logger).verify_all.raise_on_error!(raise_on_error)
53
+ hooks << RBS::Test::Hook.install(env, tp.self, logger: logger).verify_all.raise_on_error!(raise_on_error)
54
54
  end
55
55
  end
56
56
  end
@@ -0,0 +1,325 @@
1
+ module RBS
2
+ module Test
3
+ module Spy
4
+ def self.singleton_method(object, method_name)
5
+ spy = SingletonSpy.new(object: object, method_name: method_name)
6
+
7
+ if block_given?
8
+ begin
9
+ spy.setup
10
+ yield spy
11
+ ensure
12
+ spy.reset
13
+ end
14
+ else
15
+ spy
16
+ end
17
+ end
18
+
19
+ def self.instance_method(mod, method_name)
20
+ spy = InstanceSpy.new(mod: mod, method_name: method_name)
21
+
22
+ if block_given?
23
+ begin
24
+ spy.setup
25
+ yield spy
26
+ ensure
27
+ spy.reset
28
+ end
29
+ else
30
+ spy
31
+ end
32
+ end
33
+
34
+ def self.wrap(object, method_name)
35
+ spy = WrapSpy.new(object: object, method_name: method_name)
36
+
37
+ if block_given?
38
+ begin
39
+ yield spy, spy.wrapped_object
40
+ end
41
+ else
42
+ spy
43
+ end
44
+ end
45
+
46
+ class SingletonSpy
47
+ attr_accessor :callback
48
+ attr_reader :method_name
49
+ attr_reader :object
50
+
51
+ def initialize(object:, method_name:)
52
+ @object = object
53
+ @method_name = method_name
54
+ @callback = -> (_) { }
55
+ end
56
+
57
+ def setup
58
+ spy = self
59
+
60
+ object.singleton_class.class_eval do
61
+ remove_method spy.method_name
62
+ define_method spy.method_name, spy.spy()
63
+ end
64
+ end
65
+
66
+ def spy()
67
+ spy = self
68
+
69
+ -> (*args, &block) do
70
+ return_value = nil
71
+ exception = nil
72
+ block_calls = []
73
+
74
+ spy_block = if block
75
+ Object.new.instance_eval do |fresh|
76
+ -> (*block_args) do
77
+ block_exn = nil
78
+ block_return = nil
79
+
80
+ begin
81
+ block_return = if self.equal?(fresh)
82
+ # no instance eval
83
+ block.call(*block_args)
84
+ else
85
+ self.instance_exec(*block_args, &block)
86
+ end
87
+ rescue Exception => exn
88
+ block_exn = exn
89
+ end
90
+
91
+ block_calls << ArgumentsReturn.new(
92
+ arguments: block_args,
93
+ return_value: block_return,
94
+ exception: block_exn
95
+ )
96
+
97
+ if block_exn
98
+ raise block_exn
99
+ else
100
+ block_return
101
+ end
102
+ end.ruby2_keywords
103
+ end
104
+ end
105
+
106
+ begin
107
+ return_value = super(*args, &spy_block)
108
+ rescue Exception => exn
109
+ exception = exn
110
+ end
111
+
112
+ trace = CallTrace.new(
113
+ method_name: spy.method_name,
114
+ method_call: ArgumentsReturn.new(
115
+ arguments: args,
116
+ return_value: return_value,
117
+ exception: exception,
118
+ ),
119
+ block_calls: block_calls,
120
+ block_given: block != nil
121
+ )
122
+
123
+ spy.callback.call(trace)
124
+
125
+ if exception
126
+ raise exception
127
+ else
128
+ return_value
129
+ end
130
+ end.ruby2_keywords
131
+ end
132
+
133
+ def reset
134
+ if object.singleton_class.methods.include?(method_name)
135
+ object.singleton_class.remove_method method_name
136
+ end
137
+ end
138
+ end
139
+
140
+ class InstanceSpy
141
+ attr_accessor :callback
142
+ attr_reader :mod
143
+ attr_reader :method_name
144
+ attr_reader :original_method
145
+
146
+ def initialize(mod:, method_name:)
147
+ @mod = mod
148
+ @method_name = method_name
149
+ @original_method = mod.instance_method(method_name)
150
+ @callback = -> (_) { }
151
+ end
152
+
153
+ def setup
154
+ spy = self
155
+
156
+ mod.class_eval do
157
+ remove_method spy.method_name
158
+ define_method spy.method_name, spy.spy()
159
+ end
160
+ end
161
+
162
+ def reset
163
+ spy = self
164
+
165
+ mod.class_eval do
166
+ remove_method spy.method_name
167
+ define_method spy.method_name, spy.original_method
168
+ end
169
+ end
170
+
171
+ def spy
172
+ spy = self
173
+
174
+ -> (*args, &block) do
175
+ return_value = nil
176
+ exception = nil
177
+ block_calls = []
178
+
179
+ spy_block = if block
180
+ Object.new.instance_eval do |fresh|
181
+ -> (*block_args) do
182
+ block_exn = nil
183
+ block_return = nil
184
+
185
+ begin
186
+ block_return = if self.equal?(fresh)
187
+ # no instance eval
188
+ block.call(*block_args)
189
+ else
190
+ self.instance_exec(*block_args, &block)
191
+ end
192
+ rescue Exception => exn
193
+ block_exn = exn
194
+ end
195
+
196
+ block_calls << ArgumentsReturn.new(
197
+ arguments: block_args,
198
+ return_value: block_return,
199
+ exception: block_exn
200
+ )
201
+
202
+ if block_exn
203
+ raise block_exn
204
+ else
205
+ block_return
206
+ end
207
+ end.ruby2_keywords
208
+ end
209
+ end
210
+
211
+ begin
212
+ return_value = spy.original_method.bind_call(self, *args, &spy_block)
213
+ rescue Exception => exn
214
+ exception = exn
215
+ end
216
+
217
+ trace = CallTrace.new(
218
+ method_name: spy.method_name,
219
+ method_call: ArgumentsReturn.new(
220
+ arguments: args,
221
+ return_value: return_value,
222
+ exception: exception,
223
+ ),
224
+ block_calls: block_calls,
225
+ block_given: block != nil
226
+ )
227
+
228
+ spy.callback.call(trace)
229
+
230
+ if exception
231
+ raise exception
232
+ else
233
+ return_value
234
+ end
235
+ end.ruby2_keywords
236
+ end
237
+ end
238
+
239
+ class WrapSpy
240
+ attr_accessor :callback
241
+ attr_reader :object
242
+ attr_reader :method_name
243
+
244
+ def initialize(object:, method_name:)
245
+ @callback = -> (_) { }
246
+ @object = object
247
+ @method_name = method_name
248
+ end
249
+
250
+ def wrapped_object
251
+ spy = self
252
+
253
+ Class.new(BasicObject) do
254
+ define_method(:method_missing) do |name, *args, &block|
255
+ spy.object.__send__(name, *args, &block)
256
+ end
257
+
258
+ define_method(spy.method_name, -> (*args, &block) {
259
+ return_value = nil
260
+ exception = nil
261
+ block_calls = []
262
+
263
+ spy_block = if block
264
+ Object.new.instance_eval do |fresh|
265
+ -> (*block_args) do
266
+ block_exn = nil
267
+ block_return = nil
268
+
269
+ begin
270
+ block_return = if self.equal?(fresh)
271
+ # no instance eval
272
+ block.call(*block_args)
273
+ else
274
+ self.instance_exec(*block_args, &block)
275
+ end
276
+ rescue Exception => exn
277
+ block_exn = exn
278
+ end
279
+
280
+ block_calls << ArgumentsReturn.new(
281
+ arguments: block_args,
282
+ return_value: block_return,
283
+ exception: block_exn
284
+ )
285
+
286
+ if block_exn
287
+ raise block_exn
288
+ else
289
+ block_return
290
+ end
291
+ end.ruby2_keywords
292
+ end
293
+ end
294
+
295
+ begin
296
+ return_value = spy.object.__send__(spy.method_name, *args, &spy_block)
297
+ rescue ::Exception => exn
298
+ exception = exn
299
+ end
300
+
301
+ trace = CallTrace.new(
302
+ method_name: spy.method_name,
303
+ method_call: ArgumentsReturn.new(
304
+ arguments: args,
305
+ return_value: return_value,
306
+ exception: exception,
307
+ ),
308
+ block_calls: block_calls,
309
+ block_given: block != nil
310
+ )
311
+
312
+ spy.callback.call(trace)
313
+
314
+ if exception
315
+ spy.object.__send__(:raise, exception)
316
+ else
317
+ return_value
318
+ end
319
+ }.ruby2_keywords)
320
+ end.new()
321
+ end
322
+ end
323
+ end
324
+ end
325
+ end