raap 0.2.0 → 0.4.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/.rubocop.yml +29 -0
- data/README.md +27 -1
- data/Rakefile +10 -1
- data/exe/raap +3 -1
- data/lib/raap/bind_call.rb +18 -6
- data/lib/raap/cli.rb +194 -112
- data/lib/raap/function_type.rb +14 -10
- data/lib/raap/method_property.rb +77 -49
- data/lib/raap/method_type.rb +13 -6
- data/lib/raap/minitest.rb +7 -3
- data/lib/raap/rbs.rb +19 -0
- data/lib/raap/result.rb +89 -8
- data/lib/raap/sized.rb +2 -0
- data/lib/raap/symbolic_caller.rb +74 -38
- data/lib/raap/type.rb +93 -77
- data/lib/raap/type_substitution.rb +2 -1
- data/lib/raap/value/interface.rb +15 -7
- data/lib/raap/value/intersection.rb +22 -10
- data/lib/raap/value/module.rb +46 -6
- data/lib/raap/value/variable.rb +10 -1
- data/lib/raap/version.rb +1 -1
- data/lib/raap.rb +3 -3
- data/public/jacket.webp +0 -0
- data/rbs_collection.lock.yaml +61 -1
- data/rbs_collection.yaml +0 -1
- data/sig/raap.rbs +89 -75
- data/sig/shims.rbs +4 -0
- metadata +10 -10
- data/lib/raap/method_value.rb +0 -38
data/lib/raap/method_property.rb
CHANGED
@@ -2,24 +2,19 @@
|
|
2
2
|
|
3
3
|
module RaaP
|
4
4
|
class MethodProperty
|
5
|
-
class Stats < Struct.new(:success, :skip, :exception)
|
6
|
-
def initialize(success: 0, skip: 0, exception: 0)
|
5
|
+
class Stats < Struct.new(:success, :skip, :exception, :break)
|
6
|
+
def initialize(success: 0, skip: 0, exception: 0, break: false)
|
7
7
|
super
|
8
8
|
end
|
9
9
|
end
|
10
10
|
|
11
|
-
|
12
|
-
attr_reader :method_name
|
13
|
-
attr_reader :method_type
|
14
|
-
attr_reader :size_step
|
15
|
-
attr_reader :timeout
|
16
|
-
|
17
|
-
def initialize(receiver_type:, method_name:, method_type:, size_step:, timeout:)
|
11
|
+
def initialize(receiver_type:, method_name:, method_type:, size_step:, timeout:, allow_private: false)
|
18
12
|
@receiver_type = receiver_type
|
19
13
|
@method_name = method_name
|
20
14
|
@method_type = method_type
|
21
15
|
@size_step = size_step
|
22
16
|
@timeout = timeout
|
17
|
+
@allow_private = allow_private
|
23
18
|
end
|
24
19
|
|
25
20
|
def run
|
@@ -28,12 +23,26 @@ module RaaP
|
|
28
23
|
Timeout.timeout(@timeout) do
|
29
24
|
catch(:break) do
|
30
25
|
@size_step.each do |size|
|
31
|
-
|
26
|
+
call(size:, stats:).tap do |ret|
|
27
|
+
case ret
|
28
|
+
when Result::Success
|
29
|
+
stats.success += 1
|
30
|
+
when Result::Failure
|
31
|
+
# no count
|
32
|
+
when Result::Skip
|
33
|
+
stats.skip += 1
|
34
|
+
when Result::Exception
|
35
|
+
stats.exception += 1
|
36
|
+
end
|
37
|
+
|
38
|
+
yield ret
|
39
|
+
end
|
32
40
|
end
|
33
41
|
end
|
34
42
|
end
|
35
43
|
rescue Timeout::Error => exception
|
36
|
-
|
44
|
+
stats.break = true
|
45
|
+
RaaP.logger.info "Timeout: #{exception}"
|
37
46
|
end
|
38
47
|
stats
|
39
48
|
end
|
@@ -41,60 +50,75 @@ module RaaP
|
|
41
50
|
private
|
42
51
|
|
43
52
|
def call(size:, stats:)
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
53
|
+
if @method_type.rbs.each_type.find { |t| t.instance_of?(::RBS::Types::Bases::Any) }
|
54
|
+
RaaP.logger.info { "Skip type check since `#{@method_type.rbs}` includes `untyped`" }
|
55
|
+
stats.break = true
|
56
|
+
throw :break
|
57
|
+
end
|
58
|
+
receiver_value = @receiver_type.to_symbolic_call(size:)
|
59
|
+
args, kwargs, block = @method_type.arguments_to_symbolic_call(size:)
|
60
|
+
# @type var symbolic_call: symbolic_call
|
61
|
+
symbolic_call = [:call, receiver_value, @method_name, args, kwargs, block]
|
62
|
+
symbolic_caller = SymbolicCaller.new(symbolic_call, allow_private: @allow_private)
|
48
63
|
begin
|
49
|
-
# ensure
|
50
|
-
check =
|
64
|
+
# ensure symbolic_call
|
65
|
+
check = [:failure]
|
51
66
|
if return_type.instance_of?(::RBS::Types::Bases::Bottom)
|
52
67
|
begin
|
53
|
-
return_value =
|
54
|
-
rescue
|
55
|
-
check =
|
68
|
+
return_value = symbolic_caller.eval
|
69
|
+
rescue StandardError, NotImplementedError
|
70
|
+
check = [:success]
|
56
71
|
return_value = Value::Bottom.new
|
72
|
+
rescue Timeout::ExitException
|
73
|
+
raise
|
74
|
+
rescue Exception => e # rubocop:disable Lint/RescueException
|
75
|
+
RaaP.logger.error("[#{e.class}] class is not supported to check `bot` type")
|
76
|
+
raise
|
57
77
|
end
|
58
78
|
else
|
59
|
-
return_value =
|
60
|
-
check = check_return(receiver_value:, return_value
|
79
|
+
return_value = symbolic_caller.eval
|
80
|
+
check = check_return(receiver_value:, return_value:)
|
61
81
|
end
|
62
|
-
|
63
|
-
|
64
|
-
Result::Success.new(
|
65
|
-
|
66
|
-
Result::Failure.new(
|
82
|
+
case check
|
83
|
+
in [:success]
|
84
|
+
Result::Success.new(symbolic_call:, return_value:)
|
85
|
+
in [:failure]
|
86
|
+
Result::Failure.new(symbolic_call:, return_value:)
|
87
|
+
in [:exception, exception]
|
88
|
+
Result::Exception.new(symbolic_call:, exception:)
|
67
89
|
end
|
68
90
|
rescue TypeError => exception
|
69
|
-
Result::Failure.new(
|
91
|
+
Result::Failure.new(symbolic_call:, return_value:, exception:)
|
70
92
|
end
|
71
93
|
|
72
|
-
# not ensure
|
73
|
-
rescue NoMethodError => exception
|
74
|
-
|
75
|
-
Result::Skip.new(method_value:, exception:)
|
94
|
+
# not ensure symbolic_call
|
95
|
+
rescue NoMethodError, NotImplementedError => exception
|
96
|
+
Result::Skip.new(symbolic_call:, exception:)
|
76
97
|
rescue NameError => e
|
98
|
+
RaaP.logger.error("[#{e.class}] #{e.detailed_message}")
|
77
99
|
msg = e.name.nil? ? '' : "for `#{BindCall.to_s(e.receiver)}::#{e.name}`"
|
78
|
-
RaaP.logger.
|
100
|
+
RaaP.logger.warn("Implementation is not found #{msg} maybe.")
|
101
|
+
RaaP.logger.debug(e.backtrace&.join("\n"))
|
102
|
+
stats.break = true
|
79
103
|
throw :break
|
80
|
-
rescue NotImplementedError => exception
|
81
|
-
stats.skip += 1
|
82
|
-
Result::Skip.new(method_value:, exception:)
|
83
104
|
rescue SystemStackError => exception
|
84
|
-
|
85
|
-
|
86
|
-
Result::Skip.new(method_value: nil, exception:)
|
105
|
+
RaaP.logger.info "Found recursive type definition."
|
106
|
+
Result::Skip.new(symbolic_call:, exception:)
|
87
107
|
rescue => exception
|
88
|
-
|
89
|
-
Result::Exception.new(method_value:, exception:)
|
108
|
+
Result::Exception.new(symbolic_call:, exception:)
|
90
109
|
end
|
91
110
|
|
92
|
-
def check_return(receiver_value:, return_value
|
111
|
+
def check_return(receiver_value:, return_value:)
|
93
112
|
if BindCall.is_a?(receiver_value, Module)
|
94
113
|
if BindCall.is_a?(return_type, ::RBS::Types::ClassSingleton)
|
95
114
|
# ::RBS::Test::TypeCheck cannot support to check singleton class
|
96
|
-
|
115
|
+
if receiver_value == return_value
|
116
|
+
[:success]
|
117
|
+
else
|
118
|
+
[:failure]
|
119
|
+
end
|
97
120
|
end
|
121
|
+
|
98
122
|
self_class = receiver_value
|
99
123
|
instance_class = receiver_value
|
100
124
|
else
|
@@ -102,23 +126,27 @@ module RaaP
|
|
102
126
|
instance_class = BindCall.class(receiver_value)
|
103
127
|
end
|
104
128
|
type_check = ::RBS::Test::TypeCheck.new(
|
105
|
-
self_class
|
106
|
-
instance_class
|
129
|
+
self_class:,
|
130
|
+
instance_class:,
|
107
131
|
class_class: Module,
|
108
132
|
builder: RBS.builder,
|
109
133
|
sample_size: 100,
|
110
134
|
unchecked_classes: []
|
111
135
|
)
|
112
136
|
begin
|
113
|
-
type_check.value(return_value, return_type)
|
137
|
+
if type_check.value(return_value, return_type)
|
138
|
+
[:success]
|
139
|
+
else
|
140
|
+
[:failure]
|
141
|
+
end
|
114
142
|
rescue => e
|
115
|
-
|
116
|
-
|
143
|
+
RaaP.logger.debug("Type check fail by `(#{e.class}) #{e.message}`")
|
144
|
+
[:exception, e]
|
117
145
|
end
|
118
146
|
end
|
119
147
|
|
120
148
|
def return_type
|
121
|
-
method_type.rbs.type.return_type
|
149
|
+
@method_type.rbs.type.return_type
|
122
150
|
end
|
123
151
|
end
|
124
152
|
end
|
data/lib/raap/method_type.rb
CHANGED
@@ -16,25 +16,32 @@ module RaaP
|
|
16
16
|
else
|
17
17
|
raise "bad method #{method}"
|
18
18
|
end
|
19
|
-
|
19
|
+
|
20
|
+
params = (type_params_decl + rbs.type_params).uniq
|
21
|
+
ts = TypeSubstitution.new(params, type_args)
|
20
22
|
|
21
23
|
@rbs = ts.method_type_sub(rbs, self_type:, instance_type:, class_type:)
|
22
24
|
@fun_type = FunctionType.new(@rbs.type)
|
23
25
|
end
|
24
26
|
|
25
|
-
def pick_arguments(size: 10
|
26
|
-
|
27
|
-
|
27
|
+
def pick_arguments(size: 10)
|
28
|
+
SymbolicCaller.new(arguments_to_symbolic_call(size:)).eval
|
29
|
+
end
|
30
|
+
|
31
|
+
def arguments_to_symbolic_call(size: 10)
|
32
|
+
args, kwargs = @fun_type.arguments_to_symbolic_call(size:)
|
33
|
+
block = pick_block(size:)
|
28
34
|
|
29
35
|
[args, kwargs, block]
|
30
36
|
end
|
31
37
|
|
32
|
-
def pick_block(size: 10
|
38
|
+
def pick_block(size: 10)
|
33
39
|
block = @rbs.block
|
34
40
|
return nil if block.nil?
|
35
41
|
return nil if (block.required == false) && [true, false].sample
|
36
42
|
|
37
|
-
|
43
|
+
fixed_return_value = Type.new(block.type.return_type).pick(size:)
|
44
|
+
Proc.new { fixed_return_value }
|
38
45
|
end
|
39
46
|
|
40
47
|
def check_return(return_value)
|
data/lib/raap/minitest.rb
CHANGED
@@ -11,9 +11,13 @@ module RaaP
|
|
11
11
|
method_type = RaaP::MethodType.new(type)
|
12
12
|
size_step.each do |size|
|
13
13
|
# TODO assert_send_type
|
14
|
-
args, kwargs, _block = method_type.pick_arguments(size:
|
14
|
+
args, kwargs, _block = method_type.pick_arguments(size:)
|
15
15
|
return_value = yield(*args, **kwargs)
|
16
|
-
|
16
|
+
i = BindCall.inspect(return_value)
|
17
|
+
c = BindCall.class(return_value)
|
18
|
+
r = method_type.rbs.type.return_type
|
19
|
+
msg = "return value: #{i}[#{c}] is not match with `#{r}`"
|
20
|
+
assert method_type.check_return(return_value), msg
|
17
21
|
end
|
18
22
|
else
|
19
23
|
# forall("Integer", "String") { |int, str| Foo.new.int_str(int, str) }
|
@@ -24,7 +28,7 @@ module RaaP
|
|
24
28
|
end
|
25
29
|
end
|
26
30
|
size_step.each do |size|
|
27
|
-
values = types.map { |
|
31
|
+
values = types.map { |t| t.pick(size:) }
|
28
32
|
assert yield(*values)
|
29
33
|
end
|
30
34
|
end
|
data/lib/raap/rbs.rb
CHANGED
@@ -19,5 +19,24 @@ module RaaP
|
|
19
19
|
|
20
20
|
::RBS::Parser.parse_type(type, require_eof: true) or raise
|
21
21
|
end
|
22
|
+
|
23
|
+
def self.parse_method_type(method_type)
|
24
|
+
raise ArgumentError, "empty method type" if method_type == ""
|
25
|
+
|
26
|
+
::RBS::Parser.parse_method_type(method_type, require_eof: true) or raise
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.find_alias_decl(type_name, method_name)
|
30
|
+
env.class_decls[type_name].decls.each do |d|
|
31
|
+
d.decl.members.each do |member|
|
32
|
+
case member
|
33
|
+
when ::RBS::AST::Members::Alias
|
34
|
+
return member if member.new_name == method_name
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
nil
|
40
|
+
end
|
22
41
|
end
|
23
42
|
end
|
data/lib/raap/result.rb
CHANGED
@@ -2,17 +2,98 @@
|
|
2
2
|
|
3
3
|
module RaaP
|
4
4
|
module Result
|
5
|
-
module
|
5
|
+
module ReturnValueWithType
|
6
|
+
def return_value_with_type
|
7
|
+
return_type = return_value_to_type(return_value)
|
8
|
+
type = if return_type.empty? || return_type == 'nil'
|
9
|
+
''
|
10
|
+
else
|
11
|
+
"[#{return_type}]"
|
12
|
+
end
|
13
|
+
"#{BindCall.inspect(return_value)}#{type}"
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def return_value_to_type(val)
|
19
|
+
case val
|
20
|
+
when nil
|
21
|
+
'nil'
|
22
|
+
when true, false
|
23
|
+
"bool"
|
24
|
+
when Array
|
25
|
+
elem = if val.empty?
|
26
|
+
'untyped'
|
27
|
+
else
|
28
|
+
return_value_to_type(val.first)
|
29
|
+
end
|
30
|
+
"Array[#{elem}]"
|
31
|
+
when Hash
|
32
|
+
key = val.empty? ? 'untyped' : return_value_to_type(val.keys.first)
|
33
|
+
value = val.empty? ? 'untyped' : return_value_to_type(val.values.first)
|
34
|
+
"Hash[#{key}, #{value}]"
|
35
|
+
when Enumerator
|
36
|
+
elem =
|
37
|
+
begin
|
38
|
+
return_value_to_type(val.peek)
|
39
|
+
rescue StandardError
|
40
|
+
'untyped'
|
41
|
+
end
|
42
|
+
ret =
|
43
|
+
if val.size == Float::INFINITY
|
44
|
+
'bot'
|
45
|
+
else
|
46
|
+
begin
|
47
|
+
val.each {}
|
48
|
+
.tap { val.rewind }
|
49
|
+
.then { return_value_to_type(_1) }
|
50
|
+
rescue StandardError
|
51
|
+
'untyped'
|
52
|
+
end
|
53
|
+
end
|
54
|
+
"Enumerator[#{elem}, #{ret}]"
|
55
|
+
else
|
56
|
+
"#{BindCall.class(val)}"
|
57
|
+
end
|
58
|
+
rescue StandardError => e
|
59
|
+
RaaP.logger.debug("[#{e.class}] #{e.exception.detailed_message}")
|
60
|
+
RaaP.logger.debug(e.exception.backtrace&.join("\n"))
|
61
|
+
"raised #{e.class} with check return_type"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
class Success < Data.define(:symbolic_call, :return_value)
|
66
|
+
include ReturnValueWithType
|
67
|
+
|
6
68
|
def called_str
|
7
|
-
|
69
|
+
scr = SymbolicCaller.new(symbolic_call)
|
70
|
+
"#{scr.call_str} -> #{return_value_with_type}"
|
8
71
|
end
|
9
72
|
end
|
10
73
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
74
|
+
class Failure < Data.define(:symbolic_call, :return_value, :exception)
|
75
|
+
include ReturnValueWithType
|
76
|
+
|
77
|
+
def initialize(exception: nil, **)
|
78
|
+
super
|
79
|
+
end
|
80
|
+
|
81
|
+
def called_str
|
82
|
+
scr = SymbolicCaller.new(symbolic_call)
|
83
|
+
return_type =
|
84
|
+
if exception
|
85
|
+
"raised #{exception.class}"
|
86
|
+
else
|
87
|
+
return_value_with_type
|
88
|
+
end
|
89
|
+
"#{scr.call_str} -> #{return_type}"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
class Skip < Data.define(:symbolic_call, :exception)
|
94
|
+
end
|
95
|
+
|
96
|
+
class Exception < Data.define(:symbolic_call, :exception)
|
97
|
+
end
|
17
98
|
end
|
18
99
|
end
|
data/lib/raap/sized.rb
CHANGED
@@ -4,6 +4,7 @@ module RaaP
|
|
4
4
|
class Sized
|
5
5
|
def initialize(&block)
|
6
6
|
raise LocalJumpError, "no block given" unless block
|
7
|
+
|
7
8
|
@block = block
|
8
9
|
@such_that = nil
|
9
10
|
end
|
@@ -28,6 +29,7 @@ module RaaP
|
|
28
29
|
picked = yield(skip)
|
29
30
|
such_that = @such_that
|
30
31
|
return picked if such_that.nil? || such_that.call(picked)
|
32
|
+
|
31
33
|
skip += 1
|
32
34
|
raise "too many skips" unless skip < 100
|
33
35
|
end
|
data/lib/raap/symbolic_caller.rb
CHANGED
@@ -18,6 +18,7 @@ module RaaP
|
|
18
18
|
class SymbolicCaller
|
19
19
|
class Var
|
20
20
|
attr_reader :name
|
21
|
+
|
21
22
|
def initialize(name)
|
22
23
|
@name = name
|
23
24
|
end
|
@@ -32,9 +33,11 @@ module RaaP
|
|
32
33
|
end
|
33
34
|
|
34
35
|
attr_reader :symbolic_call
|
36
|
+
attr_reader :allow_private
|
35
37
|
|
36
|
-
def initialize(symbolic_call)
|
38
|
+
def initialize(symbolic_call, allow_private: false)
|
37
39
|
@symbolic_call = symbolic_call
|
40
|
+
@allow_private = allow_private
|
38
41
|
end
|
39
42
|
|
40
43
|
def eval
|
@@ -43,13 +46,23 @@ module RaaP
|
|
43
46
|
end
|
44
47
|
end
|
45
48
|
|
46
|
-
def
|
47
|
-
|
49
|
+
def call_str
|
50
|
+
symbolic_call => [:call, receiver, Symbol => method_name, Array => args, Hash => kwargs, block]
|
51
|
+
receiver = try_eval(receiver)
|
52
|
+
args, kwargs, block = try_eval([args, kwargs, block])
|
53
|
+
|
54
|
+
a = []
|
55
|
+
a << args.map(&BindCall.method(:inspect)).join(', ') if !args.empty?
|
56
|
+
a << kwargs.map { |k, v| "#{k}: #{BindCall.inspect(v)}" }.join(', ') if !kwargs.empty?
|
57
|
+
argument_str = a.join(', ')
|
58
|
+
block_str = block ? "{ }" : nil
|
59
|
+
|
60
|
+
"#{BindCall.inspect(receiver)}.#{method_name}(#{argument_str})#{block_str}"
|
48
61
|
end
|
49
62
|
|
50
63
|
def to_lines
|
51
64
|
[].tap do |lines|
|
52
|
-
walk do |symbolic_call|
|
65
|
+
walk do |symbolic_call, is_last|
|
53
66
|
symbolic_call => [:call, receiver_value, method_name, args, kwargs, block]
|
54
67
|
|
55
68
|
is_mod = receiver_value.is_a?(Module)
|
@@ -60,7 +73,7 @@ module RaaP
|
|
60
73
|
var_eq = "#{var} = "
|
61
74
|
receiver = ''
|
62
75
|
when BindCall.instance_of?(receiver_value, Var)
|
63
|
-
var_eq = ""
|
76
|
+
var_eq = "#{receiver_value} = "
|
64
77
|
var = Var.new(receiver_value.name)
|
65
78
|
receiver = var + '.'
|
66
79
|
when is_mod
|
@@ -68,22 +81,32 @@ module RaaP
|
|
68
81
|
var_eq = "#{var} = "
|
69
82
|
receiver = receiver_value.name + '.'
|
70
83
|
else
|
71
|
-
var_eq =
|
72
|
-
receiver =
|
73
|
-
var = Var.new(printable(receiver_value))
|
74
|
-
var + '.'
|
75
|
-
else
|
76
|
-
var = Var.new(var_name(receiver_value.class))
|
77
|
-
var + '.'
|
78
|
-
end
|
84
|
+
var_eq = ''
|
85
|
+
receiver = Var.new(printable(receiver_value)) + '.'
|
79
86
|
end
|
80
87
|
|
88
|
+
var_eq = '' if is_last
|
89
|
+
|
81
90
|
arguments = []
|
82
|
-
|
83
|
-
|
91
|
+
if !args.empty?
|
92
|
+
# The reproduction code is kept short and executable.
|
93
|
+
if [Value::Interface, Value::Intersection].include?(receiver_value)
|
94
|
+
if args.all? { |a| a.respond_to?(:free_variables) } && !args.all? { |a| a.free_variables.empty? }
|
95
|
+
# FIXME: Type arguments are not yet supported.
|
96
|
+
args.each do |a|
|
97
|
+
lines << "# Free variables: #{a.free_variables.to_a.join(', ')}"
|
98
|
+
end
|
99
|
+
end
|
100
|
+
arguments << args.map { |a| printable(a.to_s) }
|
101
|
+
else
|
102
|
+
arguments << args.map { |a| printable(a) }
|
103
|
+
end
|
104
|
+
end
|
105
|
+
arguments << kwargs.map { |k, v| "#{k}: #{printable(v)}" }.join(', ') if !kwargs.empty?
|
84
106
|
block_str = block ? " { }" : ""
|
85
107
|
|
86
|
-
|
108
|
+
line = "#{var_eq}#{receiver}#{method_name}(#{arguments.join(', ')})#{block_str}"
|
109
|
+
lines << line
|
87
110
|
|
88
111
|
var
|
89
112
|
end
|
@@ -92,22 +115,31 @@ module RaaP
|
|
92
115
|
|
93
116
|
private
|
94
117
|
|
95
|
-
def
|
118
|
+
def try_eval(symbolic_call)
|
119
|
+
SymbolicCaller.new(symbolic_call).eval
|
120
|
+
rescue RuntimeError, NotImplementedError
|
121
|
+
symbolic_call
|
122
|
+
end
|
123
|
+
|
124
|
+
def walk(&)
|
125
|
+
_walk(@symbolic_call, true, &)
|
126
|
+
end
|
127
|
+
|
128
|
+
def _walk(symbolic_call, is_last, &block)
|
96
129
|
return symbolic_call if BindCall::instance_of?(symbolic_call, BasicObject)
|
97
130
|
return symbolic_call if !BindCall.respond_to?(symbolic_call, :deconstruct) && !BindCall.respond_to?(symbolic_call, :deconstruct_keys)
|
98
131
|
|
99
132
|
case symbolic_call
|
100
133
|
in [:call, receiver, Symbol => method_name, Array => args, Hash => kwargs, b]
|
101
|
-
receiver = _walk(receiver, &block)
|
102
|
-
args = _walk(args, &block) if !args.empty?
|
103
|
-
kwargs = _walk(kwargs, &block) if !kwargs.empty?
|
104
|
-
block.call [:call, receiver, method_name, args, kwargs, b]
|
105
|
-
in Var
|
106
|
-
symbolic_call.name
|
134
|
+
receiver = _walk(receiver, false, &block)
|
135
|
+
args = _walk(args, false, &block) if !args.empty?
|
136
|
+
kwargs = _walk(kwargs, false, &block) if !kwargs.empty?
|
137
|
+
block.call [:call, receiver, method_name, args, kwargs, b], is_last
|
107
138
|
in Array
|
108
|
-
symbolic_call.map { |sc| _walk(sc, &block) }
|
139
|
+
symbolic_call.map { |sc| _walk(sc, false, &block) }
|
109
140
|
in Hash
|
110
|
-
symbolic_call.
|
141
|
+
symbolic_call.transform_keys { |k| _walk(k, false, &block) }
|
142
|
+
.transform_values! { |v| _walk(v, false, &block) }
|
111
143
|
else
|
112
144
|
symbolic_call
|
113
145
|
end
|
@@ -115,35 +147,39 @@ module RaaP
|
|
115
147
|
|
116
148
|
def eval_one(symbolic_call)
|
117
149
|
symbolic_call => [:call, receiver_value, method_name, args, kwargs, block]
|
118
|
-
|
150
|
+
if @allow_private
|
151
|
+
receiver_value.__send__(method_name, *args, **kwargs, &block)
|
152
|
+
else
|
153
|
+
BindCall.public_send(receiver_value, method_name, *args, **kwargs, &block)
|
154
|
+
end
|
119
155
|
end
|
120
156
|
|
121
157
|
def var_name(mod)
|
122
158
|
printable(mod).gsub('::', '_').downcase
|
123
159
|
end
|
124
160
|
|
125
|
-
def printable?(obj)
|
126
|
-
case obj
|
127
|
-
when Symbol, Integer, Float, Regexp, nil, true, false, String, Module, Var
|
128
|
-
true
|
129
|
-
else
|
130
|
-
false
|
131
|
-
end
|
132
|
-
end
|
133
|
-
|
134
161
|
def printable(obj)
|
135
162
|
case obj
|
136
163
|
when Var
|
137
164
|
obj.name
|
138
165
|
# Object from which it can get strings that can be eval with `#inspect`
|
139
|
-
when Symbol, Integer, Float, Regexp, nil, true, false
|
166
|
+
when Symbol, Integer, Float, Regexp, Range, nil, true, false
|
140
167
|
obj.inspect
|
141
168
|
when String
|
142
169
|
obj.inspect.gsub('"', "'") or raise
|
170
|
+
when Hash
|
171
|
+
hash_body = obj.map do |k, v|
|
172
|
+
ks = printable(k)
|
173
|
+
vs = printable(v)
|
174
|
+
ks.start_with?(':') ? "#{ks[1..-1]}: #{vs}" : "#{ks} => #{vs}"
|
175
|
+
end
|
176
|
+
"{#{hash_body.join(', ')}}"
|
177
|
+
when Array
|
178
|
+
"[#{obj.map { |o| printable(o) }.join(', ')}]"
|
143
179
|
when Module
|
144
|
-
BindCall.name(obj) or raise
|
180
|
+
BindCall.name(obj) or raise "`#class` method returns nil"
|
145
181
|
else
|
146
|
-
var_name(
|
182
|
+
var_name(BindCall.class(obj))
|
147
183
|
end
|
148
184
|
end
|
149
185
|
end
|