rucoa 0.8.0 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +6 -0
  3. data/Gemfile.lock +8 -8
  4. data/data/definitions_ruby_3_1 +0 -0
  5. data/lib/rucoa/configuration.rb +4 -1
  6. data/lib/rucoa/definition_store.rb +268 -75
  7. data/lib/rucoa/definitions/base.rb +14 -3
  8. data/lib/rucoa/definitions/class_definition.rb +20 -4
  9. data/lib/rucoa/definitions/constant_definition.rb +31 -19
  10. data/lib/rucoa/definitions/method_definition.rb +44 -52
  11. data/lib/rucoa/definitions/method_parameter_definition.rb +4 -1
  12. data/lib/rucoa/definitions/module_definition.rb +39 -0
  13. data/lib/rucoa/handler_concerns/diagnostics_publishable.rb +14 -3
  14. data/lib/rucoa/handlers/base.rb +12 -3
  15. data/lib/rucoa/handlers/initialized_handler.rb +33 -5
  16. data/lib/rucoa/handlers/text_document_completion_handler.rb +1 -1
  17. data/lib/rucoa/handlers/text_document_definition_handler.rb +3 -99
  18. data/lib/rucoa/handlers/text_document_did_open_handler.rb +1 -4
  19. data/lib/rucoa/handlers/text_document_hover_handler.rb +21 -13
  20. data/lib/rucoa/handlers/text_document_selection_range_handler.rb +8 -2
  21. data/lib/rucoa/location.rb +37 -0
  22. data/lib/rucoa/node_concerns/body.rb +24 -0
  23. data/lib/rucoa/node_concerns/{name_full_qualifiable.rb → qualified_name.rb} +2 -2
  24. data/lib/rucoa/node_concerns.rb +2 -1
  25. data/lib/rucoa/node_inspector.rb +22 -26
  26. data/lib/rucoa/nodes/base.rb +51 -10
  27. data/lib/rucoa/nodes/begin_node.rb +8 -0
  28. data/lib/rucoa/nodes/casgn_node.rb +1 -1
  29. data/lib/rucoa/nodes/cbase_node.rb +8 -0
  30. data/lib/rucoa/nodes/class_node.rb +63 -1
  31. data/lib/rucoa/nodes/const_node.rb +64 -5
  32. data/lib/rucoa/nodes/def_node.rb +11 -9
  33. data/lib/rucoa/nodes/defs_node.rb +21 -0
  34. data/lib/rucoa/nodes/lvar_node.rb +2 -1
  35. data/lib/rucoa/nodes/module_node.rb +2 -1
  36. data/lib/rucoa/nodes/send_node.rb +14 -10
  37. data/lib/rucoa/nodes.rb +3 -1
  38. data/lib/rucoa/parse_result.rb +29 -0
  39. data/lib/rucoa/parser.rb +40 -8
  40. data/lib/rucoa/parser_builder.rb +7 -1
  41. data/lib/rucoa/position.rb +10 -1
  42. data/lib/rucoa/range.rb +11 -1
  43. data/lib/rucoa/rbs/class_definition_mapper.rb +13 -28
  44. data/lib/rucoa/rbs/constant_definition_mapper.rb +12 -6
  45. data/lib/rucoa/rbs/method_definition_mapper.rb +12 -6
  46. data/lib/rucoa/rbs/module_definition_mapper.rb +34 -6
  47. data/lib/rucoa/rubocop/autocorrector.rb +2 -2
  48. data/lib/rucoa/rubocop/investigator.rb +6 -3
  49. data/lib/rucoa/server.rb +9 -3
  50. data/lib/rucoa/source.rb +57 -27
  51. data/lib/rucoa/source_store.rb +0 -13
  52. data/lib/rucoa/unqualified_name.rb +9 -0
  53. data/lib/rucoa/version.rb +1 -1
  54. data/lib/rucoa/yard/definition_generators/attribute_reader_definition_generator.rb +60 -0
  55. data/lib/rucoa/yard/definition_generators/attribute_writer_definition_generator.rb +60 -0
  56. data/lib/rucoa/yard/definition_generators/base.rb +117 -0
  57. data/lib/rucoa/yard/definition_generators/class_definition_generator.rb +66 -0
  58. data/lib/rucoa/yard/definition_generators/constant_assignment_definition_generator.rb +29 -0
  59. data/lib/rucoa/yard/definition_generators/method_definition_generator.rb +47 -0
  60. data/lib/rucoa/yard/definition_generators/module_definition_generator.rb +62 -0
  61. data/lib/rucoa/yard/definition_generators.rb +15 -0
  62. data/lib/rucoa/yard/definitions_loader.rb +44 -65
  63. data/lib/rucoa/yard/type.rb +46 -0
  64. data/lib/rucoa/yard.rb +2 -1
  65. data/lib/rucoa.rb +4 -1
  66. metadata +18 -4
  67. data/lib/rucoa/yard/method_definition_mapper.rb +0 -215
@@ -4,7 +4,10 @@ module Rucoa
4
4
  class NodeInspector
5
5
  # @param definition_store [Rucoa::DefinitionStore]
6
6
  # @param node [Rucoa::Node]
7
- def initialize(definition_store:, node:)
7
+ def initialize(
8
+ definition_store:,
9
+ node:
10
+ )
8
11
  @definition_store = definition_store
9
12
  @node = node
10
13
  end
@@ -90,22 +93,14 @@ module Rucoa
90
93
  def constant_definition
91
94
  return unless @node.is_a?(Nodes::ConstNode)
92
95
 
93
- module_nesting_full_qualified_names = @node.each_ancestor(:class, :module).map(&:full_qualified_name)
94
- candidate_full_qualified_names = module_nesting_full_qualified_names.flat_map do |module_nesting_full_qualified_name|
95
- [
96
- module_nesting_full_qualified_name
97
- # TODO: *ancestors_of(module_nesting_full_qualified_name)
98
- ].map do |full_qualified_name|
99
- [
100
- full_qualified_name,
101
- @node.chained_name
102
- ].join('::')
103
- end
104
- end + [@node.chained_name]
105
- candidate_full_qualified_names.find do |candidate_full_qualified_name|
106
- definition = @definition_store.select_by_full_qualified_name(candidate_full_qualified_name).first
107
- break definition if definition
108
- end
96
+ @definition_store.find_definition_by_qualified_name(
97
+ @definition_store.resolve_constant(
98
+ UnqualifiedName.new(
99
+ chained_name: @node.chained_name,
100
+ module_nesting: @node.module_nesting
101
+ )
102
+ )
103
+ )
109
104
  end
110
105
 
111
106
  # @return [Boolean]
@@ -114,20 +109,21 @@ module Rucoa
114
109
  end
115
110
 
116
111
  # @return [String, nil]
117
- def nearest_def_full_qualified_name
118
- @node.each_ancestor(:def).first&.full_qualified_name
112
+ def nearest_def_qualified_name
113
+ @node.each_ancestor(:def).first&.qualified_name
119
114
  end
120
115
 
121
116
  # @return [Array<String>]
122
117
  def return_types_for_lvar
123
- full_qualified_name = nearest_def_full_qualified_name
124
- return [] unless full_qualified_name
118
+ qualified_name = nearest_def_qualified_name
119
+ return [] unless qualified_name
125
120
 
126
- @definition_store.select_by_full_qualified_name(full_qualified_name).flat_map do |definition|
127
- definition.parameters.select do |parameter|
128
- parameter.name == @node.name
129
- end.flat_map(&:types)
130
- end
121
+ definition = @definition_store.find_definition_by_qualified_name(qualified_name)
122
+ return [] unless definition
123
+
124
+ definition.parameters.select do |parameter|
125
+ parameter.name == @node.name
126
+ end.flat_map(&:types)
131
127
  end
132
128
 
133
129
  # @return [Array<String>]
@@ -37,7 +37,10 @@ module Rucoa
37
37
  # @param types [Array<Symbol>]
38
38
  # @return [Rucoa::Nodes::Base] if a block is given
39
39
  # @return [Enumerator] if no block is given
40
- def each_ancestor(*types, &block)
40
+ def each_ancestor(
41
+ *types,
42
+ &block
43
+ )
41
44
  return to_enum(__method__, *types) unless block
42
45
 
43
46
  visit_ancestors(types, &block)
@@ -47,7 +50,10 @@ module Rucoa
47
50
  # @param types [Array<Symbol>]
48
51
  # @return [Rucoa::Nodes::Base] if a block is given
49
52
  # @return [Enumerator] if no block is given
50
- def each_child_node(*types, &block)
53
+ def each_child_node(
54
+ *types,
55
+ &block
56
+ )
51
57
  return to_enum(__method__, *types) unless block
52
58
 
53
59
  visit_child_node(types, &block)
@@ -57,7 +63,10 @@ module Rucoa
57
63
  # @param types [Array<Symbol>]
58
64
  # @return [Rucoa::Nodes::Base] if a block is given
59
65
  # @return [Enumerator] if no block is given
60
- def each_descendant(*types, &block)
66
+ def each_descendant(
67
+ *types,
68
+ &block
69
+ )
61
70
  return to_enum(__method__, *types) unless block
62
71
 
63
72
  visit_descendants(types, &block)
@@ -68,7 +77,11 @@ module Rucoa
68
77
  # Some nodes change their type depending on the context.
69
78
  # For example, `const` node can be `casgn` node.
70
79
  # @return [Rucoa::Nodes::Base]
71
- def updated(type = nil, children = nil, properties = {})
80
+ def updated(
81
+ type = nil,
82
+ children = nil,
83
+ properties = {}
84
+ )
72
85
  properties[:location] ||= @location
73
86
  ParserBuilder.node_class_for(type || @type).new(
74
87
  type || @type,
@@ -89,7 +102,7 @@ module Rucoa
89
102
  # @return [String]
90
103
  # @example returns namespace
91
104
  # node = Rucoa::Source.new(
92
- # content: <<~RUBY
105
+ # content: <<~RUBY,
93
106
  # module Foo
94
107
  # class Bar
95
108
  # def baz
@@ -97,6 +110,7 @@ module Rucoa
97
110
  # end
98
111
  # end
99
112
  # RUBY
113
+ # uri: 'file:///path/to/foo/bar.rb'
100
114
  # ).node_at(
101
115
  # Rucoa::Position.new(
102
116
  # column: 4,
@@ -105,14 +119,38 @@ module Rucoa
105
119
  # )
106
120
  # expect(node.namespace).to eq('Foo::Bar')
107
121
  # @example returns "Object" when the node is not in a namespace
108
- # node = Rucoa::Parser.call(
109
- # <<~RUBY
122
+ # node = Rucoa::Source.new(
123
+ # content: <<~RUBY,
110
124
  # foo
111
125
  # RUBY
112
- # )
126
+ # uri: 'file:///path/to/example.rb'
127
+ # ).root_node
113
128
  # expect(node.namespace).to eq('Object')
114
129
  def namespace
115
- each_ancestor(:module, :class).first&.full_qualified_name || 'Object'
130
+ module_nesting.first || 'Object'
131
+ end
132
+
133
+ # @return [Array<String>]
134
+ # @example return ["Bar::Foo", "Foo"] for class Foo::Bar::Baz
135
+ # node = Rucoa::Source.new(
136
+ # content: <<~RUBY,
137
+ # module Foo
138
+ # module Bar
139
+ # module Baz
140
+ # end
141
+ # end
142
+ # end
143
+ # RUBY
144
+ # uri: 'file:///path/to/foo/bar/baz.rb'
145
+ # ).node_at(
146
+ # Rucoa::Position.new(
147
+ # column: 4,
148
+ # line: 3
149
+ # )
150
+ # )
151
+ # expect(node.module_nesting).to eq(['Foo::Bar', 'Foo'])
152
+ def module_nesting
153
+ each_ancestor(:class, :module).map(&:qualified_name)
116
154
  end
117
155
 
118
156
  protected
@@ -120,7 +158,10 @@ module Rucoa
120
158
  # Visit all descendants.
121
159
  # @param types [Array<Symbol>]
122
160
  # @return [void]
123
- def visit_descendants(types, &block)
161
+ def visit_descendants(
162
+ types,
163
+ &block
164
+ )
124
165
  each_child_node do |child|
125
166
  yield(child) if types.empty? || types.include?(child.type)
126
167
  child.visit_descendants(types, &block)
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rucoa
4
+ module Nodes
5
+ class BeginNode < Base
6
+ end
7
+ end
8
+ end
@@ -3,7 +3,7 @@
3
3
  module Rucoa
4
4
  module Nodes
5
5
  class CasgnNode < Base
6
- include NodeConcerns::NameFullQualifiable
6
+ include NodeConcerns::QualifiedName
7
7
 
8
8
  # @return [String]
9
9
  def name
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rucoa
4
+ module Nodes
5
+ class CbaseNode < Base
6
+ end
7
+ end
8
+ end
@@ -2,7 +2,69 @@
2
2
 
3
3
  module Rucoa
4
4
  module Nodes
5
- class ClassNode < ModuleNode
5
+ class ClassNode < Base
6
+ include NodeConcerns::Body
7
+ include NodeConcerns::QualifiedName
8
+
9
+ # @return [String]
10
+ def name
11
+ const_node.name
12
+ end
13
+
14
+ # @return [String, nil]
15
+ # @example returns nil for class for `class Foo`
16
+ # node = Rucoa::Source.new(
17
+ # content: <<~RUBY,
18
+ # class Foo
19
+ # end
20
+ # RUBY
21
+ # uri: 'file:///path/to/foo.rb'
22
+ # ).root_node
23
+ # expect(node.super_class_chained_name).to be_nil
24
+ # @example returns "Bar" for class for `class Foo < Bar`
25
+ # node = Rucoa::Source.new(
26
+ # content: <<~RUBY,
27
+ # class Foo < Bar
28
+ # end
29
+ # RUBY
30
+ # uri: 'file:///path/to/foo.rb'
31
+ # ).root_node
32
+ # expect(node.super_class_chained_name).to eq('Bar')
33
+ # @example returns "Bar::Baz" for class for `class Foo < Bar::Baz`
34
+ # node = Rucoa::Source.new(
35
+ # content: <<~RUBY,
36
+ # class Foo < Bar::Baz
37
+ # end
38
+ # RUBY
39
+ # uri: 'file:///path/to/foo.rb'
40
+ # ).root_node
41
+ # expect(node.super_class_chained_name).to eq('Bar::Baz')
42
+ # @example returns "::Bar" for class for `class Foo < ::Bar`
43
+ # node = Rucoa::Source.new(
44
+ # content: <<~RUBY,
45
+ # class Foo < ::Bar
46
+ # end
47
+ # RUBY
48
+ # uri: 'file:///path/to/foo.rb'
49
+ # ).root_node
50
+ # expect(node.super_class_chained_name).to eq('::Bar')
51
+ def super_class_chained_name
52
+ return unless super_class_node.is_a?(Nodes::ConstNode)
53
+
54
+ super_class_node.chained_name
55
+ end
56
+
57
+ private
58
+
59
+ # @return [Rucoa::Nodes::ConstNode]
60
+ def const_node
61
+ children[0]
62
+ end
63
+
64
+ # @return [Rucoa::Nodes::Base, nil]
65
+ def super_class_node
66
+ children[1]
67
+ end
6
68
  end
7
69
  end
8
70
  end
@@ -5,10 +5,25 @@ module Rucoa
5
5
  class ConstNode < Base
6
6
  # @return [String]
7
7
  # @example returns "A" for "A"
8
- # node = Rucoa::Parser.call('A')
8
+ # node = Rucoa::Source.new(
9
+ # content: <<~RUBY,
10
+ # A
11
+ # RUBY
12
+ # uri: 'file:///path/to/a.rb'
13
+ # ).root_node
9
14
  # expect(node.name).to eq('A')
10
15
  # @example returns "B" for "A::B"
11
- # node = Rucoa::Parser.call('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
+ # )
12
27
  # expect(node.name).to eq('B')
13
28
  def name
14
29
  children[1].to_s
@@ -16,13 +31,34 @@ module Rucoa
16
31
 
17
32
  # @return [String]
18
33
  # @example returns "A" for "A"
19
- # node = Rucoa::Parser.call('A')
34
+ # node = Rucoa::Source.new(
35
+ # content: <<~RUBY,
36
+ # A
37
+ # RUBY
38
+ # uri: 'file:///path/to/a.rb'
39
+ # ).root_node
20
40
  # expect(node.chained_name).to eq('A')
21
41
  # @example returns "A::B" for "A::B"
22
- # node = Rucoa::Parser.call('A::B')
42
+ # node = Rucoa::Source.new(
43
+ # content: <<~RUBY,
44
+ # A::B
45
+ # RUBY
46
+ # uri: 'file:///path/to/a.rb'
47
+ # ).node_at(
48
+ # Rucoa::Position.new(
49
+ # column: 4,
50
+ # line: 1
51
+ # )
52
+ # )
23
53
  # expect(node.chained_name).to eq('A::B')
24
54
  def chained_name
25
- if receiver.is_a?(ConstNode)
55
+ case receiver
56
+ when Nodes::CbaseNode
57
+ [
58
+ '',
59
+ name
60
+ ].join('::')
61
+ when Nodes::ConstNode
26
62
  [
27
63
  receiver.chained_name,
28
64
  name
@@ -32,6 +68,29 @@ module Rucoa
32
68
  end
33
69
  end
34
70
 
71
+ # @return [Array<String>]
72
+ # @example return ["Bar::Foo", "Foo"] for class Foo::Bar::Baz
73
+ # node = Rucoa::Source.new(
74
+ # content: <<~RUBY,
75
+ # module Foo
76
+ # module Bar
77
+ # module Baz
78
+ # end
79
+ # end
80
+ # end
81
+ # RUBY
82
+ # uri: 'file:///path/to/foo/bar/baz.rb'
83
+ # ).node_at(
84
+ # Rucoa::Position.new(
85
+ # column: 4,
86
+ # line: 3
87
+ # )
88
+ # )
89
+ # expect(node.module_nesting).to eq(['Foo::Bar', 'Foo'])
90
+ def module_nesting
91
+ each_ancestor(:class, :module).map(&:qualified_name)
92
+ end
93
+
35
94
  private
36
95
 
37
96
  # @return [Rucoa::Nodes::Base, nil]
@@ -6,7 +6,7 @@ module Rucoa
6
6
  # @return [String]
7
7
  # @example returns method name
8
8
  # node = Rucoa::Source.new(
9
- # content: <<~RUBY
9
+ # content: <<~RUBY,
10
10
  # module Foo
11
11
  # class Bar
12
12
  # def baz
@@ -14,6 +14,7 @@ module Rucoa
14
14
  # end
15
15
  # end
16
16
  # RUBY
17
+ # uri: 'file:///path/to/foo/bar.rb'
17
18
  # ).node_at(
18
19
  # Rucoa::Position.new(
19
20
  # column: 4,
@@ -28,7 +29,7 @@ module Rucoa
28
29
  # @return [String]
29
30
  # @example returns full qualified name
30
31
  # node = Rucoa::Source.new(
31
- # content: <<~RUBY
32
+ # content: <<~RUBY,
32
33
  # module Foo
33
34
  # class Bar
34
35
  # def baz
@@ -36,14 +37,15 @@ module Rucoa
36
37
  # end
37
38
  # end
38
39
  # RUBY
40
+ # uri: 'file:///path/to/foo/bar.rb'
39
41
  # ).node_at(
40
42
  # Rucoa::Position.new(
41
43
  # column: 4,
42
44
  # line: 3
43
45
  # )
44
46
  # )
45
- # expect(node.full_qualified_name).to eq('Foo::Bar#baz')
46
- def full_qualified_name
47
+ # expect(node.qualified_name).to eq('Foo::Bar#baz')
48
+ def qualified_name
47
49
  [
48
50
  namespace,
49
51
  method_marker,
@@ -51,6 +53,11 @@ module Rucoa
51
53
  ].join
52
54
  end
53
55
 
56
+ # @return [Boolean]
57
+ def singleton?
58
+ each_ancestor(:sclass).any?
59
+ end
60
+
54
61
  private
55
62
 
56
63
  # @return [String]
@@ -61,11 +68,6 @@ module Rucoa
61
68
  '#'
62
69
  end
63
70
  end
64
-
65
- # @return [Boolean]
66
- def singleton?
67
- each_ancestor(:sclass).any?
68
- end
69
71
  end
70
72
  end
71
73
  end
@@ -3,10 +3,31 @@
3
3
  module Rucoa
4
4
  module Nodes
5
5
  class DefsNode < Base
6
+ # @return [String]
7
+ def qualified_name
8
+ [
9
+ namespace,
10
+ method_marker,
11
+ name
12
+ ].join
13
+ end
14
+
6
15
  # @return [String]
7
16
  def name
8
17
  children[1].to_s
9
18
  end
19
+
20
+ # @return [Boolean]
21
+ def singleton?
22
+ true
23
+ end
24
+
25
+ private
26
+
27
+ # @return [String]
28
+ def method_marker
29
+ '.'
30
+ end
10
31
  end
11
32
  end
12
33
  end
@@ -6,10 +6,11 @@ module Rucoa
6
6
  # @return [String]
7
7
  # @example returns local variable name
8
8
  # node = Rucoa::Source.new(
9
- # content: <<~RUBY
9
+ # content: <<~RUBY,
10
10
  # foo = 1
11
11
  # foo
12
12
  # RUBY
13
+ # uri: 'file:///path/to/example.rb'
13
14
  # ).node_at(
14
15
  # Rucoa::Position.new(
15
16
  # column: 2,
@@ -3,7 +3,8 @@
3
3
  module Rucoa
4
4
  module Nodes
5
5
  class ModuleNode < Base
6
- include NodeConcerns::NameFullQualifiable
6
+ include NodeConcerns::Body
7
+ include NodeConcerns::QualifiedName
7
8
 
8
9
  # @return [String]
9
10
  def name
@@ -5,11 +5,12 @@ module Rucoa
5
5
  class SendNode < Base
6
6
  # @return [Array<Rucoa::Nodes::Base>]
7
7
  # @example returns arguments
8
- # node = Rucoa::Parser.call(
9
- # <<~RUBY
8
+ # node = Rucoa::Source.new(
9
+ # content: <<~RUBY,
10
10
  # foo(bar, baz)
11
11
  # RUBY
12
- # )
12
+ # uri: 'file:///path/to/example.rb'
13
+ # ).root_node
13
14
  # expect(node.arguments.map(&:name)).to eq(
14
15
  # %w[
15
16
  # bar
@@ -22,11 +23,12 @@ module Rucoa
22
23
 
23
24
  # @return [String]
24
25
  # @example returns method name
25
- # node = Rucoa::Parser.call(
26
- # <<~RUBY
26
+ # node = Rucoa::Source.new(
27
+ # content: <<~RUBY,
27
28
  # foo(bar, baz)
28
29
  # RUBY
29
- # )
30
+ # uri: 'file:///path/to/example.rb'
31
+ # ).root_node
30
32
  # expect(node.name).to eq('foo')
31
33
  def name
32
34
  children[1].to_s
@@ -34,17 +36,19 @@ module Rucoa
34
36
 
35
37
  # @return [Rucoa::Nodes::Base, nil]
36
38
  # @example returns nil for receiver-less method call
37
- # node = Rucoa::Parser.call(
38
- # <<~RUBY
39
+ # node = Rucoa::Source.new(
40
+ # content: <<~RUBY,
39
41
  # foo(bar, baz)
40
42
  # RUBY
41
- # )
43
+ # uri: 'file:///path/to/example.rb'
44
+ # ).root_node
42
45
  # expect(node.receiver).to be_nil
43
46
  # @example returns receiver
44
47
  # node = Rucoa::Source.new(
45
- # content: <<~RUBY
48
+ # content: <<~RUBY,
46
49
  # foo.bar
47
50
  # RUBY
51
+ # uri: 'file:///path/to/example.rb'
48
52
  # ).node_at(
49
53
  # Rucoa::Position.new(
50
54
  # column: 4,
data/lib/rucoa/nodes.rb CHANGED
@@ -3,8 +3,10 @@
3
3
  module Rucoa
4
4
  module Nodes
5
5
  autoload :Base, 'rucoa/nodes/base'
6
- autoload :ClassNode, 'rucoa/nodes/class_node'
6
+ autoload :BeginNode, 'rucoa/nodes/begin_node'
7
7
  autoload :CasgnNode, 'rucoa/nodes/casgn_node'
8
+ autoload :CbaseNode, 'rucoa/nodes/cbase_node'
9
+ autoload :ClassNode, 'rucoa/nodes/class_node'
8
10
  autoload :ConstNode, 'rucoa/nodes/const_node'
9
11
  autoload :DefNode, 'rucoa/nodes/def_node'
10
12
  autoload :DefsNode, 'rucoa/nodes/defs_node'
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rucoa
4
+ class ParseResult
5
+ # @return [Array<Parser::Source::Comment>, nil]
6
+ attr_reader :associations
7
+
8
+ # @return [Rucoa::Nodes::Base, nil]
9
+ attr_reader :root_node
10
+
11
+ # @param associations [Array<Parser::Source::Comment>, nil]
12
+ # @param failed [Boolean]
13
+ # @param root_node [Rucoa::Nodes::Base, nil]
14
+ def initialize(
15
+ associations: nil,
16
+ failed: false,
17
+ root_node: nil
18
+ )
19
+ @associations = associations
20
+ @failed = failed
21
+ @root_node = root_node
22
+ end
23
+
24
+ # @return [Boolean]
25
+ def failed?
26
+ @failed
27
+ end
28
+ end
29
+ end
data/lib/rucoa/parser.rb CHANGED
@@ -3,29 +3,61 @@
3
3
  require 'parser/current'
4
4
 
5
5
  module Rucoa
6
- # Parses Ruby text code.
7
6
  class Parser
8
7
  class << self
9
8
  # @param text [String]
10
- # @return [Rucoa::Nodes::Base]
11
- def call(text)
12
- new(text).call
9
+ # @param uri [String]
10
+ # @return [Rucoa::ParseResult]
11
+ # @example returns non-failed parse result for valid Ruby source
12
+ # result = Rucoa::Parser.call(
13
+ # text: 'foo',
14
+ # uri: 'file:///path/to/foo.rb'
15
+ # )
16
+ # expect(result).not_to be_failed
17
+ # @example returns failed parse result for invalid Ruby source
18
+ # result = Rucoa::Parser.call(
19
+ # text: 'foo(',
20
+ # uri: 'file:///path/to/foo.rb'
21
+ # )
22
+ # expect(result).to be_failed
23
+ def call(
24
+ text:,
25
+ uri:
26
+ )
27
+ new(
28
+ text: text,
29
+ uri: uri
30
+ ).call
13
31
  end
14
32
  end
15
33
 
16
34
  # @param text [String]
17
- def initialize(text)
35
+ # @param uri [String]
36
+ def initialize(
37
+ text:,
38
+ uri:
39
+ )
18
40
  @text = text
41
+ @uri = uri
19
42
  end
20
43
 
21
- # @return [Rucoa::Nodes::Base]
44
+ # @return [Rucoa::ParseResult]
22
45
  def call
23
- parser.parse(
46
+ root_node, comments = parser.parse_with_comments(
24
47
  ::Parser::Source::Buffer.new(
25
- '',
48
+ @uri,
26
49
  source: @text
27
50
  )
28
51
  )
52
+ ParseResult.new(
53
+ associations: ::Parser::Source::Comment.associate_locations(
54
+ root_node,
55
+ comments
56
+ ),
57
+ root_node: root_node
58
+ )
59
+ rescue ::Parser::SyntaxError
60
+ ParseResult.new(failed: true)
29
61
  end
30
62
 
31
63
  private