ruby_mod_kit 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +89 -0
  3. data/lib/ruby_mod_kit/core_ext/eval.rb +6 -10
  4. data/lib/ruby_mod_kit/corrector.rb +3 -0
  5. data/lib/ruby_mod_kit/corrector_manager.rb +10 -6
  6. data/lib/ruby_mod_kit/feature/instance_variable_parameter/instance_variable_parameter_mission.rb +1 -1
  7. data/lib/ruby_mod_kit/feature/overload/overload_mission.rb +2 -3
  8. data/lib/ruby_mod_kit/feature/type/check/arguments/add_arguments_checker_mission.rb +56 -0
  9. data/lib/ruby_mod_kit/feature/type/check/arguments.rb +23 -0
  10. data/lib/ruby_mod_kit/feature/type/instance_variable_colon_corrector.rb +9 -4
  11. data/lib/ruby_mod_kit/feature/type/parameter_arrow_corrector.rb +27 -5
  12. data/lib/ruby_mod_kit/feature/type/rbs_inline/type_instance_variable_mission.rb +3 -2
  13. data/lib/ruby_mod_kit/feature/type/rbs_inline/type_overload_mission.rb +1 -2
  14. data/lib/ruby_mod_kit/feature/type/rbs_inline/type_parameter_mission.rb +5 -4
  15. data/lib/ruby_mod_kit/feature/type/rbs_inline/type_return_mission.rb +1 -1
  16. data/lib/ruby_mod_kit/feature/type/return_value_colon_corrector.rb +1 -0
  17. data/lib/ruby_mod_kit/feature/type/type_attr_mission.rb +3 -9
  18. data/lib/ruby_mod_kit/feature/type/yard/type_parameter_mission.rb +35 -0
  19. data/lib/ruby_mod_kit/feature/type/yard/type_return_mission.rb +30 -0
  20. data/lib/ruby_mod_kit/feature/type/yard.rb +31 -0
  21. data/lib/ruby_mod_kit/generation.rb +55 -20
  22. data/lib/ruby_mod_kit/memo/ivar_memo.rb +2 -0
  23. data/lib/ruby_mod_kit/memo/parameter_memo.rb +4 -2
  24. data/lib/ruby_mod_kit/memo_pad.rb +6 -0
  25. data/lib/ruby_mod_kit/mission.rb +0 -4
  26. data/lib/ruby_mod_kit/node/base_node.rb +11 -2
  27. data/lib/ruby_mod_kit/node/begin_node.rb +31 -0
  28. data/lib/ruby_mod_kit/node/parameter_node.rb +2 -2
  29. data/lib/ruby_mod_kit/node/wrap.rb +3 -1
  30. data/lib/ruby_mod_kit/node.rb +1 -0
  31. data/lib/ruby_mod_kit/version.rb +1 -1
  32. data/lib/ruby_mod_kit.rb +0 -5
  33. data/sig/generated/ruby_mod_kit/core_ext/eval.rbs +4 -2
  34. data/sig/generated/ruby_mod_kit/corrector.rbs +3 -0
  35. data/sig/generated/ruby_mod_kit/corrector_manager.rbs +1 -1
  36. data/sig/generated/ruby_mod_kit/feature/type/check/arguments/add_arguments_checker_mission.rbs +16 -0
  37. data/sig/generated/ruby_mod_kit/feature/type/check/arguments.rbs +15 -0
  38. data/sig/generated/ruby_mod_kit/feature/type/parameter_arrow_corrector.rbs +5 -0
  39. data/sig/generated/ruby_mod_kit/feature/type/yard/type_parameter_mission.rbs +16 -0
  40. data/sig/generated/ruby_mod_kit/feature/type/yard/type_return_mission.rbs +16 -0
  41. data/sig/generated/ruby_mod_kit/feature/type/yard.rbs +17 -0
  42. data/sig/generated/ruby_mod_kit/generation.rbs +34 -10
  43. data/sig/generated/ruby_mod_kit/memo/ivar_memo.rbs +4 -0
  44. data/sig/generated/ruby_mod_kit/memo/parameter_memo.rbs +6 -2
  45. data/sig/generated/ruby_mod_kit/memo_pad.rbs +4 -0
  46. data/sig/generated/ruby_mod_kit/mission.rbs +0 -4
  47. data/sig/generated/ruby_mod_kit/node/base_node.rbs +5 -1
  48. data/sig/generated/ruby_mod_kit/node/begin_node.rbs +26 -0
  49. data/sig/generated/ruby_mod_kit/node/parameter_node.rbs +1 -1
  50. metadata +14 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bb9b6cf5cb887308d1237eb07d40b4b2b2514173c5e76d19e13a27687f2c107f
4
- data.tar.gz: 418e2d01aec4c8f8b4f0b6241625a0b550aec118a3dbd0618987171bb270e4f7
3
+ metadata.gz: e5888d6187dc2620b37315d72fddee6b134bbd14181277ff600e864eb9c06ca0
4
+ data.tar.gz: 7ffb4ec96c231e6122eeaa7d47601f67a28620951ed08e9d3b3888e9fa684fbc
5
5
  SHA512:
6
- metadata.gz: 17a8efaedb26b0b3256fd0b24501298a1f56fdf4dc8d5c33adc8cb6005abf6c5fcca4c0d1d634b34784dd2528ec57c8d2effdaf4042bc522a15359c86b01b804
7
- data.tar.gz: 73758c1ef48bcb7884a6f37859115b952474084abca4b6560f7d21c5380ec4bece1f97e165e6ef27b8270b0f5209877f5b2b63f1cd408ed5b4b6f5cb517d8dc1
6
+ metadata.gz: 3c2e632593d2d0a7061f8a71a7e65131a1b72434ac3853467024503d13c57328abe88ade105b2532baf94d44bd428bd02b4eae9e0c50462d4dca6bebc767d4f9
7
+ data.tar.gz: 81b17d66702c1fc89c77bc3270f74608fca6ed8e9a12f26c04ea69f7d0bdceb4b91b104bfa45b0f944e5ba5dae79e789de720b8a5605df0d4ac4bb4e48e62d6d
data/README.md CHANGED
@@ -15,6 +15,95 @@ If bundler is not being used to manage dependencies, install the gem by executin
15
15
 
16
16
  ## Usage
17
17
 
18
+ ### as library
19
+
20
+ `RubyModKit.transpile` returns transpiled script.
21
+
22
+ ```
23
+ require "ruby_mod_kit"
24
+ eval(
25
+ RubyModKit.transpile(<<~RBM),
26
+ class Foo
27
+ getter @foo: Integer
28
+ def initialize(@foo)
29
+ end
30
+ end
31
+ RBM
32
+ )
33
+ p Foo.new(1).foo # => 1
34
+ ```
35
+
36
+ `require "ruby_mod_kit/core_ext/eval"` gives `RubyModKit.eval`.
37
+
38
+ ```
39
+ require "ruby_mod_kit/core_ext/eval"
40
+ RubyModKit.eval(<<~RBM)
41
+ class Foo
42
+ getter @foo: Integer
43
+ def initialize(@foo)
44
+ end
45
+ end
46
+ RBM
47
+ p Foo.new(1).foo # => 1
48
+ ```
49
+
50
+ `require "ruby_mod_kit/core_ext/load"` gives `RubyModKit.load` and `RubyModKit.require`.
51
+
52
+ ```
53
+ require "ruby_mod_kit/core_ext/load"
54
+ require "tmpdir"
55
+
56
+ script = <<~RBM
57
+ class Foo
58
+ getter @foo: Integer
59
+ def initialize(@foo)
60
+ end
61
+ end
62
+ RBM
63
+
64
+ Dir.mktmpdir do |tmpdir|
65
+ File.write("#{tmpdir}/some_lib.rbm", script)
66
+ $LOAD_PATH << tmpdir
67
+ RubyModKit.require "some_lib"
68
+ end
69
+
70
+ p Foo.new(1).foo # => 1
71
+ ```
72
+
73
+ And `require "ruby_mod_kit/core_ext"` is more powerfull but dangerous. It overwrites `eval`, `require` and `load`.
74
+
75
+ ```
76
+ require "ruby_mod_kit/core_ext"
77
+ eval(<<~RBM)
78
+ class Foo
79
+ getter @foo: Integer
80
+ def initialize(@foo)
81
+ end
82
+ end
83
+ RBM
84
+ p Foo.new(1).foo # => 1
85
+ ```
86
+
87
+ ```
88
+ require "ruby_mod_kit/core_ext"
89
+ require "tmpdir"
90
+
91
+ script = <<~RBM
92
+ class Foo
93
+ getter @foo: Integer
94
+ def initialize(@foo)
95
+ end
96
+ end
97
+ RBM
98
+
99
+ Dir.mktmpdir do |tmpdir|
100
+ File.write("#{tmpdir}/some_lib.rbm", script)
101
+ $LOAD_PATH << tmpdir
102
+ require "some_lib"
103
+ end
104
+
105
+ p Foo.new(1).foo # => 1
106
+ ```
18
107
  ### as command line tool
19
108
 
20
109
  #### `transpile`
@@ -12,19 +12,15 @@ module RubyModKit
12
12
  module_function
13
13
 
14
14
  # @rbs expr: String
15
- # @rbs *rest: Object
15
+ # @rbs binding: Binding
16
+ # @rbs fname: String
17
+ # @rbs lineno: Integer
16
18
  # @rbs transpile: bool
17
19
  # @rbs return: Object
18
- def eval(expr, *rest, transpile: true)
19
- if transpile
20
- fname = rest[1].is_a?(String) ? rest[1] : "(eval)"
21
- expr = RubyModKit.transpile(expr, filename: fname)
22
- end
20
+ def eval(expr, binding = TOPLEVEL_BINDING, fname = "(eval)", lineno = 1, transpile: true)
21
+ expr = RubyModKit.transpile(expr, filename: fname) if transpile
23
22
 
24
- case rest
25
- in [] | [Binding] | [Binding, String] | [Binding, String, Integer]
26
- super(expr, *rest)
27
- end
23
+ super(expr, binding, fname, lineno)
28
24
  end
29
25
  end
30
26
  end
@@ -16,5 +16,8 @@ module RubyModKit
16
16
  def correct(_parse_error, _generation)
17
17
  raise RubyModKit::Error, "Unexpected type #{self.class}"
18
18
  end
19
+
20
+ # @rbs return: void
21
+ def setup; end
19
22
  end
20
23
  end
@@ -5,13 +5,13 @@
5
5
  module RubyModKit
6
6
  # the class to manege parse error correctors
7
7
  class CorrectorManager
8
- # @rbs @previous_error_messages: Array[String]
8
+ # @rbs @previous_source: String
9
9
  # @rbs @correctors_error_map: Hash[Symbol, Array[Corrector]]
10
10
 
11
11
  # @rbs features: Array[Feature]
12
12
  # @rbs return: void
13
13
  def initialize(features)
14
- @previous_error_messages = []
14
+ @previous_source = +""
15
15
  @correctors_error_map = {}
16
16
  features.each do |feature|
17
17
  feature.create_correctors.each do |corrector|
@@ -28,7 +28,11 @@ module RubyModKit
28
28
  return true if generation.errors.empty?
29
29
 
30
30
  check_prev_errors(generation)
31
- @previous_error_messages = generation.errors.map(&:message)
31
+ @previous_source = generation.script.dup
32
+
33
+ @correctors_error_map.each_value do |correctors|
34
+ correctors.each(&:setup)
35
+ end
32
36
 
33
37
  generation.errors.each do |parse_error|
34
38
  correctors = @correctors_error_map[parse_error.type] || next
@@ -43,16 +47,16 @@ module RubyModKit
43
47
  # @rbs generation: Generation
44
48
  # @rbs return: void
45
49
  def check_prev_errors(generation)
46
- return if @previous_error_messages.empty?
50
+ return if @previous_source.empty?
47
51
  return if generation.errors.empty?
48
- return if @previous_error_messages != generation.errors.map(&:message)
52
+ return if @previous_source != generation.script
49
53
 
50
54
  message = +""
51
55
  generation.errors.each do |parse_error|
52
56
  message << "\n" unless message.empty?
53
57
  message << "#{generation.name}:#{parse_error.location.start_line}:#{parse_error.message} "
54
58
  message << "(#{parse_error.type})"
55
- line = generation.lines[parse_error.location.start_line - 1]
59
+ line = generation.line(parse_error)
56
60
  if line
57
61
  message << "\n#{line.chomp}\n"
58
62
  message << "#{" " * parse_error.location.start_column}^#{"~" * [parse_error.location.length - 1, 0].max}"
@@ -10,7 +10,7 @@ module RubyModKit
10
10
  # @rbs generation: Generation
11
11
  # @rbs return: bool
12
12
  def perform(generation)
13
- generation.memo_pad.parameters_memo.each_value do |parameter_memo|
13
+ generation.memo_pad.each_parameter_memo do |parameter_memo|
14
14
  next unless parameter_memo.ivar_parameter
15
15
 
16
16
  offset = parameter_memo.offset
@@ -37,9 +37,8 @@ module RubyModKit
37
37
  raise RubyModKit::Error unless first_def_node.is_a?(Node::DefNode)
38
38
  raise RubyModKit::Error unless name.is_a?(Symbol)
39
39
 
40
- start_line = first_def_node.location.start_line - 1
41
- indent = generation.lines[start_line][/\A */] || ""
42
- src_offset = generation.offsets[start_line]
40
+ indent = generation.line_indent(first_def_node)
41
+ src_offset = generation.line_offset(first_def_node) || raise(RubyModKit::Error)
43
42
  script = +""
44
43
 
45
44
  overload_memo = generation.memo_pad.overload_memo(first_method_memo.offset, name)
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ # rbs_inline: enabled
4
+
5
+ module RubyModKit
6
+ class Feature
7
+ class Type
8
+ module Check
9
+ # The mission to add magic comment
10
+ class AddArgumentsCheckerMission < Mission
11
+ # @rbs generation: Generation
12
+ # @rbs return: bool
13
+ def perform(generation)
14
+ # reload if line break is added
15
+ line_break_added = false
16
+
17
+ generation.memo_pad.methods_memo.each do |offset, method_memo|
18
+ def_node = generation.root_node.def_node_at(offset)
19
+ raise RubyModKit::Error, "DefNode not found" unless def_node
20
+ next if method_memo.parameters.empty?
21
+
22
+ def_line = generation.line(def_node.location.start_line - 1)
23
+ def_indent = def_line[/\A\s*/] || ""
24
+
25
+ location = def_node.body_location || def_node.end_keyword_loc
26
+ next unless location
27
+
28
+ def_right_loc = def_node.rparen_loc || def_node.name_loc
29
+ offset = location.start_offset - location.start_column
30
+ indent = "#{def_indent} "
31
+ if location.start_line == def_right_loc.end_line
32
+ between_def_and_loc = generation[def_right_loc.end_offset...location.start_offset]
33
+ length = between_def_and_loc[/\A[ ^t]*;[ ^t]*\z/]&.length
34
+ if length
35
+ line_break_added = true
36
+ generation[def_right_loc.end_offset, length] = "\n#{def_indent}"
37
+ end
38
+ end
39
+ next if line_break_added
40
+
41
+ method_memo.parameters.each do |parameter_memo|
42
+ next if parameter_memo.untyped? || !parameter_memo.name
43
+ next if parameter_memo.qualifier # TODO: qualifier support
44
+
45
+ type = parameter_memo.type
46
+ type = type.gsub(/\[([^\[\]]+)\]/, "") # TODO: type variable support
47
+ generation[offset, 0] = "#{indent}#{parameter_memo.name} => #{type}\n"
48
+ end
49
+ end
50
+ !line_break_added
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ # rbs_inline: enabled
4
+
5
+ module RubyModKit
6
+ class Feature
7
+ class Type
8
+ module Check
9
+ # namespace for arguments type checker
10
+ class Arguments < Feature
11
+ # @rbs return: Array[Mission]
12
+ def create_missions
13
+ [
14
+ AddArgumentsCheckerMission.new,
15
+ ]
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+
23
+ require_relative "arguments/add_arguments_checker_mission"
@@ -9,7 +9,7 @@ module RubyModKit
9
9
  class InstanceVariableColonCorrector < Corrector
10
10
  VISIBILITIES = %i[private public protected].freeze #: Array[Symbol]
11
11
  ATTR_PATTERNS = %i[attr_reader reader getter attr_writer writer setter attr_accessor accessor property].freeze #: Array[Symbol]
12
- REGEXP = /(\A\s*)(?:(#{VISIBILITIES.join("|")}) )?(?:(#{ATTR_PATTERNS.join("|")}) )?@(\w*)\s*:\s*(.*)\n/.freeze #: Regexp
12
+ REGEXP = /(\A\s*)(?:(#{VISIBILITIES.join("|")}) )?(?:(#{ATTR_PATTERNS.join("|")}) )?@(\w*)\s*:\s*(.*)\n(\n+)?/.freeze #: Regexp
13
13
 
14
14
  # @rbs return: Array[Symbol]
15
15
  def correctable_error_types
@@ -22,11 +22,14 @@ module RubyModKit
22
22
  def correct(parse_error, generation)
23
23
  return if parse_error.location.slice != ":"
24
24
 
25
- def_parent_node = generation.root_node.statements_node_at(parse_error.location.start_offset)&.parent
25
+ def_parent_node = generation.root_node.def_parent_node_at(
26
+ parse_error.location.start_offset,
27
+ allowed: [Node::CallNode, Node::UntypedNode, Node::StatementsNode],
28
+ )
26
29
  return unless def_parent_node.is_a?(Node::DefParentNode)
27
30
 
28
- line = generation.line(parse_error)
29
- line_offset = generation.src_offset(parse_error) || return
31
+ line_offset = generation.line_offset(parse_error) || return
32
+ line = generation[line_offset..]
30
33
  return if line !~ REGEXP
31
34
 
32
35
  length = ::Regexp.last_match(0)&.length
@@ -35,6 +38,7 @@ module RubyModKit
35
38
  attr_kind = ::Regexp.last_match(3)
36
39
  ivar_name = ::Regexp.last_match(4)
37
40
  type = ::Regexp.last_match(5)
41
+ separator = ::Regexp.last_match(6)
38
42
  return if !length || !indent || !ivar_name || !type
39
43
 
40
44
  ivar_memo = generation.memo_pad.def_parent_memo(def_parent_node).ivar_memo(ivar_name.to_sym)
@@ -43,6 +47,7 @@ module RubyModKit
43
47
  ivar_memo.indent = indent
44
48
  ivar_memo.attr_kind = attr_kind if attr_kind
45
49
  ivar_memo.visibility = visibility.to_sym if visibility
50
+ ivar_memo.separator = separator if separator
46
51
 
47
52
  generation[line_offset, length] = ""
48
53
  end
@@ -7,11 +7,19 @@ module RubyModKit
7
7
  class Type
8
8
  # the class to correct `def foo(Bar => bar, *Buz => buz)` -> `def foo(bar, *buz)`
9
9
  class ParameterArrowCorrector < Corrector
10
+ # @rbs @last_parameter_offsets: Set[Integer]
11
+
10
12
  # @rbs return: Array[Symbol]
11
13
  def correctable_error_types
12
14
  %i[unexpected_token_ignore def_params_term_paren argument_formal_constant]
13
15
  end
14
16
 
17
+ # @rbs return: void
18
+ def setup
19
+ super
20
+ @last_parameter_offsets = Set.new
21
+ end
22
+
15
23
  # @rbs parse_error: Prism::ParseError
16
24
  # @rbs generation: Generation
17
25
  # @rbs return: void
@@ -35,17 +43,29 @@ module RubyModKit
35
43
  def_node = generation.root_node.def_node_at(parse_error.location.start_offset) || return
36
44
  def_parent_node = def_node.parent
37
45
  parameters_node, body_node, = def_node.children
46
+ body_node = body_node.children[0] if body_node.is_a?(Node::BeginNode)
38
47
  return if !def_parent_node || !parameters_node || !body_node
39
48
 
40
49
  last_parameter_node = parameters_node.children.max_by(&:offset) || return
41
50
  last_parameter_offset = last_parameter_node.offset
51
+ return if @last_parameter_offsets.include?(last_parameter_offset)
42
52
 
53
+ @last_parameter_offsets << last_parameter_offset
43
54
  right_node = body_node.children.find { _1.offset >= parse_error.location.end_offset } || return
44
55
  right_offset = right_node.offset
56
+ name = right_node.slice[/\A\w+/]
45
57
  parameter_type = generation[last_parameter_offset...right_offset] || raise(RubyModKit::Error)
46
58
  parameter_type = parameter_type.sub(/\s*=>\s*\z/, "")
47
- generation[last_parameter_offset, right_offset - last_parameter_offset] = ""
48
- generation.memo_pad.parameter_memo(last_parameter_node).type = parameter_type
59
+ qualifier = nil
60
+ parameter_type = parameter_type.sub(/\A&\(\((.*)\) *: +(.*)\)\z/) do
61
+ qualifier = "&"
62
+ "(#{::Regexp.last_match(1)}) -> #{::Regexp.last_match(2)}"
63
+ end
64
+ generation[last_parameter_offset, right_offset - last_parameter_offset] = qualifier.to_s
65
+ parameter_memo = generation.memo_pad.parameter_memo(last_parameter_node)
66
+ parameter_memo.name = name.to_sym if name
67
+ parameter_memo.type = parameter_type
68
+ parameter_memo.qualifier = qualifier if qualifier
49
69
  end
50
70
 
51
71
  # @rbs parse_error: Prism::ParseError
@@ -56,15 +76,17 @@ module RubyModKit
56
76
  return if column < 0
57
77
 
58
78
  line = generation.line(parse_error)[column..] || return
59
- line =~ /\A\*(.*?)\s*=>\s*/
60
- length = ::Regexp.last_match(0)&.length || return
61
- type = ::Regexp.last_match(1) || return
79
+ line =~ /(\A\*(.*?)\s*=>\s*)(\w*)/
80
+ length = ::Regexp.last_match(1)&.length || return
81
+ type = ::Regexp.last_match(2) || return
82
+ name = ::Regexp.last_match(3)
62
83
  offset = parse_error.location.start_offset - 1
63
84
  parameter_position_node = generation.root_node.node_at(offset + length) || return
64
85
 
65
86
  generation[parse_error.location.start_offset, length - 1] = ""
66
87
  parameter_memo = generation.memo_pad.parameter_memo(parameter_position_node)
67
88
  parameter_memo.type = type
89
+ parameter_memo.name = name.to_sym if name
68
90
  parameter_memo.qualifier = "*"
69
91
  end
70
92
 
@@ -15,9 +15,10 @@ module RubyModKit
15
15
  def_parent_memo.ivars_memo.each do |name, ivar_memo|
16
16
  offset = ivar_memo.offset || next
17
17
  def_parent_node = generation.root_node.def_parent_node_at(offset) || next
18
- body_line_offset = generation.offsets[def_parent_node.location.start_line]
18
+ body_line_offset = generation.line_offset(def_parent_node, 1) || next
19
19
  generation.memo_pad.flags[:rbs_annotated] = true
20
- generation[body_line_offset, 0] = "#{ivar_memo.indent}# @rbs @#{name}: #{ivar_memo.type}\n"
20
+ script = "#{ivar_memo.indent}# @rbs @#{name}: #{ivar_memo.type}\n#{ivar_memo.separator}"
21
+ generation[body_line_offset, 0] = script
21
22
  end
22
23
  end
23
24
  true
@@ -15,8 +15,7 @@ module RubyModKit
15
15
  overload_memo.correct_offset(generation.root_node)
16
16
  offset = overload_memo.offset
17
17
  def_node = generation.root_node.def_node_at(offset) || raise(RubyModKit::Error)
18
- start_line = def_node.location.start_line - 1
19
- indent = generation.lines[start_line][/\A */] || ""
18
+ indent = generation.line_indent(def_node)
20
19
  offset -= indent.length
21
20
 
22
21
  annotation = +""
@@ -11,21 +11,22 @@ module RubyModKit
11
11
  # @rbs generation: Generation
12
12
  # @rbs return: bool
13
13
  def perform(generation)
14
- generation.memo_pad.parameters_memo.each do |offset, parameter_memo|
14
+ generation.memo_pad.each_parameter_memo do |parameter_memo|
15
15
  next if parameter_memo.untyped?
16
16
 
17
+ offset = parameter_memo.offset
17
18
  def_node = generation.root_node.def_node_at(offset)
18
19
  raise RubyModKit::Error, "DefNode not found" if !def_node || !def_node.is_a?(Node::DefNode)
19
20
 
20
21
  parameter_node = generation.root_node.parameter_node_at(offset)
21
22
  raise RubyModKit::Error, "ParameterNode not found" unless parameter_node
22
23
 
24
+ line_offset = generation.line_offset(def_node) || raise(RubyModKit::Error)
23
25
  type = parameter_memo.type
24
- src_offset = generation.offsets[def_node.location.start_line - 1]
25
- indent = def_node.offset - src_offset
26
+ indent = generation.line_indent(def_node)
26
27
  qualified_name = "#{parameter_memo.qualifier}#{parameter_node.name}"
27
28
  generation.memo_pad.flags[:rbs_annotated] = true
28
- generation[src_offset, 0] = "#{" " * indent}# @rbs #{qualified_name}: #{type}\n"
29
+ generation[line_offset, 0] = "#{indent}# @rbs #{qualified_name}: #{type}\n"
29
30
  end
30
31
  true
31
32
  end
@@ -16,7 +16,7 @@ module RubyModKit
16
16
  raise RubyModKit::Error, "DefNode not found" if !def_node || !def_node.is_a?(Node::DefNode)
17
17
  next if method_memo.untyped?
18
18
 
19
- src_offset = generation.offsets[def_node.location.start_line - 1]
19
+ src_offset = generation.line_offset(def_node) || raise(RubyModKit::Error)
20
20
  indent = offset - src_offset
21
21
  generation.memo_pad.flags[:rbs_annotated] = true
22
22
  generation[src_offset, 0] = "#{" " * indent}# @rbs return: #{method_memo.type}\n"
@@ -19,6 +19,7 @@ module RubyModKit
19
19
  return if parse_error.location.slice != ":"
20
20
 
21
21
  def_node = generation.root_node.statements_node_at(parse_error.location.start_offset)&.parent
22
+ def_node = def_node.parent if def_node.is_a?(Node::BeginNode)
22
23
  return unless def_node.is_a?(Node::DefNode)
23
24
 
24
25
  lparen_loc = def_node.lparen_loc
@@ -29,19 +29,13 @@ module RubyModKit
29
29
  ivars_memo.keep_if { |_, ivar_memo| ivar_memo.attr_kind }
30
30
  next if ivars_memo.empty?
31
31
 
32
- add_first_separator_line = false
33
32
  if attr_adding_line == 0
34
33
  attr_adding_line = def_parent_node.location.start_line
35
- prev_line = nil
36
- while generation.line(attr_adding_line) =~ /\A\s*#.*|\A$/
37
- prev_line = ::Regexp.last_match(0)
38
- attr_adding_line += 1
39
- end
40
- add_first_separator_line = prev_line != ""
34
+ attr_adding_line += 1 while generation.line(attr_adding_line) =~ /\A\s*#.*|\A$/
41
35
  end
42
36
  line = generation.line(attr_adding_line) || next
43
37
  add_separator_line = line != "\n" && line !~ /\A\s*end$/
44
- offset = generation.src_offset(attr_adding_line) || next
38
+ offset = generation.line_offset(attr_adding_line) || next
45
39
 
46
40
  body_node = def_parent_node.body_node
47
41
  if body_node
@@ -50,9 +44,9 @@ module RubyModKit
50
44
  else
51
45
  def_parent_line = generation.line(def_parent_node)
52
46
  indent = " #{def_parent_line[/\A\s*/]}"
47
+ generation[offset, 0] = "\n"
53
48
  end
54
49
 
55
- generation[offset, 0] = "\n" if add_first_separator_line
56
50
  ivars_memo.each do |name, ivar_memo|
57
51
  attr = ivar_memo.attr_kind
58
52
  attr = "#{ivar_memo.visibility} #{attr}" if ivar_memo.visibility
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ # rbs_inline: enabled
4
+
5
+ module RubyModKit
6
+ class Feature
7
+ class Type
8
+ class Yard
9
+ # The mission for parameter types
10
+ class TypeParameterMission < Mission
11
+ # @rbs generation: Generation
12
+ # @rbs return: bool
13
+ def perform(generation)
14
+ generation.memo_pad.each_parameter_memo do |parameter_memo|
15
+ next if parameter_memo.untyped?
16
+
17
+ offset = parameter_memo.offset
18
+ def_node = generation.root_node.def_node_at(offset)
19
+ raise RubyModKit::Error, "DefNode not found" if !def_node || !def_node.is_a?(Node::DefNode)
20
+
21
+ parameter_node = generation.root_node.parameter_node_at(offset)
22
+ raise RubyModKit::Error, "ParameterNode not found" unless parameter_node
23
+
24
+ line_offset = generation.line_offset(def_node) || raise(RubyModKit::Error)
25
+ indent = generation.line_indent(def_node)
26
+ script = "#{indent}# @param #{parameter_node.name} [#{Yard.rbs2yard(parameter_memo.type)}]\n"
27
+ generation[line_offset, 0] = script
28
+ end
29
+ true
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ # rbs_inline: enabled
4
+
5
+ module RubyModKit
6
+ class Feature
7
+ class Type
8
+ class Yard
9
+ # The mission for return value type
10
+ class TypeReturnMission < Mission
11
+ # @rbs generation: Generation
12
+ # @rbs return: bool
13
+ def perform(generation)
14
+ generation.memo_pad.methods_memo.each do |offset, method_memo|
15
+ def_node = generation.root_node.def_node_at(offset)
16
+ raise RubyModKit::Error, "DefNode not found" if !def_node || !def_node.is_a?(Node::DefNode)
17
+ next if method_memo.untyped?
18
+
19
+ src_offset = generation.line_offset(def_node) || raise(RubyModKit::Error)
20
+ indent = offset - src_offset
21
+ generation.memo_pad.flags[:rbs_annotated] = true
22
+ generation[src_offset, 0] = "#{" " * indent}# @return [#{Yard.rbs2yard(method_memo.type)}]\n"
23
+ end
24
+ true
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ # rbs_inline: enabled
4
+
5
+ module RubyModKit
6
+ class Feature
7
+ class Type
8
+ # namespace for type with rbs-line feature
9
+ class Yard < Feature
10
+ # @rbs return: Array[Mission]
11
+ def create_missions
12
+ [
13
+ TypeParameterMission.new,
14
+ TypeReturnMission.new,
15
+ ]
16
+ end
17
+
18
+ class << self
19
+ # @rbs type: String
20
+ # @rbs return: String
21
+ def rbs2yard(type)
22
+ type.gsub(/\s*\|\s*/, ", ").tr("[]", "<>").gsub(/(?<=^|\W)bool(?=$|\W)/, "Boolean")
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+
30
+ require_relative "yard/type_parameter_mission"
31
+ require_relative "yard/type_return_mission"