rucoa 0.8.0 → 0.10.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.
- checksums.yaml +4 -4
- data/.rubocop.yml +6 -0
- data/Gemfile.lock +8 -8
- data/data/definitions_ruby_3_1 +0 -0
- data/lib/rucoa/configuration.rb +4 -1
- data/lib/rucoa/definition_store.rb +268 -75
- data/lib/rucoa/definitions/base.rb +14 -3
- data/lib/rucoa/definitions/class_definition.rb +20 -4
- data/lib/rucoa/definitions/constant_definition.rb +31 -19
- data/lib/rucoa/definitions/method_definition.rb +44 -52
- data/lib/rucoa/definitions/method_parameter_definition.rb +4 -1
- data/lib/rucoa/definitions/module_definition.rb +39 -0
- data/lib/rucoa/handler_concerns/diagnostics_publishable.rb +14 -3
- data/lib/rucoa/handlers/base.rb +12 -3
- data/lib/rucoa/handlers/initialized_handler.rb +33 -5
- data/lib/rucoa/handlers/text_document_completion_handler.rb +1 -1
- data/lib/rucoa/handlers/text_document_definition_handler.rb +3 -99
- data/lib/rucoa/handlers/text_document_did_open_handler.rb +1 -4
- data/lib/rucoa/handlers/text_document_hover_handler.rb +21 -13
- data/lib/rucoa/handlers/text_document_selection_range_handler.rb +8 -2
- data/lib/rucoa/location.rb +37 -0
- data/lib/rucoa/node_concerns/body.rb +24 -0
- data/lib/rucoa/node_concerns/{name_full_qualifiable.rb → qualified_name.rb} +2 -2
- data/lib/rucoa/node_concerns.rb +2 -1
- data/lib/rucoa/node_inspector.rb +22 -26
- data/lib/rucoa/nodes/base.rb +51 -10
- data/lib/rucoa/nodes/begin_node.rb +8 -0
- data/lib/rucoa/nodes/casgn_node.rb +1 -1
- data/lib/rucoa/nodes/cbase_node.rb +8 -0
- data/lib/rucoa/nodes/class_node.rb +63 -1
- data/lib/rucoa/nodes/const_node.rb +64 -5
- data/lib/rucoa/nodes/def_node.rb +11 -9
- data/lib/rucoa/nodes/defs_node.rb +21 -0
- data/lib/rucoa/nodes/lvar_node.rb +2 -1
- data/lib/rucoa/nodes/module_node.rb +2 -1
- data/lib/rucoa/nodes/send_node.rb +14 -10
- data/lib/rucoa/nodes.rb +3 -1
- data/lib/rucoa/parse_result.rb +29 -0
- data/lib/rucoa/parser.rb +40 -8
- data/lib/rucoa/parser_builder.rb +7 -1
- data/lib/rucoa/position.rb +10 -1
- data/lib/rucoa/range.rb +11 -1
- data/lib/rucoa/rbs/class_definition_mapper.rb +13 -28
- data/lib/rucoa/rbs/constant_definition_mapper.rb +12 -6
- data/lib/rucoa/rbs/method_definition_mapper.rb +12 -6
- data/lib/rucoa/rbs/module_definition_mapper.rb +34 -6
- data/lib/rucoa/rubocop/autocorrector.rb +2 -2
- data/lib/rucoa/rubocop/investigator.rb +6 -3
- data/lib/rucoa/server.rb +9 -3
- data/lib/rucoa/source.rb +57 -27
- data/lib/rucoa/source_store.rb +0 -13
- data/lib/rucoa/unqualified_name.rb +9 -0
- data/lib/rucoa/version.rb +1 -1
- data/lib/rucoa/yard/definition_generators/attribute_reader_definition_generator.rb +60 -0
- data/lib/rucoa/yard/definition_generators/attribute_writer_definition_generator.rb +60 -0
- data/lib/rucoa/yard/definition_generators/base.rb +117 -0
- data/lib/rucoa/yard/definition_generators/class_definition_generator.rb +66 -0
- data/lib/rucoa/yard/definition_generators/constant_assignment_definition_generator.rb +29 -0
- data/lib/rucoa/yard/definition_generators/method_definition_generator.rb +47 -0
- data/lib/rucoa/yard/definition_generators/module_definition_generator.rb +62 -0
- data/lib/rucoa/yard/definition_generators.rb +15 -0
- data/lib/rucoa/yard/definitions_loader.rb +44 -65
- data/lib/rucoa/yard/type.rb +46 -0
- data/lib/rucoa/yard.rb +2 -1
- data/lib/rucoa.rb +4 -1
- metadata +18 -4
- data/lib/rucoa/yard/method_definition_mapper.rb +0 -215
data/lib/rucoa/node_inspector.rb
CHANGED
@@ -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(
|
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
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
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
|
118
|
-
@node.each_ancestor(:def).first&.
|
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
|
-
|
124
|
-
return [] unless
|
118
|
+
qualified_name = nearest_def_qualified_name
|
119
|
+
return [] unless qualified_name
|
125
120
|
|
126
|
-
@definition_store.
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
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>]
|
data/lib/rucoa/nodes/base.rb
CHANGED
@@ -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(
|
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(
|
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(
|
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(
|
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::
|
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
|
-
|
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(
|
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)
|
@@ -2,7 +2,69 @@
|
|
2
2
|
|
3
3
|
module Rucoa
|
4
4
|
module Nodes
|
5
|
-
class ClassNode <
|
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::
|
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::
|
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::
|
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::
|
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
|
-
|
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]
|
data/lib/rucoa/nodes/def_node.rb
CHANGED
@@ -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.
|
46
|
-
def
|
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,
|
@@ -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::
|
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::
|
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::
|
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 :
|
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
|
-
# @
|
11
|
-
|
12
|
-
|
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
|
-
|
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::
|
44
|
+
# @return [Rucoa::ParseResult]
|
22
45
|
def call
|
23
|
-
parser.
|
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
|