raap 0.6.0 → 0.7.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: 5780226ede8755c1ef7f82e18b7e8d96a63d2ab6eb253bc8964f5745776f993f
4
- data.tar.gz: 6e9dd39a302f555cac12ecb6232a7c2f39d206911fcee7a30650d5fe4a9cbc63
3
+ metadata.gz: 13f734d53db009621045979dfc7d705b14c2f378625ff36067784995e8889134
4
+ data.tar.gz: 472adf32ff8ea739d83a5b41c6a62e80149b29e34d44536df844010eb2e8cb90
5
5
  SHA512:
6
- metadata.gz: 2841e75bc0b03742cc0d9268f9ec2ae69f2f9c6e1f579ec6e794db5e9b8f80d763fac4ce28abd7361e19ada8f6289e594b6a9a3cdc63b1806181a69a9f49bb6a
7
- data.tar.gz: a3057811c5d13ac4f891fc2c2082b91f33a1a8d35d3c9b6e1ccb1871c268127811caa6f2708c878ef35ae4cc25143db62c4e5801ded32cfad9a1db50387753a6
6
+ metadata.gz: cc3782c7a65e098eef727163ccc069ca27b339eeaadc7be44abd2eac94c78fa74443c413364e579998dd49aa11c5be38bd27f6504f92759580ec893dd54a3e97
7
+ data.tar.gz: 68e133fa67a03d4c84ab264c1e0fd1c40204da8995a552e99912eb61c1cddb14d9c81bac26c4aa04615d9833dfa74ad64bd212071dd3195dacad6ae85bd23b54
data/.rubocop.yml CHANGED
@@ -8,6 +8,8 @@ Lint:
8
8
  Enabled: true
9
9
  Lint/EmptyBlock:
10
10
  Enabled: false
11
+ Lint/SymbolConversion:
12
+ Enabled: false
11
13
 
12
14
  Style:
13
15
  Enabled: false
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # RaaP
2
2
 
3
- <img src="https://raw.githubusercontent.com/ksss/raap/main/public/jacket.webp" width=400/>
3
+ <img src="https://raw.githubusercontent.com/ksss/raap/main/public/jacket.webp" width=500/>
4
4
 
5
5
  ## RBS as a Property
6
6
 
@@ -14,6 +14,10 @@ The return value of the method is checked to see if it matches the type, if not,
14
14
 
15
15
  If you write an RBS, it becomes a test case.
16
16
 
17
+ ## Example
18
+
19
+ <img src="https://raw.githubusercontent.com/ksss/raap/main/public/example.webp" width=700/>
20
+
17
21
  ## Concept
18
22
 
19
23
  If you has next signature.
@@ -88,6 +92,20 @@ $ raap $(cat test/raap.txt) # You can manage the methods to be tested in a fil
88
92
  - info: A somewhat visualized representation of the execution state.
89
93
  - debug: All information including stack traces.
90
94
 
95
+ ## Coverage
96
+
97
+ RaaP randomly selects a type and generates a value for optional and union types.
98
+
99
+ By default, displays the coverage of the type that actually produced the value.
100
+
101
+ The coverage display can help you determine if a correction is needed.
102
+
103
+ ### Meaning of colored types
104
+
105
+ - 🔴 Red: A type that has never been used to generate or validate a value.
106
+ - 🟡 Yellow: It is systematically difficult to determine if the type was used or not. (FIXME)
107
+ - 🟢 Green: The type used to generate and validate the value.
108
+
91
109
  ## Size
92
110
 
93
111
  Random values are determined based on size.
@@ -150,6 +168,42 @@ You can specify size of step like `Integer#step: (to: Integer, by: Integer)`.
150
168
  By default, raap only validates public methods.
151
169
  However, by setting this option, it is possible to intentionally validate private methods in the RBS.
152
170
 
171
+ ### `--preload path`
172
+
173
+ Simply call `Kernel.load`.
174
+ However, this simplifies the preliminary preparation.
175
+
176
+ #### Preload examples
177
+
178
+ 1) Check signature of aws-sdk-s3
179
+
180
+ ```rb
181
+ $ cat preload.rb
182
+ require 'aws-sdk-s3'
183
+
184
+ # Register initialize of `Aws::S3::Client` class.
185
+ RaaP::Type.register("Aws::S3::Client") do
186
+ [:call, Aws::S3::Client, :new, [], { stub_responses: true }, nil]
187
+ end
188
+
189
+ $ raap --preload ./preload.rb 'Aws::S3::Client#get_object'
190
+ ```
191
+
192
+ 2) Output ruby coverage by simplecov
193
+
194
+ ```rb
195
+ $ cat preload.rb
196
+ require 'simplecov'
197
+
198
+ SimpleCov.command_name 'raap'
199
+ SimpleCov.start do
200
+ enable_coverage :branch
201
+ add_filter "/test/"
202
+ end
203
+
204
+ $ bundle exec raap --preload ./preload.rb -r my_class 'MyClass'
205
+ ```
206
+
153
207
  ## First support is CLI
154
208
 
155
209
  In RaaP, usage through the CLI is the primary support focus, and efforts are made to maintain compatibility. The use of the library's code (such as `RaaP::Type`) does not guarantee compatibility.
data/lib/raap/cli.rb CHANGED
@@ -12,6 +12,7 @@ module RaaP
12
12
  :size_to,
13
13
  :size_by,
14
14
  :allow_private,
15
+ :coverage,
15
16
  keyword_init: true
16
17
  )
17
18
 
@@ -44,6 +45,7 @@ module RaaP
44
45
  size_from: 0,
45
46
  size_to: 99,
46
47
  size_by: 1,
48
+ coverage: true,
47
49
  allow_private: false,
48
50
  )
49
51
  @argv = argv
@@ -80,6 +82,12 @@ module RaaP
80
82
  o.on('--allow-private', "default: #{@option.allow_private}") do
81
83
  @option.allow_private = true
82
84
  end
85
+ o.on('--preload path', 'Kernel.load path') do |path|
86
+ Kernel.load path
87
+ end
88
+ o.on('--[no-]coverage', "Show coverage for RBS (default: #{@option.coverage})") do |arg|
89
+ @option.coverage = arg
90
+ end
83
91
  end.parse!(@argv)
84
92
 
85
93
  @option.dirs.each do |dir|
@@ -300,6 +308,7 @@ module RaaP
300
308
  timeout: @option.timeout,
301
309
  allow_private: @option.allow_private,
302
310
  )
311
+ RaaP::Coverage.start(method_type) if @option.coverage
303
312
  start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
304
313
  stats = prop.run do |called|
305
314
  case called
@@ -337,6 +346,9 @@ module RaaP
337
346
  end
338
347
  end_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
339
348
  puts
349
+ RaaP::Coverage.show($stdout) if @option.coverage
350
+ puts
351
+
340
352
  time_diff = end_time - start_time
341
353
  time = ", time: #{(time_diff * 1000).round}ms"
342
354
  stats_log = "success: #{stats.success}, skip: #{stats.skip}, exception: #{stats.exception}#{time}"
@@ -0,0 +1,188 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RaaP
4
+ module Coverage
5
+ class Writer
6
+ def initialize(method_type, cov)
7
+ @method_type = method_type
8
+ @cov = cov
9
+ @cur = 0
10
+ end
11
+
12
+ def write(io)
13
+ RaaP.logger.debug { "Coverage: #{@cov}" }
14
+ ml = @method_type.location
15
+ unless ml
16
+ RaaP.logger.warn("No location information for `#{@method_type}`")
17
+ return
18
+ end
19
+ if ml.key?(:keyword)
20
+ # attr_{reader,writer,accessor}
21
+ phantom_member = RBS.parse_member(ml.source)
22
+ case phantom_member
23
+ when ::RBS::AST::Members::Attribute
24
+ unless phantom_member.location
25
+ RaaP.logger.warn("No location information for `#{phantom_member}`")
26
+ return
27
+ end
28
+ write_type(io, "return", phantom_member.type, :abs)
29
+ io.write(slice(@cur, @cur...phantom_member.location.end_pos))
30
+ else
31
+ RaaP.logger.error("#{phantom_member.class} is not supported")
32
+ return
33
+ end
34
+ else
35
+ # def name: () -> type
36
+ phantom_method_type = RBS.parse_method_type(ml.source)
37
+ phantom_method_type.type.yield_self do |fun|
38
+ case fun
39
+ when ::RBS::Types::Function
40
+ fun.required_positionals.each_with_index { |param, i| write_param(io, "req_#{i}", param, :abs) }
41
+ fun.optional_positionals.each_with_index { |param, i| write_param(io, "opt_#{i}", param, :opt) }
42
+ fun.rest_positionals&.yield_self { |param| write_param(io, "rest", param, :opt) }
43
+ fun.trailing_positionals.each_with_index { |param, i| write_param(io, "trail_#{i}", param, :abs) }
44
+ fun.required_keywords.each { |key, param| write_param(io, "keyreq_#{key}", param, :abs) }
45
+ fun.optional_keywords.each { |key, param| write_param(io, "key_#{key}", param, :opt) }
46
+ fun.rest_keywords&.yield_self { |param| write_param(io, "keyrest", param, :opt) }
47
+ # when ::RBS::Types::UntypedFunction
48
+ end
49
+ end
50
+
51
+ phantom_method_type.block&.yield_self do |b|
52
+ b.type.each_param.with_index { |param, i| write_param(io, "block_param_#{i}", param, :opt) }
53
+ write_type(io, "block_return", b.type.return_type, :abs)
54
+ end
55
+ write_type(io, "return", phantom_method_type.type.return_type, :abs)
56
+ raise unless phantom_method_type.location
57
+
58
+ io.write(slice(@cur, @cur...phantom_method_type.location.end_pos))
59
+ end
60
+
61
+ io.puts
62
+ end
63
+
64
+ private
65
+
66
+ def slice(start, range)
67
+ ml = @method_type.location
68
+ raise unless ml
69
+
70
+ ml.source[start, range.end - range.begin] or raise
71
+ end
72
+
73
+ def write_param(io, position, param, accuracy)
74
+ write_type(io, position, param.type, accuracy)
75
+ end
76
+
77
+ def write_type(io, position, type, accuracy)
78
+ unless type.location
79
+ RaaP.logger.warn("No location information for `#{type}`")
80
+ return
81
+ end
82
+ io.write(slice(@cur, @cur...type.location.start_pos))
83
+ @cur = type.location.start_pos
84
+ case type
85
+ when ::RBS::Types::Tuple, ::RBS::Types::Union
86
+ name = type.class.name.split('::').last.downcase
87
+ type.types.each_with_index do |t, i|
88
+ t.location or raise
89
+ io.write(slice(@cur, @cur...t.location.start_pos)) # ( or [
90
+ @cur = t.location.start_pos
91
+ write_type(io, "#{position}_#{name}_#{i}", t, accuracy)
92
+ end
93
+ when ::RBS::Types::Optional
94
+ raise unless type.location
95
+
96
+ write_type(io, "#{position}_optional_left", type.type, accuracy)
97
+ io.write(slice(@cur, @cur...(type.location.end_pos - 1)))
98
+ @cur = type.location.end_pos - 1
99
+ if @cov.include?("#{position}_optional_right".to_sym)
100
+ io.write(green('?'))
101
+ else
102
+ io.write(red('?'))
103
+ end
104
+ raise unless type.location
105
+
106
+ @cur = type.location.end_pos
107
+ when ::RBS::Types::Variable
108
+ case accuracy
109
+ when :abs
110
+ io.write(green(type.name.to_s))
111
+ when :opt
112
+ # Variables are substed so raap don't know if they've been used.
113
+ io.write(yellow(type.name.to_s))
114
+ end
115
+ raise unless type.location
116
+
117
+ @cur = type.location.end_pos
118
+ else
119
+ raise unless type.location
120
+
121
+ if @cov.include?(position.to_sym)
122
+ io.write(green(type.location.source))
123
+ else
124
+ io.write(red(type.location.source))
125
+ end
126
+ @cur = type.location.end_pos
127
+ end
128
+ end
129
+
130
+ def green(str) = "\e[32m#{str}\e[0m"
131
+ def red(str) = "\e[1;4;41m#{str}\e[0m"
132
+ def yellow(str) = "\e[93m#{str}\e[0m"
133
+ end
134
+
135
+ class << self
136
+ def start(method_type)
137
+ @cov = Set.new
138
+ @method_type = method_type
139
+ end
140
+
141
+ def running?
142
+ !!@cov
143
+ end
144
+
145
+ # position: req_0
146
+ # type: union_1
147
+ def log(position)
148
+ return unless running?
149
+
150
+ cov << position.to_sym
151
+ end
152
+
153
+ def cov
154
+ @cov or raise
155
+ end
156
+
157
+ def show(io)
158
+ return unless running?
159
+
160
+ writer = Writer.new(@method_type, cov)
161
+ writer.write(io)
162
+ end
163
+
164
+ def new_type_with_log(position, type)
165
+ case type
166
+ when ::RBS::Types::Tuple
167
+ # FIXME: Support Union in Tuple
168
+ type.types.each_with_index do |_t, i|
169
+ log("#{position}_tuple_#{i}")
170
+ end
171
+ Type.new(type)
172
+ when ::RBS::Types::Union
173
+ i = Random.rand(type.types.length)
174
+ new_type_with_log("#{position}_union_#{i}", type.types[i])
175
+ when ::RBS::Types::Optional
176
+ if Random.rand(2).zero?
177
+ new_type_with_log("#{position}_optional_left", type.type)
178
+ else
179
+ new_type_with_log("#{position}_optional_right", ::RBS::Types::Bases::Nil.new(location: nil))
180
+ end
181
+ else
182
+ log(position)
183
+ Type.new(type)
184
+ end
185
+ end
186
+ end
187
+ end
188
+ end
@@ -26,42 +26,62 @@ module RaaP
26
26
  when type.respond_to?(:each_pair)
27
27
  type.each_pair.to_h { |k, v| [k, to_symbolic_call_recursive(v, size: size)] }
28
28
  when type.respond_to?(:each)
29
- type.each.map { |v| to_symbolic_call_recursive(v, size: size) }
29
+ type.map { |v| to_symbolic_call_recursive(v, size: size) }
30
30
  else
31
31
  type.to_symbolic_call(size: size)
32
32
  end
33
33
  end
34
34
 
35
35
  def build_args_type
36
- reqs = @fun.required_positionals.map { |param| Type.new(param.type) }
37
- tras = @fun.trailing_positionals.map { |param| Type.new(param.type) }
38
- sampled_optional_positionals = @fun.optional_positionals.take(Random.rand(@fun.optional_positionals.length + 1))
39
- opts = sampled_optional_positionals.map { |param| Type.new(param.type) }
36
+ reqs = @fun.required_positionals.map.with_index do |param, i|
37
+ build_type_with_coverage("req_#{i}", param)
38
+ end
39
+
40
+ take_num = Random.rand(@fun.optional_positionals.length + 1)
41
+ opts = @fun.optional_positionals.take(take_num).map.each_with_index do |param, i|
42
+ build_type_with_coverage("opt_#{i}", param)
43
+ end
44
+
40
45
  rest = []
41
- if (param = @fun.rest_positionals)
42
- rest = Array.new(Random.rand(0..3)) { Type.new(param.type) }
46
+ if (rest_param = @fun.rest_positionals)
47
+ rest = Array.new(Random.rand(4)) do
48
+ build_type_with_coverage("rest", rest_param)
49
+ end
50
+ end
51
+
52
+ tras = @fun.trailing_positionals.map.with_index do |param, i|
53
+ build_type_with_coverage("trail_#{i}", param)
43
54
  end
55
+
44
56
  [reqs, opts, rest, tras].flatten
45
57
  end
46
58
 
47
59
  def build_kwargs_type
48
- reqs = @fun.required_keywords.transform_values { |param| Type.new(param.type) }
60
+ reqs = @fun.required_keywords.keys.to_h do |key|
61
+ [key, build_type_with_coverage("keyreq_#{key}", @fun.required_keywords[key])]
62
+ end
49
63
  rand = Random.rand(@fun.optional_keywords.length + 1)
50
- opts = @fun.optional_keywords.to_a.sample(rand).to_h { |name, param| [name, Type.new(param.type)] }
64
+ opts = @fun.optional_keywords.to_a.sample(rand).to_h do |key, param|
65
+ [key, build_type_with_coverage("key_#{key}", param)]
66
+ end
51
67
  kwargs = reqs.to_h.merge(opts)
52
68
  if (param = @fun.rest_keywords)
53
- keys = Array.new(Random.rand(0..3)) do
69
+ keys = Array.new(Random.rand(4)) do
54
70
  random_key = nil
55
71
  loop do
56
72
  # @type var random_key: Symbol
57
73
  random_key = Type.new("Symbol").pick(size: 6)
58
74
  break unless kwargs.key?(random_key)
59
75
  end
60
- [random_key, Type.new(param.type)]
76
+ [random_key, build_type_with_coverage("keyrest", param)]
61
77
  end
62
78
  kwargs.merge!(keys.to_h)
63
79
  end
64
80
  kwargs
65
81
  end
82
+
83
+ def build_type_with_coverage(position, param)
84
+ Coverage.new_type_with_log(position, param.type)
85
+ end
66
86
  end
67
87
  end
@@ -67,8 +67,9 @@ module RaaP
67
67
  begin
68
68
  return_value = symbolic_caller.eval
69
69
  rescue StandardError, NotImplementedError
70
- check = [:success]
71
70
  return_value = Value::Bottom.new
71
+ coverage("return", return_value, return_type)
72
+ check = [:success]
72
73
  rescue Timeout::ExitException
73
74
  raise
74
75
  rescue Exception => e # rubocop:disable Lint/RescueException
@@ -113,6 +114,7 @@ module RaaP
113
114
  if BindCall.is_a?(return_type, ::RBS::Types::ClassSingleton)
114
115
  # ::RBS::Test::TypeCheck cannot support to check singleton class
115
116
  if receiver_value == return_value
117
+ coverage("return", return_value, return_type)
116
118
  [:success]
117
119
  else
118
120
  [:failure]
@@ -135,6 +137,7 @@ module RaaP
135
137
  )
136
138
  begin
137
139
  if type_check.value(return_value, return_type)
140
+ coverage("return", return_value, return_type, type_check)
138
141
  [:success]
139
142
  else
140
143
  [:failure]
@@ -148,5 +151,33 @@ module RaaP
148
151
  def return_type
149
152
  @method_type.rbs.type.return_type
150
153
  end
154
+
155
+ def coverage(position, return_value, return_type, type_check = nil)
156
+ return unless Coverage.running?
157
+
158
+ case return_type
159
+ when ::RBS::Types::Tuple
160
+ return_type.types.zip(return_value).each_with_index do |(type, value), i|
161
+ if type_check&.value(value, type)
162
+ coverage("#{position}_tuple_#{i}", value, type, type_check)
163
+ end
164
+ end
165
+ when ::RBS::Types::Union
166
+ return_type.types.each_with_index do |type, i|
167
+ if type_check&.value(return_value, type)
168
+ coverage("#{position}_union_#{i}", return_value, type, type_check)
169
+ break
170
+ end
171
+ end
172
+ when ::RBS::Types::Optional
173
+ if return_value.nil?
174
+ Coverage.log("#{position}_optional_right")
175
+ else
176
+ coverage("#{position}_optional_left", return_value, return_type.type, type_check)
177
+ end
178
+ else
179
+ Coverage.log(position)
180
+ end
181
+ end
151
182
  end
152
183
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module RaaP
4
4
  class MethodType
5
- attr_reader :rbs
5
+ attr_reader :rbs, :original_rbs
6
6
 
7
7
  def initialize(method, type_params_decl: [], type_args: [], self_type: nil, instance_type: nil, class_type: nil)
8
8
  rbs =
@@ -20,8 +20,10 @@ module RaaP
20
20
  params = (type_params_decl + rbs.type_params).uniq
21
21
  ts = TypeSubstitution.new(params, type_args)
22
22
 
23
+ @original_rbs = rbs
23
24
  @rbs = ts.method_type_sub(rbs, self_type: self_type, instance_type: instance_type, class_type: class_type)
24
- @fun_type = FunctionType.new(@rbs.type)
25
+ function_or_untypedfunction = __skip__ = @rbs.type
26
+ @fun_type = FunctionType.new(function_or_untypedfunction)
25
27
  end
26
28
 
27
29
  def pick_arguments(size: 10)
@@ -41,7 +43,14 @@ module RaaP
41
43
  return nil if (block.required == false) && [true, false].sample
42
44
 
43
45
  fixed_return_value = Type.new(block.type.return_type).pick(size: size)
44
- Proc.new { fixed_return_value }
46
+ Proc.new do
47
+ block.type.each_param.with_index do |_param, i|
48
+ Coverage.log("block_param_#{i}")
49
+ end
50
+
51
+ Coverage.new_type_with_log("block_return", block.type.return_type)
52
+ fixed_return_value
53
+ end
45
54
  end
46
55
 
47
56
  def check_return(return_value)
data/lib/raap/rbs.rb CHANGED
@@ -26,6 +26,48 @@ module RaaP
26
26
  ::RBS::Parser.parse_method_type(method_type, require_eof: true) or raise
27
27
  end
28
28
 
29
+ def self.parse_member(member_type)
30
+ _, _, decls = ::RBS::Parser.parse_signature(<<~RBS)
31
+ module MemberScope
32
+ #{member_type}
33
+ end
34
+ RBS
35
+ decl = decls.first or raise
36
+ raise unless decl.is_a?(::RBS::AST::Declarations::Module)
37
+
38
+ member = decl.members.first or raise
39
+ raise unless member.is_a?(::RBS::AST::Members::Attribute)
40
+
41
+ member.tap do |m|
42
+ m = __skip__ = m
43
+ _shift_location(m.type, -m.location.start_pos)
44
+ _shift_location(m, -m.location.start_pos)
45
+ end
46
+ end
47
+
48
+ def self._shift_location(localable, shift)
49
+ return if localable.location.nil?
50
+
51
+ l = localable.instance_variable_get("@location")
52
+ localable.instance_variable_set(
53
+ "@location",
54
+ ::RBS::Location.new(
55
+ buffer: ::RBS::Buffer.new(
56
+ name: l.buffer.name,
57
+ content: l.buffer.content[-shift..l.end_pos],
58
+ ),
59
+ start_pos: l.start_pos + shift,
60
+ end_pos: l.end_pos + shift,
61
+ )
62
+ )
63
+ case localable
64
+ when ::RBS::Types::Union
65
+ localable.types.each { |t| _shift_location(t, shift) }
66
+ when ::RBS::Types::Optional
67
+ _shift_location(localable.type, shift)
68
+ end
69
+ end
70
+
29
71
  def self.find_alias_decl(type_name, method_name)
30
72
  env.class_decls[type_name].decls.each do |d|
31
73
  d.decl.members.each do |member|
data/lib/raap/type.rb CHANGED
@@ -24,6 +24,7 @@ module RaaP
24
24
  def self.register(type_name, &block)
25
25
  raise ArgumentError, "block is required" unless block
26
26
 
27
+ type_name = "::#{type_name}" if !type_name.start_with?("::")
27
28
  GENERATORS[type_name] = __skip__ = block
28
29
  end
29
30
 
@@ -69,11 +70,12 @@ module RaaP
69
70
  t = instance.args[0] ? Type.new(instance.args[0], range: range) : Type.random
70
71
  array(t)
71
72
  end
72
- register("::Binding") { sized { binding } }
73
+ register("::Binding") { binding }
73
74
  register("::Complex") { complex }
74
- register("::Data") { sized { Data.define } }
75
+ register("::Data") { Data.define }
75
76
  register("::Encoding") { encoding }
76
- register("::FalseClass") { sized { false } }
77
+ register("::FalseClass") { false }
78
+ register("::File") { File.open("/dev/null") }
77
79
  register("::Float") { float }
78
80
  register("::Hash") do
79
81
  instance = __skip__ = type
@@ -82,18 +84,18 @@ module RaaP
82
84
  dict(key, value)
83
85
  end
84
86
  register("::Integer") { integer }
85
- register("::IO") { sized { $stdout } }
86
- register("::Method") { sized { temp_method_object } }
87
- register("::NilClass") { sized { nil } }
88
- register("::Proc") { sized { Proc.new {} } }
87
+ register("::IO") { $stdout }
88
+ register("::Method") { temp_method_object }
89
+ register("::NilClass") { nil }
90
+ register("::Proc") { Proc.new {} }
89
91
  register("::Rational") { rational }
90
92
  register("::Regexp") { sized { |size| Regexp.new(string.pick(size: size)) } }
91
93
  register("::String") { string }
92
- register("::Struct") { sized { Struct.new(:foo, :bar).new } }
94
+ register("::Struct") { Struct.new(:foo, :bar).new }
93
95
  register("::Symbol") { symbol }
94
- register("::Time") { sized { [:call, Time, :now, [], {}, nil] } }
95
- register("::TrueClass") { sized { true } }
96
- register("::UnboundMethod") { sized { temp_method_object.unbind } }
96
+ register("::Time") { [:call, Time, :now, [], {}, nil] }
97
+ register("::TrueClass") { true }
98
+ register("::UnboundMethod") { temp_method_object.unbind }
97
99
 
98
100
  attr_reader :type
99
101
  attr_reader :range
@@ -176,7 +178,7 @@ module RaaP
176
178
  Object.const_get(type.name.to_s)
177
179
  when ::RBS::Types::ClassInstance
178
180
  case gen = GENERATORS[type.name.absolute!.to_s]
179
- in Proc then instance_exec(&gen).pick(size: size)
181
+ in Proc then pick_by_generator(gen, size: size)
180
182
  in nil then to_symbolic_call_from_initialize(type, size: size)
181
183
  end
182
184
  when ::RBS::Types::Record
@@ -186,7 +188,7 @@ module RaaP
186
188
  when ::RBS::Types::Literal
187
189
  type.literal
188
190
  when ::RBS::Types::Bases::Bool
189
- bool.pick(size: size)
191
+ bool
190
192
  when ::RBS::Types::Bases::Any
191
193
  Type.random.to_symbolic_call(size: size)
192
194
  when ::RBS::Types::Bases::Nil
@@ -198,6 +200,16 @@ module RaaP
198
200
 
199
201
  private
200
202
 
203
+ def pick_by_generator(gen, size:)
204
+ ret = instance_exec(&gen)
205
+ case ret
206
+ when Sized
207
+ ret.pick(size: size)
208
+ else
209
+ ret
210
+ end
211
+ end
212
+
201
213
  def to_symbolic_call_from_initialize(type, size:)
202
214
  type_name = type.name.absolute!
203
215
  const = Object.const_get(type_name.to_s)
@@ -301,16 +313,12 @@ module RaaP
301
313
  end
302
314
 
303
315
  def encoding
304
- sized do
305
- e = Encoding.list.sample or raise
306
- [:call, Encoding, :find, [e.name], {}, nil]
307
- end
316
+ e = Encoding.list.sample or raise
317
+ [:call, Encoding, :find, [e.name], {}, nil]
308
318
  end
309
319
 
310
320
  def bool
311
- sized do
312
- Random.rand(2) == 0
313
- end
321
+ Random.rand(2) == 0
314
322
  end
315
323
 
316
324
  def temp_method_object
@@ -25,6 +25,10 @@ module RaaP
25
25
  instance_type = instance_type.is_a?(::String) ? RBS.parse_type(instance_type) : instance_type
26
26
  class_type = class_type.is_a?(::String) ? RBS.parse_type(class_type) : class_type
27
27
  sub = build
28
+ if sub.empty? && self_type.nil? && instance_type.nil? && class_type.nil?
29
+ return method_type
30
+ end
31
+
28
32
  ::RBS::MethodType.new(
29
33
  type_params: [],
30
34
  type: method_type.type.sub(sub).then { |ty| sub(ty, self_type: self_type, instance_type: instance_type, class_type: class_type) },
@@ -2,9 +2,9 @@
2
2
 
3
3
  module RaaP
4
4
  module Value
5
- class Interface < BasicObject
5
+ class Interface
6
6
  class << self
7
- def define_method_from_interface(base_class, type, size: 3)
7
+ def define_method_from_interface(base_mod, type, size: 3)
8
8
  type = type.is_a?(::String) ? RBS.parse_type(type) : type
9
9
  unless type.instance_of?(::RBS::Types::Interface)
10
10
  ::Kernel.raise ::TypeError, "not an interface type: #{type}"
@@ -22,7 +22,7 @@ module RaaP
22
22
  ts = TypeSubstitution.new(type_params, type.args)
23
23
  subed_method_type = ts.method_type_sub(method_type, self_type: self_type, instance_type: instance_type, class_type: class_type)
24
24
 
25
- BindCall.define_method(base_class, name) do |*_, &b|
25
+ BindCall.define_method(base_mod, name) do |*_, &b|
26
26
  @fixed_return_value ||= {}
27
27
  @fixed_return_value[name] ||= if self_type == subed_method_type.type.return_type
28
28
  self
@@ -30,16 +30,13 @@ module RaaP
30
30
  Type.new(subed_method_type.type.return_type).pick(size: size)
31
31
  end
32
32
  # @type var b: Proc?
33
- if b
33
+ if b && subed_method_type.block && subed_method_type.block.type.is_a?(::RBS::Types::Function)
34
34
  @fixed_block_arguments ||= {}
35
- @fixed_block_arguments[name] ||= if subed_method_type.block
36
- size.times.map do
37
- FunctionType.new(subed_method_type.block.type)
38
- .pick_arguments(size: size)
39
- end
40
- else
41
- []
42
- end
35
+ @fixed_block_arguments[name] ||= size.times.map do
36
+ FunctionType.new(subed_method_type.block.type)
37
+ .pick_arguments(size: size)
38
+ end
39
+
43
40
  @fixed_block_arguments[name].each do |a, kw|
44
41
  b.call(*a, **kw)
45
42
  end
@@ -68,14 +65,6 @@ module RaaP
68
65
  @size = size
69
66
  end
70
67
 
71
- def respond_to?(name, _include_all = false)
72
- @definition.methods.has_key?(name.to_sym)
73
- end
74
-
75
- def class
76
- Interface
77
- end
78
-
79
68
  def inspect
80
69
  "#<interface @type=`#{@type}` @methods=#{@definition.methods.keys} @size=#{@size}>"
81
70
  end
@@ -17,19 +17,18 @@ module RaaP
17
17
  raise ArgumentError, "intersection type must have at least one class instance type in `#{instances}`"
18
18
  end
19
19
 
20
- base = instances.find { |c| c.is_a?(::Class) } || BasicObject
20
+ base = instances.find { |c| c.is_a?(::Class) } || Object
21
21
 
22
22
  c = Class.new(base) do
23
23
  instances.select { |i| !i.is_a?(::Class) }.each do |m|
24
24
  include(m)
25
25
  end
26
26
 
27
- interfaces = type.types.select do |t|
28
- t.instance_of?(::RBS::Types::Interface)
29
- end
30
-
31
- interfaces.each do |interface|
32
- Interface.define_method_from_interface(self, interface, size: size)
27
+ type.types.each do |t|
28
+ case t
29
+ when ::RBS::Types::Interface
30
+ Interface.define_method_from_interface(self, t, size: size)
31
+ end
33
32
  end
34
33
  end
35
34
  type = ::RBS::Types::ClassInstance.new(name: TypeName(base.name), args: [], location: nil)
@@ -2,7 +2,7 @@
2
2
 
3
3
  module RaaP
4
4
  module Value
5
- class Variable < BasicObject
5
+ class Variable
6
6
  attr_reader :type
7
7
 
8
8
  def initialize(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.6.0"
4
+ VERSION = "0.7.0"
5
5
  end
data/lib/raap.rb CHANGED
@@ -23,6 +23,7 @@ module RaaP
23
23
 
24
24
  autoload :BindCall, "raap/bind_call"
25
25
  autoload :CLI, "raap/cli"
26
+ autoload :Coverage, "raap/coverage"
26
27
  autoload :FunctionType, "raap/function_type"
27
28
  autoload :MethodProperty, "raap/method_property"
28
29
  autoload :MethodType, "raap/method_type"
Binary file
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, ?allow_private: bool) -> 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, ?coverage: 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, ?allow_private: bool) -> 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, ?coverage: 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, :allow_private]
28
+ def self.members: () -> [ :dirs, :requires, :library, :timeout, :size_from, :size_to, :size_by, :allow_private, :coverage]
29
29
 
30
- def members: () -> [ :dirs, :requires, :library, :timeout, :size_from, :size_to, :size_by, :allow_private]
30
+ def members: () -> [ :dirs, :requires, :library, :timeout, :size_from, :size_to, :size_by, :allow_private, :coverage]
31
31
 
32
32
  attr_accessor dirs: ::Array[String]
33
33
 
@@ -44,6 +44,8 @@ module RaaP
44
44
  attr_accessor size_by: ::Integer
45
45
 
46
46
  attr_accessor allow_private: bool
47
+
48
+ attr_accessor coverage: bool
47
49
  end
48
50
 
49
51
  type property_result = [Integer, Symbol, ::RBS::MethodType, StringIO?]
@@ -71,6 +73,39 @@ module RaaP
71
73
  def report: () -> Integer
72
74
  end
73
75
 
76
+ module Coverage
77
+ type locs = [::RBS::Buffer::loc, ::RBS::Buffer::loc]
78
+ type accuracy = :abs | :opt
79
+ class Writer
80
+ @method_type: ::RBS::MethodType
81
+ @cov: ::Set[Symbol]
82
+ @cur: Integer
83
+
84
+ def initialize: (::RBS::MethodType, Set[Symbol]) -> void
85
+ def write: (IO) -> void
86
+
87
+ private
88
+
89
+ def method_type_location: () -> ::RBS::Location[untyped, untyped]
90
+ def slice: (Integer, Range[Integer]) -> String
91
+ def write_param: (IO, String, ::RBS::Types::Function::Param, accuracy) -> void
92
+ def write_type: (IO, String, ::RBS::Types::t, accuracy) -> void
93
+ def green: (String) -> String
94
+ def red: (String) -> String
95
+ def yellow: (String) -> String
96
+ end
97
+
98
+ self.@cov: Set[Symbol]?
99
+ self.@method_type: ::RBS::MethodType
100
+
101
+ def self.start: (::RBS::MethodType) -> void
102
+ def self.running?: () -> bool
103
+ def self.log: (String | Symbol) -> void
104
+ def self.cov: () -> Set[Symbol]
105
+ def self.show: (IO) -> void
106
+ def self.new_type_with_log: (String, ::RBS::Types::t) -> Type
107
+ end
108
+
74
109
  class FunctionType
75
110
  @fun: ::RBS::Types::Function
76
111
 
@@ -83,6 +118,7 @@ module RaaP
83
118
  def to_symbolic_call_recursive: (untyped, size: Integer) -> untyped
84
119
  def build_args_type: () -> Array[Type]
85
120
  def build_kwargs_type: () -> Hash[Symbol, Type]
121
+ def build_type_with_coverage: (String, ::RBS::Types::Function::Param) -> Type
86
122
  end
87
123
 
88
124
  class MethodProperty
@@ -108,10 +144,13 @@ module RaaP
108
144
  def call: (size: Integer, stats: Stats) -> (Result::Success | Result::Failure | Result::Skip | Result::Exception)
109
145
  def check_return: (receiver_value: untyped, return_value: untyped) -> ([Symbol] | [Symbol, Exception])
110
146
  def return_type: () -> RBS::Types::t
147
+ def original_return_type: () -> RBS::Types::t
148
+ def coverage: (String, untyped, RBS::Types::t, ?RBS::Test::TypeCheck?) -> void
111
149
  end
112
150
 
113
151
  class MethodType
114
152
  attr_reader rbs: ::RBS::MethodType
153
+ attr_reader original_rbs: ::RBS::MethodType
115
154
  @fun_type: FunctionType
116
155
 
117
156
  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
@@ -134,6 +173,8 @@ module RaaP
134
173
  def self.loader: () -> ::RBS::EnvironmentLoader
135
174
  def self.parse_type: (String) -> ::RBS::Types::t
136
175
  def self.parse_method_type: (String) -> ::RBS::MethodType
176
+ def self.parse_member: (String) -> ::RBS::AST::Members::Attribute
177
+ def self._shift_location: (untyped, Integer) -> void
137
178
  def self.find_alias_decl: (::RBS::TypeName, Symbol) -> ::RBS::AST::Members::Alias?
138
179
  end
139
180
 
@@ -242,7 +283,7 @@ module RaaP
242
283
  GENERATORS: Hash[String, ^() -> Sized[untyped]]
243
284
  SIMPLE_SOURCE: Array[String]
244
285
 
245
- def self.register: (String) { () [self: instance] -> Sized[untyped] } -> void
286
+ def self.register: (String) { () [self: instance] -> untyped } -> void
246
287
  def self.random: () -> Type
247
288
  def self.random_without_basic_object: () -> Type
248
289
  def self.call_new_from: (Module, ::RBS::Types::ClassInstance, size: Integer) -> symbolic_call
@@ -278,8 +319,8 @@ module RaaP
278
319
  def symbol: () -> Sized[Symbol]
279
320
  def array: (Type) -> Sized[Array[untyped]]
280
321
  def dict: (Type, Type) -> Sized[Hash[untyped, untyped]]
281
- def encoding: () -> Sized[symbolic_call]
282
- def bool: () -> Sized[bool]
322
+ def encoding: () -> symbolic_call
323
+ def bool: () -> bool
283
324
  def temp_method_object: () -> ::Method
284
325
  end
285
326
 
@@ -289,19 +330,19 @@ module RaaP
289
330
  def class: () -> class
290
331
  end
291
332
 
292
- class Interface < BasicObject
333
+ class Interface
293
334
  @type: ::RBS::Types::Interface
294
335
  @size: Integer
295
336
  @definition: ::RBS::Definition
296
337
 
297
- def self.define_method_from_interface: (Class base_class, String | ::RBS::Types::Interface type, ?size: Integer) -> void
338
+ def self.define_method_from_interface: (::Module base_class, String | ::RBS::Types::Interface type, ?size: Integer) -> void
298
339
  def initialize: (String | ::RBS::Types::Interface | String, ?size: Integer) -> void
299
340
  def respond_to?: (Symbol, ?boolish) -> bool
300
341
  def inspect: () -> String
301
342
  def class: () -> class
302
343
  end
303
344
 
304
- class Intersection < BasicObject
345
+ module Intersection
305
346
  @type: ::RBS::Types::Intersection
306
347
  @children: Array[Type]
307
348
  @size: Integer
@@ -328,7 +369,7 @@ module RaaP
328
369
  def class: () -> class
329
370
  end
330
371
 
331
- class Variable < BasicObject
372
+ class Variable
332
373
  attr_reader type: ::RBS::Types::Variable
333
374
 
334
375
  def initialize: (::RBS::Types::Variable | String | Symbol) -> 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.6.0
4
+ version: 0.7.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-04-25 00:00:00.000000000 Z
11
+ date: 2024-05-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rbs
@@ -57,6 +57,7 @@ files:
57
57
  - lib/raap.rb
58
58
  - lib/raap/bind_call.rb
59
59
  - lib/raap/cli.rb
60
+ - lib/raap/coverage.rb
60
61
  - lib/raap/function_type.rb
61
62
  - lib/raap/method_property.rb
62
63
  - lib/raap/method_type.rb
@@ -77,6 +78,7 @@ files:
77
78
  - lib/raap/value/void.rb
78
79
  - lib/raap/version.rb
79
80
  - lib/shims.rb
81
+ - public/example.webp
80
82
  - public/jacket.webp
81
83
  - rbs_collection.lock.yaml
82
84
  - rbs_collection.yaml
@@ -102,7 +104,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
102
104
  - !ruby/object:Gem::Version
103
105
  version: '0'
104
106
  requirements: []
105
- rubygems_version: 3.2.33
107
+ rubygems_version: 3.5.9
106
108
  signing_key:
107
109
  specification_version: 4
108
110
  summary: RBS as a Property