rucoa 0.7.0 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +1 -1
  3. data/README.md +4 -1
  4. data/data/definitions_ruby_3_1 +0 -0
  5. data/lib/rucoa/configuration.rb +10 -0
  6. data/lib/rucoa/definition_store.rb +194 -27
  7. data/lib/rucoa/definitions/class_definition.rb +82 -0
  8. data/lib/rucoa/definitions/constant_definition.rb +7 -7
  9. data/lib/rucoa/definitions/method_definition.rb +18 -6
  10. data/lib/rucoa/definitions/module_definition.rb +8 -0
  11. data/lib/rucoa/definitions.rb +2 -0
  12. data/lib/rucoa/handlers/initialize_handler.rb +1 -0
  13. data/lib/rucoa/handlers/initialized_handler.rb +33 -5
  14. data/lib/rucoa/handlers/text_document_completion_handler.rb +2 -2
  15. data/lib/rucoa/handlers/text_document_definition_handler.rb +155 -0
  16. data/lib/rucoa/handlers/text_document_did_open_handler.rb +1 -4
  17. data/lib/rucoa/handlers/text_document_hover_handler.rb +3 -4
  18. data/lib/rucoa/handlers.rb +1 -0
  19. data/lib/rucoa/node_concerns/{name_full_qualifiable.rb → name_fully_qualifiable.rb} +2 -2
  20. data/lib/rucoa/node_concerns.rb +1 -1
  21. data/lib/rucoa/node_inspector.rb +56 -34
  22. data/lib/rucoa/nodes/base.rb +32 -7
  23. data/lib/rucoa/nodes/casgn_node.rb +1 -1
  24. data/lib/rucoa/nodes/cbase_node.rb +8 -0
  25. data/lib/rucoa/nodes/class_node.rb +62 -1
  26. data/lib/rucoa/nodes/const_node.rb +72 -0
  27. data/lib/rucoa/nodes/def_node.rb +11 -9
  28. data/lib/rucoa/nodes/defs_node.rb +21 -0
  29. data/lib/rucoa/nodes/lvar_node.rb +2 -1
  30. data/lib/rucoa/nodes/module_node.rb +1 -1
  31. data/lib/rucoa/nodes/send_node.rb +14 -10
  32. data/lib/rucoa/nodes.rb +1 -0
  33. data/lib/rucoa/parse_result.rb +29 -0
  34. data/lib/rucoa/parser.rb +40 -8
  35. data/lib/rucoa/parser_builder.rb +1 -0
  36. data/lib/rucoa/position.rb +1 -1
  37. data/lib/rucoa/rbs/class_definition_mapper.rb +46 -0
  38. data/lib/rucoa/rbs/constant_definition_mapper.rb +2 -2
  39. data/lib/rucoa/rbs/module_definition_mapper.rb +40 -0
  40. data/lib/rucoa/rbs/ruby_definitions_loader.rb +11 -7
  41. data/lib/rucoa/rbs.rb +2 -0
  42. data/lib/rucoa/rubocop/autocorrector.rb +12 -1
  43. data/lib/rucoa/rubocop/investigator.rb +10 -1
  44. data/lib/rucoa/server.rb +2 -1
  45. data/lib/rucoa/source.rb +47 -24
  46. data/lib/rucoa/source_store.rb +0 -13
  47. data/lib/rucoa/version.rb +1 -1
  48. data/lib/rucoa/yard/definitions_loader.rb +320 -48
  49. data/lib/rucoa/yard/type.rb +46 -0
  50. data/lib/rucoa/yard.rb +1 -1
  51. data/lib/rucoa.rb +1 -0
  52. metadata +11 -4
  53. 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
@@ -7,10 +7,7 @@ module Rucoa
7
7
 
8
8
  def call
9
9
  source_store.update(source)
10
- definition_store.update_definitions_defined_in(
11
- source.path,
12
- definitions: source.definitions
13
- )
10
+ definition_store.update_from(source)
14
11
  publish_diagnostics_on(uri)
15
12
  end
16
13
 
@@ -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
@@ -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'
@@ -2,9 +2,9 @@
2
2
 
3
3
  module Rucoa
4
4
  module NodeConcerns
5
- module NameFullQualifiable
5
+ module NameFullyQualifiable
6
6
  # @return [String]
7
- def full_qualified_name
7
+ def fully_qualified_name
8
8
  [
9
9
  name,
10
10
  *each_ancestor(:class, :constant, :module).map(&:name)
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Rucoa
4
4
  module NodeConcerns
5
- autoload :NameFullQualifiable, 'rucoa/node_concerns/name_full_qualifiable'
5
+ autoload :NameFullyQualifiable, 'rucoa/node_concerns/name_fully_qualifiable'
6
6
  end
7
7
  end
@@ -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<String>]
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
- method_full_qualified_names.flat_map do |full_qualified_name|
17
- @definition_store.select_by_full_qualified_name(full_qualified_name)
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 [Array<String>]
78
- def method_full_qualified_names
79
- method_receiver_types.map do |type|
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
- type,
82
- @node.name
83
- ].join(method_kind_symbol)
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 [String, nil]
88
- def method_kind_symbol
89
- return unless @node.is_a?(Nodes::SendNode)
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 nearest_def_full_qualified_name
101
- @node.each_ancestor(:def).first&.full_qualified_name
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
- full_qualified_name = nearest_def_full_qualified_name
107
- return [] unless full_qualified_name
123
+ fully_qualified_name = nearest_def_fully_qualified_name
124
+ return [] unless fully_qualified_name
108
125
 
109
- @definition_store.select_by_full_qualified_name(full_qualified_name).flat_map do |definition|
110
- definition.parameters.select do |parameter|
111
- parameter.name == @node.name
112
- end.flat_map(&:types)
113
- end
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
- method_full_qualified_names.flat_map do |full_qualified_name|
119
- @definition_store.select_by_full_qualified_name(full_qualified_name).flat_map(&:return_types)
120
- end.uniq
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
@@ -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::Parser.call(
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
- each_ancestor(:module, :class).first&.full_qualified_name || 'Object'
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(*types) do |child|
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
@@ -3,7 +3,7 @@
3
3
  module Rucoa
4
4
  module Nodes
5
5
  class CasgnNode < Base
6
- include NodeConcerns::NameFullQualifiable
6
+ include NodeConcerns::NameFullyQualifiable
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,68 @@
2
2
 
3
3
  module Rucoa
4
4
  module Nodes
5
- class ClassNode < ModuleNode
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
@@ -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.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