rucoa 0.7.0 → 0.9.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/Gemfile.lock +1 -1
- data/README.md +4 -1
- data/data/definitions_ruby_3_1 +0 -0
- data/lib/rucoa/configuration.rb +10 -0
- data/lib/rucoa/definition_store.rb +194 -27
- data/lib/rucoa/definitions/class_definition.rb +82 -0
- data/lib/rucoa/definitions/constant_definition.rb +7 -7
- data/lib/rucoa/definitions/method_definition.rb +18 -6
- data/lib/rucoa/definitions/module_definition.rb +8 -0
- data/lib/rucoa/definitions.rb +2 -0
- data/lib/rucoa/handlers/initialize_handler.rb +1 -0
- data/lib/rucoa/handlers/initialized_handler.rb +33 -5
- data/lib/rucoa/handlers/text_document_completion_handler.rb +2 -2
- data/lib/rucoa/handlers/text_document_definition_handler.rb +155 -0
- data/lib/rucoa/handlers/text_document_did_open_handler.rb +1 -4
- data/lib/rucoa/handlers/text_document_hover_handler.rb +3 -4
- data/lib/rucoa/handlers.rb +1 -0
- data/lib/rucoa/node_concerns/{name_full_qualifiable.rb → name_fully_qualifiable.rb} +2 -2
- data/lib/rucoa/node_concerns.rb +1 -1
- data/lib/rucoa/node_inspector.rb +56 -34
- data/lib/rucoa/nodes/base.rb +32 -7
- 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 +62 -1
- data/lib/rucoa/nodes/const_node.rb +72 -0
- 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 +1 -1
- data/lib/rucoa/nodes/send_node.rb +14 -10
- data/lib/rucoa/nodes.rb +1 -0
- data/lib/rucoa/parse_result.rb +29 -0
- data/lib/rucoa/parser.rb +40 -8
- data/lib/rucoa/parser_builder.rb +1 -0
- data/lib/rucoa/position.rb +1 -1
- data/lib/rucoa/rbs/class_definition_mapper.rb +46 -0
- data/lib/rucoa/rbs/constant_definition_mapper.rb +2 -2
- data/lib/rucoa/rbs/module_definition_mapper.rb +40 -0
- data/lib/rucoa/rbs/ruby_definitions_loader.rb +11 -7
- data/lib/rucoa/rbs.rb +2 -0
- data/lib/rucoa/rubocop/autocorrector.rb +12 -1
- data/lib/rucoa/rubocop/investigator.rb +10 -1
- data/lib/rucoa/server.rb +2 -1
- data/lib/rucoa/source.rb +47 -24
- data/lib/rucoa/source_store.rb +0 -13
- data/lib/rucoa/version.rb +1 -1
- data/lib/rucoa/yard/definitions_loader.rb +320 -48
- data/lib/rucoa/yard/type.rb +46 -0
- data/lib/rucoa/yard.rb +1 -1
- data/lib/rucoa.rb +1 -0
- metadata +11 -4
- data/lib/rucoa/yard/definition_mapper.rb +0 -217
@@ -0,0 +1,155 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Rucoa
|
4
|
+
module Handlers
|
5
|
+
class TextDocumentDefinitionHandler < Base
|
6
|
+
def call
|
7
|
+
respond(location)
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
# @return [Hash, nil]
|
13
|
+
def location
|
14
|
+
return unless reponsible?
|
15
|
+
|
16
|
+
{
|
17
|
+
range: location_range.to_vscode_range,
|
18
|
+
uri: location_uri
|
19
|
+
}
|
20
|
+
end
|
21
|
+
|
22
|
+
# @return [Boolean]
|
23
|
+
def reponsible?
|
24
|
+
configuration.enables_definition? &&
|
25
|
+
!location_uri.nil? &&
|
26
|
+
!location_source.nil?
|
27
|
+
end
|
28
|
+
|
29
|
+
# @return [Rucoa::Range]
|
30
|
+
def location_range
|
31
|
+
return Range.from_parser_range(location_node.location.expression) if location_node
|
32
|
+
|
33
|
+
Position.new.to_range
|
34
|
+
end
|
35
|
+
|
36
|
+
# @return [String, nil]
|
37
|
+
def location_uri
|
38
|
+
return unless definition
|
39
|
+
|
40
|
+
if definition.source_path.start_with?('Untitled-')
|
41
|
+
"untitled:#{definition.source_path}"
|
42
|
+
else
|
43
|
+
"file://#{definition.source_path}"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# @return [Rucoa::Nodes::Base, nil]
|
48
|
+
def location_node
|
49
|
+
@location_node ||=
|
50
|
+
case definition
|
51
|
+
when Definitions::ClassDefinition
|
52
|
+
find_class_node
|
53
|
+
when Definitions::ModuleDefinition
|
54
|
+
find_module_node
|
55
|
+
when Definitions::MethodDefinition
|
56
|
+
find_method_node
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# @return [Rucoa::Source, nil]
|
61
|
+
def location_source
|
62
|
+
source_store.get(location_uri)
|
63
|
+
end
|
64
|
+
|
65
|
+
# @return [Rucoa::Position]
|
66
|
+
def position
|
67
|
+
Position.from_vscode_position(
|
68
|
+
request.dig('params', 'position')
|
69
|
+
)
|
70
|
+
end
|
71
|
+
|
72
|
+
# @return [String]
|
73
|
+
def uri
|
74
|
+
request.dig('params', 'textDocument', 'uri')
|
75
|
+
end
|
76
|
+
|
77
|
+
# @return [Rucoa::Source, nil]
|
78
|
+
def source
|
79
|
+
source_store.get(uri)
|
80
|
+
end
|
81
|
+
|
82
|
+
# @return [Rucoa::Nodes::Base]
|
83
|
+
def node
|
84
|
+
source&.node_at(position)
|
85
|
+
end
|
86
|
+
|
87
|
+
# @return [Rucoa::Definitions::Base, nil]
|
88
|
+
def definition
|
89
|
+
@definition ||= NodeInspector.new(
|
90
|
+
definition_store: definition_store,
|
91
|
+
node: node
|
92
|
+
).definitions.first
|
93
|
+
end
|
94
|
+
|
95
|
+
# @return [Rucoa::Nodes::ClassNode, nil]
|
96
|
+
def find_class_node
|
97
|
+
find_by_fully_qualified_name(
|
98
|
+
fully_qualified_name: definition.fully_qualified_name,
|
99
|
+
klass: Nodes::ClassNode
|
100
|
+
) || find_by_name(
|
101
|
+
klass: Nodes::ClassNode,
|
102
|
+
name: definition.name
|
103
|
+
)
|
104
|
+
end
|
105
|
+
|
106
|
+
# @return [Rucoa::Nodes::ModuleNode, nil]
|
107
|
+
def find_module_node
|
108
|
+
find_by_fully_qualified_name(
|
109
|
+
fully_qualified_name: definition.fully_qualified_name,
|
110
|
+
klass: Nodes::ModuleNode
|
111
|
+
) || find_by_name(
|
112
|
+
klass: Nodes::ModuleNode,
|
113
|
+
name: definition.name
|
114
|
+
)
|
115
|
+
end
|
116
|
+
|
117
|
+
# @return [Rucoa::Nodes::MethodNode, nil]
|
118
|
+
def find_method_node
|
119
|
+
location_root_or_descendant_nodes.reverse.find do |node|
|
120
|
+
node.is_a?(Nodes::DefNode) &&
|
121
|
+
node.name == definition.method_name &&
|
122
|
+
node.namespace == definition.namespace
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
# @param fully_qualified_name [String]
|
127
|
+
# @param klass [Class]
|
128
|
+
# @return [Rucoa::Nodes::Base, nil]
|
129
|
+
def find_by_fully_qualified_name(fully_qualified_name:, klass:)
|
130
|
+
location_root_or_descendant_nodes.reverse.find do |node|
|
131
|
+
node.is_a?(klass) &&
|
132
|
+
node.fully_qualified_name == fully_qualified_name
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
# @param name [String]
|
137
|
+
# @param klass [Class]
|
138
|
+
# @return [Rucoa::Nodes::Base, nil]
|
139
|
+
def find_by_name(klass:, name:)
|
140
|
+
location_root_or_descendant_nodes.reverse.find do |node|
|
141
|
+
node.is_a?(klass) &&
|
142
|
+
node.name == name
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
# @return [Array<Rucoa::Nodes::Base>]
|
147
|
+
def location_root_or_descendant_nodes
|
148
|
+
@location_root_or_descendant_nodes ||= [
|
149
|
+
location_source.root_node,
|
150
|
+
*location_source.root_node.descendants
|
151
|
+
]
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
@@ -23,14 +23,13 @@ module Rucoa
|
|
23
23
|
def responsible?
|
24
24
|
configuration.enables_hover? &&
|
25
25
|
!source.nil? &&
|
26
|
-
!node.nil?
|
26
|
+
!node.nil? &&
|
27
|
+
!method_definitions.empty?
|
27
28
|
end
|
28
29
|
|
29
30
|
# @return [String, nil]
|
30
31
|
def contents
|
31
32
|
method_definition = method_definitions.first
|
32
|
-
return unless method_definition
|
33
|
-
|
34
33
|
[
|
35
34
|
method_definition.signatures.join("\n"),
|
36
35
|
method_definition.description
|
@@ -66,7 +65,7 @@ module Rucoa
|
|
66
65
|
|
67
66
|
# @return [Array<Rucoa::Definitions::MethodDefinition>]
|
68
67
|
def method_definitions
|
69
|
-
NodeInspector.new(
|
68
|
+
@method_definitions ||= NodeInspector.new(
|
70
69
|
definition_store: definition_store,
|
71
70
|
node: node
|
72
71
|
).method_definitions
|
data/lib/rucoa/handlers.rb
CHANGED
@@ -9,6 +9,7 @@ module Rucoa
|
|
9
9
|
autoload :ShutdownHandler, 'rucoa/handlers/shutdown_handler'
|
10
10
|
autoload :TextDocumentCodeActionHandler, 'rucoa/handlers/text_document_code_action_handler'
|
11
11
|
autoload :TextDocumentCompletionHandler, 'rucoa/handlers/text_document_completion_handler'
|
12
|
+
autoload :TextDocumentDefinitionHandler, 'rucoa/handlers/text_document_definition_handler'
|
12
13
|
autoload :TextDocumentDidChangeHandler, 'rucoa/handlers/text_document_did_change_handler'
|
13
14
|
autoload :TextDocumentDidCloseHandler, 'rucoa/handlers/text_document_did_close_handler'
|
14
15
|
autoload :TextDocumentDidOpenHandler, 'rucoa/handlers/text_document_did_open_handler'
|
data/lib/rucoa/node_concerns.rb
CHANGED
data/lib/rucoa/node_inspector.rb
CHANGED
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'set'
|
4
|
-
|
5
3
|
module Rucoa
|
6
4
|
class NodeInspector
|
7
5
|
# @param definition_store [Rucoa::DefinitionStore]
|
@@ -11,10 +9,24 @@ module Rucoa
|
|
11
9
|
@node = node
|
12
10
|
end
|
13
11
|
|
14
|
-
# @return [Array<
|
12
|
+
# @return [Array<Rucoa::Definitions::Base>]
|
13
|
+
def definitions
|
14
|
+
case @node
|
15
|
+
when Nodes::ConstNode
|
16
|
+
[constant_definition]
|
17
|
+
when Nodes::SendNode
|
18
|
+
method_definitions
|
19
|
+
else
|
20
|
+
[]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# @return [Array<Rucoa::Definitions::MethodDefinition>]
|
15
25
|
def method_definitions
|
16
|
-
|
17
|
-
@definition_store.
|
26
|
+
method_receiver_types.flat_map do |type|
|
27
|
+
@definition_store.instance_method_definitions_of(type)
|
28
|
+
end.select do |method_definition|
|
29
|
+
method_definition.method_name == @node.name
|
18
30
|
end
|
19
31
|
end
|
20
32
|
|
@@ -36,7 +48,7 @@ module Rucoa
|
|
36
48
|
def return_types
|
37
49
|
case @node.type
|
38
50
|
when :const
|
39
|
-
[@node.name]
|
51
|
+
["singleton<#{@node.name}>"]
|
40
52
|
when :lvar
|
41
53
|
return_types_for_lvar
|
42
54
|
when :send
|
@@ -74,50 +86,60 @@ module Rucoa
|
|
74
86
|
|
75
87
|
private
|
76
88
|
|
77
|
-
# @return [
|
78
|
-
def
|
79
|
-
|
89
|
+
# @return [Rucoa::Definitions::ConstantDefinition, nil]
|
90
|
+
def constant_definition
|
91
|
+
return unless @node.is_a?(Nodes::ConstNode)
|
92
|
+
|
93
|
+
module_nesting = @node.module_nesting
|
94
|
+
candidate_fully_qualified_names = module_nesting.flat_map do |module_nesting_fully_qualified_name|
|
80
95
|
[
|
81
|
-
|
82
|
-
|
83
|
-
].
|
96
|
+
module_nesting_fully_qualified_name
|
97
|
+
# TODO: *ancestors_of(module_nesting_fully_qualified_name)
|
98
|
+
].map do |fully_qualified_name|
|
99
|
+
[
|
100
|
+
fully_qualified_name,
|
101
|
+
@node.chained_name
|
102
|
+
].join('::')
|
103
|
+
end
|
104
|
+
end + [@node.chained_name]
|
105
|
+
candidate_fully_qualified_names.find do |candidate_fully_qualified_name|
|
106
|
+
definition = @definition_store.find_definition_by_fully_qualified_name(candidate_fully_qualified_name)
|
107
|
+
break definition if definition
|
84
108
|
end
|
85
109
|
end
|
86
110
|
|
87
|
-
# @return [
|
88
|
-
def
|
89
|
-
|
90
|
-
|
91
|
-
case @node.receiver
|
92
|
-
when Nodes::ConstNode
|
93
|
-
'.'
|
94
|
-
else
|
95
|
-
'#'
|
96
|
-
end
|
111
|
+
# @return [Boolean]
|
112
|
+
def singleton_method_call?
|
113
|
+
@node.is_a?(Nodes::ConstNode)
|
97
114
|
end
|
98
115
|
|
99
116
|
# @return [String, nil]
|
100
|
-
def
|
101
|
-
@node.each_ancestor(:def).first&.
|
117
|
+
def nearest_def_fully_qualified_name
|
118
|
+
@node.each_ancestor(:def).first&.fully_qualified_name
|
102
119
|
end
|
103
120
|
|
104
121
|
# @return [Array<String>]
|
105
122
|
def return_types_for_lvar
|
106
|
-
|
107
|
-
return [] unless
|
123
|
+
fully_qualified_name = nearest_def_fully_qualified_name
|
124
|
+
return [] unless fully_qualified_name
|
108
125
|
|
109
|
-
@definition_store.
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
126
|
+
definition = @definition_store.find_definition_by_fully_qualified_name(fully_qualified_name)
|
127
|
+
return [] unless definition
|
128
|
+
|
129
|
+
definition.parameters.select do |parameter|
|
130
|
+
parameter.name == @node.name
|
131
|
+
end.flat_map(&:types)
|
114
132
|
end
|
115
133
|
|
116
134
|
# @return [Array<String>]
|
117
135
|
def return_types_for_send
|
118
|
-
|
119
|
-
@definition_store.
|
120
|
-
|
136
|
+
method_receiver_types.flat_map do |type|
|
137
|
+
@definition_store.find_method_definition_by(
|
138
|
+
method_name: @node.name,
|
139
|
+
namespace: type,
|
140
|
+
singleton: singleton_method_call?
|
141
|
+
)&.return_types
|
142
|
+
end.compact
|
121
143
|
end
|
122
144
|
end
|
123
145
|
end
|
data/lib/rucoa/nodes/base.rb
CHANGED
@@ -89,7 +89,7 @@ module Rucoa
|
|
89
89
|
# @return [String]
|
90
90
|
# @example returns namespace
|
91
91
|
# node = Rucoa::Source.new(
|
92
|
-
# content: <<~RUBY
|
92
|
+
# content: <<~RUBY,
|
93
93
|
# module Foo
|
94
94
|
# class Bar
|
95
95
|
# def baz
|
@@ -97,6 +97,7 @@ module Rucoa
|
|
97
97
|
# end
|
98
98
|
# end
|
99
99
|
# RUBY
|
100
|
+
# uri: 'file:///path/to/foo/bar.rb'
|
100
101
|
# ).node_at(
|
101
102
|
# Rucoa::Position.new(
|
102
103
|
# column: 4,
|
@@ -105,14 +106,38 @@ module Rucoa
|
|
105
106
|
# )
|
106
107
|
# expect(node.namespace).to eq('Foo::Bar')
|
107
108
|
# @example returns "Object" when the node is not in a namespace
|
108
|
-
# node = Rucoa::
|
109
|
-
# <<~RUBY
|
109
|
+
# node = Rucoa::Source.new(
|
110
|
+
# content: <<~RUBY,
|
110
111
|
# foo
|
111
112
|
# RUBY
|
112
|
-
#
|
113
|
+
# uri: 'file:///path/to/example.rb'
|
114
|
+
# ).root_node
|
113
115
|
# expect(node.namespace).to eq('Object')
|
114
116
|
def namespace
|
115
|
-
|
117
|
+
module_nesting.first || 'Object'
|
118
|
+
end
|
119
|
+
|
120
|
+
# @return [Array<String>]
|
121
|
+
# @example return ["Bar::Foo", "Foo"] for class Foo::Bar::Baz
|
122
|
+
# node = Rucoa::Source.new(
|
123
|
+
# content: <<~RUBY,
|
124
|
+
# module Foo
|
125
|
+
# module Bar
|
126
|
+
# module Baz
|
127
|
+
# end
|
128
|
+
# end
|
129
|
+
# end
|
130
|
+
# RUBY
|
131
|
+
# uri: 'file:///path/to/foo/bar/baz.rb'
|
132
|
+
# ).node_at(
|
133
|
+
# Rucoa::Position.new(
|
134
|
+
# column: 4,
|
135
|
+
# line: 3
|
136
|
+
# )
|
137
|
+
# )
|
138
|
+
# expect(node.module_nesting).to eq(['Foo::Bar', 'Foo'])
|
139
|
+
def module_nesting
|
140
|
+
each_ancestor(:class, :module).map(&:fully_qualified_name)
|
116
141
|
end
|
117
142
|
|
118
143
|
protected
|
@@ -121,8 +146,8 @@ module Rucoa
|
|
121
146
|
# @param types [Array<Symbol>]
|
122
147
|
# @return [void]
|
123
148
|
def visit_descendants(types, &block)
|
124
|
-
each_child_node
|
125
|
-
yield(child)
|
149
|
+
each_child_node do |child|
|
150
|
+
yield(child) if types.empty? || types.include?(child.type)
|
126
151
|
child.visit_descendants(types, &block)
|
127
152
|
end
|
128
153
|
end
|
@@ -2,7 +2,68 @@
|
|
2
2
|
|
3
3
|
module Rucoa
|
4
4
|
module Nodes
|
5
|
-
class ClassNode <
|
5
|
+
class ClassNode < Base
|
6
|
+
include NodeConcerns::NameFullyQualifiable
|
7
|
+
|
8
|
+
# @return [String]
|
9
|
+
def name
|
10
|
+
const_node.name
|
11
|
+
end
|
12
|
+
|
13
|
+
# @return [String, nil]
|
14
|
+
# @example returns nil for class for `class Foo`
|
15
|
+
# node = Rucoa::Source.new(
|
16
|
+
# content: <<~RUBY,
|
17
|
+
# class Foo
|
18
|
+
# end
|
19
|
+
# RUBY
|
20
|
+
# uri: 'file:///path/to/foo.rb'
|
21
|
+
# ).root_node
|
22
|
+
# expect(node.super_class_chained_name).to be_nil
|
23
|
+
# @example returns "Bar" for class for `class Foo < Bar`
|
24
|
+
# node = Rucoa::Source.new(
|
25
|
+
# content: <<~RUBY,
|
26
|
+
# class Foo < Bar
|
27
|
+
# end
|
28
|
+
# RUBY
|
29
|
+
# uri: 'file:///path/to/foo.rb'
|
30
|
+
# ).root_node
|
31
|
+
# expect(node.super_class_chained_name).to eq('Bar')
|
32
|
+
# @example returns "Bar::Baz" for class for `class Foo < Bar::Baz`
|
33
|
+
# node = Rucoa::Source.new(
|
34
|
+
# content: <<~RUBY,
|
35
|
+
# class Foo < Bar::Baz
|
36
|
+
# end
|
37
|
+
# RUBY
|
38
|
+
# uri: 'file:///path/to/foo.rb'
|
39
|
+
# ).root_node
|
40
|
+
# expect(node.super_class_chained_name).to eq('Bar::Baz')
|
41
|
+
# @example returns "::Bar" for class for `class Foo < ::Bar`
|
42
|
+
# node = Rucoa::Source.new(
|
43
|
+
# content: <<~RUBY,
|
44
|
+
# class Foo < ::Bar
|
45
|
+
# end
|
46
|
+
# RUBY
|
47
|
+
# uri: 'file:///path/to/foo.rb'
|
48
|
+
# ).root_node
|
49
|
+
# expect(node.super_class_chained_name).to eq('::Bar')
|
50
|
+
def super_class_chained_name
|
51
|
+
return unless super_class_node.is_a?(Nodes::ConstNode)
|
52
|
+
|
53
|
+
super_class_node.chained_name
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
# @return [Rucoa::Nodes::ConstNode]
|
59
|
+
def const_node
|
60
|
+
children[0]
|
61
|
+
end
|
62
|
+
|
63
|
+
# @return [Rucoa::Nodes::Base, nil]
|
64
|
+
def super_class_node
|
65
|
+
children[1]
|
66
|
+
end
|
6
67
|
end
|
7
68
|
end
|
8
69
|
end
|
@@ -4,9 +4,81 @@ module Rucoa
|
|
4
4
|
module Nodes
|
5
5
|
class ConstNode < Base
|
6
6
|
# @return [String]
|
7
|
+
# @example returns "A" for "A"
|
8
|
+
# node = Rucoa::Parser.call(
|
9
|
+
# path: '/path/to/example.rb',
|
10
|
+
# text: 'A'
|
11
|
+
# ).root_node
|
12
|
+
# expect(node.name).to eq('A')
|
13
|
+
# @example returns "B" for "A::B"
|
14
|
+
# node = Rucoa::Parser.call(
|
15
|
+
# path: '/path/to/example.rb',
|
16
|
+
# text: 'A::B'
|
17
|
+
# ).root_node
|
18
|
+
# expect(node.name).to eq('B')
|
7
19
|
def name
|
8
20
|
children[1].to_s
|
9
21
|
end
|
22
|
+
|
23
|
+
# @return [String]
|
24
|
+
# @example returns "A" for "A"
|
25
|
+
# node = Rucoa::Parser.call(
|
26
|
+
# path: '/path/to/example.rb',
|
27
|
+
# text: 'A'
|
28
|
+
# ).root_node
|
29
|
+
# expect(node.chained_name).to eq('A')
|
30
|
+
# @example returns "A::B" for "A::B"
|
31
|
+
# node = Rucoa::Parser.call(
|
32
|
+
# path: '/path/to/example.rb',
|
33
|
+
# text: 'A::B'
|
34
|
+
# ).root_node
|
35
|
+
# expect(node.chained_name).to eq('A::B')
|
36
|
+
def chained_name
|
37
|
+
case receiver
|
38
|
+
when Nodes::CbaseNode
|
39
|
+
[
|
40
|
+
'',
|
41
|
+
name
|
42
|
+
].join('::')
|
43
|
+
when Nodes::ConstNode
|
44
|
+
[
|
45
|
+
receiver.chained_name,
|
46
|
+
name
|
47
|
+
].join('::')
|
48
|
+
else
|
49
|
+
name
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# @return [Array<String>]
|
54
|
+
# @example return ["Bar::Foo", "Foo"] for class Foo::Bar::Baz
|
55
|
+
# node = Rucoa::Source.new(
|
56
|
+
# content: <<~RUBY,
|
57
|
+
# module Foo
|
58
|
+
# module Bar
|
59
|
+
# module Baz
|
60
|
+
# end
|
61
|
+
# end
|
62
|
+
# end
|
63
|
+
# RUBY
|
64
|
+
# uri: 'file:///path/to/foo/bar/baz.rb'
|
65
|
+
# ).node_at(
|
66
|
+
# Rucoa::Position.new(
|
67
|
+
# column: 4,
|
68
|
+
# line: 3
|
69
|
+
# )
|
70
|
+
# )
|
71
|
+
# expect(node.module_nesting).to eq(['Foo::Bar', 'Foo'])
|
72
|
+
def module_nesting
|
73
|
+
each_ancestor(:class, :module).map(&:fully_qualified_name)
|
74
|
+
end
|
75
|
+
|
76
|
+
private
|
77
|
+
|
78
|
+
# @return [Rucoa::Nodes::Base, nil]
|
79
|
+
def receiver
|
80
|
+
children[0]
|
81
|
+
end
|
10
82
|
end
|
11
83
|
end
|
12
84
|
end
|
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.fully_qualified_name).to eq('Foo::Bar#baz')
|
48
|
+
def fully_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 fully_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
|