rucoa 0.9.0 → 0.11.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 +9 -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 +350 -105
- data/lib/rucoa/definitions/base.rb +14 -3
- data/lib/rucoa/definitions/class_definition.rb +14 -64
- 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 +53 -0
- data/lib/rucoa/handler_concerns/diagnostics_publishable.rb +14 -3
- data/lib/rucoa/handlers/base.rb +12 -3
- data/lib/rucoa/handlers/text_document_definition_handler.rb +3 -99
- 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_fully_qualifiable.rb → qualified_name.rb} +2 -2
- data/lib/rucoa/node_concerns.rb +2 -1
- data/lib/rucoa/node_inspector.rb +29 -23
- data/lib/rucoa/nodes/base.rb +22 -6
- data/lib/rucoa/nodes/begin_node.rb +8 -0
- data/lib/rucoa/nodes/casgn_node.rb +1 -1
- data/lib/rucoa/nodes/class_node.rb +2 -1
- data/lib/rucoa/nodes/const_node.rb +33 -15
- data/lib/rucoa/nodes/def_node.rb +2 -2
- data/lib/rucoa/nodes/defs_node.rb +1 -1
- data/lib/rucoa/nodes/module_node.rb +2 -1
- data/lib/rucoa/nodes.rb +2 -1
- data/lib/rucoa/parser.rb +14 -14
- data/lib/rucoa/parser_builder.rb +6 -1
- data/lib/rucoa/position.rb +10 -1
- data/lib/rucoa/range.rb +11 -1
- data/lib/rucoa/rbs/class_definition_mapper.rb +14 -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 +39 -6
- data/lib/rucoa/rubocop/investigator.rb +4 -1
- data/lib/rucoa/server.rb +9 -3
- data/lib/rucoa/source.rb +19 -4
- 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 +76 -0
- data/lib/rucoa/yard/definition_generators/attribute_writer_definition_generator.rb +76 -0
- data/lib/rucoa/yard/definition_generators/base.rb +117 -0
- data/lib/rucoa/yard/definition_generators/class_definition_generator.rb +67 -0
- data/lib/rucoa/yard/definition_generators/constant_assignment_definition_generator.rb +29 -0
- data/lib/rucoa/yard/definition_generators/method_definition_generator.rb +60 -0
- data/lib/rucoa/yard/definition_generators/module_definition_generator.rb +68 -0
- data/lib/rucoa/yard/definition_generators.rb +15 -0
- data/lib/rucoa/yard/definitions_loader.rb +1 -271
- data/lib/rucoa/yard.rb +1 -0
- data/lib/rucoa.rb +4 -2
- metadata +15 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cec8d0284ecf97b03cd43de02d36c16263910dba3c5a1052f73df0bf0fd51f68
|
4
|
+
data.tar.gz: b83c8aad102fbd510a0f7474394ab8cf91cd17976bbc365e188c276789815e9a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3042168fc7a78f71854f96d8367f9f4e1e0c62d4300b4feef36b6596e602b3c40c5150d1d6f0902ab5d7b1015179cdf10c2d1e6beabe68cbf3fa1114f6cdb00e
|
7
|
+
data.tar.gz: 6721bdccd41cb883d6b6ab97a5a990b878e088a7832ccb6c42bcc642ff13f1ab3126d8893a43b47a29295caa0ff14ed4b59bdf5ab0ca95c14a4536dee11eb899
|
data/.rubocop.yml
CHANGED
@@ -32,9 +32,18 @@ RSpec/NamedSubject:
|
|
32
32
|
Security/MarshalLoad:
|
33
33
|
Enabled: false
|
34
34
|
|
35
|
+
Sevencop/AutoloadOrdered:
|
36
|
+
Enabled: true
|
37
|
+
|
35
38
|
Sevencop/HashLiteralOrder:
|
36
39
|
Enabled: true
|
37
40
|
|
41
|
+
Sevencop/MethodDefinitionKeywordArgumentsOrdered:
|
42
|
+
Enabled: true
|
43
|
+
|
44
|
+
Sevencop/MethodDefinitionMultilineArguments:
|
45
|
+
Enabled: true
|
46
|
+
|
38
47
|
Style/Documentation:
|
39
48
|
Enabled: false
|
40
49
|
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
rucoa (0.
|
4
|
+
rucoa (0.11.0)
|
5
5
|
parser
|
6
6
|
rbs
|
7
7
|
rubocop
|
@@ -27,13 +27,13 @@ GEM
|
|
27
27
|
rspec-mocks (~> 3.11.0)
|
28
28
|
rspec-core (3.11.0)
|
29
29
|
rspec-support (~> 3.11.0)
|
30
|
-
rspec-expectations (3.11.
|
30
|
+
rspec-expectations (3.11.1)
|
31
31
|
diff-lcs (>= 1.2.0, < 2.0)
|
32
32
|
rspec-support (~> 3.11.0)
|
33
33
|
rspec-mocks (3.11.1)
|
34
34
|
diff-lcs (>= 1.2.0, < 2.0)
|
35
35
|
rspec-support (~> 3.11.0)
|
36
|
-
rspec-support (3.11.
|
36
|
+
rspec-support (3.11.1)
|
37
37
|
rubocop (1.36.0)
|
38
38
|
json (~> 2.3)
|
39
39
|
parallel (~> 1.10)
|
@@ -46,17 +46,17 @@ GEM
|
|
46
46
|
unicode-display_width (>= 1.4.0, < 3.0)
|
47
47
|
rubocop-ast (1.21.0)
|
48
48
|
parser (>= 3.1.1.0)
|
49
|
-
rubocop-performance (1.
|
49
|
+
rubocop-performance (1.15.0)
|
50
50
|
rubocop (>= 1.7.0, < 2.0)
|
51
51
|
rubocop-ast (>= 0.4.0)
|
52
52
|
rubocop-rake (0.6.0)
|
53
53
|
rubocop (~> 1.0)
|
54
|
-
rubocop-rspec (2.
|
55
|
-
rubocop (~> 1.
|
54
|
+
rubocop-rspec (2.13.2)
|
55
|
+
rubocop (~> 1.33)
|
56
56
|
ruby-progressbar (1.11.0)
|
57
|
-
sevencop (0.
|
57
|
+
sevencop (0.13.0)
|
58
58
|
rubocop
|
59
|
-
unicode-display_width (2.
|
59
|
+
unicode-display_width (2.3.0)
|
60
60
|
webrick (1.7.0)
|
61
61
|
yard (0.9.28)
|
62
62
|
webrick (~> 1.7.0)
|
data/data/definitions_ruby_3_1
CHANGED
Binary file
|
data/lib/rucoa/configuration.rb
CHANGED
@@ -3,22 +3,29 @@
|
|
3
3
|
module Rucoa
|
4
4
|
class DefinitionStore
|
5
5
|
def initialize
|
6
|
-
@
|
7
|
-
@
|
6
|
+
@definition_by_qualified_name = {}
|
7
|
+
@qualified_names_by_uri = ::Hash.new { |hash, key| hash[key] = [] }
|
8
|
+
end
|
9
|
+
|
10
|
+
# @return [String]
|
11
|
+
def inspect
|
12
|
+
"#<#{self.class} definitions_count=#{@definition_by_qualified_name.count}>"
|
8
13
|
end
|
9
14
|
|
10
15
|
# @param definitions [Array<Rucoa::Definition::Base>]
|
11
16
|
# @return [void]
|
12
17
|
def bulk_add(definitions)
|
13
|
-
definitions.
|
14
|
-
|
15
|
-
|
18
|
+
definitions.group_by(&:qualified_name).each_value.map do |grouped_definitions|
|
19
|
+
grouped_definitions.reduce(:merge!)
|
20
|
+
end.each do |definition|
|
21
|
+
@qualified_names_by_uri[definition.location.uri] << definition.qualified_name if definition.location
|
22
|
+
@definition_by_qualified_name[definition.qualified_name] = definition
|
16
23
|
end
|
17
24
|
end
|
18
25
|
|
19
26
|
# @param source [Rucoa::Source]
|
20
27
|
# @return [void]
|
21
|
-
# @example resolves super class name
|
28
|
+
# @example resolves super class name from definitions
|
22
29
|
# definition_store = Rucoa::DefinitionStore.new
|
23
30
|
# foo = Rucoa::Source.new(
|
24
31
|
# content: <<~RUBY,
|
@@ -40,115 +47,297 @@ module Rucoa
|
|
40
47
|
# uri: 'file:///path/to/a/bar.rb',
|
41
48
|
# )
|
42
49
|
# definition_store.update_from(bar)
|
43
|
-
# definition = definition_store.
|
44
|
-
# expect(definition.
|
50
|
+
# definition = definition_store.find_definition_by_qualified_name('A::Bar')
|
51
|
+
# expect(definition.super_class_qualified_name).to eq('A::Foo')
|
52
|
+
# @example resolves included module names from definitions
|
53
|
+
# definition_store = Rucoa::DefinitionStore.new
|
54
|
+
# foo = Rucoa::Source.new(
|
55
|
+
# content: <<~RUBY,
|
56
|
+
# module A
|
57
|
+
# module Foo
|
58
|
+
# end
|
59
|
+
# end
|
60
|
+
# RUBY
|
61
|
+
# uri: 'file:///path/to/a/foo.rb',
|
62
|
+
# )
|
63
|
+
# definition_store.update_from(foo)
|
64
|
+
# bar = Rucoa::Source.new(
|
65
|
+
# content: <<~RUBY,
|
66
|
+
# module A
|
67
|
+
# class Bar
|
68
|
+
# include Foo
|
69
|
+
# end
|
70
|
+
# end
|
71
|
+
# RUBY
|
72
|
+
# uri: 'file:///path/to/a/bar.rb',
|
73
|
+
# )
|
74
|
+
# definition_store.update_from(bar)
|
75
|
+
# definition = definition_store.find_definition_by_qualified_name('A::Bar')
|
76
|
+
# expect(definition.included_module_qualified_names).to eq(%w[A::Foo])
|
45
77
|
def update_from(source)
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
source.definitions.group_by(&:source_path).each do |source_path, definitions|
|
50
|
-
@fully_qualified_names_by_uri["file://#{source_path}"] += definitions.map(&:fully_qualified_name)
|
51
|
-
definitions.each do |definition|
|
52
|
-
@definition_by_full_qualified_name[definition.fully_qualified_name] = definition
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
source.definitions.each do |definition|
|
57
|
-
next unless definition.is_a?(Definitions::ClassDefinition)
|
58
|
-
next if definition.super_class_resolved?
|
59
|
-
|
60
|
-
definition.super_class_fully_qualified_name = resolve_super_class_of(definition)
|
61
|
-
end
|
78
|
+
delete_definitions_in(source)
|
79
|
+
add_definitions_in(source)
|
80
|
+
resolve_constants_in(source)
|
62
81
|
end
|
63
82
|
|
64
|
-
# @param
|
83
|
+
# @param qualified_name [String]
|
65
84
|
# @return [Rucoa::Definitions::Base, nil]
|
66
|
-
def
|
67
|
-
@
|
85
|
+
def find_definition_by_qualified_name(qualified_name)
|
86
|
+
@definition_by_qualified_name[qualified_name]
|
68
87
|
end
|
69
88
|
|
70
89
|
# @param method_name [String]
|
71
90
|
# @param namespace [String]
|
72
91
|
# @param singleton [Boolean]
|
73
92
|
# @return [Rucoa::Definition::MethodDefinition, nil]
|
74
|
-
# @example
|
93
|
+
# @example Supports inheritance
|
94
|
+
# source = Rucoa::Source.new(
|
95
|
+
# content: <<~RUBY,
|
96
|
+
# class A
|
97
|
+
# def foo
|
98
|
+
# end
|
99
|
+
# end
|
100
|
+
#
|
101
|
+
# class B < A
|
102
|
+
# end
|
103
|
+
# RUBY
|
104
|
+
# uri: 'file:///path/to/example.rb'
|
105
|
+
# )
|
75
106
|
# definition_store = Rucoa::DefinitionStore.new
|
76
|
-
# definition_store.
|
107
|
+
# definition_store.update_from(source)
|
77
108
|
# subject = definition_store.find_method_definition_by(
|
78
|
-
# method_name: '
|
79
|
-
# namespace: '
|
80
|
-
# singleton:
|
109
|
+
# method_name: 'foo',
|
110
|
+
# namespace: 'B',
|
111
|
+
# singleton: false
|
81
112
|
# )
|
82
|
-
# expect(subject.
|
83
|
-
|
84
|
-
|
113
|
+
# expect(subject.qualified_name).to eq('A#foo')
|
114
|
+
# @example supports `include`
|
115
|
+
# source = Rucoa::Source.new(
|
116
|
+
# content: <<~RUBY,
|
117
|
+
# module A
|
118
|
+
# def foo
|
119
|
+
# end
|
120
|
+
# end
|
121
|
+
#
|
122
|
+
# class B
|
123
|
+
# include A
|
124
|
+
# end
|
125
|
+
# RUBY
|
126
|
+
# uri: 'file:///path/to/example.rb'
|
127
|
+
# )
|
128
|
+
# definition_store = Rucoa::DefinitionStore.new
|
129
|
+
# definition_store.update_from(source)
|
130
|
+
# subject = definition_store.find_method_definition_by(
|
131
|
+
# method_name: 'foo',
|
132
|
+
# namespace: 'B',
|
133
|
+
# singleton: false
|
134
|
+
# )
|
135
|
+
# expect(subject.qualified_name).to eq('A#foo')
|
136
|
+
# @example supports `prepend`
|
137
|
+
# source = Rucoa::Source.new(
|
138
|
+
# content: <<~RUBY,
|
139
|
+
# module A
|
140
|
+
# def foo
|
141
|
+
# end
|
142
|
+
# end
|
143
|
+
#
|
144
|
+
# class B
|
145
|
+
# prepend A
|
146
|
+
#
|
147
|
+
# def foo
|
148
|
+
# end
|
149
|
+
# end
|
150
|
+
# RUBY
|
151
|
+
# uri: 'file:///path/to/example.rb'
|
152
|
+
# )
|
153
|
+
# definition_store = Rucoa::DefinitionStore.new
|
154
|
+
# definition_store.update_from(source)
|
155
|
+
# subject = definition_store.find_method_definition_by(
|
156
|
+
# method_name: 'foo',
|
157
|
+
# namespace: 'B',
|
158
|
+
# singleton: false
|
159
|
+
# )
|
160
|
+
# expect(subject.qualified_name).to eq('A#foo')
|
161
|
+
def find_method_definition_by(
|
162
|
+
method_name:,
|
163
|
+
namespace:,
|
164
|
+
singleton: false
|
165
|
+
)
|
166
|
+
definition = find_definition_by_qualified_name(namespace)
|
85
167
|
return unless definition
|
86
168
|
|
87
|
-
|
88
|
-
namespace,
|
89
|
-
*ancestor_definitions_of(definition).map(&:fully_qualified_name)
|
90
|
-
].find do |fully_qualified_name|
|
169
|
+
ancestors_of(definition).find do |ancestor|
|
91
170
|
method_marker = singleton ? '.' : '#'
|
92
|
-
|
93
|
-
|
171
|
+
qualified_method_name = [
|
172
|
+
ancestor.qualified_name,
|
94
173
|
method_marker,
|
95
174
|
method_name
|
96
175
|
].join
|
97
|
-
|
98
|
-
break
|
176
|
+
method_definition = find_definition_by_qualified_name(qualified_method_name)
|
177
|
+
break method_definition if method_definition
|
99
178
|
end
|
100
179
|
end
|
101
180
|
|
102
181
|
# @param type [String]
|
103
182
|
# @return [Array<Rucoa::Definitions::MethodDefinition>]
|
104
|
-
# @example
|
183
|
+
# @example supports simple instance method
|
184
|
+
# source = Rucoa::Source.new(
|
185
|
+
# content: <<~RUBY,
|
186
|
+
# class A
|
187
|
+
# def foo
|
188
|
+
# end
|
189
|
+
# end
|
190
|
+
# RUBY
|
191
|
+
# uri: 'file:///path/to/example.rb'
|
192
|
+
# )
|
193
|
+
# definition_store = Rucoa::DefinitionStore.new
|
194
|
+
# definition_store.update_from(source)
|
195
|
+
# subject = definition_store.instance_method_definitions_of('A')
|
196
|
+
# expect(subject.map(&:qualified_name)).to eq(%w[A#foo])
|
197
|
+
# @example supports inheritance
|
198
|
+
# source = Rucoa::Source.new(
|
199
|
+
# content: <<~RUBY,
|
200
|
+
# class A
|
201
|
+
# def foo
|
202
|
+
# end
|
203
|
+
# end
|
204
|
+
#
|
205
|
+
# class B < A
|
206
|
+
# end
|
207
|
+
# RUBY
|
208
|
+
# uri: 'file:///path/to/example.rb'
|
209
|
+
# )
|
210
|
+
# definition_store = Rucoa::DefinitionStore.new
|
211
|
+
# definition_store.update_from(source)
|
212
|
+
# subject = definition_store.instance_method_definitions_of('B')
|
213
|
+
# expect(subject.map(&:qualified_name)).to eq(%w[A#foo])
|
214
|
+
# @example supports `include`
|
215
|
+
# source = Rucoa::Source.new(
|
216
|
+
# content: <<~RUBY,
|
217
|
+
# module A
|
218
|
+
# def foo
|
219
|
+
# end
|
220
|
+
# end
|
221
|
+
#
|
222
|
+
# class B
|
223
|
+
# include A
|
224
|
+
# end
|
225
|
+
# RUBY
|
226
|
+
# uri: 'file:///path/to/example.rb'
|
227
|
+
# )
|
105
228
|
# definition_store = Rucoa::DefinitionStore.new
|
106
|
-
# definition_store.
|
107
|
-
# subject = definition_store.instance_method_definitions_of('
|
108
|
-
# expect(subject.map(&:
|
109
|
-
# @example
|
229
|
+
# definition_store.update_from(source)
|
230
|
+
# subject = definition_store.instance_method_definitions_of('B')
|
231
|
+
# expect(subject.map(&:qualified_name)).to eq(%w[A#foo])
|
232
|
+
# @example supports `prepend`
|
233
|
+
# source = Rucoa::Source.new(
|
234
|
+
# content: <<~RUBY,
|
235
|
+
# module A
|
236
|
+
# def foo
|
237
|
+
# end
|
238
|
+
# end
|
239
|
+
#
|
240
|
+
# class B
|
241
|
+
# prepend A
|
242
|
+
#
|
243
|
+
# def foo
|
244
|
+
# end
|
245
|
+
# end
|
246
|
+
# RUBY
|
247
|
+
# uri: 'file:///path/to/example.rb'
|
248
|
+
# )
|
110
249
|
# definition_store = Rucoa::DefinitionStore.new
|
111
|
-
# definition_store.
|
112
|
-
# subject = definition_store.instance_method_definitions_of('
|
113
|
-
# expect(subject.map(&:
|
250
|
+
# definition_store.update_from(source)
|
251
|
+
# subject = definition_store.instance_method_definitions_of('B')
|
252
|
+
# expect(subject.map(&:qualified_name)).to eq(%w[A#foo])
|
114
253
|
def instance_method_definitions_of(type)
|
115
254
|
singleton_class_name = singleton_class_name_from(type)
|
116
255
|
return singleton_method_definitions_of(singleton_class_name) if singleton_class_name
|
117
256
|
|
118
|
-
class_or_module_definition =
|
257
|
+
class_or_module_definition = find_definition_by_qualified_name(type)
|
119
258
|
return [] unless class_or_module_definition
|
120
259
|
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
definitions.select do |definition|
|
127
|
-
definition.namespace == fully_qualified_type_name
|
260
|
+
method_definitions = self.method_definitions
|
261
|
+
ancestors_of(class_or_module_definition).flat_map do |ancestor|
|
262
|
+
method_definitions.select do |method_definition|
|
263
|
+
method_definition.namespace == ancestor.qualified_name &&
|
264
|
+
method_definition.instance_method?
|
128
265
|
end
|
129
|
-
end
|
266
|
+
end.uniq(&:method_name)
|
130
267
|
end
|
131
268
|
|
132
269
|
# @param type [String]
|
133
270
|
# @return [Array<Rucoa::Definitions::MethodDefinition>]
|
134
|
-
# @example
|
271
|
+
# @example supports simple singleton method
|
272
|
+
# source = Rucoa::Source.new(
|
273
|
+
# content: <<~RUBY,
|
274
|
+
# class A
|
275
|
+
# def self.foo
|
276
|
+
# end
|
277
|
+
# end
|
278
|
+
# RUBY
|
279
|
+
# uri: 'file:///path/to/example.rb'
|
280
|
+
# )
|
281
|
+
# definition_store = Rucoa::DefinitionStore.new
|
282
|
+
# definition_store.update_from(source)
|
283
|
+
# subject = definition_store.singleton_method_definitions_of('A')
|
284
|
+
# expect(subject.map(&:qualified_name)).to include('A.foo')
|
285
|
+
# @example supports super class's singleton method
|
286
|
+
# source = Rucoa::Source.new(
|
287
|
+
# content: <<~RUBY,
|
288
|
+
# class A
|
289
|
+
# def self.foo
|
290
|
+
# end
|
291
|
+
# end
|
292
|
+
#
|
293
|
+
# class B < A
|
294
|
+
# end
|
295
|
+
# RUBY
|
296
|
+
# uri: 'file:///path/to/example.rb'
|
297
|
+
# )
|
135
298
|
# definition_store = Rucoa::DefinitionStore.new
|
136
|
-
# definition_store.
|
137
|
-
# subject = definition_store.singleton_method_definitions_of('
|
138
|
-
# expect(subject.map(&:
|
299
|
+
# definition_store.update_from(source)
|
300
|
+
# subject = definition_store.singleton_method_definitions_of('B')
|
301
|
+
# expect(subject.map(&:qualified_name)).to include('A.foo')
|
302
|
+
# @example supports extended module's instance method
|
303
|
+
# source = Rucoa::Source.new(
|
304
|
+
# content: <<~RUBY,
|
305
|
+
# module A
|
306
|
+
# def foo
|
307
|
+
# end
|
308
|
+
# end
|
309
|
+
#
|
310
|
+
# class B
|
311
|
+
# def self.foo
|
312
|
+
# end
|
313
|
+
# end
|
314
|
+
#
|
315
|
+
# class C < B
|
316
|
+
# extend A
|
317
|
+
# end
|
318
|
+
# RUBY
|
319
|
+
# uri: 'file:///path/to/example.rb'
|
320
|
+
# )
|
321
|
+
# definition_store = Rucoa::DefinitionStore.new
|
322
|
+
# definition_store.update_from(source)
|
323
|
+
# subject = definition_store.singleton_method_definitions_of('C')
|
324
|
+
# expect(subject.map(&:qualified_name)).to eq(%w[A#foo])
|
139
325
|
def singleton_method_definitions_of(type)
|
140
|
-
class_or_module_definition =
|
326
|
+
class_or_module_definition = find_definition_by_qualified_name(type)
|
141
327
|
return [] unless class_or_module_definition
|
142
328
|
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
329
|
+
method_definitions = self.method_definitions
|
330
|
+
ancestors_of(class_or_module_definition).flat_map do |ancestor|
|
331
|
+
method_definitions.select do |method_definition|
|
332
|
+
method_definition.namespace == ancestor.qualified_name &&
|
333
|
+
method_definition.singleton_method?
|
334
|
+
end + ancestor.extended_module_qualified_names.flat_map do |extended_module_qualified_name|
|
335
|
+
method_definitions.select do |method_definition|
|
336
|
+
method_definition.namespace == extended_module_qualified_name &&
|
337
|
+
method_definition.instance_method?
|
338
|
+
end
|
150
339
|
end
|
151
|
-
end
|
340
|
+
end.uniq(&:method_name)
|
152
341
|
end
|
153
342
|
|
154
343
|
# @param namespace [String]
|
@@ -159,42 +348,79 @@ module Rucoa
|
|
159
348
|
end
|
160
349
|
end
|
161
350
|
|
351
|
+
# @todo Search ancestors.
|
352
|
+
# @param unqualified_name [Rucoa::UnqualifiedName]
|
353
|
+
# @return [String]
|
354
|
+
def resolve_constant(unqualified_name)
|
355
|
+
(
|
356
|
+
unqualified_name.module_nesting.map do |prefix|
|
357
|
+
"#{prefix}::#{unqualified_name.chained_name}"
|
358
|
+
end + [unqualified_name.chained_name]
|
359
|
+
).find do |candidate|
|
360
|
+
find_definition_by_qualified_name(candidate)
|
361
|
+
end || unqualified_name.chained_name
|
362
|
+
end
|
363
|
+
|
162
364
|
private
|
163
365
|
|
164
366
|
# @param source [Rucoa::Source]
|
165
367
|
# @return [void]
|
166
|
-
def
|
167
|
-
@
|
168
|
-
@
|
368
|
+
def delete_definitions_in(source)
|
369
|
+
@qualified_names_by_uri[source.uri].each do |qualified_name|
|
370
|
+
@definition_by_qualified_name.delete(qualified_name)
|
169
371
|
end
|
170
|
-
@
|
372
|
+
@qualified_names_by_uri.delete(source.uri)
|
171
373
|
end
|
172
374
|
|
173
375
|
# @param type [String]
|
174
376
|
# @return [String, nil]
|
175
377
|
def singleton_class_name_from(type)
|
176
|
-
type[/singleton<(\w+)>/, 1]
|
378
|
+
type[/singleton<([\w:]+)>/, 1]
|
379
|
+
end
|
380
|
+
|
381
|
+
# @param definition [Rucoa::Definitions::Class, Rucoa::Definitions::Module]
|
382
|
+
# @return [Array<Rucoa::Definitions::Class>] The classes and modules that are traced in method search (as `Module#ancestors` in Ruby)
|
383
|
+
def ancestors_of(definition)
|
384
|
+
if definition.is_a?(Rucoa::Definitions::ClassDefinition)
|
385
|
+
[definition, *super_class_definitions_of(definition)]
|
386
|
+
else
|
387
|
+
[definition]
|
388
|
+
end.flat_map do |base|
|
389
|
+
module_ancestors_of(base)
|
390
|
+
end
|
177
391
|
end
|
178
392
|
|
179
|
-
# @param
|
180
|
-
# @return [Array<Rucoa::Definitions::Class>]
|
181
|
-
def
|
182
|
-
|
393
|
+
# @param definition [Rucoa::Definitions::Class, Rucoa::Definitions::Module]
|
394
|
+
# @return [Array<Rucoa::Definitions::Class, Rucoa::Definitions::Module>] An array of prepended, itself, and included definitions
|
395
|
+
def module_ancestors_of(definition)
|
396
|
+
[
|
397
|
+
*definition.prepended_module_qualified_names.filter_map do |qualified_name|
|
398
|
+
find_definition_by_qualified_name(qualified_name)
|
399
|
+
end.reverse,
|
400
|
+
definition,
|
401
|
+
*definition.included_module_qualified_names.filter_map do |qualified_name|
|
402
|
+
find_definition_by_qualified_name(qualified_name)
|
403
|
+
end.reverse
|
404
|
+
]
|
405
|
+
end
|
183
406
|
|
407
|
+
# @param definition [Rucoa::Definitions::Class]
|
408
|
+
# @return [Array<Rucoa::Definitions::Class>] super "class"es (not including modules) in closest-first order
|
409
|
+
def super_class_definitions_of(definition)
|
184
410
|
result = []
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
break unless class_definition
|
411
|
+
while (super_class_qualified_name = definition.super_class_qualified_name)
|
412
|
+
super_definition = find_definition_by_qualified_name(super_class_qualified_name)
|
413
|
+
break unless super_definition
|
189
414
|
|
190
|
-
result <<
|
415
|
+
result << super_definition
|
416
|
+
definition = super_definition
|
191
417
|
end
|
192
418
|
result
|
193
419
|
end
|
194
420
|
|
195
421
|
# @return [Array<Rucoa::Definitions::Base>]
|
196
422
|
def definitions
|
197
|
-
@
|
423
|
+
@definition_by_qualified_name.values
|
198
424
|
end
|
199
425
|
|
200
426
|
# @return [Array<Rucoa::Definition::MethodDefinition>]
|
@@ -202,29 +428,48 @@ module Rucoa
|
|
202
428
|
definitions.grep(Definitions::MethodDefinition)
|
203
429
|
end
|
204
430
|
|
205
|
-
# @return [Array<Rucoa::Definition::MethodDefinition>]
|
206
|
-
def instance_method_definitions
|
207
|
-
method_definitions.select(&:instance_method?)
|
208
|
-
end
|
209
|
-
|
210
|
-
# @return [Array<Rucoa::Definition::MethodDefinition>]
|
211
|
-
def singleton_method_definitions
|
212
|
-
method_definitions.select(&:singleton_method?)
|
213
|
-
end
|
214
|
-
|
215
431
|
# @return [Array<Rucoa::Definition::ConstantDefinition>]
|
216
432
|
def constant_definitions
|
217
433
|
definitions.grep(Definitions::ConstantDefinition)
|
218
434
|
end
|
219
435
|
|
220
|
-
# @param
|
221
|
-
# @return [
|
222
|
-
def
|
223
|
-
|
436
|
+
# @param source [Rucoa::Source]
|
437
|
+
# @return [void]
|
438
|
+
def add_definitions_in(source)
|
439
|
+
source.definitions.group_by do |definition|
|
440
|
+
definition.location.uri
|
441
|
+
end.each do |uri, definitions|
|
442
|
+
@qualified_names_by_uri[uri] += definitions.map(&:qualified_name)
|
443
|
+
definitions.each do |definition|
|
444
|
+
@definition_by_qualified_name[definition.qualified_name] = definition
|
445
|
+
end
|
446
|
+
end
|
447
|
+
end
|
448
|
+
|
449
|
+
# @param source [Rucoa::Source]
|
450
|
+
# @return [void]
|
451
|
+
def resolve_constants_in(source)
|
452
|
+
source.definitions.each do |definition|
|
453
|
+
next unless definition.is_a?(Definitions::ClassDefinition)
|
454
|
+
|
455
|
+
definition.super_class_qualified_name = resolve_constant(definition.super_class_unqualified_name)
|
456
|
+
definition.super_class_unqualified_name = nil
|
457
|
+
|
458
|
+
definition.extended_module_qualified_names = definition.extended_module_unqualified_names.map do |unqualified_name|
|
459
|
+
resolve_constant(unqualified_name)
|
460
|
+
end
|
461
|
+
definition.extended_module_unqualified_names = []
|
224
462
|
|
225
|
-
|
226
|
-
|
227
|
-
|
463
|
+
definition.included_module_qualified_names = definition.included_module_unqualified_names.map do |unqualified_name|
|
464
|
+
resolve_constant(unqualified_name)
|
465
|
+
end
|
466
|
+
definition.included_module_unqualified_names = []
|
467
|
+
|
468
|
+
definition.prepended_module_qualified_names = definition.prepended_module_unqualified_names.map do |unqualified_name|
|
469
|
+
resolve_constant(unqualified_name)
|
470
|
+
end
|
471
|
+
definition.prepended_module_unqualified_names = []
|
472
|
+
end
|
228
473
|
end
|
229
474
|
end
|
230
475
|
end
|
@@ -3,9 +3,20 @@
|
|
3
3
|
module Rucoa
|
4
4
|
module Definitions
|
5
5
|
class Base
|
6
|
-
# @return [String]
|
7
|
-
|
8
|
-
|
6
|
+
# @return [String, nil]
|
7
|
+
attr_reader :description
|
8
|
+
|
9
|
+
# @return [Rucoa::Location, nil]
|
10
|
+
attr_accessor :location
|
11
|
+
|
12
|
+
# @param description [String, nil]
|
13
|
+
# @param location [Rucoa::Location, nil]
|
14
|
+
def initialize(
|
15
|
+
description:,
|
16
|
+
location:
|
17
|
+
)
|
18
|
+
@description = description
|
19
|
+
@location = location
|
9
20
|
end
|
10
21
|
end
|
11
22
|
end
|