ruby_mod_kit 0.0.3 → 0.0.5

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.
Files changed (91) hide show
  1. checksums.yaml +4 -4
  2. data/.ruby_mod_kit.yml +5 -0
  3. data/README.md +89 -0
  4. data/lib/ruby_mod_kit/cli.rb +17 -2
  5. data/lib/ruby_mod_kit/config.rb +53 -0
  6. data/lib/ruby_mod_kit/core_ext/eval.rb +6 -10
  7. data/lib/ruby_mod_kit/corrector.rb +4 -3
  8. data/lib/ruby_mod_kit/corrector_manager.rb +18 -18
  9. data/lib/ruby_mod_kit/feature/instance_variable_parameter/instance_variable_parameter_corrector.rb +5 -7
  10. data/lib/ruby_mod_kit/feature/instance_variable_parameter/instance_variable_parameter_mission.rb +4 -11
  11. data/lib/ruby_mod_kit/feature/overload/overload_mission.rb +8 -12
  12. data/lib/ruby_mod_kit/feature/type/check/arguments/add_arguments_checker_mission.rb +56 -0
  13. data/lib/ruby_mod_kit/feature/type/check/arguments.rb +23 -0
  14. data/lib/ruby_mod_kit/feature/type/instance_variable_colon_corrector.rb +20 -12
  15. data/lib/ruby_mod_kit/feature/type/parameter_arrow_corrector.rb +35 -19
  16. data/lib/ruby_mod_kit/feature/type/rbs_inline/add_magic_comment_mission.rb +49 -0
  17. data/lib/ruby_mod_kit/feature/type/rbs_inline/type_attr_mission.rb +12 -7
  18. data/lib/ruby_mod_kit/feature/type/rbs_inline/type_instance_variable_mission.rb +7 -8
  19. data/lib/ruby_mod_kit/feature/type/rbs_inline/type_overload_mission.rb +6 -9
  20. data/lib/ruby_mod_kit/feature/type/rbs_inline/type_parameter_mission.rb +9 -10
  21. data/lib/ruby_mod_kit/feature/type/rbs_inline/type_return_mission.rb +5 -7
  22. data/lib/ruby_mod_kit/feature/type/rbs_inline.rb +3 -0
  23. data/lib/ruby_mod_kit/feature/type/return_value_colon_corrector.rb +5 -6
  24. data/lib/ruby_mod_kit/feature/type/type_attr_mission.rb +13 -17
  25. data/lib/ruby_mod_kit/feature/type/yard/type_parameter_mission.rb +35 -0
  26. data/lib/ruby_mod_kit/feature/type/yard/type_return_mission.rb +30 -0
  27. data/lib/ruby_mod_kit/feature/type/yard.rb +31 -0
  28. data/lib/ruby_mod_kit/feature.rb +0 -6
  29. data/lib/ruby_mod_kit/generation.rb +83 -39
  30. data/lib/ruby_mod_kit/memo/ivar_memo.rb +4 -0
  31. data/lib/ruby_mod_kit/memo/overload_memo.rb +1 -0
  32. data/lib/ruby_mod_kit/memo/parameter_memo.rb +4 -2
  33. data/lib/ruby_mod_kit/memo.rb +0 -2
  34. data/lib/ruby_mod_kit/memo_pad.rb +9 -0
  35. data/lib/ruby_mod_kit/mission.rb +1 -8
  36. data/lib/ruby_mod_kit/node/base_node.rb +39 -12
  37. data/lib/ruby_mod_kit/node/begin_node.rb +31 -0
  38. data/lib/ruby_mod_kit/node/call_node.rb +1 -1
  39. data/lib/ruby_mod_kit/node/def_node.rb +1 -1
  40. data/lib/ruby_mod_kit/node/def_parent_node.rb +13 -6
  41. data/lib/ruby_mod_kit/node/parameter_node.rb +3 -3
  42. data/lib/ruby_mod_kit/node/program_node.rb +6 -1
  43. data/lib/ruby_mod_kit/node/statements_node.rb +1 -1
  44. data/lib/ruby_mod_kit/node/symbol_node.rb +2 -1
  45. data/lib/ruby_mod_kit/node/untyped_node.rb +1 -1
  46. data/lib/ruby_mod_kit/node/wrap.rb +3 -1
  47. data/lib/ruby_mod_kit/node.rb +1 -2
  48. data/lib/ruby_mod_kit/version.rb +1 -1
  49. data/lib/ruby_mod_kit.rb +11 -11
  50. data/ruby_mod_kit.gemspec +7 -1
  51. data/sig/generated/ruby_mod_kit/cli.rbs +5 -0
  52. data/sig/generated/ruby_mod_kit/config.rbs +21 -0
  53. data/sig/generated/ruby_mod_kit/core_ext/eval.rbs +4 -2
  54. data/sig/generated/ruby_mod_kit/corrector.rbs +4 -3
  55. data/sig/generated/ruby_mod_kit/corrector_manager.rbs +3 -7
  56. data/sig/generated/ruby_mod_kit/feature/instance_variable_parameter/instance_variable_parameter_corrector.rbs +1 -3
  57. data/sig/generated/ruby_mod_kit/feature/instance_variable_parameter/instance_variable_parameter_mission.rbs +1 -8
  58. data/sig/generated/ruby_mod_kit/feature/overload/overload_mission.rbs +1 -4
  59. data/sig/generated/ruby_mod_kit/feature/type/check/arguments/add_arguments_checker_mission.rbs +16 -0
  60. data/sig/generated/ruby_mod_kit/feature/type/check/arguments.rbs +15 -0
  61. data/sig/generated/ruby_mod_kit/feature/type/instance_variable_colon_corrector.rbs +7 -3
  62. data/sig/generated/ruby_mod_kit/feature/type/parameter_arrow_corrector.rbs +8 -9
  63. data/sig/generated/ruby_mod_kit/feature/type/rbs_inline/add_magic_comment_mission.rbs +21 -0
  64. data/sig/generated/ruby_mod_kit/feature/type/rbs_inline/type_attr_mission.rbs +1 -4
  65. data/sig/generated/ruby_mod_kit/feature/type/rbs_inline/type_instance_variable_mission.rbs +1 -4
  66. data/sig/generated/ruby_mod_kit/feature/type/rbs_inline/type_overload_mission.rbs +1 -4
  67. data/sig/generated/ruby_mod_kit/feature/type/rbs_inline/type_parameter_mission.rbs +1 -4
  68. data/sig/generated/ruby_mod_kit/feature/type/rbs_inline/type_return_mission.rbs +1 -4
  69. data/sig/generated/ruby_mod_kit/feature/type/return_value_colon_corrector.rbs +1 -3
  70. data/sig/generated/ruby_mod_kit/feature/type/type_attr_mission.rbs +3 -4
  71. data/sig/generated/ruby_mod_kit/feature/type/yard/type_parameter_mission.rbs +16 -0
  72. data/sig/generated/ruby_mod_kit/feature/type/yard/type_return_mission.rbs +16 -0
  73. data/sig/generated/ruby_mod_kit/feature/type/yard.rbs +17 -0
  74. data/sig/generated/ruby_mod_kit/feature.rbs +0 -4
  75. data/sig/generated/ruby_mod_kit/generation.rbs +55 -15
  76. data/sig/generated/ruby_mod_kit/memo/ivar_memo.rbs +8 -0
  77. data/sig/generated/ruby_mod_kit/memo/overload_memo.rbs +2 -0
  78. data/sig/generated/ruby_mod_kit/memo/parameter_memo.rbs +6 -2
  79. data/sig/generated/ruby_mod_kit/memo_pad.rbs +8 -0
  80. data/sig/generated/ruby_mod_kit/mission.rbs +1 -8
  81. data/sig/generated/ruby_mod_kit/node/base_node.rbs +22 -8
  82. data/sig/generated/ruby_mod_kit/node/begin_node.rbs +26 -0
  83. data/sig/generated/ruby_mod_kit/node/def_parent_node.rbs +5 -0
  84. data/sig/generated/ruby_mod_kit/node/parameter_node.rbs +1 -1
  85. data/sig/generated/ruby_mod_kit/node/program_node.rbs +3 -0
  86. data/sig/generated/ruby_mod_kit/node/symbol_node.rbs +2 -0
  87. data/sig/generated/ruby_mod_kit.rbs +6 -3
  88. data/sig/yaml.rbs +3 -0
  89. metadata +21 -5
  90. data/sig/generated/ruby_mod_kit/memo.rbs +0 -7
  91. data/sig/generated/ruby_mod_kit/node.rbs +0 -7
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 36509ee4c00db1106b7447ba1d4fe09ee2fd2a8f8ce763c40b1da185f19cfc61
4
- data.tar.gz: eccbdb68bb6159aa95c7fda5d171e4089b9dfa9b262ef136caf019fa3c339d7f
3
+ metadata.gz: e5888d6187dc2620b37315d72fddee6b134bbd14181277ff600e864eb9c06ca0
4
+ data.tar.gz: 7ffb4ec96c231e6122eeaa7d47601f67a28620951ed08e9d3b3888e9fa684fbc
5
5
  SHA512:
6
- metadata.gz: a8b12f06259193345becd29a14a1c6397481c41b390daed390cf4ed0bc7016afe0fbcf9ba95a9c3639b37150c98791d3e501cf2490725bfc5cf3c405fdc99f94
7
- data.tar.gz: 684d9b858ac50e78b40f92a2d1cb8ddaafb99983bbdafc7788d786878af5b03c2187995bbe312de59495c9e4f796c352a9e203428d91018075a88791a79320eb
6
+ metadata.gz: 3c2e632593d2d0a7061f8a71a7e65131a1b72434ac3853467024503d13c57328abe88ade105b2532baf94d44bd428bd02b4eae9e0c50462d4dca6bebc767d4f9
7
+ data.tar.gz: 81b17d66702c1fc89c77bc3270f74608fca6ed8e9a12f26c04ea69f7d0bdceb4b91b104bfa45b0f944e5ba5dae79e789de720b8a5605df0d4ac4bb4e48e62d6d
data/.ruby_mod_kit.yml ADDED
@@ -0,0 +1,5 @@
1
+ features:
2
+ - instance_variable_parameter
3
+ - overload
4
+ - type
5
+ - type/rbs_inline
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,7 +12,7 @@ module RubyModKit
12
12
  # @rbs *args: String
13
13
  # @rbs return: void
14
14
  def exec(*args)
15
- RubyModKit.execute_file(*args)
15
+ RubyModKit.execute_file(*args, config: config)
16
16
  end
17
17
 
18
18
  desc "transpile", "transpile rbm files"
@@ -28,9 +28,24 @@ module RubyModKit
28
28
  else
29
29
  options[:output]
30
30
  end
31
+ config = self.config
31
32
  args.each do |path|
32
- RubyModKit.transpile_file(path, output: output || RubyModKit.rb_path(path))
33
+ RubyModKit.transpile_file(path, output: output || RubyModKit.rb_path(path), config: config)
33
34
  end
34
35
  end
36
+
37
+ private
38
+
39
+ # @rbs return: Config | nil
40
+ def config
41
+ if options[:config]
42
+ config_path = options[:config]
43
+ if_none = :raise
44
+ else
45
+ config_path = "."
46
+ if_none = nil
47
+ end
48
+ Config.load(config_path, if_none: if_none)
49
+ end
35
50
  end
36
51
  end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ # rbs_inline: enabled
4
+
5
+ require "yaml"
6
+
7
+ module RubyModKit
8
+ # config class
9
+ class Config
10
+ # @rbs @features: Array[Config]
11
+
12
+ attr_reader :features #: Array[Config]
13
+
14
+ DEFAULT_FEATURES = %w[instance_variable_parameter overload type type/rbs_inline].freeze #: Array[String]
15
+
16
+ # @rbs features: Array[String]
17
+ # @rbs return: void
18
+ def initialize(features: DEFAULT_FEATURES)
19
+ @features = features.sort.map do |feature_name|
20
+ raise ArgumentError, "invalid feature: #{feature_name}" if feature_name.include?(".")
21
+
22
+ require "ruby_mod_kit/feature/#{feature_name}"
23
+ const_name = feature_name
24
+ .gsub(/[A-Za-z0-9]+/) { (::Regexp.last_match(0) || "").capitalize }
25
+ .gsub("_", "").gsub("/", "::")
26
+ Feature.const_get(const_name).new
27
+ end
28
+ end
29
+
30
+ class << self
31
+ # @rbs path: String
32
+ # @rbs if_none: nil | Symbol
33
+ # @rbs return: Config | nil
34
+ def load(path, if_none: nil)
35
+ return load(File.join(path, ".ruby_mod_kit.yml"), if_none: if_none) if File.directory?(path)
36
+
37
+ unless File.exist?(path)
38
+ case if_none
39
+ when nil
40
+ return nil
41
+ when :raise
42
+ raise LoadError, "Can't load #{path}"
43
+ else
44
+ raise ArgumentError, "unexpected if_none: #{if_none.inspect}"
45
+ end
46
+ end
47
+
48
+ options = YAML.safe_load(File.read(path), symbolize_names: true)
49
+ new(**options) if options.is_a?(Hash)
50
+ end
51
+ end
52
+ end
53
+ end
@@ -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
@@ -12,11 +12,12 @@ module RubyModKit
12
12
 
13
13
  # @rbs _parse_error: Prism::ParseError
14
14
  # @rbs _generation: Generation
15
- # @rbs _root_node: Node::ProgramNode
16
- # @rbs _memo_pad: MemoPad
17
15
  # @rbs return: void
18
- def correct(_parse_error, _generation, _root_node, _memo_pad)
16
+ def correct(_parse_error, _generation)
19
17
  raise RubyModKit::Error, "Unexpected type #{self.class}"
20
18
  end
19
+
20
+ # @rbs return: void
21
+ def setup; end
21
22
  end
22
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|
@@ -23,20 +23,21 @@ module RubyModKit
23
23
  end
24
24
 
25
25
  # @rbs generation: Generation
26
- # @rbs root_node: Node::ProgramNode
27
- # @rbs parse_result: Prism::ParseResult
28
- # @rbs memo_pad: MemoPad
29
26
  # @rbs return: bool
30
- def perform(generation, root_node, parse_result, memo_pad)
31
- return true if parse_result.errors.empty?
27
+ def perform(generation)
28
+ return true if generation.errors.empty?
32
29
 
33
- check_prev_errors(generation, parse_result)
34
- @previous_error_messages = parse_result.errors.map(&:message)
30
+ check_prev_errors(generation)
31
+ @previous_source = generation.script.dup
35
32
 
36
- parse_result.errors.each do |parse_error|
33
+ @correctors_error_map.each_value do |correctors|
34
+ correctors.each(&:setup)
35
+ end
36
+
37
+ generation.errors.each do |parse_error|
37
38
  correctors = @correctors_error_map[parse_error.type] || next
38
39
  correctors.each do |corrector|
39
- corrector.correct(parse_error, generation, root_node, memo_pad)
40
+ corrector.correct(parse_error, generation)
40
41
  end
41
42
  end
42
43
 
@@ -44,19 +45,18 @@ module RubyModKit
44
45
  end
45
46
 
46
47
  # @rbs generation: Generation
47
- # @rbs parse_result: Prism::ParseResult
48
48
  # @rbs return: void
49
- def check_prev_errors(generation, parse_result)
50
- return if @previous_error_messages.empty?
51
- return if parse_result.errors.empty?
52
- return if @previous_error_messages != parse_result.errors.map(&:message)
49
+ def check_prev_errors(generation)
50
+ return if @previous_source.empty?
51
+ return if generation.errors.empty?
52
+ return if @previous_source != generation.script
53
53
 
54
54
  message = +""
55
- parse_result.errors.each do |parse_error|
55
+ generation.errors.each do |parse_error|
56
56
  message << "\n" unless message.empty?
57
57
  message << "#{generation.name}:#{parse_error.location.start_line}:#{parse_error.message} "
58
58
  message << "(#{parse_error.type})"
59
- line = parse_result.source.lines[parse_error.location.start_line - 1]
59
+ line = generation.line(parse_error)
60
60
  if line
61
61
  message << "\n#{line.chomp}\n"
62
62
  message << "#{" " * parse_error.location.start_column}^#{"~" * [parse_error.location.length - 1, 0].max}"
@@ -14,26 +14,24 @@ module RubyModKit
14
14
 
15
15
  # @rbs parse_error: Prism::ParseError
16
16
  # @rbs generation: Generation
17
- # @rbs root_node: Node::ProgramNode
18
- # @rbs memo_pad: MemoPad
19
17
  # @rbs return: void
20
- def correct(parse_error, generation, root_node, memo_pad)
18
+ def correct(parse_error, generation)
21
19
  src_offset = parse_error.location.start_offset
22
20
 
23
21
  name = parse_error.location.slice[1..]
24
22
  raise RubyModKit::Error unless name
25
23
 
26
- parameter_position_node = root_node.node_at(src_offset)
24
+ parameter_position_node = generation.root_node.node_at(src_offset)
27
25
  raise RubyModKit::Error unless parameter_position_node
28
26
 
29
27
  generation[src_offset, parse_error.location.length] = name
30
- parameter_memo = memo_pad.parameter_memo(parameter_position_node)
28
+ parameter_memo = generation.memo_pad.parameter_memo(parameter_position_node)
31
29
  parameter_memo.ivar_parameter = true
32
30
 
33
31
  return unless parameter_memo.untyped?
34
32
 
35
- def_parent_node = root_node.def_parent_node_at(parse_error.location.start_offset) || return
36
- ivar_memo_type = memo_pad.def_parent_memo(def_parent_node).ivar_memo(name.to_sym).type || return
33
+ def_parent_node = generation.root_node.def_parent_node_at(parse_error.location.start_offset) || return
34
+ ivar_memo_type = generation.memo_pad.def_parent_memo(def_parent_node).ivar_memo(name.to_sym).type || return
37
35
  parameter_memo.type = ivar_memo_type
38
36
  end
39
37
  end
@@ -7,24 +7,17 @@ module RubyModKit
7
7
  class InstanceVariableParameter
8
8
  # The mission for instance variable arguments
9
9
  class InstanceVariableParameterMission < Mission
10
- # @rbs @assignment: String
11
-
12
- attr_reader :assignment #: String
13
-
14
10
  # @rbs generation: Generation
15
- # @rbs root_node: Node::ProgramNode
16
- # @rbs _parse_result: Prism::ParseResult
17
- # @rbs memo_pad: MemoPad
18
11
  # @rbs return: bool
19
- def perform(generation, root_node, _parse_result, memo_pad)
20
- memo_pad.parameters_memo.each_value do |parameter_memo|
12
+ def perform(generation)
13
+ generation.memo_pad.each_parameter_memo do |parameter_memo|
21
14
  next unless parameter_memo.ivar_parameter
22
15
 
23
16
  offset = parameter_memo.offset
24
- parameter_node = root_node.parameter_node_at(offset)
17
+ parameter_node = generation.root_node.parameter_node_at(offset)
25
18
  raise RubyModKit::Error unless parameter_node
26
19
 
27
- def_node = root_node.def_node_at(offset)
20
+ def_node = generation.root_node.def_node_at(offset)
28
21
  raise RubyModKit::Error, "DefNode not found" unless def_node
29
22
 
30
23
  def_body_location = def_node.body_location
@@ -20,15 +20,12 @@ module RubyModKit
20
20
  end
21
21
 
22
22
  # @rbs generation: Generation
23
- # @rbs root_node: Node::ProgramNode
24
- # @rbs parse_result: Prism::ParseResult
25
- # @rbs memo_pad: MemoPad
26
23
  # @rbs return: bool
27
- def perform(generation, root_node, parse_result, memo_pad)
24
+ def perform(generation)
28
25
  return true if @modified
29
26
 
30
- method_memo_groups = memo_pad.methods_memo.each_value.group_by do |method_memo|
31
- [root_node.def_parent_node_at(method_memo.offset), method_memo.name]
27
+ method_memo_groups = generation.memo_pad.methods_memo.each_value.group_by do |method_memo|
28
+ [generation.root_node.def_parent_node_at(method_memo.offset), method_memo.name]
32
29
  end
33
30
  method_memo_groups.each_value do |method_memos|
34
31
  next if method_memos.length <= 1
@@ -36,16 +33,15 @@ module RubyModKit
36
33
  @modified = true
37
34
  first_method_memo = method_memos.first
38
35
  name = first_method_memo.name
39
- first_def_node = root_node.def_node_at(first_method_memo.offset)
36
+ first_def_node = generation.root_node.def_node_at(first_method_memo.offset)
40
37
  raise RubyModKit::Error unless first_def_node.is_a?(Node::DefNode)
41
38
  raise RubyModKit::Error unless name.is_a?(Symbol)
42
39
 
43
- start_line = first_def_node.location.start_line - 1
44
- indent = parse_result.source.lines[start_line][/\A */] || ""
45
- src_offset = parse_result.source.offsets[start_line]
40
+ indent = generation.line_indent(first_def_node)
41
+ src_offset = generation.line_offset(first_def_node) || raise(RubyModKit::Error)
46
42
  script = +""
47
43
 
48
- overload_memo = memo_pad.overload_memo(first_method_memo.offset, name)
44
+ overload_memo = generation.memo_pad.overload_memo(first_method_memo.offset, name)
49
45
 
50
46
  method_memos.each do |method_memo|
51
47
  type = method_memo.type
@@ -57,7 +53,7 @@ module RubyModKit
57
53
  overload_prefix = +"#{OVERLOAD_METHOD_MAP[name] || name}_"
58
54
  method_memos.each_with_index do |method_memo, i|
59
55
  overload_name = "#{overload_prefix}_overload#{i}"
60
- def_node = root_node.def_node_at(method_memo.offset)
56
+ def_node = generation.root_node.def_node_at(method_memo.offset)
61
57
  raise RubyModKit::Error if !def_node || !def_node.is_a?(Node::DefNode)
62
58
 
63
59
  name_loc = def_node.name_loc
@@ -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"
@@ -7,6 +7,10 @@ module RubyModKit
7
7
  class Type
8
8
  # the class to correct `@var: Type` -> `# @rbs @var: Type`
9
9
  class InstanceVariableColonCorrector < Corrector
10
+ VISIBILITIES = %i[private public protected].freeze #: Array[Symbol]
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(\n+)?/.freeze #: Regexp
13
+
10
14
  # @rbs return: Array[Symbol]
11
15
  def correctable_error_types
12
16
  %i[unexpected_token_ignore]
@@ -14,32 +18,36 @@ module RubyModKit
14
18
 
15
19
  # @rbs parse_error: Prism::ParseError
16
20
  # @rbs generation: Generation
17
- # @rbs root_node: Node::ProgramNode
18
- # @rbs memo_pad: MemoPad
19
21
  # @rbs return: void
20
- def correct(parse_error, generation, root_node, memo_pad)
22
+ def correct(parse_error, generation)
21
23
  return if parse_error.location.slice != ":"
22
24
 
23
- def_parent_node = 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
+ )
24
29
  return unless def_parent_node.is_a?(Node::DefParentNode)
25
30
 
26
- line = generation.line(parse_error)
27
- line_offset = generation.src_offset(parse_error) || return
28
- attr_patterns = %i[attr_reader reader getter attr_writer writer setter attr_accessor accessor property]
29
- return if line !~ /(\A\s*)(?:(#{attr_patterns.join("|")}) )?@(\w*)\s*:\s*(.*)\n/
31
+ line_offset = generation.line_offset(parse_error) || return
32
+ line = generation[line_offset..]
33
+ return if line !~ REGEXP
30
34
 
31
35
  length = ::Regexp.last_match(0)&.length
32
36
  indent = ::Regexp.last_match(1)
33
- attr_kind = ::Regexp.last_match(2)
34
- ivar_name = ::Regexp.last_match(3)
35
- type = ::Regexp.last_match(4)
37
+ visibility = ::Regexp.last_match(2)
38
+ attr_kind = ::Regexp.last_match(3)
39
+ ivar_name = ::Regexp.last_match(4)
40
+ type = ::Regexp.last_match(5)
41
+ separator = ::Regexp.last_match(6)
36
42
  return if !length || !indent || !ivar_name || !type
37
43
 
38
- ivar_memo = memo_pad.def_parent_memo(def_parent_node).ivar_memo(ivar_name.to_sym)
44
+ ivar_memo = generation.memo_pad.def_parent_memo(def_parent_node).ivar_memo(ivar_name.to_sym)
39
45
  ivar_memo.type = type
40
46
  ivar_memo.offset = line_offset
41
47
  ivar_memo.indent = indent
42
48
  ivar_memo.attr_kind = attr_kind if attr_kind
49
+ ivar_memo.visibility = visibility.to_sym if visibility
50
+ ivar_memo.separator = separator if separator
43
51
 
44
52
  generation[line_offset, length] = ""
45
53
  end