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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +9 -0
- data/Gemfile +2 -0
- data/Rakefile +2 -3
- data/docs/stdlib.md +0 -2
- data/docs/syntax.md +6 -3
- data/goodcheck.yml +65 -0
- data/lib/rbs.rb +1 -0
- data/lib/rbs/ast/declarations.rb +44 -6
- data/lib/rbs/definition_builder.rb +33 -34
- data/lib/rbs/environment.rb +49 -36
- data/lib/rbs/errors.rb +43 -25
- data/lib/rbs/factory.rb +14 -0
- data/lib/rbs/parser.y +60 -11
- data/lib/rbs/prototype/rb.rb +1 -1
- data/lib/rbs/prototype/rbi.rb +1 -1
- data/lib/rbs/prototype/runtime.rb +1 -1
- data/lib/rbs/test.rb +81 -3
- data/lib/rbs/test/errors.rb +1 -1
- data/lib/rbs/test/hook.rb +133 -259
- data/lib/rbs/test/observer.rb +17 -0
- data/lib/rbs/test/setup.rb +12 -15
- data/lib/rbs/test/spy.rb +0 -321
- data/lib/rbs/test/tester.rb +116 -0
- data/lib/rbs/test/type_check.rb +43 -5
- data/lib/rbs/version.rb +1 -1
- data/lib/rbs/writer.rb +2 -2
- data/schema/decls.json +21 -10
- data/stdlib/builtin/proc.rbs +1 -2
- data/stdlib/logger/formatter.rbs +23 -0
- data/stdlib/logger/log_device.rbs +39 -0
- data/stdlib/logger/logger.rbs +507 -0
- data/stdlib/logger/period.rbs +7 -0
- data/stdlib/logger/severity.rbs +8 -0
- metadata +11 -3
- data/lib/rbs/test/test_helper.rb +0 -180
data/lib/rbs/errors.rb
CHANGED
@@ -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
|
data/lib/rbs/factory.rb
ADDED
@@ -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
|
data/lib/rbs/parser.y
CHANGED
@@ -106,28 +106,28 @@ rule
|
|
106
106
|
}
|
107
107
|
|
108
108
|
module_decl:
|
109
|
-
annotations kMODULE start_new_scope class_name module_type_params
|
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
|
-
|
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
|
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
|
-
|
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
|
-
|
139
|
-
{ result =
|
140
|
-
| kCOLON
|
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
|
-
|
1127
|
-
|
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
|
-
|
1254
|
-
|
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,
|
data/lib/rbs/prototype/rb.rb
CHANGED
data/lib/rbs/prototype/rbi.rb
CHANGED
data/lib/rbs/test.rb
CHANGED
@@ -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
|
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
|
-
|
23
|
-
|
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
|
data/lib/rbs/test/errors.rb
CHANGED
data/lib/rbs/test/hook.rb
CHANGED
@@ -3,291 +3,165 @@ require "pp"
|
|
3
3
|
|
4
4
|
module RBS
|
5
5
|
module Test
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
def
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
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
|
-
|
65
|
-
|
66
|
-
|
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.
|
73
|
-
|
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
|
-
|
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
|
-
|
96
|
-
|
97
|
-
|
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
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
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
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
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
|
-
|
101
|
+
# break?
|
102
|
+
block_calls << ::RBS::Test::ArgumentsReturn.break(
|
103
|
+
arguments: block_args
|
104
|
+
)
|
226
105
|
end
|
227
106
|
end
|
228
107
|
|
229
|
-
|
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
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
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
|
-
|
254
|
-
|
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
|
-
|
261
|
-
|
262
|
-
rescue => exn
|
263
|
-
exn.backtrace.drop(skip)
|
264
|
-
end
|
146
|
+
result
|
147
|
+
end
|
265
148
|
|
266
|
-
|
267
|
-
|
268
|
-
self
|
269
|
-
ensure
|
270
|
-
disable
|
149
|
+
ruby2_keywords :#{with_name}
|
150
|
+
RUBY
|
271
151
|
end
|
272
152
|
|
273
|
-
def
|
274
|
-
|
275
|
-
end
|
153
|
+
def self.hook_instance_method(klass, method, key:)
|
154
|
+
line, source = hook_method_source("#{klass}#", method, key)
|
276
155
|
|
277
|
-
|
278
|
-
|
156
|
+
klass.module_eval(source, __FILE__, line)
|
157
|
+
setup_alias_method_chain klass, method
|
279
158
|
end
|
280
159
|
|
281
|
-
def self.
|
282
|
-
|
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
|
-
|
288
|
-
|
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
|