rucoa 0.11.0 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +12 -3
  3. data/Gemfile.lock +3 -3
  4. data/README.md +6 -1
  5. data/images/document-highlight.gif +0 -0
  6. data/lib/rucoa/configuration.rb +22 -12
  7. data/lib/rucoa/definition_store.rb +131 -131
  8. data/lib/rucoa/definitions/method_definition.rb +11 -11
  9. data/lib/rucoa/handler_concerns/configuration_requestable.rb +7 -7
  10. data/lib/rucoa/handler_concerns/diagnostics_publishable.rb +11 -11
  11. data/lib/rucoa/handler_concerns/text_document_position_parameters.rb +29 -0
  12. data/lib/rucoa/handler_concerns/text_document_uri_parameters.rb +21 -0
  13. data/lib/rucoa/handler_concerns.rb +2 -0
  14. data/lib/rucoa/handlers/base.rb +9 -9
  15. data/lib/rucoa/handlers/initialize_handler.rb +1 -0
  16. data/lib/rucoa/handlers/initialized_handler.rb +16 -16
  17. data/lib/rucoa/handlers/text_document_code_action_handler.rb +12 -12
  18. data/lib/rucoa/handlers/text_document_completion_handler.rb +85 -99
  19. data/lib/rucoa/handlers/text_document_definition_handler.rb +11 -30
  20. data/lib/rucoa/handlers/text_document_did_close_handler.rb +2 -8
  21. data/lib/rucoa/handlers/text_document_did_open_handler.rb +3 -7
  22. data/lib/rucoa/handlers/text_document_document_highlight_handler.rb +531 -0
  23. data/lib/rucoa/handlers/text_document_document_symbol_handler.rb +47 -76
  24. data/lib/rucoa/handlers/text_document_formatting_handler.rb +16 -24
  25. data/lib/rucoa/handlers/text_document_hover_handler.rb +24 -43
  26. data/lib/rucoa/handlers/text_document_range_formatting_handler.rb +17 -25
  27. data/lib/rucoa/handlers/text_document_selection_range_handler.rb +11 -19
  28. data/lib/rucoa/handlers/text_document_signature_help_handler.rb +17 -36
  29. data/lib/rucoa/handlers.rb +1 -0
  30. data/lib/rucoa/node_concerns/body.rb +1 -1
  31. data/lib/rucoa/node_concerns/modifier.rb +35 -0
  32. data/lib/rucoa/node_concerns/qualified_name.rb +5 -5
  33. data/lib/rucoa/node_concerns/rescue.rb +21 -0
  34. data/lib/rucoa/node_concerns/variable.rb +26 -0
  35. data/lib/rucoa/node_concerns.rb +3 -0
  36. data/lib/rucoa/node_inspector.rb +5 -5
  37. data/lib/rucoa/nodes/arg_node.rb +26 -0
  38. data/lib/rucoa/nodes/args_node.rb +14 -0
  39. data/lib/rucoa/nodes/base.rb +111 -47
  40. data/lib/rucoa/nodes/begin_node.rb +2 -0
  41. data/lib/rucoa/nodes/block_node.rb +38 -0
  42. data/lib/rucoa/nodes/case_node.rb +24 -0
  43. data/lib/rucoa/nodes/const_node.rb +26 -26
  44. data/lib/rucoa/nodes/cvar_node.rb +9 -0
  45. data/lib/rucoa/nodes/cvasgn_node.rb +9 -0
  46. data/lib/rucoa/nodes/def_node.rb +28 -13
  47. data/lib/rucoa/nodes/ensure_node.rb +19 -0
  48. data/lib/rucoa/nodes/for_node.rb +8 -0
  49. data/lib/rucoa/nodes/gvar_node.rb +9 -0
  50. data/lib/rucoa/nodes/gvasgn_node.rb +9 -0
  51. data/lib/rucoa/nodes/if_node.rb +34 -0
  52. data/lib/rucoa/nodes/ivar_node.rb +9 -0
  53. data/lib/rucoa/nodes/ivasgn_node.rb +9 -0
  54. data/lib/rucoa/nodes/lvar_node.rb +1 -18
  55. data/lib/rucoa/nodes/lvasgn_node.rb +9 -0
  56. data/lib/rucoa/nodes/resbody_node.rb +8 -0
  57. data/lib/rucoa/nodes/rescue_node.rb +17 -0
  58. data/lib/rucoa/nodes/send_node.rb +40 -0
  59. data/lib/rucoa/nodes/until_node.rb +9 -0
  60. data/lib/rucoa/nodes/when_node.rb +8 -0
  61. data/lib/rucoa/nodes/while_node.rb +9 -0
  62. data/lib/rucoa/nodes.rb +19 -1
  63. data/lib/rucoa/parser_builder.rb +26 -2
  64. data/lib/rucoa/range.rb +9 -3
  65. data/lib/rucoa/rbs/constant_definition_mapper.rb +5 -5
  66. data/lib/rucoa/rbs/method_definition_mapper.rb +18 -18
  67. data/lib/rucoa/rbs/module_definition_mapper.rb +13 -13
  68. data/lib/rucoa/rbs/ruby_definitions_loader.rb +5 -5
  69. data/lib/rucoa/rubocop/configuration_checker.rb +7 -7
  70. data/lib/rucoa/server.rb +24 -23
  71. data/lib/rucoa/source.rb +6 -6
  72. data/lib/rucoa/source_store.rb +8 -8
  73. data/lib/rucoa/version.rb +1 -1
  74. data/lib/rucoa/yard/definition_generators/method_definition_generator.rb +1 -1
  75. data/lib/rucoa/yard/definitions_loader.rb +1 -1
  76. data/rucoa.gemspec +0 -1
  77. metadata +28 -4
  78. data/lib/rucoa/nodes/defs_node.rb +0 -33
@@ -14,24 +14,19 @@ module Rucoa
14
14
  end
15
15
  end
16
16
 
17
- # @return [Rucoa::Nodes::Base, nil]
18
- def parent
19
- @mutable_attributes[:parent]
20
- end
21
-
22
- # @param node [Rucoa::Nodes::Base]
23
- def parent=(node)
24
- @mutable_attributes[:parent] = node
25
- end
26
-
27
17
  # @return [Array<Rucoa::Nodes::Base>]
28
18
  def ancestors
29
19
  each_ancestor.to_a
30
20
  end
31
21
 
32
22
  # @return [Array<Rucoa::Nodes::Base>]
33
- def descendants
34
- each_descendant.to_a
23
+ def child_nodes
24
+ each_child_node.to_a
25
+ end
26
+
27
+ # @return [Array<Rucoa::Nodes::Base>]
28
+ def descendant_nodes
29
+ each_descendant_node.to_a
35
30
  end
36
31
 
37
32
  # @param types [Array<Symbol>]
@@ -63,33 +58,16 @@ module Rucoa
63
58
  # @param types [Array<Symbol>]
64
59
  # @return [Rucoa::Nodes::Base] if a block is given
65
60
  # @return [Enumerator] if no block is given
66
- def each_descendant(
61
+ def each_descendant_node(
67
62
  *types,
68
63
  &block
69
64
  )
70
65
  return to_enum(__method__, *types) unless block
71
66
 
72
- visit_descendants(types, &block)
67
+ visit_descendant_nodes(types, &block)
73
68
  self
74
69
  end
75
70
 
76
- # @note Override.
77
- # Some nodes change their type depending on the context.
78
- # For example, `const` node can be `casgn` node.
79
- # @return [Rucoa::Nodes::Base]
80
- def updated(
81
- type = nil,
82
- children = nil,
83
- properties = {}
84
- )
85
- properties[:location] ||= @location
86
- ParserBuilder.node_class_for(type || @type).new(
87
- type || @type,
88
- children || @children,
89
- properties
90
- )
91
- end
92
-
93
71
  # @param position [Rucoa::Position]
94
72
  # @return [Boolean]
95
73
  def include_position?(position)
@@ -98,6 +76,29 @@ module Rucoa
98
76
  Range.from_parser_range(location.expression).include?(position)
99
77
  end
100
78
 
79
+ # @return [Array<String>]
80
+ # @example return ["Bar::Foo", "Foo"] for class Foo::Bar::Baz
81
+ # node = Rucoa::Source.new(
82
+ # content: <<~RUBY,
83
+ # module Foo
84
+ # module Bar
85
+ # module Baz
86
+ # end
87
+ # end
88
+ # end
89
+ # RUBY
90
+ # uri: 'file:///path/to/foo/bar/baz.rb'
91
+ # ).node_at(
92
+ # Rucoa::Position.new(
93
+ # column: 4,
94
+ # line: 3
95
+ # )
96
+ # )
97
+ # expect(node.module_nesting).to eq(['Foo::Bar', 'Foo'])
98
+ def module_nesting
99
+ each_ancestor(:class, :module).map(&:qualified_name)
100
+ end
101
+
101
102
  # @note namespace is a String representation of `Module.nesting`.
102
103
  # @return [String]
103
104
  # @example returns namespace
@@ -130,46 +131,109 @@ module Rucoa
130
131
  module_nesting.first || 'Object'
131
132
  end
132
133
 
133
- # @return [Array<String>]
134
- # @example return ["Bar::Foo", "Foo"] for class Foo::Bar::Baz
134
+ # @return [Array<Rucoa::Nodes::Base>]
135
+ # @example returns next siblings
135
136
  # node = Rucoa::Source.new(
136
137
  # content: <<~RUBY,
137
- # module Foo
138
- # module Bar
139
- # module Baz
140
- # end
141
- # end
138
+ # def foo
139
+ # a
140
+ # b
141
+ # c
142
+ # d
143
+ # e
142
144
  # end
143
145
  # RUBY
144
- # uri: 'file:///path/to/foo/bar/baz.rb'
146
+ # uri: 'file:///path/to/example.rb'
145
147
  # ).node_at(
146
148
  # Rucoa::Position.new(
147
- # column: 4,
148
- # line: 3
149
+ # column: 2,
150
+ # line: 4
149
151
  # )
150
152
  # )
151
- # expect(node.module_nesting).to eq(['Foo::Bar', 'Foo'])
152
- def module_nesting
153
- each_ancestor(:class, :module).map(&:qualified_name)
153
+ # expect(node.next_sibling_nodes.map(&:name)).to eq(%w[d e])
154
+ def next_sibling_nodes
155
+ return [] unless parent
156
+
157
+ parent.child_nodes[(sibling_node_index + 1)..]
158
+ end
159
+
160
+ # @return [Rucoa::Nodes::Base, nil]
161
+ def parent
162
+ @mutable_attributes[:parent]
163
+ end
164
+
165
+ # @param node [Rucoa::Nodes::Base]
166
+ def parent=(node)
167
+ @mutable_attributes[:parent] = node
168
+ end
169
+
170
+ # @return [Array<Rucoa::Nodes::Base>]
171
+ # @example returns previous siblings
172
+ # node = Rucoa::Source.new(
173
+ # content: <<~RUBY,
174
+ # def foo
175
+ # a
176
+ # b
177
+ # c
178
+ # d
179
+ # e
180
+ # end
181
+ # RUBY
182
+ # uri: 'file:///path/to/example.rb'
183
+ # ).node_at(
184
+ # Rucoa::Position.new(
185
+ # column: 2,
186
+ # line: 4
187
+ # )
188
+ # )
189
+ # expect(node.previous_sibling_nodes.map(&:name)).to eq(%w[a b])
190
+ def previous_sibling_nodes
191
+ return [] unless parent
192
+
193
+ parent.child_nodes[0...sibling_node_index]
194
+ end
195
+
196
+ # @note Override.
197
+ # Some nodes change their type depending on the context.
198
+ # For example, `const` node can be `casgn` node.
199
+ # @return [Rucoa::Nodes::Base]
200
+ def updated(
201
+ type = nil,
202
+ children = nil,
203
+ properties = {}
204
+ )
205
+ properties[:location] ||= @location
206
+ ParserBuilder.node_class_for(type || @type).new(
207
+ type || @type,
208
+ children || @children,
209
+ properties
210
+ )
154
211
  end
155
212
 
156
213
  protected
157
214
 
158
- # Visit all descendants.
215
+ # Visit all descendant_nodes.
159
216
  # @param types [Array<Symbol>]
160
217
  # @return [void]
161
- def visit_descendants(
218
+ def visit_descendant_nodes(
162
219
  types,
163
220
  &block
164
221
  )
165
222
  each_child_node do |child|
166
223
  yield(child) if types.empty? || types.include?(child.type)
167
- child.visit_descendants(types, &block)
224
+ child.visit_descendant_nodes(types, &block)
168
225
  end
169
226
  end
170
227
 
171
228
  private
172
229
 
230
+ # @return [Integer, nil]
231
+ def sibling_node_index
232
+ parent&.child_nodes&.index do |child|
233
+ child.equal?(self)
234
+ end
235
+ end
236
+
173
237
  # Visits all ancestors.
174
238
  # @param types [Array<Symbol>]
175
239
  # @return [void]
@@ -3,6 +3,8 @@
3
3
  module Rucoa
4
4
  module Nodes
5
5
  class BeginNode < Base
6
+ include NodeConcerns::Body
7
+ include NodeConcerns::Rescue
6
8
  end
7
9
  end
8
10
  end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rucoa
4
+ module Nodes
5
+ class BlockNode < Base
6
+ include NodeConcerns::Body
7
+ include NodeConcerns::Rescue
8
+
9
+ # @return [Array<Rucoa::Nodes::ArgNode>]
10
+ # @example returns arguments
11
+ # node = Rucoa::Source.new(
12
+ # content: <<~RUBY,
13
+ # foo do |bar, baz|
14
+ # end
15
+ # RUBY
16
+ # uri: 'file:///path/to/example.rb'
17
+ # ).root_node
18
+ # expect(node.arguments.map(&:name)).to eq(%w[bar baz])
19
+ def arguments
20
+ children[-2]
21
+ end
22
+
23
+ # @return [Rucoa::Nodes::SendNode]
24
+ # @example returns send node
25
+ # node = Rucoa::Source.new(
26
+ # content: <<~RUBY,
27
+ # foo do
28
+ # end
29
+ # RUBY
30
+ # uri: 'file:///foo.rb'
31
+ # ).root_node
32
+ # expect(node.send_node.name).to eq('foo')
33
+ def send_node
34
+ children[0]
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rucoa
4
+ module Nodes
5
+ class CaseNode < Base
6
+ # @return [Array<Rucoa::Nodes::Base>]
7
+ # @example returns when nodes
8
+ # node = Rucoa::Source.new(
9
+ # content: <<~RUBY,
10
+ # case foo
11
+ # when 1
12
+ # when 2
13
+ # else
14
+ # end
15
+ # RUBY
16
+ # uri: 'file:///foo.rb'
17
+ # ).root_node
18
+ # expect(node.whens.length).to eq(2)
19
+ def whens
20
+ children[1...-1]
21
+ end
22
+ end
23
+ end
24
+ end
@@ -3,32 +3,6 @@
3
3
  module Rucoa
4
4
  module Nodes
5
5
  class ConstNode < Base
6
- # @return [String]
7
- # @example returns "A" for "A"
8
- # node = Rucoa::Source.new(
9
- # content: <<~RUBY,
10
- # A
11
- # RUBY
12
- # uri: 'file:///path/to/a.rb'
13
- # ).root_node
14
- # expect(node.name).to eq('A')
15
- # @example returns "B" for "A::B"
16
- # node = Rucoa::Source.new(
17
- # content: <<~RUBY,
18
- # A::B
19
- # RUBY
20
- # uri: 'file:///path/to/a.rb'
21
- # ).node_at(
22
- # Rucoa::Position.new(
23
- # column: 4,
24
- # line: 1
25
- # )
26
- # )
27
- # expect(node.name).to eq('B')
28
- def name
29
- children[1].to_s
30
- end
31
-
32
6
  # @return [String]
33
7
  # @example returns "A" for "A"
34
8
  # node = Rucoa::Source.new(
@@ -91,6 +65,32 @@ module Rucoa
91
65
  each_ancestor(:class, :module).map(&:qualified_name)
92
66
  end
93
67
 
68
+ # @return [String]
69
+ # @example returns "A" for "A"
70
+ # node = Rucoa::Source.new(
71
+ # content: <<~RUBY,
72
+ # A
73
+ # RUBY
74
+ # uri: 'file:///path/to/a.rb'
75
+ # ).root_node
76
+ # expect(node.name).to eq('A')
77
+ # @example returns "B" for "A::B"
78
+ # node = Rucoa::Source.new(
79
+ # content: <<~RUBY,
80
+ # A::B
81
+ # RUBY
82
+ # uri: 'file:///path/to/a.rb'
83
+ # ).node_at(
84
+ # Rucoa::Position.new(
85
+ # column: 4,
86
+ # line: 1
87
+ # )
88
+ # )
89
+ # expect(node.name).to eq('B')
90
+ def name
91
+ children[1].to_s
92
+ end
93
+
94
94
  private
95
95
 
96
96
  # @return [Rucoa::Nodes::Base, nil]
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rucoa
4
+ module Nodes
5
+ class CvarNode < Base
6
+ include NodeConcerns::Variable
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rucoa
4
+ module Nodes
5
+ class CvasgnNode < Base
6
+ include NodeConcerns::Variable
7
+ end
8
+ end
9
+ end
@@ -3,6 +3,32 @@
3
3
  module Rucoa
4
4
  module Nodes
5
5
  class DefNode < Base
6
+ include NodeConcerns::Body
7
+ include NodeConcerns::Rescue
8
+
9
+ # @return [Array<Rucoa::Nodes::ArgNode>]
10
+ # @example returns arguments
11
+ # node = Rucoa::Source.new(
12
+ # content: <<~RUBY,
13
+ # def foo(bar, baz)
14
+ # end
15
+ # RUBY
16
+ # uri: 'file:///path/to/example.rb'
17
+ # ).root_node
18
+ # expect(node.arguments.map(&:name)).to eq(%w[bar baz])
19
+ def arguments
20
+ children[-2]
21
+ end
22
+
23
+ # @return [String]
24
+ def method_marker
25
+ if singleton?
26
+ '.'
27
+ else
28
+ '#'
29
+ end
30
+ end
31
+
6
32
  # @return [String]
7
33
  # @example returns method name
8
34
  # node = Rucoa::Source.new(
@@ -23,7 +49,7 @@ module Rucoa
23
49
  # )
24
50
  # expect(node.name).to eq('baz')
25
51
  def name
26
- children[0].to_s
52
+ children[-3].to_s
27
53
  end
28
54
 
29
55
  # @return [String]
@@ -55,18 +81,7 @@ module Rucoa
55
81
 
56
82
  # @return [Boolean]
57
83
  def singleton?
58
- each_ancestor(:sclass).any?
59
- end
60
-
61
- private
62
-
63
- # @return [String]
64
- def method_marker
65
- if singleton?
66
- '.'
67
- else
68
- '#'
69
- end
84
+ type == :defs || each_ancestor(:sclass).any?
70
85
  end
71
86
  end
72
87
  end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rucoa
4
+ module Nodes
5
+ class EnsureNode < Base
6
+ # @return [Rucoa::Nodes::Base, nil]
7
+ def body
8
+ children[0]
9
+ end
10
+
11
+ # @return [Rucoa::Nodes::RescueNode, nil]
12
+ def rescue
13
+ return unless body.is_a?(Nodes::RescueNode)
14
+
15
+ body
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rucoa
4
+ module Nodes
5
+ class ForNode < Base
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rucoa
4
+ module Nodes
5
+ class GvarNode < Base
6
+ include NodeConcerns::Variable
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rucoa
4
+ module Nodes
5
+ class GvasgnNode < Base
6
+ include NodeConcerns::Variable
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rucoa
4
+ module Nodes
5
+ class IfNode < Base
6
+ include NodeConcerns::Modifier
7
+
8
+ # @return [Rucoa::Nodes::Base, nil]
9
+ def branch_else
10
+ children[2]
11
+ end
12
+
13
+ # @return [Rucoa::Nodes::Base, nil]
14
+ def branch_if
15
+ children[1]
16
+ end
17
+
18
+ # @return [Rucoa::Nodes::Base]
19
+ def condition
20
+ children[0]
21
+ end
22
+
23
+ # @return [Rucoa::Nodes::IfNode, nil]
24
+ def elsif
25
+ branch_else if branch_else.is_a?(Nodes::IfNode)
26
+ end
27
+
28
+ # @return [Boolean]
29
+ def elsif?
30
+ parent.is_a?(Nodes::IfNode) && equal?(parent.elsif)
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rucoa
4
+ module Nodes
5
+ class IvarNode < Base
6
+ include NodeConcerns::Variable
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rucoa
4
+ module Nodes
5
+ class IvasgnNode < Base
6
+ include NodeConcerns::Variable
7
+ end
8
+ end
9
+ end
@@ -3,24 +3,7 @@
3
3
  module Rucoa
4
4
  module Nodes
5
5
  class LvarNode < Base
6
- # @return [String]
7
- # @example returns local variable name
8
- # node = Rucoa::Source.new(
9
- # content: <<~RUBY,
10
- # foo = 1
11
- # foo
12
- # RUBY
13
- # uri: 'file:///path/to/example.rb'
14
- # ).node_at(
15
- # Rucoa::Position.new(
16
- # column: 2,
17
- # line: 2
18
- # )
19
- # )
20
- # expect(node.name).to eq('foo')
21
- def name
22
- children[0].to_s
23
- end
6
+ include NodeConcerns::Variable
24
7
  end
25
8
  end
26
9
  end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rucoa
4
+ module Nodes
5
+ class LvasgnNode < Base
6
+ include NodeConcerns::Variable
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rucoa
4
+ module Nodes
5
+ class ResbodyNode < Base
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rucoa
4
+ module Nodes
5
+ class RescueNode < Base
6
+ # @return [Rucoa::Nodes::Base, nil]
7
+ def body
8
+ children[0]
9
+ end
10
+
11
+ # @return [Array<Rucoa::Nodes::Resbody>]
12
+ def resbodies
13
+ children[1..-2]
14
+ end
15
+ end
16
+ end
17
+ end
@@ -21,6 +21,39 @@ module Rucoa
21
21
  children[2..]
22
22
  end
23
23
 
24
+ # @return [Rucoa::Nodes::BlockNode, nil]
25
+ # @example returns nil for method call without block
26
+ # node = Rucoa::Source.new(
27
+ # content: <<~RUBY,
28
+ # foo
29
+ # RUBY
30
+ # uri: 'file:///path/to/example.rb'
31
+ # ).node_at(
32
+ # Rucoa::Position.new(
33
+ # column: 0,
34
+ # line: 1
35
+ # )
36
+ # )
37
+ # expect(node.block).to be_nil
38
+ # @example returns block
39
+ # node = Rucoa::Source.new(
40
+ # content: <<~RUBY,
41
+ # foo do
42
+ # bar
43
+ # end
44
+ # RUBY
45
+ # uri: 'file:///path/to/example.rb'
46
+ # ).node_at(
47
+ # Rucoa::Position.new(
48
+ # column: 0,
49
+ # line: 1
50
+ # )
51
+ # )
52
+ # expect(node.block).to be_a(Rucoa::Nodes::BlockNode)
53
+ def block
54
+ parent if called_with_block?
55
+ end
56
+
24
57
  # @return [String]
25
58
  # @example returns method name
26
59
  # node = Rucoa::Source.new(
@@ -59,6 +92,13 @@ module Rucoa
59
92
  def receiver
60
93
  children[0]
61
94
  end
95
+
96
+ private
97
+
98
+ # @return [Boolean]
99
+ def called_with_block?
100
+ parent.is_a?(Nodes::BlockNode) && equal?(parent.send_node)
101
+ end
62
102
  end
63
103
  end
64
104
  end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rucoa
4
+ module Nodes
5
+ class UntilNode < Base
6
+ include NodeConcerns::Modifier
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rucoa
4
+ module Nodes
5
+ class WhenNode < Base
6
+ end
7
+ end
8
+ end