raap 0.7.0 → 0.8.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 13f734d53db009621045979dfc7d705b14c2f378625ff36067784995e8889134
4
- data.tar.gz: 472adf32ff8ea739d83a5b41c6a62e80149b29e34d44536df844010eb2e8cb90
3
+ metadata.gz: f119356b79f6beb968f26d019dda506e8eada4a48e178bd029e7e97d187f2d2c
4
+ data.tar.gz: f72f9d682ff47f11d51ebcf547a7f991c75b9be731eabc018fbb5b5a727dc358
5
5
  SHA512:
6
- metadata.gz: cc3782c7a65e098eef727163ccc069ca27b339eeaadc7be44abd2eac94c78fa74443c413364e579998dd49aa11c5be38bd27f6504f92759580ec893dd54a3e97
7
- data.tar.gz: 68e133fa67a03d4c84ab264c1e0fd1c40204da8995a552e99912eb61c1cddb14d9c81bac26c4aa04615d9833dfa74ad64bd212071dd3195dacad6ae85bd23b54
6
+ metadata.gz: 7d3fbbfd916eb8526d9021e94408f4af402d80455c89b822c74557a76a31b8fc93a0d7acd8e47efdca32a8b1a19fb37a2b8f997e3c7ad6083e2f61d72052973a
7
+ data.tar.gz: cfbeb8a13d53e16a6e51701c30354ea1537c8b6b7a7ef46665b7e0efe9db43a4ce769370f38f558e4a384c80a039960faa65acbc8648c8f36e3725a53c2c1075
data/README.md CHANGED
@@ -57,6 +57,10 @@ Then, you can start loop again.
57
57
 
58
58
  Finally, you get the perfect RBS!
59
59
 
60
+ ## Slide
61
+
62
+ https://speakerdeck.com/ksss/raap
63
+
60
64
  ## Installation
61
65
 
62
66
  Install the gem and add to the application's Gemfile by executing:
data/lib/raap/cli.rb CHANGED
@@ -38,9 +38,6 @@ module RaaP
38
38
  def initialize(argv)
39
39
  # defaults
40
40
  @option = Option.new(
41
- dirs: [],
42
- requires: [],
43
- libraries: [],
44
41
  timeout: 3,
45
42
  size_from: 0,
46
43
  size_to: 99,
@@ -56,13 +53,13 @@ module RaaP
56
53
  def load
57
54
  OptionParser.new do |o|
58
55
  o.on('-I', '--include PATH') do |path|
59
- @option.dirs << path
56
+ RaaP::RBS.loader.add(path: Pathname(path))
60
57
  end
61
58
  o.on('--library lib', 'load rbs library') do |lib|
62
- @option.libraries << lib
59
+ RaaP::RBS.loader.add(library: lib, version: nil)
63
60
  end
64
61
  o.on('--require lib', 'require ruby library') do |lib|
65
- @option.requires << lib
62
+ require lib
66
63
  end
67
64
  o.on('--log-level level', "default: info") do |arg|
68
65
  RaaP.logger.level = arg
@@ -90,16 +87,6 @@ module RaaP
90
87
  end
91
88
  end.parse!(@argv)
92
89
 
93
- @option.dirs.each do |dir|
94
- RaaP::RBS.loader.add(path: Pathname(dir))
95
- end
96
- @option.libraries.each do |lib|
97
- RaaP::RBS.loader.add(library: lib, version: nil)
98
- end
99
- @option.requires.each do |lib|
100
- require lib
101
- end
102
-
103
90
  self
104
91
  end
105
92
 
data/lib/raap/coverage.rb CHANGED
@@ -25,7 +25,7 @@ module RaaP
25
25
  RaaP.logger.warn("No location information for `#{phantom_member}`")
26
26
  return
27
27
  end
28
- write_type(io, "return", phantom_member.type, :abs)
28
+ write_type(io, "return", phantom_member.type)
29
29
  io.write(slice(@cur, @cur...phantom_member.location.end_pos))
30
30
  else
31
31
  RaaP.logger.error("#{phantom_member.class} is not supported")
@@ -37,22 +37,22 @@ module RaaP
37
37
  phantom_method_type.type.yield_self do |fun|
38
38
  case fun
39
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) }
40
+ fun.required_positionals.each_with_index { |param, i| write_param(io, "req_#{i}", param) }
41
+ fun.optional_positionals.each_with_index { |param, i| write_param(io, "opt_#{i}", param) }
42
+ fun.rest_positionals&.yield_self { |param| write_param(io, "rest", param) }
43
+ fun.trailing_positionals.each_with_index { |param, i| write_param(io, "trail_#{i}", param) }
44
+ fun.required_keywords.each { |key, param| write_param(io, "keyreq_#{key}", param) }
45
+ fun.optional_keywords.each { |key, param| write_param(io, "key_#{key}", param) }
46
+ fun.rest_keywords&.yield_self { |param| write_param(io, "keyrest", param) }
47
47
  # when ::RBS::Types::UntypedFunction
48
48
  end
49
49
  end
50
50
 
51
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)
52
+ b.type.each_param.with_index { |param, i| write_param(io, "block_param_#{i}", param) }
53
+ write_type(io, "block_return", b.type.return_type)
54
54
  end
55
- write_type(io, "return", phantom_method_type.type.return_type, :abs)
55
+ write_type(io, "return", phantom_method_type.type.return_type)
56
56
  raise unless phantom_method_type.location
57
57
 
58
58
  io.write(slice(@cur, @cur...phantom_method_type.location.end_pos))
@@ -70,11 +70,11 @@ module RaaP
70
70
  ml.source[start, range.end - range.begin] or raise
71
71
  end
72
72
 
73
- def write_param(io, position, param, accuracy)
74
- write_type(io, position, param.type, accuracy)
73
+ def write_param(io, position, param)
74
+ write_type(io, position, param.type)
75
75
  end
76
76
 
77
- def write_type(io, position, type, accuracy)
77
+ def write_type(io, position, type)
78
78
  unless type.location
79
79
  RaaP.logger.warn("No location information for `#{type}`")
80
80
  return
@@ -88,12 +88,12 @@ module RaaP
88
88
  t.location or raise
89
89
  io.write(slice(@cur, @cur...t.location.start_pos)) # ( or [
90
90
  @cur = t.location.start_pos
91
- write_type(io, "#{position}_#{name}_#{i}", t, accuracy)
91
+ write_type(io, "#{position}_#{name}_#{i}", t)
92
92
  end
93
93
  when ::RBS::Types::Optional
94
94
  raise unless type.location
95
95
 
96
- write_type(io, "#{position}_optional_left", type.type, accuracy)
96
+ write_type(io, "#{position}_optional_left", type.type)
97
97
  io.write(slice(@cur, @cur...(type.location.end_pos - 1)))
98
98
  @cur = type.location.end_pos - 1
99
99
  if @cov.include?("#{position}_optional_right".to_sym)
@@ -103,17 +103,6 @@ module RaaP
103
103
  end
104
104
  raise unless type.location
105
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
106
  @cur = type.location.end_pos
118
107
  else
119
108
  raise unless type.location
@@ -129,7 +118,6 @@ module RaaP
129
118
 
130
119
  def green(str) = "\e[32m#{str}\e[0m"
131
120
  def red(str) = "\e[1;4;41m#{str}\e[0m"
132
- def yellow(str) = "\e[93m#{str}\e[0m"
133
121
  end
134
122
 
135
123
  class << self
@@ -142,8 +130,6 @@ module RaaP
142
130
  !!@cov
143
131
  end
144
132
 
145
- # position: req_0
146
- # type: union_1
147
133
  def log(position)
148
134
  return unless running?
149
135
 
@@ -151,7 +137,7 @@ module RaaP
151
137
  end
152
138
 
153
139
  def cov
154
- @cov or raise
140
+ @cov or raise("Coverage is not started")
155
141
  end
156
142
 
157
143
  def show(io)
@@ -162,25 +148,31 @@ module RaaP
162
148
  end
163
149
 
164
150
  def new_type_with_log(position, type)
151
+ log_with_type(position, type) do |t|
152
+ Type.new(t)
153
+ end
154
+ end
155
+
156
+ def log_with_type(position, type, &block)
165
157
  case type
166
158
  when ::RBS::Types::Tuple
167
159
  # FIXME: Support Union in Tuple
168
160
  type.types.each_with_index do |_t, i|
169
161
  log("#{position}_tuple_#{i}")
170
162
  end
171
- Type.new(type)
163
+ block&.call(type)
172
164
  when ::RBS::Types::Union
173
165
  i = Random.rand(type.types.length)
174
- new_type_with_log("#{position}_union_#{i}", type.types[i])
166
+ log_with_type("#{position}_union_#{i}", type.types[i], &block)
175
167
  when ::RBS::Types::Optional
176
168
  if Random.rand(2).zero?
177
- new_type_with_log("#{position}_optional_left", type.type)
169
+ log_with_type("#{position}_optional_left", type.type, &block)
178
170
  else
179
- new_type_with_log("#{position}_optional_right", ::RBS::Types::Bases::Nil.new(location: nil))
171
+ log_with_type("#{position}_optional_right", ::RBS::Types::Bases::Nil.new(location: nil), &block)
180
172
  end
181
173
  else
182
174
  log(position)
183
- Type.new(type)
175
+ block&.call(type)
184
176
  end
185
177
  end
186
178
  end
@@ -2,8 +2,9 @@
2
2
 
3
3
  module RaaP
4
4
  class FunctionType
5
- def initialize(fun)
5
+ def initialize(fun, coverage: true)
6
6
  @fun = fun
7
+ @coverage = coverage
7
8
  end
8
9
 
9
10
  def pick_arguments(size: 10)
@@ -81,7 +82,11 @@ module RaaP
81
82
  end
82
83
 
83
84
  def build_type_with_coverage(position, param)
84
- Coverage.new_type_with_log(position, param.type)
85
+ if @coverage
86
+ Coverage.new_type_with_log(position, param.type)
87
+ else
88
+ Type.new(param.type)
89
+ end
85
90
  end
86
91
  end
87
92
  end
@@ -50,7 +50,7 @@ module RaaP
50
50
  private
51
51
 
52
52
  def call(size:, stats:)
53
- if @method_type.rbs.type.each_type.find { |t| t.instance_of?(::RBS::Types::Bases::Any) }
53
+ if @method_type.rbs.type.each_param.find { |param| param.type.each_type.find { |t| t.instance_of?(::RBS::Types::Bases::Any) } }
54
54
  RaaP.logger.info { "Skip type check since `#{@method_type.rbs}` includes `untyped`" }
55
55
  stats.break = true
56
56
  throw :break
@@ -2,7 +2,7 @@
2
2
 
3
3
  module RaaP
4
4
  class MethodType
5
- attr_reader :rbs, :original_rbs
5
+ attr_reader :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 =
@@ -19,11 +19,17 @@ module RaaP
19
19
 
20
20
  params = (type_params_decl + rbs.type_params).uniq
21
21
  ts = TypeSubstitution.new(params, type_args)
22
-
23
- @original_rbs = rbs
24
22
  @rbs = ts.method_type_sub(rbs, self_type: self_type, instance_type: instance_type, class_type: class_type)
25
23
  function_or_untypedfunction = __skip__ = @rbs.type
26
24
  @fun_type = FunctionType.new(function_or_untypedfunction)
25
+ @type_check = ::RBS::Test::TypeCheck.new(
26
+ self_class: (_ = self_type),
27
+ instance_class: (_ = instance_type),
28
+ class_class: (_ = class_type),
29
+ builder: RBS.builder,
30
+ sample_size: 100,
31
+ unchecked_classes: []
32
+ )
27
33
  end
28
34
 
29
35
  def pick_arguments(size: 10)
@@ -42,28 +48,63 @@ module RaaP
42
48
  return nil if block.nil?
43
49
  return nil if (block.required == false) && [true, false].sample
44
50
 
45
- fixed_return_value = Type.new(block.type.return_type).pick(size: size)
46
- Proc.new do
47
- block.type.each_param.with_index do |_param, i|
48
- Coverage.log("block_param_#{i}")
51
+ args_name = []
52
+ args_source = []
53
+ resource = [*'a'..'z']
54
+ case fun = block.type
55
+ when ::RBS::Types::Function
56
+ # FIXME: Support keyword types
57
+ fun.required_positionals.each do
58
+ resource.shift.tap do |name|
59
+ args_name << name
60
+ args_source << name
61
+ end
62
+ end
63
+ fun.optional_positionals.each do |param|
64
+ resource.shift.tap do |name|
65
+ # FIXME: Support without literal type
66
+ default = Type.new(param.type).pick(size: size)
67
+ args_name << name
68
+ args_source << "#{name} = #{default}"
69
+ end
70
+ end
71
+ fun.rest_positionals&.yield_self do |_|
72
+ resource.shift.tap do |name|
73
+ args_name << "*#{name}"
74
+ args_source << "*#{name}"
75
+ end
76
+ end
77
+ fun.trailing_positionals.each do
78
+ resource.shift.tap do |name|
79
+ args_name << name
80
+ args_source << name
81
+ end
49
82
  end
50
-
51
- Coverage.new_type_with_log("block_return", block.type.return_type)
52
- fixed_return_value
53
83
  end
84
+ # Hack: Use local variable in eval
85
+ fixed_return_value = Type.new(block.type.return_type).pick(size: size)
86
+ _ = fixed_return_value
87
+ type_check = @type_check
88
+ _ = type_check
89
+ eval(<<~RUBY) # rubocop:disable Security/Eval
90
+ -> (#{args_source.join(', ')}) do
91
+ i = 0
92
+ type_check.zip_args([#{args_name.join(', ')}], block.type) do |val, param|
93
+ unless type_check.value(val, param.type)
94
+ raise TypeError, "block argument type mismatch: expected `(\#{fun.param_to_s})`, got \#{BindCall.inspect([#{args_name.join(', ')}])}"
95
+ end
96
+
97
+ Coverage.log_with_type("block_param_\#{i}", param.type)
98
+ i += 1
99
+ end
100
+ Coverage.log_with_type("block_return", block.type.return_type)
101
+ fixed_return_value
102
+ end
103
+ RUBY
54
104
  end
55
105
 
56
106
  def check_return(return_value)
57
- untyped = __skip__ = nil
58
- type_check = ::RBS::Test::TypeCheck.new(
59
- self_class: untyped, # cannot support `self`
60
- instance_class: untyped, # cannot support `instance`
61
- class_class: untyped, # cannot support `class`
62
- builder: RBS.builder,
63
- sample_size: 100,
64
- unchecked_classes: []
65
- )
66
- type_check.value(return_value, rbs.type.return_type)
107
+ @type_check.value(return_value, rbs.type.return_type)
67
108
  end
68
109
  end
69
110
  end
@@ -33,7 +33,7 @@ module RaaP
33
33
  if b && subed_method_type.block && subed_method_type.block.type.is_a?(::RBS::Types::Function)
34
34
  @fixed_block_arguments ||= {}
35
35
  @fixed_block_arguments[name] ||= size.times.map do
36
- FunctionType.new(subed_method_type.block.type)
36
+ FunctionType.new(subed_method_type.block.type, coverage: false)
37
37
  .pick_arguments(size: size)
38
38
  end
39
39
 
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.7.0"
4
+ VERSION = "0.8.0"
5
5
  end
data/sig/raap.rbs CHANGED
@@ -19,21 +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, ?coverage: bool) -> instance
22
+ def self.new: (?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, ?coverage: bool) -> instance
24
+ def self.[]: (?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, :coverage]
28
+ def self.members: () -> [ :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, :coverage]
31
-
32
- attr_accessor dirs: ::Array[String]
33
-
34
- attr_accessor requires: ::Array[String]
35
-
36
- attr_accessor libraries: ::Array[String]
30
+ def members: () -> [ :timeout, :size_from, :size_to, :size_by, :allow_private, :coverage]
37
31
 
38
32
  attr_accessor timeout: (Integer | Float | nil)
39
33
 
@@ -75,7 +69,6 @@ module RaaP
75
69
 
76
70
  module Coverage
77
71
  type locs = [::RBS::Buffer::loc, ::RBS::Buffer::loc]
78
- type accuracy = :abs | :opt
79
72
  class Writer
80
73
  @method_type: ::RBS::MethodType
81
74
  @cov: ::Set[Symbol]
@@ -88,11 +81,10 @@ module RaaP
88
81
 
89
82
  def method_type_location: () -> ::RBS::Location[untyped, untyped]
90
83
  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
84
+ def write_param: (IO, String, ::RBS::Types::Function::Param) -> void
85
+ def write_type: (IO, String, ::RBS::Types::t) -> void
93
86
  def green: (String) -> String
94
87
  def red: (String) -> String
95
- def yellow: (String) -> String
96
88
  end
97
89
 
98
90
  self.@cov: Set[Symbol]?
@@ -104,12 +96,15 @@ module RaaP
104
96
  def self.cov: () -> Set[Symbol]
105
97
  def self.show: (IO) -> void
106
98
  def self.new_type_with_log: (String, ::RBS::Types::t) -> Type
99
+ def self.log_with_type: (String, ::RBS::Types::t) -> nil
100
+ | (String, ::RBS::Types::t) ?{ (::RBS::Types::t) -> Type } -> Type
107
101
  end
108
102
 
109
103
  class FunctionType
110
104
  @fun: ::RBS::Types::Function
105
+ @coverage: boolish
111
106
 
112
- def initialize: (::RBS::Types::Function) -> void
107
+ def initialize: (::RBS::Types::Function, ?coverage: boolish) -> void
113
108
  def pick_arguments: (?size: Integer) -> [Array[untyped], Hash[Symbol, untyped]]
114
109
  def arguments_to_symbolic_call: (?size: Integer) -> [Array[untyped], Hash[Symbol, untyped]]
115
110
 
@@ -150,8 +145,8 @@ module RaaP
150
145
 
151
146
  class MethodType
152
147
  attr_reader rbs: ::RBS::MethodType
153
- attr_reader original_rbs: ::RBS::MethodType
154
148
  @fun_type: FunctionType
149
+ @type_check: ::RBS::Test::TypeCheck
155
150
 
156
151
  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
157
152
  def pick_arguments: (?size: Integer) -> [Array[untyped], Hash[Symbol, untyped], ::Proc?]
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.7.0
4
+ version: 0.8.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-05-08 00:00:00.000000000 Z
11
+ date: 2024-06-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rbs