ruby_mod_kit 0.0.1 → 0.0.3

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 (117) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +14 -8
  3. data/lib/ruby_mod_kit/cli.rb +10 -1
  4. data/lib/ruby_mod_kit/core_ext/eval.rb +36 -0
  5. data/lib/ruby_mod_kit/core_ext/load.rb +74 -0
  6. data/lib/ruby_mod_kit/core_ext.rb +7 -0
  7. data/lib/ruby_mod_kit/corrector.rb +22 -0
  8. data/lib/ruby_mod_kit/corrector_manager.rb +68 -0
  9. data/lib/ruby_mod_kit/feature/instance_variable_parameter/instance_variable_parameter_corrector.rb +42 -0
  10. data/lib/ruby_mod_kit/feature/instance_variable_parameter/instance_variable_parameter_mission.rb +49 -0
  11. data/lib/ruby_mod_kit/feature/instance_variable_parameter.rb +27 -0
  12. data/lib/ruby_mod_kit/feature/overload/overload_mission.rb +80 -0
  13. data/lib/ruby_mod_kit/feature/overload.rb +19 -0
  14. data/lib/ruby_mod_kit/feature/type/instance_variable_colon_corrector.rb +49 -0
  15. data/lib/ruby_mod_kit/feature/type/parameter_arrow_corrector.rb +90 -0
  16. data/lib/ruby_mod_kit/feature/type/rbs_inline/type_attr_mission.rb +41 -0
  17. data/lib/ruby_mod_kit/feature/type/rbs_inline/type_instance_variable_mission.rb +31 -0
  18. data/lib/ruby_mod_kit/feature/type/rbs_inline/type_overload_mission.rb +43 -0
  19. data/lib/ruby_mod_kit/feature/type/rbs_inline/type_parameter_mission.rb +38 -0
  20. data/lib/ruby_mod_kit/feature/type/rbs_inline/type_return_mission.rb +32 -0
  21. data/lib/ruby_mod_kit/feature/type/rbs_inline.rb +29 -0
  22. data/lib/ruby_mod_kit/feature/type/return_value_colon_corrector.rb +45 -0
  23. data/lib/ruby_mod_kit/feature/type/type_attr_mission.rb +67 -0
  24. data/lib/ruby_mod_kit/feature/type.rb +31 -0
  25. data/lib/ruby_mod_kit/feature.rb +24 -0
  26. data/lib/ruby_mod_kit/generation.rb +60 -22
  27. data/lib/ruby_mod_kit/memo/def_parent_memo.rb +36 -0
  28. data/lib/ruby_mod_kit/memo/{ivar.rb → ivar_memo.rb} +17 -3
  29. data/lib/ruby_mod_kit/memo/{method.rb → method_memo.rb} +7 -7
  30. data/lib/ruby_mod_kit/memo/offset_memo.rb +1 -1
  31. data/lib/ruby_mod_kit/memo/overload_memo.rb +46 -0
  32. data/lib/ruby_mod_kit/memo/{parameter.rb → parameter_memo.rb} +3 -3
  33. data/lib/ruby_mod_kit/memo.rb +7 -64
  34. data/lib/ruby_mod_kit/memo_pad.rb +69 -0
  35. data/lib/ruby_mod_kit/mission.rb +5 -24
  36. data/lib/ruby_mod_kit/node/base_node.rb +137 -0
  37. data/lib/ruby_mod_kit/node/call_node.rb +10 -6
  38. data/lib/ruby_mod_kit/node/def_node.rb +10 -6
  39. data/lib/ruby_mod_kit/node/def_parent_node.rb +41 -0
  40. data/lib/ruby_mod_kit/node/parameter_node.rb +12 -8
  41. data/lib/ruby_mod_kit/node/program_node.rb +2 -2
  42. data/lib/ruby_mod_kit/node/statements_node.rb +10 -6
  43. data/lib/ruby_mod_kit/node/symbol_node.rb +10 -6
  44. data/lib/ruby_mod_kit/node/untyped_node.rb +10 -6
  45. data/lib/ruby_mod_kit/node/wrap.rb +43 -0
  46. data/lib/ruby_mod_kit/node.rb +5 -149
  47. data/lib/ruby_mod_kit/offset_diff.rb +12 -6
  48. data/lib/ruby_mod_kit/version.rb +1 -1
  49. data/lib/ruby_mod_kit.rb +43 -11
  50. data/ruby_mod_kit.gemspec +1 -6
  51. data/sig/generated/ruby_mod_kit/core_ext/eval.rbs +17 -0
  52. data/sig/generated/ruby_mod_kit/core_ext/load.rbs +33 -0
  53. data/sig/generated/ruby_mod_kit/corrector.rbs +16 -0
  54. data/sig/generated/ruby_mod_kit/corrector_manager.rbs +26 -0
  55. data/sig/generated/ruby_mod_kit/feature/instance_variable_parameter/instance_variable_parameter_corrector.rbs +20 -0
  56. data/sig/generated/ruby_mod_kit/feature/instance_variable_parameter/instance_variable_parameter_mission.rbs +21 -0
  57. data/sig/generated/ruby_mod_kit/feature/instance_variable_parameter.rbs +14 -0
  58. data/sig/generated/ruby_mod_kit/feature/overload/overload_mission.rbs +24 -0
  59. data/sig/generated/ruby_mod_kit/feature/overload.rbs +11 -0
  60. data/sig/generated/ruby_mod_kit/feature/type/instance_variable_colon_corrector.rbs +20 -0
  61. data/sig/generated/ruby_mod_kit/feature/type/parameter_arrow_corrector.rbs +39 -0
  62. data/sig/generated/ruby_mod_kit/feature/type/rbs_inline/type_attr_mission.rbs +19 -0
  63. data/sig/generated/ruby_mod_kit/feature/type/rbs_inline/type_instance_variable_mission.rbs +19 -0
  64. data/sig/generated/ruby_mod_kit/feature/type/rbs_inline/type_overload_mission.rbs +19 -0
  65. data/sig/generated/ruby_mod_kit/feature/type/rbs_inline/type_parameter_mission.rbs +19 -0
  66. data/sig/generated/ruby_mod_kit/feature/type/rbs_inline/type_return_mission.rbs +19 -0
  67. data/sig/generated/ruby_mod_kit/feature/type/rbs_inline.rbs +13 -0
  68. data/sig/generated/ruby_mod_kit/feature/type/return_value_colon_corrector.rbs +20 -0
  69. data/sig/generated/ruby_mod_kit/feature/type/type_attr_mission.rbs +20 -0
  70. data/sig/generated/ruby_mod_kit/feature/type.rbs +14 -0
  71. data/sig/generated/ruby_mod_kit/feature.rbs +16 -0
  72. data/sig/generated/ruby_mod_kit/generation.rbs +25 -10
  73. data/sig/generated/ruby_mod_kit/memo/def_parent_memo.rbs +24 -0
  74. data/sig/generated/ruby_mod_kit/memo/{ivar.rbs → ivar_memo.rbs} +15 -3
  75. data/sig/generated/ruby_mod_kit/memo/{method.rbs → method_memo.rbs} +8 -8
  76. data/sig/generated/ruby_mod_kit/memo/offset_memo.rbs +1 -1
  77. data/sig/generated/ruby_mod_kit/memo/overload_memo.rbs +32 -0
  78. data/sig/generated/ruby_mod_kit/memo/{parameter.rbs → parameter_memo.rbs} +3 -3
  79. data/sig/generated/ruby_mod_kit/memo.rbs +2 -36
  80. data/sig/generated/ruby_mod_kit/memo_pad.rbs +46 -0
  81. data/sig/generated/ruby_mod_kit/mission.rbs +4 -12
  82. data/sig/generated/ruby_mod_kit/node/base_node.rbs +65 -0
  83. data/sig/generated/ruby_mod_kit/node/call_node.rbs +11 -6
  84. data/sig/generated/ruby_mod_kit/node/def_node.rbs +11 -6
  85. data/sig/generated/ruby_mod_kit/node/def_parent_node.rbs +31 -0
  86. data/sig/generated/ruby_mod_kit/node/parameter_node.rbs +13 -8
  87. data/sig/generated/ruby_mod_kit/node/program_node.rbs +2 -2
  88. data/sig/generated/ruby_mod_kit/node/statements_node.rbs +11 -6
  89. data/sig/generated/ruby_mod_kit/node/symbol_node.rbs +11 -6
  90. data/sig/generated/ruby_mod_kit/node/untyped_node.rbs +11 -6
  91. data/sig/generated/ruby_mod_kit/node/wrap.rbs +12 -0
  92. data/sig/generated/ruby_mod_kit/node.rbs +2 -58
  93. data/sig/generated/ruby_mod_kit/offset_diff.rbs +3 -1
  94. data/sig/generated/ruby_mod_kit.rbs +13 -2
  95. data/sig/thor.rbs +2 -0
  96. metadata +63 -43
  97. data/lib/ruby_mod_kit/memo/class.rb +0 -27
  98. data/lib/ruby_mod_kit/mission/fix_parse_error.rb +0 -213
  99. data/lib/ruby_mod_kit/mission/ivar_arg.rb +0 -42
  100. data/lib/ruby_mod_kit/mission/overload.rb +0 -73
  101. data/lib/ruby_mod_kit/mission/type_attr.rb +0 -75
  102. data/lib/ruby_mod_kit/mission/type_parameter.rb +0 -39
  103. data/lib/ruby_mod_kit/mission/type_return.rb +0 -33
  104. data/lib/ruby_mod_kit/node/class_node.rb +0 -37
  105. data/lib/ruby_mod_kit/transpiler.rb +0 -20
  106. data/sig/generated/examples/user.rbs +0 -60
  107. data/sig/generated/ruby_mod_kit/memo/class.rbs +0 -20
  108. data/sig/generated/ruby_mod_kit/memo/located.rbs +0 -14
  109. data/sig/generated/ruby_mod_kit/memo/parameter_type.rbs +0 -14
  110. data/sig/generated/ruby_mod_kit/mission/fix_parse_error.rbs +0 -73
  111. data/sig/generated/ruby_mod_kit/mission/ivar_arg.rbs +0 -19
  112. data/sig/generated/ruby_mod_kit/mission/overload.rbs +0 -20
  113. data/sig/generated/ruby_mod_kit/mission/type_attr.rbs +0 -18
  114. data/sig/generated/ruby_mod_kit/mission/type_parameter.rbs +0 -18
  115. data/sig/generated/ruby_mod_kit/mission/type_return.rbs +0 -18
  116. data/sig/generated/ruby_mod_kit/node/class_node.rbs +0 -29
  117. data/sig/generated/ruby_mod_kit/transpiler.rbs +0 -11
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e3a08a3d1865aa1abd27922326dc12e4cfc6c9a621f0c73882a64c12a80cc3d4
4
- data.tar.gz: d30dd20e654a68c233f33925f6f27938a3920675df07dea1377f31ba8fa42ab6
3
+ metadata.gz: 36509ee4c00db1106b7447ba1d4fe09ee2fd2a8f8ce763c40b1da185f19cfc61
4
+ data.tar.gz: eccbdb68bb6159aa95c7fda5d171e4089b9dfa9b262ef136caf019fa3c339d7f
5
5
  SHA512:
6
- metadata.gz: cc67818cecc1c39a1aaf1f925a8ebd59dab9220a77e0d1e2dd19be99ea7b8b72e582e4a8d794966ab411125b229084f339f85cd427eebf33e29f88ee576eb111
7
- data.tar.gz: ed11c866fba06fe283e1957ba41c2138194cdc3d5049dfe9cefdee662519d3e222ef5ac8b9b5f491e579fef4db049c11b3b46074f5f7fe8585c7cf2c84ab94d5
6
+ metadata.gz: a8b12f06259193345becd29a14a1c6397481c41b390daed390cf4ed0bc7016afe0fbcf9ba95a9c3639b37150c98791d3e501cf2490725bfc5cf3c405fdc99f94
7
+ data.tar.gz: 684d9b858ac50e78b40f92a2d1cb8ddaafb99983bbdafc7788d786878af5b03c2187995bbe312de59495c9e4f796c352a9e203428d91018075a88791a79320eb
data/README.md CHANGED
@@ -20,20 +20,26 @@ If bundler is not being used to manage dependencies, install the gem by executin
20
20
  #### `transpile`
21
21
 
22
22
  You can get transpiled ruby script from .rbm file by `ruby_mod_kit transpile` command.
23
+ `transpile` command outputs script to stdout by default. `--output` can change output target.
24
+ `--output=.rb` is a special pattern that means "Output the original script file name with the extension changed to .rb".
23
25
 
24
- ```
25
- ruby_mod_kit transpile path/to/script.rbm
26
- ```
26
+ These below have the same meaning: "Output ruby script to stdout".
27
+
28
+ $ ruby_mod_kit transpile path/to/script.rbm
29
+ $ ruby_mod_kit transpile --output=- path/to/script.rbm
30
+ $ ruby_mod_kit transpile --output=/dev/stdout path/to/script.rbm
31
+
32
+ These below have the same meaning: "Output ruby script to `path/to/script.rb`".
33
+
34
+ $ ruby_mod_kit transpile path/to/script.rbm > path/to/script.rb
35
+ $ ruby_mod_kit transpile --output=path/to/script.rb path/to/script.rbm
36
+ $ ruby_mod_kit transpile --output=.rb path/to/script.rbm
27
37
 
28
38
  #### `exec`
29
39
 
30
40
  You can run transpiled ruby script by `ruby_mod_kit exec` command.
31
41
 
32
- ```
33
- ruby_mod_kit transpile path/to/script.rbm
34
- ```
35
-
36
- The command also creates/updates ruby script before running.
42
+ $ ruby_mod_kit exec path/to/script.rbm
37
43
 
38
44
  ## Feature
39
45
 
@@ -16,11 +16,20 @@ module RubyModKit
16
16
  end
17
17
 
18
18
  desc "transpile", "transpile rbm files"
19
+ method_option :output, type: :string
19
20
  # @rbs *args: String
20
21
  # @rbs return: void
21
22
  def transpile(*args)
23
+ output = case options[:output]
24
+ when nil, "-", "/dev/stdout"
25
+ $stdout
26
+ when ".rb"
27
+ nil
28
+ else
29
+ options[:output]
30
+ end
22
31
  args.each do |path|
23
- RubyModKit.transpile_file(path)
32
+ RubyModKit.transpile_file(path, output: output || RubyModKit.rb_path(path))
24
33
  end
25
34
  end
26
35
  end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ # rbs_inline: enabled
4
+
5
+ require "ruby_mod_kit"
6
+
7
+ # Define RubyMotKit.eval
8
+ module RubyModKit
9
+ module CoreExt
10
+ # the extension for eval
11
+ module Eval
12
+ module_function
13
+
14
+ # @rbs expr: String
15
+ # @rbs *rest: Object
16
+ # @rbs transpile: bool
17
+ # @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
23
+
24
+ case rest
25
+ in [] | [Binding] | [Binding, String] | [Binding, String, Integer]
26
+ super(expr, *rest)
27
+ end
28
+ end
29
+ end
30
+ end
31
+
32
+ class << self
33
+ include(CoreExt::Eval)
34
+ public :eval
35
+ end
36
+ end
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ # rbs_inline: enabled
4
+
5
+ require "ruby_mod_kit"
6
+ require_relative "eval"
7
+
8
+ # Define RubyMotKit.load/require
9
+ module RubyModKit
10
+ module CoreExt
11
+ # the extension for load/require
12
+ module Load
13
+ LOADABLE_EXTS = %w[.rb .rbm .so .o .dll].freeze #: Array[String]
14
+
15
+ module_function
16
+
17
+ # @rbs path: String
18
+ # @rbs wrap: bool
19
+ # @rbs return: bool
20
+ def load(path, wrap = false) # rubocop:disable Style/OptionalBooleanParameter
21
+ return super unless path.end_with?(".rbm")
22
+
23
+ b = wrap ? binding : TOPLEVEL_BINDING
24
+ RubyModKit::CoreExt::Eval.eval(File.read(path), b, path)
25
+ true
26
+ end
27
+
28
+ # @rbs path: String
29
+ # @rbs return: bool
30
+ def require(path)
31
+ require_path = Load.require_path(path)
32
+ return super unless require_path&.end_with?(".rbm")
33
+ return false if Load.loaded_features.include?(require_path)
34
+
35
+ Load.loaded_features << require_path
36
+ load(require_path)
37
+ true
38
+ end
39
+
40
+ class << self
41
+ # @rbs return: Array[String]
42
+ def loaded_features
43
+ $LOADED_FEATURES
44
+ end
45
+
46
+ # @rbs return: Array[String]
47
+ def load_path
48
+ $LOAD_PATH
49
+ end
50
+
51
+ # @rbs path: String
52
+ # @rbs expanded: bool
53
+ # @rbs return: String | nil
54
+ def require_path(path, expanded: false)
55
+ if !expanded && !File.absolute_path?(path)
56
+ return load_path.each.lazy.map { require_path(File.join(_1, path), expanded: true) }.find(&:itself)
57
+ end
58
+
59
+ pathes = if path.end_with?(*LOADABLE_EXTS)
60
+ [path]
61
+ else
62
+ LOADABLE_EXTS.map { "#{path}#{_1}" }
63
+ end
64
+ pathes.find { File.exist?(_1) }
65
+ end
66
+ end
67
+ end
68
+ end
69
+
70
+ class << self
71
+ include(CoreExt::Load)
72
+ public :load, :require, :require_relative
73
+ end
74
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "core_ext/eval"
4
+ require_relative "core_ext/load"
5
+
6
+ Object.prepend(RubyModKit::CoreExt::Eval)
7
+ Object.prepend(RubyModKit::CoreExt::Load)
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ # rbs_inline: enabled
4
+
5
+ module RubyModKit
6
+ # the base class of corrector
7
+ class Corrector
8
+ # @rbs return: Array[Symbol]
9
+ def correctable_error_types
10
+ []
11
+ end
12
+
13
+ # @rbs _parse_error: Prism::ParseError
14
+ # @rbs _generation: Generation
15
+ # @rbs _root_node: Node::ProgramNode
16
+ # @rbs _memo_pad: MemoPad
17
+ # @rbs return: void
18
+ def correct(_parse_error, _generation, _root_node, _memo_pad)
19
+ raise RubyModKit::Error, "Unexpected type #{self.class}"
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ # rbs_inline: enabled
4
+
5
+ module RubyModKit
6
+ # the class to manege parse error correctors
7
+ class CorrectorManager
8
+ # @rbs @previous_error_messages: Array[String]
9
+ # @rbs @correctors_error_map: Hash[Symbol, Array[Corrector]]
10
+
11
+ # @rbs features: Array[Feature]
12
+ # @rbs return: void
13
+ def initialize(features)
14
+ @previous_error_messages = []
15
+ @correctors_error_map = {}
16
+ features.each do |feature|
17
+ feature.create_correctors.each do |corrector|
18
+ corrector.correctable_error_types.each do |error_type|
19
+ (@correctors_error_map[error_type] ||= []) << corrector
20
+ end
21
+ end
22
+ end
23
+ end
24
+
25
+ # @rbs generation: Generation
26
+ # @rbs root_node: Node::ProgramNode
27
+ # @rbs parse_result: Prism::ParseResult
28
+ # @rbs memo_pad: MemoPad
29
+ # @rbs return: bool
30
+ def perform(generation, root_node, parse_result, memo_pad)
31
+ return true if parse_result.errors.empty?
32
+
33
+ check_prev_errors(generation, parse_result)
34
+ @previous_error_messages = parse_result.errors.map(&:message)
35
+
36
+ parse_result.errors.each do |parse_error|
37
+ correctors = @correctors_error_map[parse_error.type] || next
38
+ correctors.each do |corrector|
39
+ corrector.correct(parse_error, generation, root_node, memo_pad)
40
+ end
41
+ end
42
+
43
+ false
44
+ end
45
+
46
+ # @rbs generation: Generation
47
+ # @rbs parse_result: Prism::ParseResult
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)
53
+
54
+ message = +""
55
+ parse_result.errors.each do |parse_error|
56
+ message << "\n" unless message.empty?
57
+ message << "#{generation.name}:#{parse_error.location.start_line}:#{parse_error.message} "
58
+ message << "(#{parse_error.type})"
59
+ line = parse_result.source.lines[parse_error.location.start_line - 1]
60
+ if line
61
+ message << "\n#{line.chomp}\n"
62
+ message << "#{" " * parse_error.location.start_column}^#{"~" * [parse_error.location.length - 1, 0].max}"
63
+ end
64
+ end
65
+ raise RubyModKit::SyntaxError, message
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ # rbs_inline: enabled
4
+
5
+ module RubyModKit
6
+ class Feature
7
+ class InstanceVariableParameter
8
+ # the class to correct `def foo(@bar) ...` -> `def foo(bar) ...`
9
+ class InstanceVariableParameterCorrector < Corrector
10
+ # @rbs return: Array[Symbol]
11
+ def correctable_error_types
12
+ %i[argument_formal_ivar]
13
+ end
14
+
15
+ # @rbs parse_error: Prism::ParseError
16
+ # @rbs generation: Generation
17
+ # @rbs root_node: Node::ProgramNode
18
+ # @rbs memo_pad: MemoPad
19
+ # @rbs return: void
20
+ def correct(parse_error, generation, root_node, memo_pad)
21
+ src_offset = parse_error.location.start_offset
22
+
23
+ name = parse_error.location.slice[1..]
24
+ raise RubyModKit::Error unless name
25
+
26
+ parameter_position_node = root_node.node_at(src_offset)
27
+ raise RubyModKit::Error unless parameter_position_node
28
+
29
+ generation[src_offset, parse_error.location.length] = name
30
+ parameter_memo = memo_pad.parameter_memo(parameter_position_node)
31
+ parameter_memo.ivar_parameter = true
32
+
33
+ return unless parameter_memo.untyped?
34
+
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
37
+ parameter_memo.type = ivar_memo_type
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ # rbs_inline: enabled
4
+
5
+ module RubyModKit
6
+ class Feature
7
+ class InstanceVariableParameter
8
+ # The mission for instance variable arguments
9
+ class InstanceVariableParameterMission < Mission
10
+ # @rbs @assignment: String
11
+
12
+ attr_reader :assignment #: String
13
+
14
+ # @rbs generation: Generation
15
+ # @rbs root_node: Node::ProgramNode
16
+ # @rbs _parse_result: Prism::ParseResult
17
+ # @rbs memo_pad: MemoPad
18
+ # @rbs return: bool
19
+ def perform(generation, root_node, _parse_result, memo_pad)
20
+ memo_pad.parameters_memo.each_value do |parameter_memo|
21
+ next unless parameter_memo.ivar_parameter
22
+
23
+ offset = parameter_memo.offset
24
+ parameter_node = root_node.parameter_node_at(offset)
25
+ raise RubyModKit::Error unless parameter_node
26
+
27
+ def_node = root_node.def_node_at(offset)
28
+ raise RubyModKit::Error, "DefNode not found" unless def_node
29
+
30
+ def_body_location = def_node.body_location
31
+ end_loc = def_node.end_keyword_loc
32
+ if def_body_location
33
+ indent = def_body_location.start_column
34
+ src_offset = def_body_location.start_offset - indent
35
+ elsif end_loc
36
+ indent = end_loc.start_column + 2
37
+ src_offset = end_loc.start_offset - indent + 2
38
+ end
39
+ raise RubyModKit::Error if !src_offset || !indent
40
+
41
+ name = parameter_node.name
42
+ generation[src_offset, 0] = "#{" " * indent}@#{name} = #{name}\n"
43
+ end
44
+ true
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ # rbs_inline: enabled
4
+
5
+ module RubyModKit
6
+ class Feature
7
+ # namespace for instance_variable parameter feature
8
+ class InstanceVariableParameter < Feature
9
+ # @rbs return: Array[Corrector]
10
+ def create_correctors
11
+ [
12
+ InstanceVariableParameterCorrector.new,
13
+ ]
14
+ end
15
+
16
+ # @rbs return: Array[Mission]
17
+ def create_missions
18
+ [
19
+ InstanceVariableParameterMission.new,
20
+ ]
21
+ end
22
+ end
23
+ end
24
+ end
25
+
26
+ require_relative "instance_variable_parameter/instance_variable_parameter_corrector"
27
+ require_relative "instance_variable_parameter/instance_variable_parameter_mission"
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ # rbs_inline: enabled
4
+
5
+ module RubyModKit
6
+ class Feature
7
+ class Overload
8
+ # The mission for overload
9
+ class OverloadMission < Mission
10
+ # @rbs @modified: bool
11
+
12
+ OVERLOAD_METHOD_MAP = {
13
+ "*": "_mul",
14
+ }.freeze #: Hash[Symbol, String]
15
+
16
+ # @rbs return: void
17
+ def initialize
18
+ super
19
+ @modified = false
20
+ end
21
+
22
+ # @rbs generation: Generation
23
+ # @rbs root_node: Node::ProgramNode
24
+ # @rbs parse_result: Prism::ParseResult
25
+ # @rbs memo_pad: MemoPad
26
+ # @rbs return: bool
27
+ def perform(generation, root_node, parse_result, memo_pad)
28
+ return true if @modified
29
+
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]
32
+ end
33
+ method_memo_groups.each_value do |method_memos|
34
+ next if method_memos.length <= 1
35
+
36
+ @modified = true
37
+ first_method_memo = method_memos.first
38
+ name = first_method_memo.name
39
+ first_def_node = root_node.def_node_at(first_method_memo.offset)
40
+ raise RubyModKit::Error unless first_def_node.is_a?(Node::DefNode)
41
+ raise RubyModKit::Error unless name.is_a?(Symbol)
42
+
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]
46
+ script = +""
47
+
48
+ overload_memo = memo_pad.overload_memo(first_method_memo.offset, name)
49
+
50
+ method_memos.each do |method_memo|
51
+ type = method_memo.type
52
+ type = "(#{type})" if type.include?(" ")
53
+ overload_memo.add_overload_type(method_memo.parameters.map(&:type), type)
54
+ end
55
+
56
+ script << "def #{name}(*args)\n case args\n"
57
+ overload_prefix = +"#{OVERLOAD_METHOD_MAP[name] || name}_"
58
+ method_memos.each_with_index do |method_memo, i|
59
+ overload_name = "#{overload_prefix}_overload#{i}"
60
+ def_node = root_node.def_node_at(method_memo.offset)
61
+ raise RubyModKit::Error if !def_node || !def_node.is_a?(Node::DefNode)
62
+
63
+ name_loc = def_node.name_loc
64
+ generation[name_loc.start_offset, name_loc.length] = overload_name
65
+ script << " in [#{method_memo.parameters.map(&:type).join(", ")}]\n"
66
+ script << " #{overload_name}(*args)\n"
67
+ end
68
+ script << " end\nend\n\n"
69
+
70
+ script.gsub!(/^(?=.)/, indent)
71
+ generation[src_offset, 0] = script
72
+ end
73
+
74
+ # if script has been changed, request reparsing before proceeding to the next mission
75
+ !@modified
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ # rbs_inline: enabled
4
+
5
+ module RubyModKit
6
+ class Feature
7
+ # namespace for overload feature
8
+ class Overload < Feature
9
+ # @rbs return: Array[Mission]
10
+ def create_missions
11
+ [
12
+ OverloadMission.new,
13
+ ]
14
+ end
15
+ end
16
+ end
17
+ end
18
+
19
+ require_relative "overload/overload_mission"
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ # rbs_inline: enabled
4
+
5
+ module RubyModKit
6
+ class Feature
7
+ class Type
8
+ # the class to correct `@var: Type` -> `# @rbs @var: Type`
9
+ class InstanceVariableColonCorrector < Corrector
10
+ # @rbs return: Array[Symbol]
11
+ def correctable_error_types
12
+ %i[unexpected_token_ignore]
13
+ end
14
+
15
+ # @rbs parse_error: Prism::ParseError
16
+ # @rbs generation: Generation
17
+ # @rbs root_node: Node::ProgramNode
18
+ # @rbs memo_pad: MemoPad
19
+ # @rbs return: void
20
+ def correct(parse_error, generation, root_node, memo_pad)
21
+ return if parse_error.location.slice != ":"
22
+
23
+ def_parent_node = root_node.statements_node_at(parse_error.location.start_offset)&.parent
24
+ return unless def_parent_node.is_a?(Node::DefParentNode)
25
+
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/
30
+
31
+ length = ::Regexp.last_match(0)&.length
32
+ 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)
36
+ return if !length || !indent || !ivar_name || !type
37
+
38
+ ivar_memo = memo_pad.def_parent_memo(def_parent_node).ivar_memo(ivar_name.to_sym)
39
+ ivar_memo.type = type
40
+ ivar_memo.offset = line_offset
41
+ ivar_memo.indent = indent
42
+ ivar_memo.attr_kind = attr_kind if attr_kind
43
+
44
+ generation[line_offset, length] = ""
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+
3
+ # rbs_inline: enabled
4
+
5
+ module RubyModKit
6
+ class Feature
7
+ class Type
8
+ # the class to correct `def foo(Bar => bar, *Buz => buz)` -> `def foo(bar, *buz)`
9
+ class ParameterArrowCorrector < Corrector
10
+ # @rbs return: Array[Symbol]
11
+ def correctable_error_types
12
+ %i[unexpected_token_ignore def_params_term_paren argument_formal_constant]
13
+ end
14
+
15
+ # @rbs parse_error: Prism::ParseError
16
+ # @rbs generation: Generation
17
+ # @rbs root_node: Node::ProgramNode
18
+ # @rbs memo_pad: MemoPad
19
+ # @rbs return: void
20
+ def correct(parse_error, generation, root_node, memo_pad)
21
+ case parse_error.type
22
+ when :unexpected_token_ignore
23
+ return if parse_error.location.slice != "=>"
24
+
25
+ remove_arrow_before_parameter(parse_error, generation, root_node, memo_pad)
26
+ when :def_params_term_paren
27
+ remove_arrow_after_quailifier(parse_error, generation, root_node, memo_pad)
28
+ when :argument_formal_constant
29
+ wrap_parameter_type_for_next_parse(parse_error, generation)
30
+ end
31
+ end
32
+
33
+ # @rbs parse_error: Prism::ParseError
34
+ # @rbs generation: Generation
35
+ # @rbs root_node: Node::ProgramNode
36
+ # @rbs memo_pad: MemoPad
37
+ # @rbs return: void
38
+ def remove_arrow_before_parameter(parse_error, generation, root_node, memo_pad)
39
+ def_node = root_node.def_node_at(parse_error.location.start_offset) || return
40
+ def_parent_node = def_node.parent
41
+ parameters_node, body_node, = def_node.children
42
+ return if !def_parent_node || !parameters_node || !body_node
43
+
44
+ last_parameter_node = parameters_node.children.max_by(&:offset) || return
45
+ last_parameter_offset = last_parameter_node.offset
46
+
47
+ right_node = body_node.children.find { _1.offset >= parse_error.location.end_offset } || return
48
+ right_offset = right_node.offset
49
+ parameter_type = generation[last_parameter_offset...right_offset] || raise(RubyModKit::Error)
50
+ parameter_type = parameter_type.sub(/\s*=>\s*\z/, "")
51
+ generation[last_parameter_offset, right_offset - last_parameter_offset] = ""
52
+ memo_pad.parameter_memo(last_parameter_node).type = parameter_type
53
+ end
54
+
55
+ # @rbs parse_error: Prism::ParseError
56
+ # @rbs generation: Generation
57
+ # @rbs root_node: Node::ProgramNode
58
+ # @rbs memo_pad: MemoPad
59
+ # @rbs return: void
60
+ def remove_arrow_after_quailifier(parse_error, generation, root_node, memo_pad)
61
+ column = parse_error.location.start_column - 1
62
+ return if column < 0
63
+
64
+ line = generation.line(parse_error)[column..] || return
65
+ line =~ /\A\*(.*?)\s*=>\s*/
66
+ length = ::Regexp.last_match(0)&.length || return
67
+ type = ::Regexp.last_match(1) || return
68
+ offset = parse_error.location.start_offset - 1
69
+ parameter_position_node = root_node.node_at(offset + length) || return
70
+
71
+ generation[parse_error.location.start_offset, length - 1] = ""
72
+ parameter_memo = memo_pad.parameter_memo(parameter_position_node)
73
+ parameter_memo.type = type
74
+ parameter_memo.qualifier = "*"
75
+ end
76
+
77
+ # @rbs parse_error: Prism::ParseError
78
+ # @rbs generation: Generation
79
+ # @rbs return: void
80
+ def wrap_parameter_type_for_next_parse(parse_error, generation)
81
+ line = generation.line(parse_error)
82
+ line = line[parse_error.location.start_column..] || return
83
+ parameter_type = line[/(\A[A-Z]\w*(?:::[A-Z]\w*)+)(?:\s*=>\s*)/, 1] || return
84
+ src_offset = parse_error.location.start_offset
85
+ generation[src_offset, parameter_type.length] = "(#{parameter_type})"
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ # rbs_inline: enabled
4
+
5
+ module RubyModKit
6
+ class Feature
7
+ class Type
8
+ class RbsInline
9
+ # The mission for parameter types
10
+ class TypeAttrMission < Mission
11
+ # @rbs generation: Generation
12
+ # @rbs root_node: Node::ProgramNode
13
+ # @rbs _parse_result: Prism::ParseResult
14
+ # @rbs memo_pad: MemoPad
15
+ # @rbs return: bool
16
+ def perform(generation, root_node, _parse_result, memo_pad)
17
+ memo_pad.def_parents_memo.each_value do |def_parent_memo|
18
+ ivars_memo = def_parent_memo.ivars_memo.dup
19
+ def_parent_node = root_node.def_parent_node_at(def_parent_memo.offset) || raise(RubyModKit::Error)
20
+ def_parent_node.body_node&.children&.each do |call_node|
21
+ break if ivars_memo.empty?
22
+ next unless call_node.is_a?(Node::CallNode)
23
+ next unless %i[attr_reader attr_writer attr_accessor].include?(call_node.name)
24
+
25
+ argument_nodes = call_node.children[0].children
26
+ next if argument_nodes.size != 1 || !argument_nodes[0].is_a?(Node::SymbolNode)
27
+
28
+ name = argument_nodes[0].value || next
29
+ ivar_memo = ivars_memo.delete(name) || next
30
+ line = generation.line(call_node)
31
+ length = line[/\A\s*(#{call_node.name}\s+:#{name})(?=\n\z)/, 1]&.length || next
32
+ generation[call_node.location.start_offset + length, 0] = " #: #{ivar_memo.type}"
33
+ end
34
+ end
35
+ true
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end