raap 0.7.0 → 0.8.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: 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