raap 0.1.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3e9d7ac0f6d02b3bc1dce9ad5d49d47d0b73825cfdb60a9e2a9f60a7ab0538a4
4
- data.tar.gz: 5e4204d5ce36b5b271ff715ad460533e27edd625c7e2b9a075d8d4e6db4ff6e0
3
+ metadata.gz: 507ed156280ed3e0db1f2eb454bb03c57aa473d537d8c6ea5905ad852eba550d
4
+ data.tar.gz: 3108fa50c664702f79141a3c0b5e83934d6742468d1d51bfb2febb5b64a00b12
5
5
  SHA512:
6
- metadata.gz: cd12a1a50335e228a4700dd048d66f835a0963b4dd7373a890c02c9975d1587c9929604d18b6ce51a1696ce67c3b15c9d9f2d06f76aa22e9a9f6f467c8ee3fbb
7
- data.tar.gz: f1cb139f0169359bda70f3cbaa03db45f110941d7559531d4f5c02cc8c04ec477f22effb293a6e64db90218101069a9084255d4b75cf64aa0403af20cc4f910b
6
+ metadata.gz: 269e220d72b9861881de860a71a2adff318105595880fe73e86492e255c9bb32fbeff7ac3685b83ea11d792a02b1509eb969d9956483a9415608530a3f8806bd
7
+ data.tar.gz: df4e40973681eb292d7844aa5ed1427b7155f619c6ebea53792149f430ab28e42a0a0f52df9517a3af9af1e08494eaccdd8d4d84313c9d24184f6403a51e1dc5
data/README.md CHANGED
@@ -12,17 +12,54 @@ The return value of the method is checked to see if it matches the type, if not,
12
12
 
13
13
  If you write an RBS, it becomes a test case.
14
14
 
15
- ## Installation
15
+ ## Concept
16
+
17
+ If you has next signature.
18
+
19
+ ```rbs
20
+ class Foo
21
+ end
22
+
23
+ class Bar
24
+ def initialize: (foo: Foo) -> void
25
+ def f2s: (Float) -> String
26
+ end
27
+ ```
28
+
29
+ Then, RaaP run next testing code automaticaly.
30
+
31
+ ```rb
32
+ describe Bar do
33
+ let(:foo) { Foo.new }
34
+ let(:bar) { Bar.new(foo: foo) }
35
+
36
+ it "#f2s" do
37
+ 100.times do |size|
38
+ float = Random.rand * size
39
+ expect(bar.f2s(float)).to be_a(String)
40
+ end
41
+ end
42
+ end
43
+ ```
44
+
45
+ If you got a failure?
46
+
47
+ - Fix RBS
48
+ - Fix implementation of `Bar#f2s`
16
49
 
17
- TODO: Replace `UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG` with your gem name right after releasing it to RubyGems.org. Please do not do it earlier due to security reasons. Alternatively, replace this section with instructions to install your gem from git if you don't plan to release to RubyGems.org.
50
+ Then, you can start loop again.
51
+
52
+ Finally, you get the perfect RBS!
53
+
54
+ ## Installation
18
55
 
19
56
  Install the gem and add to the application's Gemfile by executing:
20
57
 
21
- $ bundle add UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG
58
+ $ bundle add raap
22
59
 
23
60
  If bundler is not being used to manage dependencies, install the gem by executing:
24
61
 
25
- $ gem install UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG
62
+ $ gem install raap
26
63
 
27
64
  ## Usage
28
65
 
@@ -41,6 +78,21 @@ For example, an Integer with size zero is `0` and an Array is `[]`.
41
78
 
42
79
  RaaP, like other property-based tests, changes the size 100 times from 0 to 99 by default to generate test data.
43
80
 
81
+ ## Symbolic call
82
+
83
+ You may possibly see the following data structure in the debug logs.
84
+
85
+ ```rb
86
+ [:call, Object, :method, [], {}, nil]
87
+ ```
88
+
89
+ This is a data structure of the state of the method call.
90
+
91
+ Symbolic call is a tuple beginning with `:call`, followed by the receiver, method name, positional arguments, keyword arguments, and block arguments, in that order.
92
+ And the receiver and arguments are nestable.
93
+
94
+ It is used in QuickCheck and Proper to keep as much history of method calls as possible.
95
+
44
96
  ## Options
45
97
 
46
98
  ### `-I PATH` or `--include PATH`
@@ -8,6 +8,7 @@ module RaaP
8
8
  def extend(...) = ::Kernel.instance_method(:extend).bind_call(...)
9
9
  def name(...) = ::Module.instance_method(:name).bind_call(...)
10
10
  def to_s(...) = ::Kernel.instance_method(:to_s).bind_call(...)
11
+ def public_send(...) = ::Kernel.instance_method(:public_send).bind_call(...)
11
12
 
12
13
  def class(obj)
13
14
  if respond_to?(obj, :class)
data/lib/raap/cli.rb CHANGED
@@ -16,6 +16,7 @@ module RaaP
16
16
  :size_from,
17
17
  :size_to,
18
18
  :size_by,
19
+ :allow_private,
19
20
  keyword_init: true
20
21
  )
21
22
 
@@ -28,6 +29,7 @@ module RaaP
28
29
  size_from: 0,
29
30
  size_to: 99,
30
31
  size_by: 1,
32
+ allow_private: false,
31
33
  )
32
34
 
33
35
  def initialize(argv)
@@ -60,6 +62,9 @@ module RaaP
60
62
  o.on('--size-by int', Integer, "default: #{CLI.option.size_by}") do |arg|
61
63
  CLI.option.size_by = arg
62
64
  end
65
+ o.on('--allow-private', "default: #{CLI.option.allow_private}") do
66
+ CLI.option.allow_private = true
67
+ end
63
68
  end.parse!(@argv)
64
69
 
65
70
  CLI.option.dirs.each do |dir|
@@ -103,7 +108,11 @@ module RaaP
103
108
 
104
109
  def run_by_instance(tag:)
105
110
  t, m = tag.split('#', 2)
111
+ t or raise
112
+ m or raise
106
113
  type = RBS.parse_type(t)
114
+ type = __skip__ = type
115
+ raise "cannot specified #{type}" unless type.respond_to?(:name)
107
116
  receiver_type = Type.new(type.to_s)
108
117
  method_name = m.to_sym
109
118
  definition = RBS.builder.build_instance(type.name)
@@ -121,7 +130,11 @@ module RaaP
121
130
 
122
131
  def run_by_singleton(tag:)
123
132
  t, m = tag.split('.', 2)
133
+ t or raise
134
+ m or raise
124
135
  type = RBS.parse_type(t)
136
+ raise "cannot specified #{type.class}" unless type.respond_to?(:name)
137
+ type = __skip__ = type
125
138
  receiver_type = Type.new("singleton(#{type.name})")
126
139
  method_name = m.to_sym
127
140
  definition = RBS.builder.build_singleton(type.name)
@@ -150,6 +163,8 @@ module RaaP
150
163
 
151
164
  def run_by_type_name(tag:)
152
165
  type = RBS.parse_type(tag)
166
+ type = __skip__ = type
167
+ raise "cannot specified #{type.class}" unless type.respond_to?(:name)
153
168
  type_name = type.name.absolute!
154
169
 
155
170
  ret = []
@@ -157,6 +172,7 @@ module RaaP
157
172
  definition = RBS.builder.build_singleton(type_name)
158
173
  type_params_decl = definition.type_params_decl
159
174
  definition.methods.filter_map do |method_name, method|
175
+ next unless method.accessibility == :public
160
176
  next if method.defined_in != type_name
161
177
  next if method_name == :fork || method_name == :spawn # TODO: skip solution
162
178
  puts "# #{type_name}.#{method_name}"
@@ -169,6 +185,7 @@ module RaaP
169
185
  definition = RBS.builder.build_instance(type_name)
170
186
  type_params_decl = definition.type_params_decl
171
187
  definition.methods.filter_map do |method_name, method|
188
+ next unless method.accessibility == :public
172
189
  next if method.defined_in != type_name
173
190
  next if method_name == :fork || method_name == :spawn # TODO: skip solution
174
191
  puts "# #{type_name}##{method_name}"
@@ -182,12 +199,13 @@ module RaaP
182
199
  end
183
200
 
184
201
  def property(receiver_type:, type_params_decl:, method_type:, method_name:)
202
+ rtype = __skip__ = receiver_type.type
185
203
  if receiver_type.type.instance_of?(::RBS::Types::ClassSingleton)
186
204
  prefix = 'self.'
187
205
  type_args = []
188
206
  else
189
207
  prefix = ''
190
- type_args = receiver_type.type.args
208
+ type_args = rtype.args
191
209
  end
192
210
  puts "## def #{prefix}#{method_name}: #{method_type}"
193
211
  status = 0
@@ -198,23 +216,27 @@ module RaaP
198
216
  method_type,
199
217
  type_params_decl:,
200
218
  type_args:,
201
- self_type: receiver_type.type,
202
- instance_type: ::RBS::Types::ClassInstance.new(name: receiver_type.type.name, args: type_args, location: nil),
203
- class_type: ::RBS::Types::ClassSingleton.new(name: receiver_type.type.name, location: nil),
219
+ self_type: rtype,
220
+ instance_type: ::RBS::Types::ClassInstance.new(name: rtype.name, args: type_args, location: nil),
221
+ class_type: ::RBS::Types::ClassSingleton.new(name: rtype.name, location: nil),
204
222
  ),
205
223
  size_step: CLI.option.size_from.step(to: CLI.option.size_to, by: CLI.option.size_by),
206
224
  timeout: CLI.option.timeout,
225
+ allow_private: true,
207
226
  ).run do |called|
208
227
  case called
209
228
  in Result::Success => s
210
- RaaP.logger.debug { "Success: #{s.called_str}" }
211
229
  print '.'
230
+ RaaP.logger.debug { "Success: #{s.called_str}" }
212
231
  in Result::Failure => f
213
232
  puts 'F'
214
233
  puts "Failed in case of `#{f.called_str}`"
234
+ if e = f.exception
235
+ RaaP.logger.debug { "Failure: [#{e.class}] #{e.message}" }
236
+ end
215
237
  puts
216
238
  RaaP.logger.debug { PP.pp(f.symbolic_call, ''.dup) }
217
- puts "# call stack:"
239
+ puts "### call stack:"
218
240
  puts
219
241
  puts "```"
220
242
  puts SymbolicCaller.new(f.symbolic_call).to_lines.join("\n")
@@ -223,10 +245,14 @@ module RaaP
223
245
  throw :break
224
246
  in Result::Skip => s
225
247
  print 'S'
248
+ RaaP.logger.debug { PP.pp(s.symbolic_call, ''.dup) }
249
+ RaaP.logger.debug("Skip: [#{s.exception.class}] #{s.exception.message}")
250
+ RaaP.logger.debug(s.exception.backtrace.join("\n"))
226
251
  in Result::Exception => e
227
- RaaP.logger.info("#{e.exception.class}: #{e.exception.message}")
228
- RaaP.logger.debug(e.exception.backtrace.join("\n"))
229
252
  print 'E'
253
+ RaaP.logger.debug { PP.pp(e.symbolic_call, ''.dup) }
254
+ RaaP.logger.debug("Exception: [#{e.exception.class}] #{e.exception.message}")
255
+ RaaP.logger.debug(e.exception.backtrace.join("\n"))
230
256
  end
231
257
  end
232
258
  puts
@@ -8,25 +8,17 @@ module RaaP
8
8
  end
9
9
  end
10
10
 
11
- attr_reader :receiver_type
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
26
21
  stats = Stats.new
27
- if receiver_type.type.to_s == 'String' && method_name == :initialize
28
- return stats
29
- end
30
22
  begin
31
23
  Timeout.timeout(@timeout) do
32
24
  catch(:break) do
@@ -44,47 +36,53 @@ module RaaP
44
36
  private
45
37
 
46
38
  def call(size:, stats:)
47
- receiver_value = receiver_type.pick(size: size, eval: false)
48
- arguments = method_type.pick_arguments(size: size, eval: false)
49
- method_value = MethodValue.new(receiver_value:, arguments:, method_name:, size:)
50
- symbolic_call = method_value.to_symbolic_call
51
- check = false
52
- if return_type.instance_of?(::RBS::Types::Bases::Bottom)
53
- begin
54
- return_value = SymbolicCaller.new(symbolic_call).eval
55
- rescue => e
56
- check = true
57
- return_value = Value::Bottom.new
39
+ receiver_value = @receiver_type.pick(size: size, eval: false)
40
+ args, kwargs, block = @method_type.pick_arguments(size: size, eval: false)
41
+ # @type var symbolic_call: symbolic_call
42
+ symbolic_call = [:call, receiver_value, @method_name, args, kwargs, block]
43
+ symbolic_caller = SymbolicCaller.new(symbolic_call, allow_private: @allow_private)
44
+ begin
45
+ # ensure symbolic_call
46
+ check = false
47
+ if return_type.instance_of?(::RBS::Types::Bases::Bottom)
48
+ begin
49
+ return_value = symbolic_caller.eval
50
+ rescue StandardError, NotImplementedError
51
+ check = true
52
+ return_value = Value::Bottom.new
53
+ end
54
+ else
55
+ return_value = symbolic_caller.eval
56
+ check = check_return(receiver_value:, return_value:, method_type: @method_type)
58
57
  end
59
- else
60
- return_value = SymbolicCaller.new(symbolic_call).eval
61
- check = check_return(receiver_value:, return_value:, method_type:)
62
- end
63
- if check
64
- stats.success += 1
65
- Result::Success.new(method_value:, return_value:)
66
- else
67
- Result::Failure.new(method_value:, return_value:, symbolic_call:)
58
+ if check
59
+ stats.success += 1
60
+ Result::Success.new(symbolic_call:, return_value:)
61
+ else
62
+ Result::Failure.new(symbolic_call:, return_value:)
63
+ end
64
+ rescue TypeError => exception
65
+ Result::Failure.new(symbolic_call:, return_value:, exception:)
68
66
  end
67
+
68
+ # not ensure symbolic_call
69
69
  rescue NoMethodError => exception
70
70
  stats.skip += 1
71
- Result::Skip.new(method_value:, exception:)
71
+ Result::Skip.new(symbolic_call:, exception:)
72
72
  rescue NameError => e
73
73
  msg = e.name.nil? ? '' : "for `#{BindCall.to_s(e.receiver)}::#{e.name}`"
74
74
  RaaP.logger.error("Implementation is not found #{msg} maybe.")
75
75
  throw :break
76
76
  rescue NotImplementedError => exception
77
77
  stats.skip += 1
78
- Result::Skip.new(method_value:, exception:)
78
+ Result::Skip.new(symbolic_call:, exception:)
79
79
  rescue SystemStackError => exception
80
80
  stats.skip += 1
81
81
  RaaP.logger.warn "Found recursive type definition."
82
- Result::Skip.new(method_value: nil, exception:)
83
- rescue TypeError => exception
84
- Result::Failure.new(method_value:, return_value:, symbolic_call:)
82
+ Result::Skip.new(symbolic_call:, exception:)
85
83
  rescue => exception
86
84
  stats.exception += 1
87
- Result::Exception.new(method_value:, exception:)
85
+ Result::Exception.new(symbolic_call:, exception:)
88
86
  end
89
87
 
90
88
  def check_return(receiver_value:, return_value:, method_type:)
@@ -104,7 +102,7 @@ module RaaP
104
102
  instance_class: instance_class,
105
103
  class_class: Module,
106
104
  builder: RBS.builder,
107
- sample_size: 1,
105
+ sample_size: 100,
108
106
  unchecked_classes: []
109
107
  )
110
108
  begin
@@ -116,7 +114,7 @@ module RaaP
116
114
  end
117
115
 
118
116
  def return_type
119
- method_type.rbs.type.return_type
117
+ @method_type.rbs.type.return_type
120
118
  end
121
119
  end
122
120
  end
@@ -36,5 +36,18 @@ module RaaP
36
36
 
37
37
  Proc.new { Type.new(block.type.return_type).pick(size:, eval:) }
38
38
  end
39
+
40
+ def check_return(return_value)
41
+ untyped = __skip__ = nil
42
+ type_check = ::RBS::Test::TypeCheck.new(
43
+ self_class: untyped, # cannot support `self`
44
+ instance_class: untyped, # cannot support `instance`
45
+ class_class: untyped, # cannot support `class`
46
+ builder: RBS.builder,
47
+ sample_size: 100,
48
+ unchecked_classes: []
49
+ )
50
+ type_check.value(return_value, rbs.type.return_type)
51
+ end
39
52
  end
40
53
  end
@@ -0,0 +1,35 @@
1
+ require 'minitest'
2
+
3
+ module RaaP
4
+ module Minitest
5
+ def forall(*types, size_step: 0...100)
6
+ # @type self: Minitest::Test
7
+
8
+ if types.length == 1 && types.first.instance_of?(String) && types.first.start_with?("(")
9
+ # forall("(Integer) -> String") { |int| Foo.new.int2str(int) }
10
+ type = types.first
11
+ method_type = RaaP::MethodType.new(type)
12
+ size_step.each do |size|
13
+ # TODO assert_send_type
14
+ args, kwargs, _block = method_type.pick_arguments(size: size)
15
+ return_value = yield(*args, **kwargs)
16
+ assert method_type.check_return(return_value), "return value: #{BindCall.inspect(return_value)}[#{BindCall.class(return_value)}] is not match with `#{method_type.rbs.type.return_type}`"
17
+ end
18
+ else
19
+ # forall("Integer", "String") { |int, str| Foo.new.int_str(int, str) }
20
+ types.map! do |type|
21
+ case type
22
+ in String then RaaP::Type.new(type)
23
+ else type
24
+ end
25
+ end
26
+ size_step.each do |size|
27
+ values = types.map { |type| type.pick(size: size) }
28
+ assert yield(*values)
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+
35
+ Minitest::Test.include RaaP::Minitest
data/lib/raap/result.rb CHANGED
@@ -4,15 +4,20 @@ module RaaP
4
4
  module Result
5
5
  module CalledStr
6
6
  def called_str
7
- "#{method_value.call_str} -> #{return_value.inspect}[#{return_value.class}]"
7
+ scr = SymbolicCaller.new(symbolic_call)
8
+ "#{scr.call_str} -> #{return_value.inspect}[#{return_value.class}]"
8
9
  end
9
10
  end
10
11
 
11
- Success = Data.define(:method_value, :return_value)
12
+ Success = Data.define(:symbolic_call, :return_value)
12
13
  Success.include CalledStr
13
- Failure = Data.define(:method_value, :return_value, :symbolic_call)
14
+ Failure = Data.define(:symbolic_call, :return_value, :exception) do
15
+ def initialize(exception: nil, **)
16
+ super
17
+ end
18
+ end
14
19
  Failure.include CalledStr
15
- Skip = Data.define(:method_value, :exception)
16
- Exception = Data.define(:method_value, :exception)
20
+ Skip = Data.define(:symbolic_call, :exception)
21
+ Exception = Data.define(:symbolic_call, :exception)
17
22
  end
18
23
  end
@@ -16,10 +16,27 @@ module RaaP
16
16
  # c = C.new(a: a, b: b)
17
17
  # c.run() { }
18
18
  class SymbolicCaller
19
+ class Var
20
+ attr_reader :name
21
+ def initialize(name)
22
+ @name = name
23
+ end
24
+
25
+ def +(other)
26
+ "#{self}#{other}"
27
+ end
28
+
29
+ def to_s
30
+ @name
31
+ end
32
+ end
33
+
19
34
  attr_reader :symbolic_call
35
+ attr_reader :allow_private
20
36
 
21
- def initialize(symbolic_call)
37
+ def initialize(symbolic_call, allow_private: false)
22
38
  @symbolic_call = symbolic_call
39
+ @allow_private = allow_private
23
40
  end
24
41
 
25
42
  def eval
@@ -28,8 +45,18 @@ module RaaP
28
45
  end
29
46
  end
30
47
 
31
- def walk(&)
32
- _walk(@symbolic_call, &)
48
+ def call_str
49
+ symbolic_call => [:call, receiver, Symbol => method_name, Array => args, Hash => kwargs, b]
50
+ receiver = try_eval(receiver)
51
+ args, kwargs, block = try_eval([args, kwargs, block])
52
+
53
+ a = []
54
+ a << args.map(&:inspect).join(', ') if !args.empty?
55
+ a << kwargs.map { |k ,v| "#{k}: #{BindCall.inspect(v)}" }.join(', ') if !kwargs.empty?
56
+ argument_str = a.join(', ')
57
+ block_str = block ? "{ }" : nil
58
+
59
+ "#{BindCall.inspect(receiver)}.#{method_name}(#{argument_str})#{block_str}"
33
60
  end
34
61
 
35
62
  def to_lines
@@ -39,19 +66,22 @@ module RaaP
39
66
 
40
67
  is_mod = receiver_value.is_a?(Module)
41
68
 
42
- if receiver_value == Kernel
43
- var = "#{var_name(method_name)} = "
69
+ case
70
+ when receiver_value == Kernel
71
+ var = Var.new(method_name.to_s.downcase)
72
+ var_eq = "#{var} = "
44
73
  receiver = ''
45
- elsif is_mod
46
- var = "#{var_name(receiver_value)} = "
74
+ when BindCall.instance_of?(receiver_value, Var)
75
+ var_eq = ""
76
+ var = Var.new(receiver_value.name)
77
+ receiver = var + '.'
78
+ when is_mod
79
+ var = Var.new(var_name(receiver_value))
80
+ var_eq = "#{var} = "
47
81
  receiver = receiver_value.name + '.'
48
82
  else
49
- var = ""
50
- receiver = if printable?(receiver_value)
51
- printable(receiver_value) + '.'
52
- else
53
- var_name(receiver_value.class) + '.'
54
- end
83
+ var_eq = ""
84
+ receiver = Var.new(printable(receiver_value)) + '.'
55
85
  end
56
86
 
57
87
  arguments = []
@@ -59,15 +89,25 @@ module RaaP
59
89
  arguments << kwargs.map{|k,v| "#{k}: #{printable(v)}" }.join(', ') if !kwargs.empty?
60
90
  block_str = block ? " { }" : ""
61
91
 
62
- lines << "#{var}#{receiver}#{method_name}(#{arguments.join(', ')})#{block_str}"
92
+ lines << "#{var_eq}#{receiver}#{method_name}(#{arguments.join(', ')})#{block_str}"
63
93
 
64
- eval_one(symbolic_call)
94
+ var
65
95
  end
66
96
  end
67
97
  end
68
98
 
69
99
  private
70
100
 
101
+ def try_eval(symbolic_call)
102
+ SymbolicCaller.new(symbolic_call).eval
103
+ rescue RuntimeError, NotImplementedError
104
+ symbolic_call
105
+ end
106
+
107
+ def walk(&)
108
+ _walk(@symbolic_call, &)
109
+ end
110
+
71
111
  def _walk(symbolic_call, &block)
72
112
  return symbolic_call if BindCall::instance_of?(symbolic_call, BasicObject)
73
113
  return symbolic_call if !BindCall.respond_to?(symbolic_call, :deconstruct) && !BindCall.respond_to?(symbolic_call, :deconstruct_keys)
@@ -78,6 +118,8 @@ module RaaP
78
118
  args = _walk(args, &block) if !args.empty?
79
119
  kwargs = _walk(kwargs, &block) if !kwargs.empty?
80
120
  block.call [:call, receiver, method_name, args, kwargs, b]
121
+ in Var
122
+ symbolic_call.name
81
123
  in Array
82
124
  symbolic_call.map { |sc| _walk(sc, &block) }
83
125
  in Hash
@@ -89,12 +131,10 @@ module RaaP
89
131
 
90
132
  def eval_one(symbolic_call)
91
133
  symbolic_call => [:call, receiver_value, method_name, args, kwargs, block]
92
-
93
- begin
134
+ if @allow_private
94
135
  receiver_value.__send__(method_name, *args, **kwargs, &block)
95
- rescue => e
96
- RaaP.logger.error("Cannot eval symbolic call #{symbolic_call} with #{e.class}")
97
- raise
136
+ else
137
+ BindCall.public_send(receiver_value, method_name, *args, **kwargs, &block)
98
138
  end
99
139
  end
100
140
 
@@ -102,22 +142,28 @@ module RaaP
102
142
  printable(mod).gsub('::', '_').downcase
103
143
  end
104
144
 
105
- def printable?(obj)
106
- case obj
107
- when Symbol, Integer, Float, Regexp, nil, true, false, String, Module
108
- true
109
- else
110
- false
145
+ def printable(obj)
146
+ if obj in [:call, _, Symbol, Array, Hash, _]
147
+ return _walk(obj)
111
148
  end
112
- end
113
149
 
114
- def printable(obj)
115
150
  case obj
151
+ when Var
152
+ obj.name
116
153
  # Object from which it can get strings that can be eval with `#inspect`
117
154
  when Symbol, Integer, Float, Regexp, nil, true, false
118
155
  obj.inspect
119
156
  when String
120
157
  obj.inspect.gsub('"', "'") or raise
158
+ when Hash
159
+ hash_body = obj.map do |k, v|
160
+ ks = printable(k)
161
+ vs = printable(v)
162
+ ks.start_with?(':') ? "#{ks[1..-1]}: #{vs}" : "#{ks} => #{vs}"
163
+ end
164
+ "{#{hash_body.join(', ')}}"
165
+ when Array
166
+ "[#{obj.map { |o| printable(o) }.join(', ')}]"
121
167
  when Module
122
168
  BindCall.name(obj) or raise
123
169
  else
data/lib/raap/type.rb CHANGED
@@ -23,12 +23,14 @@ module RaaP
23
23
 
24
24
  # Type.register "::Integer::positive" { sized { |size| size } }
25
25
  def self.register(type_name, &block)
26
- GENERATORS[type_name] = block
26
+ raise ArgumentError, "block is required" unless block
27
+ GENERATORS[type_name] = __skip__ = block
27
28
  end
28
29
 
29
30
  # Special class case
30
31
  register("::Array") do
31
- t = type.args[0] || 'untyped'
32
+ _type = __skip__ = type
33
+ t = _type.args[0] || 'untyped'
32
34
  array(Type.new(t, range: range))
33
35
  end
34
36
  register("::Binding") { sized { binding } }
@@ -40,8 +42,9 @@ module RaaP
40
42
  register("::Hash") do
41
43
  sized do |size|
42
44
  Array.new(integer.pick(size: size).abs).to_h do
43
- k = type.args[0] || 'untyped'
44
- v = type.args[1] || 'untyped'
45
+ _type = __skip__ = type
46
+ k = _type.args[0] || 'untyped'
47
+ v = _type.args[1] || 'untyped'
45
48
  [Type.new(k).pick(size: size), Type.new(v).pick(size: size)]
46
49
  end
47
50
  end
@@ -66,10 +69,20 @@ module RaaP
66
69
  def initialize(type, range: nil..nil)
67
70
  @type = parse(type)
68
71
  @range = range
72
+ @such_that = nil
73
+ end
74
+
75
+ def such_that(&block)
76
+ @such_that = block
77
+ self
69
78
  end
70
79
 
71
80
  def sized(&block)
72
- Sized.new(&block)
81
+ Sized.new(&block).tap do |sized|
82
+ if s = @such_that
83
+ sized.such_that(&s)
84
+ end
85
+ end
73
86
  end
74
87
 
75
88
  def pick(size: 10, eval: true)
@@ -87,7 +100,17 @@ module RaaP
87
100
  when ::RBS::Types::Union
88
101
  type.types.sample&.then { |t| Type.new(t).pick(size:) }
89
102
  when ::RBS::Types::Intersection
90
- Value::Intersection.new(type, size: size)
103
+ [:call, Value::Intersection, :new, [type], {size:}, nil]
104
+ when ::RBS::Types::Interface
105
+ [:call, Value::Interface, :new, [type], {size:}, nil]
106
+ when ::RBS::Types::Variable
107
+ [:call, Value::Variable, :new, [type], {}, nil]
108
+ when ::RBS::Types::Bases::Void
109
+ [:call, Value::Void, :new, [], {}, nil]
110
+ when ::RBS::Types::Bases::Top
111
+ [:call, Value::Top, :new, [], {}, nil]
112
+ when ::RBS::Types::Bases::Bottom
113
+ [:call, Value::Bottom, :new, [], {}, nil]
91
114
  when ::RBS::Types::Optional
92
115
  case Random.rand(2)
93
116
  in 0 then Type.new(type.type).pick(size:)
@@ -104,16 +127,12 @@ module RaaP
104
127
  raise "cannot resolve `instance` type"
105
128
  when ::RBS::Types::Bases::Self
106
129
  raise "cannot resolve `self` type"
107
- when ::RBS::Types::Interface
108
- Value::Interface.new(type, size: size)
109
- when ::RBS::Types::Variable
110
- Value::Variable.new(type)
111
130
  when ::RBS::Types::ClassSingleton
112
131
  Object.const_get(type.name.to_s)
113
132
  when ::RBS::Types::ClassInstance
114
133
  case gen = GENERATORS[type.name.absolute!.to_s]
115
- when Proc then instance_exec(&gen).pick(size: size)
116
- when nil then pick_from_initialize(type, size:)
134
+ in Proc then instance_exec(&gen).pick(size: size)
135
+ in nil then pick_from_initialize(type, size:)
117
136
  end
118
137
  when ::RBS::Types::Record
119
138
  type.fields.transform_values { |t| Type.new(t).pick(size:) }
@@ -123,21 +142,17 @@ module RaaP
123
142
  type.literal
124
143
  when ::RBS::Types::Bases::Bool
125
144
  bool.pick(size: size)
126
- when ::RBS::Types::Bases::Void
127
- Value::Void.new
128
145
  when ::RBS::Types::Bases::Any
129
146
  untyped.pick(size: size)
130
147
  when ::RBS::Types::Bases::Nil
131
148
  nil
132
- when ::RBS::Types::Bases::Top
133
- Value::Top.new
134
- when ::RBS::Types::Bases::Bottom
135
- Value::Bottom.new
136
149
  else
137
150
  raise "not implemented #{type.to_s}"
138
151
  end
139
152
  end
140
153
 
154
+ private
155
+
141
156
  def pick_from_initialize(type, size:)
142
157
  type_name = type.name.absolute!
143
158
  const = Object.const_get(type_name.to_s)
@@ -162,12 +177,10 @@ module RaaP
162
177
  raise
163
178
  end
164
179
  else
165
- Value::Module.new(type)
180
+ [:call, Value::Module, :new, [type], {}, nil]
166
181
  end
167
182
  end
168
183
 
169
- private
170
-
171
184
  def parse(type)
172
185
  case type
173
186
  when String
@@ -279,24 +292,28 @@ module RaaP
279
292
 
280
293
  def encoding
281
294
  sized do
282
- # @type block: RaaP::symbolic_call
283
- e = Encoding.list.sample
295
+ e = Encoding.list.sample or raise
284
296
  [:call, Encoding, :find, [e.name], {} , nil]
285
297
  end
286
298
  end
287
299
 
288
300
  def bool
289
- sized { [true, false].sample }
301
+ sized do
302
+ Random.rand(2) == 0
303
+ end
290
304
  end
291
305
 
292
306
  def untyped
293
- case Random.rand(5)
307
+ case Random.rand(9)
294
308
  in 0 then integer
295
309
  in 1 then float
296
- in 2 then string
297
- in 3 then symbol
298
- in 4 then bool
299
- in 5 then encoding
310
+ in 2 then rational
311
+ in 3 then complex
312
+ in 4 then string
313
+ in 5 then symbol
314
+ in 6 then bool
315
+ in 7 then encoding
316
+ in 8 then sized { [:call, BasicObject, :new, [], {}, nil] }
300
317
  end
301
318
  end
302
319
 
@@ -1,13 +1,14 @@
1
1
  module RaaP
2
2
  module Value
3
3
  # FIXME: consider self_types
4
- class Module < BasicObject
4
+ # HINT: intersection?
5
+ class Module
5
6
  attr_reader :type
6
7
 
7
8
  def initialize(type)
8
9
  @type = type
9
10
  const = ::Object.const_get(type.name.absolute!.to_s)
10
- BindCall.extend(self, const)
11
+ extend(const)
11
12
  end
12
13
 
13
14
  def inspect = "#<module #{@type}>"
data/lib/raap/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RaaP
4
- VERSION = "0.1.0"
4
+ VERSION = "0.3.0"
5
5
  end
data/lib/raap.rb CHANGED
@@ -16,14 +16,14 @@ module RaaP
16
16
  end
17
17
 
18
18
  self.logger = ::Logger.new($stdout)
19
- self.logger.level = ::Logger::WARN
19
+ self.logger.level = ::Logger::INFO
20
20
 
21
21
  autoload :BindCall, "raap/bind_call"
22
22
  autoload :CLI, "raap/cli"
23
23
  autoload :FunctionType, "raap/function_type"
24
24
  autoload :MethodProperty, "raap/method_property"
25
25
  autoload :MethodType, "raap/method_type"
26
- autoload :MethodValue, "raap/method_value"
26
+ autoload :Minitest, "raap/minitest"
27
27
  autoload :RBS, "raap/rbs"
28
28
  autoload :Result, "raap/result"
29
29
  autoload :Sized, "raap/sized"
data/sig/raap.rbs CHANGED
@@ -19,15 +19,15 @@ module RaaP
19
19
 
20
20
  class CLI
21
21
  class Option < ::Struct[untyped]
22
- def self.new: (?dirs: ::Array[String], ?requires: ::Array[String], ?libraries: ::Array[String], ?timeout: (Integer | Float | nil), ?size_from: ::Integer, ?size_to: ::Integer, ?size_by: ::Integer) -> instance
22
+ def self.new: (?dirs: ::Array[String], ?requires: ::Array[String], ?libraries: ::Array[String], ?timeout: (Integer | Float | nil), ?size_from: ::Integer, ?size_to: ::Integer, ?size_by: ::Integer, ?allow_private: bool) -> instance
23
23
 
24
- def self.[]: (?dirs: ::Array[String], ?requires: ::Array[String], ?libraries: ::Array[String], ?timeout: (Integer | Float | nil), ?size_from: ::Integer, ?size_to: ::Integer, ?size_by: ::Integer) -> instance
24
+ def self.[]: (?dirs: ::Array[String], ?requires: ::Array[String], ?libraries: ::Array[String], ?timeout: (Integer | Float | nil), ?size_from: ::Integer, ?size_to: ::Integer, ?size_by: ::Integer, ?allow_private: bool) -> instance
25
25
 
26
26
  def self.keyword_init?: () -> true
27
27
 
28
- def self.members: () -> [ :dirs, :requires, :library, :timeout, :size_from, :size_to, :size_by]
28
+ def self.members: () -> [ :dirs, :requires, :library, :timeout, :size_from, :size_to, :size_by, :allow_private]
29
29
 
30
- def members: () -> [ :dirs, :requires, :library, :timeout, :size_from, :size_to, :size_by]
30
+ def members: () -> [ :dirs, :requires, :library, :timeout, :size_from, :size_to, :size_by, :allow_private]
31
31
 
32
32
  attr_accessor dirs: ::Array[String]
33
33
 
@@ -42,6 +42,8 @@ module RaaP
42
42
  attr_accessor size_to: ::Integer
43
43
 
44
44
  attr_accessor size_by: ::Integer
45
+
46
+ attr_accessor allow_private: bool
45
47
  end
46
48
 
47
49
  @argv: Array[String]
@@ -81,12 +83,15 @@ module RaaP
81
83
  attr_accessor skip: Integer
82
84
  attr_accessor exception: Integer
83
85
  end
84
- attr_reader receiver_type: Type
85
- attr_reader method_name: Symbol
86
- attr_reader method_type: MethodType
87
- attr_reader size_step: _Each[Integer]
88
- attr_reader timeout: (Integer | Float | nil)
89
- def initialize: (receiver_type: Type, method_name: Symbol, method_type: MethodType, size_step: _Each[Integer], timeout: (Integer | Float | nil)) -> void
86
+
87
+ @receiver_type: Type
88
+ @method_name: Symbol
89
+ @method_type: MethodType
90
+ @size_step: _Each[Integer]
91
+ @timeout: (Integer | Float | nil)
92
+ @allow_private: bool
93
+
94
+ def initialize: (receiver_type: Type, method_name: Symbol, method_type: MethodType, size_step: _Each[Integer], timeout: (Integer | Float | nil), ?allow_private: bool) -> void
90
95
  def run: () { (Result::Success | Result::Failure | Result::Skip | Result::Exception) -> void } -> Stats
91
96
 
92
97
  private
@@ -103,33 +108,17 @@ module RaaP
103
108
  def initialize: (::RBS::MethodType | String method, ?type_params_decl: Array[untyped], ?type_args: Array[untyped], ?self_type: ::RBS::Types::ClassInstance?, ?instance_type: ::RBS::Types::ClassInstance?, ?class_type: ::RBS::Types::ClassSingleton?) -> void
104
109
  def pick_arguments: (?size: Integer, ?eval: bool) -> [Array[untyped], Hash[Symbol, untyped], ::Proc?]
105
110
  def pick_block: (?size: Integer, ?eval: bool) -> ::Proc?
111
+ def check_return: (untyped) -> bool
106
112
  end
107
113
 
108
- class MethodValue < Data
109
- def self.new: (untyped receiver_value, [Array[untyped], Hash[Symbol, untyped], ::Proc?] arguments, Symbol method_name, Integer size) -> instance
110
- | (receiver_value: untyped, arguments: [Array[untyped], Hash[Symbol, untyped], ::Proc?], method_name: Symbol, size: Integer) -> instance
111
-
112
- def self.[]: (untyped receiver_value, [Array[untyped], Hash[Symbol, untyped], ::Proc?] arguments, Symbol method_name, Integer size) -> instance
113
- | (receiver_value: untyped, arguments: [Array[untyped], Hash[Symbol, untyped], ::Proc?], method_name: Symbol, size: Integer) -> instance
114
-
115
- def self.members: () -> [ :receiver_value, :arguments, :method_name, :size ]
116
- def members: () -> [ :receiver_value, :arguments, :method_name, :size ]
117
-
118
- attr_reader receiver_value: untyped
119
- attr_reader arguments: [Array[untyped], Hash[Symbol, untyped], ::Proc?]
120
- attr_reader method_name: Symbol
121
- attr_reader size: Integer
122
-
123
- def to_symbolic_call: () -> symbolic_call
124
- def call_str: () -> String
125
-
126
- private
127
-
128
- def argument_str: () -> String
129
- def block_str: () -> String?
114
+ module Minitest
130
115
  end
131
116
 
132
117
  module RBS
118
+ self.@builder: ::RBS::DefinitionBuilder
119
+ self.@env: ::RBS::Environment
120
+ self.@loader: ::RBS::EnvironmentLoader
121
+
133
122
  def self.builder: () -> ::RBS::DefinitionBuilder
134
123
  def self.env: () -> ::RBS::Environment
135
124
  def self.loader: () -> ::RBS::EnvironmentLoader
@@ -138,60 +127,67 @@ module RaaP
138
127
 
139
128
  module Result
140
129
  interface _MethodValueReturnValue
141
- def method_value: () -> MethodValue
130
+ def symbolic_call: () -> symbolic_call
142
131
  def return_value: () -> untyped
143
132
  end
144
133
  module CalledStr : _MethodValueReturnValue
145
134
  def called_str: () -> String
146
135
  end
147
136
  class Success < Data
148
- def self.new: (method_value: MethodValue, return_value: untyped) -> instance
149
- attr_reader method_value: MethodValue
137
+ def self.new: (symbolic_call: symbolic_call, return_value: untyped) -> instance
138
+ attr_reader symbolic_call: symbolic_call
150
139
  attr_reader return_value: untyped
151
140
  include CalledStr
152
141
  end
153
142
  class Failure < Data
154
- def self.new: (method_value: MethodValue, return_value: untyped, symbolic_call: symbolic_call) -> instance
155
- attr_reader method_value: MethodValue
156
- attr_reader return_value: untyped
143
+ def self.new: (symbolic_call: symbolic_call, return_value: untyped, ?exception: ::Exception?) -> instance
157
144
  attr_reader symbolic_call: symbolic_call
145
+ attr_reader return_value: untyped
146
+ attr_reader exception: ::Exception?
158
147
  include CalledStr
159
148
  end
160
149
  class Skip < Data
161
- def self.new: (method_value: MethodValue?, exception: ::Exception) -> instance
162
- attr_reader method_value: MethodValue?
150
+ def self.new: (symbolic_call: symbolic_call?, exception: ::Exception) -> instance
151
+ attr_reader symbolic_call: symbolic_call?
163
152
  attr_reader exception: ::Exception
164
153
  end
165
154
  class Exception < Data
166
- def self.new: (method_value: MethodValue?, exception: ::Exception) -> instance
167
- attr_reader method_value: MethodValue?
155
+ def self.new: (symbolic_call: symbolic_call?, exception: ::Exception) -> instance
156
+ attr_reader symbolic_call: symbolic_call?
168
157
  attr_reader exception: ::Exception
169
158
  end
170
159
  end
171
160
 
172
- interface _Pick[T]
173
- def pick: (size: Integer) -> T
174
- end
175
-
176
- class Sized
161
+ class Sized[T]
177
162
  @block: ::Proc
178
163
  @such_that: ::Proc?
179
164
 
180
165
  def initialize: () { (Integer) -> untyped } -> void
181
- include _Pick[untyped]
166
+ def pick: (size: Integer) -> T
182
167
  def such_that: () { (untyped) -> boolish } -> self
183
168
  def such_that_loop: [R] () { (Integer) -> R } -> R
184
169
  end
185
170
 
186
171
  class SymbolicCaller
172
+ class Var
173
+ attr_reader name: String
174
+ def initialize: (String name) -> void
175
+ def +: (String) -> String
176
+ def to_s: () -> String
177
+ end
178
+
187
179
  attr_reader symbolic_call: untyped
188
- def initialize: (untyped) -> void
180
+ attr_reader allow_private: bool
181
+
182
+ def initialize: (untyped, ?allow_private: bool) -> void
189
183
  def eval: () -> untyped
190
- def walk: () ?{ (symbolic_call) -> untyped} -> untyped
184
+ def call_str: () -> String
191
185
  def to_lines: () -> Array[String]
192
186
 
193
187
  private
194
188
 
189
+ def try_eval: (untyped) -> untyped
190
+ def walk: () ?{ (symbolic_call) -> untyped} -> untyped
195
191
  def _walk: (untyped) ?{ (symbolic_call) -> untyped} -> untyped
196
192
  def eval_one: (symbolic_call) -> untyped
197
193
  def var_name: (Module) -> String
@@ -213,7 +209,7 @@ module RaaP
213
209
  def map_type: { (untyped) -> untyped } -> untyped
214
210
  end
215
211
 
216
- def sub: (_MapType search, self_type: ::RBS::Types::ClassInstance?, instance_type: ::RBS::Types::ClassInstance?, ?class_type: ::RBS::Types::ClassSingleton?) -> untyped
212
+ def sub: (_MapType search, self_type: ::RBS::Types::ClassInstance?, instance_type: ::RBS::Types::ClassInstance?, class_type: ::RBS::Types::ClassSingleton?) -> untyped
217
213
  end
218
214
 
219
215
  class Type
@@ -222,39 +218,45 @@ module RaaP
222
218
  def self.positive_float: () -> Float
223
219
  end
224
220
 
225
- GENERATORS: Hash[String, ^() -> _Pick[untyped] | Proc]
221
+ @such_that: (^(untyped) -> ::boolish)?
222
+
223
+ GENERATORS: Hash[String, ^() -> Sized[untyped]]
226
224
  SIMPLE_SOURCE: Array[String]
227
225
  RECURSION: Hash[String, :found | :logged]
228
226
 
229
- def self.register: (String) { () [self: instance] -> _Pick[untyped] } -> void
227
+ def self.register: (String) { () [self: instance] -> Sized[untyped] } -> void
230
228
  attr_reader type: ::RBS::Types::t
231
229
  attr_reader range: Range[untyped]
232
230
 
233
231
  def initialize: (String | ::RBS::Types::t, ?range: Range[untyped]) -> void
234
232
 
235
- include _Pick[untyped]
236
- def pick: (?size: Integer, ?eval: bool) -> untyped | ...
233
+ # Define rule for generating values
234
+ # type.such_that { |i| i != 0 }.pick #=> ensure that the value is not 0
235
+ def such_that: () { (untyped) -> boolish } -> self
236
+
237
+ # Basic API for materializing values
238
+ def pick: (?size: Integer, ?eval: bool) -> untyped
237
239
  def to_symbolic_call: (?size: Integer) -> untyped
238
- def pick_from_initialize: (::RBS::Types::ClassInstance, size: Integer) -> untyped
239
- def sized: () { (Integer size) -> untyped } -> _Pick[untyped]
240
+ def sized: [T] () { (Integer size) -> T } -> Sized[T]
240
241
 
241
242
  private
242
243
 
244
+ def pick_from_initialize: (::RBS::Types::ClassInstance, size: Integer) -> (symbolic_call | Value::Module)
243
245
  def parse: (String | ::RBS::Types::t) -> ::RBS::Types::t?
244
246
  def try: (times: Integer, size: Integer) { (Integer size) -> untyped } -> untyped
245
247
 
246
- def numeric: () -> _Pick[Numeric]
247
- def integer: () -> _Pick[Integer]
248
- def none_zero_integer: () -> _Pick[Integer]
249
- def float: () -> _Pick[Float]
250
- def rational: () -> _Pick[Rational]
251
- def complex: () -> _Pick[Complex]
252
- def string: () -> _Pick[String]
253
- def symbol: () -> _Pick[Symbol]
254
- def array: (Type) -> _Pick[Array[untyped]]
255
- def encoding: () -> _Pick[Encoding]
256
- def bool: () -> _Pick[bool]
257
- def untyped: () -> _Pick[untyped]
248
+ def numeric: () -> Sized[Numeric]
249
+ def integer: () -> Sized[Integer]
250
+ def none_zero_integer: () -> Sized[Integer]
251
+ def float: () -> Sized[Float]
252
+ def rational: () -> Sized[symbolic_call]
253
+ def complex: () -> Sized[symbolic_call]
254
+ def string: () -> Sized[String]
255
+ def symbol: () -> Sized[Symbol]
256
+ def array: (Type) -> Sized[Array[untyped]]
257
+ def encoding: () -> Sized[symbolic_call]
258
+ def bool: () -> Sized[bool]
259
+ def untyped: () -> Sized[untyped]
258
260
  def temp_method_object: () -> ::Method
259
261
  end
260
262
 
@@ -284,7 +286,7 @@ module RaaP
284
286
  def class: () -> class
285
287
  end
286
288
 
287
- class Module < BasicObject
289
+ class Module
288
290
  attr_reader type: ::RBS::Types::ClassInstance
289
291
 
290
292
  def initialize: (::RBS::Types::ClassInstance) -> void
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: raap
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - ksss
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-03-20 00:00:00.000000000 Z
11
+ date: 2024-03-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rbs
@@ -59,7 +59,7 @@ files:
59
59
  - lib/raap/function_type.rb
60
60
  - lib/raap/method_property.rb
61
61
  - lib/raap/method_type.rb
62
- - lib/raap/method_value.rb
62
+ - lib/raap/minitest.rb
63
63
  - lib/raap/rbs.rb
64
64
  - lib/raap/result.rb
65
65
  - lib/raap/sized.rb
@@ -1,38 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module RaaP
4
- class MethodValue < Data.define(
5
- :receiver_value,
6
- :arguments,
7
- :method_name,
8
- :size
9
- )
10
- def to_symbolic_call
11
- args, kwargs, block = arguments
12
- [:call, receiver_value, method_name, args, kwargs, block]
13
- end
14
-
15
- def call_str
16
- r = SymbolicCaller.new(receiver_value).eval
17
- "#{BindCall.inspect(r)}.#{method_name}(#{argument_str})#{block_str}"
18
- end
19
-
20
- private
21
-
22
- def argument_str
23
- args, kwargs, _ = SymbolicCaller.new(arguments).eval
24
-
25
- r = []
26
- r << args.map(&:inspect).join(', ') if !args.empty?
27
- r << kwargs.map { |k ,v| "#{k}: #{BindCall.inspect(v)}" }.join(', ') if !kwargs.empty?
28
- r.join(', ')
29
- end
30
-
31
- def block_str
32
- _, _, block = SymbolicCaller.new(arguments).eval
33
- if block
34
- "{ }"
35
- end
36
- end
37
- end
38
- end