rucoa 0.9.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.
Files changed (56) 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 +216 -83
  7. data/lib/rucoa/definitions/base.rb +14 -3
  8. data/lib/rucoa/definitions/class_definition.rb +14 -64
  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/text_document_definition_handler.rb +3 -99
  16. data/lib/rucoa/handlers/text_document_hover_handler.rb +21 -13
  17. data/lib/rucoa/handlers/text_document_selection_range_handler.rb +8 -2
  18. data/lib/rucoa/location.rb +37 -0
  19. data/lib/rucoa/node_concerns/body.rb +24 -0
  20. data/lib/rucoa/node_concerns/{name_fully_qualifiable.rb → qualified_name.rb} +2 -2
  21. data/lib/rucoa/node_concerns.rb +2 -1
  22. data/lib/rucoa/node_inspector.rb +17 -22
  23. data/lib/rucoa/nodes/base.rb +22 -6
  24. data/lib/rucoa/nodes/begin_node.rb +8 -0
  25. data/lib/rucoa/nodes/casgn_node.rb +1 -1
  26. data/lib/rucoa/nodes/class_node.rb +2 -1
  27. data/lib/rucoa/nodes/const_node.rb +33 -15
  28. data/lib/rucoa/nodes/def_node.rb +2 -2
  29. data/lib/rucoa/nodes/defs_node.rb +1 -1
  30. data/lib/rucoa/nodes/module_node.rb +2 -1
  31. data/lib/rucoa/nodes.rb +2 -1
  32. data/lib/rucoa/parser.rb +14 -14
  33. data/lib/rucoa/parser_builder.rb +6 -1
  34. data/lib/rucoa/position.rb +10 -1
  35. data/lib/rucoa/range.rb +11 -1
  36. data/lib/rucoa/rbs/class_definition_mapper.rb +13 -28
  37. data/lib/rucoa/rbs/constant_definition_mapper.rb +12 -6
  38. data/lib/rucoa/rbs/method_definition_mapper.rb +12 -6
  39. data/lib/rucoa/rbs/module_definition_mapper.rb +34 -6
  40. data/lib/rucoa/rubocop/investigator.rb +4 -1
  41. data/lib/rucoa/server.rb +8 -2
  42. data/lib/rucoa/source.rb +19 -4
  43. data/lib/rucoa/unqualified_name.rb +9 -0
  44. data/lib/rucoa/version.rb +1 -1
  45. data/lib/rucoa/yard/definition_generators/attribute_reader_definition_generator.rb +60 -0
  46. data/lib/rucoa/yard/definition_generators/attribute_writer_definition_generator.rb +60 -0
  47. data/lib/rucoa/yard/definition_generators/base.rb +117 -0
  48. data/lib/rucoa/yard/definition_generators/class_definition_generator.rb +66 -0
  49. data/lib/rucoa/yard/definition_generators/constant_assignment_definition_generator.rb +29 -0
  50. data/lib/rucoa/yard/definition_generators/method_definition_generator.rb +47 -0
  51. data/lib/rucoa/yard/definition_generators/module_definition_generator.rb +62 -0
  52. data/lib/rucoa/yard/definition_generators.rb +15 -0
  53. data/lib/rucoa/yard/definitions_loader.rb +1 -271
  54. data/lib/rucoa/yard.rb +1 -0
  55. data/lib/rucoa.rb +4 -2
  56. metadata +15 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 237fa68185426d66437c43fc2a3f34f7f85ee7309eb4ed6bb6ce4e31b5dfbb6e
4
- data.tar.gz: e9f96daf65c7ccef564b2e06756497fd4d98bd946911487ca2fdd32740436e4b
3
+ metadata.gz: 3344309136313473ea6d4fecd4c57745fb4bc8fc1404c40f7126c0a5d5eef440
4
+ data.tar.gz: 1bfb57eee21c860f54b8c82452717d987a31bc977a5a7853b6e08b0d486fd5ac
5
5
  SHA512:
6
- metadata.gz: 3698e9db246d46ce64314df9b4a7418278a6e9f65cc2e80dfece624b547c5ab238af42b456370d1096e872f6e30aefdb132b5b2bd435ec03d1e6cccdac0a908a
7
- data.tar.gz: 5088d4dcc1fa5ad6e053a155246da87602071fa8283b4f42e1b4e9040b222be5f82622343ad2467b5cdf8003b02293e70ea8d391dc99f478ee36a1389311a9d4
6
+ metadata.gz: 4e9efaf6fd608590febfdc450ba487306d35832196f026a77e6ce8b314b78f477a1a79179637153a3977be407ab0f7079ff8bdb23611a0ea2e0f89681bb9637d
7
+ data.tar.gz: cef07b36f534e390a977f694bf5ce97010b14fce34b990b19742682112a741b17914750e1c8de2e881da03620e8d01bce5d0014bc284b1afc725a0de91a8b88b
data/.rubocop.yml CHANGED
@@ -32,9 +32,15 @@ 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/MethodDefinitionMultilineArguments:
42
+ Enabled: true
43
+
38
44
  Style/Documentation:
39
45
  Enabled: false
40
46
 
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rucoa (0.9.0)
4
+ rucoa (0.10.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.0)
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.0)
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.14.3)
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.12.1)
55
- rubocop (~> 1.31)
54
+ rubocop-rspec (2.13.2)
55
+ rubocop (~> 1.33)
56
56
  ruby-progressbar (1.11.0)
57
- sevencop (0.10.0)
57
+ sevencop (0.12.1)
58
58
  rubocop
59
- unicode-display_width (2.2.0)
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)
Binary file
@@ -148,7 +148,10 @@ module Rucoa
148
148
  # @param keys [Array<String>]
149
149
  # @param default [Object]
150
150
  # @return [Object]
151
- def fetch(*keys, default:)
151
+ def fetch(
152
+ *keys,
153
+ default:
154
+ )
152
155
  value = @settings.dig(*keys)
153
156
  if value.nil?
154
157
  default
@@ -3,22 +3,29 @@
3
3
  module Rucoa
4
4
  class DefinitionStore
5
5
  def initialize
6
- @definition_by_full_qualified_name = {}
7
- @fully_qualified_names_by_uri = ::Hash.new { |hash, key| hash[key] = [] }
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.each do |definition|
14
- @fully_qualified_names_by_uri["file://#{definition.source_path}"] << definition.fully_qualified_name
15
- @definition_by_full_qualified_name[definition.fully_qualified_name] = definition
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 correctly by using existent definitions
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,62 +47,134 @@ module Rucoa
40
47
  # uri: 'file:///path/to/a/bar.rb',
41
48
  # )
42
49
  # definition_store.update_from(bar)
43
- # definition = definition_store.find_definition_by_fully_qualified_name('A::Bar')
44
- # expect(definition.super_class_fully_qualified_name).to eq('A::Foo')
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
- delete_definitions_about(source)
47
-
48
- # Need to store definitions before super class resolution.
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 fully_qualified_name [String]
83
+ # @param qualified_name [String]
65
84
  # @return [Rucoa::Definitions::Base, nil]
66
- def find_definition_by_fully_qualified_name(fully_qualified_name)
67
- @definition_by_full_qualified_name[fully_qualified_name]
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 has the ability to find `IO.write` from `File.write`
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.bulk_add(Rucoa::DefinitionArchiver.load)
107
+ # definition_store.update_from(source)
77
108
  # subject = definition_store.find_method_definition_by(
78
- # method_name: 'write',
79
- # namespace: 'File',
80
- # singleton: true
109
+ # method_name: 'foo',
110
+ # namespace: 'B',
111
+ # singleton: false
81
112
  # )
82
- # expect(subject.fully_qualified_name).to eq('IO.write')
83
- def find_method_definition_by(method_name:, namespace:, singleton: false)
84
- definition = find_definition_by_fully_qualified_name(namespace)
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
- fully_qualified_method_name = [
93
- fully_qualified_name,
171
+ qualified_method_name = [
172
+ ancestor.qualified_name,
94
173
  method_marker,
95
174
  method_name
96
175
  ].join
97
- definition = find_definition_by_fully_qualified_name(fully_qualified_method_name)
98
- break definition if definition
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
 
@@ -105,26 +184,23 @@ module Rucoa
105
184
  # definition_store = Rucoa::DefinitionStore.new
106
185
  # definition_store.bulk_add(Rucoa::DefinitionArchiver.load)
107
186
  # subject = definition_store.instance_method_definitions_of('File')
108
- # expect(subject.map(&:fully_qualified_name)).to include('IO#raw')
187
+ # expect(subject.map(&:qualified_name)).to include('IO#raw')
109
188
  # @example responds to `singleton<File>`
110
189
  # definition_store = Rucoa::DefinitionStore.new
111
190
  # definition_store.bulk_add(Rucoa::DefinitionArchiver.load)
112
191
  # subject = definition_store.instance_method_definitions_of('singleton<File>')
113
- # expect(subject.map(&:fully_qualified_name)).to include('IO.write')
192
+ # expect(subject.map(&:qualified_name)).to include('IO.write')
114
193
  def instance_method_definitions_of(type)
115
194
  singleton_class_name = singleton_class_name_from(type)
116
195
  return singleton_method_definitions_of(singleton_class_name) if singleton_class_name
117
196
 
118
- class_or_module_definition = find_definition_by_fully_qualified_name(type)
197
+ class_or_module_definition = find_definition_by_qualified_name(type)
119
198
  return [] unless class_or_module_definition
120
199
 
121
- definitions = instance_method_definitions
122
- [
123
- class_or_module_definition,
124
- *ancestor_definitions_of(class_or_module_definition)
125
- ].map(&:fully_qualified_name).flat_map do |fully_qualified_type_name|
126
- definitions.select do |definition|
127
- definition.namespace == fully_qualified_type_name
200
+ method_definitions = instance_method_definitions
201
+ ancestors_of(class_or_module_definition).flat_map do |ancestor|
202
+ method_definitions.select do |method_definition|
203
+ method_definition.namespace == ancestor.qualified_name
128
204
  end
129
205
  end
130
206
  end
@@ -135,18 +211,15 @@ module Rucoa
135
211
  # definition_store = Rucoa::DefinitionStore.new
136
212
  # definition_store.bulk_add(Rucoa::DefinitionArchiver.load)
137
213
  # subject = definition_store.singleton_method_definitions_of('File')
138
- # expect(subject.map(&:fully_qualified_name)).to include('IO.write')
214
+ # expect(subject.map(&:qualified_name)).to include('IO.write')
139
215
  def singleton_method_definitions_of(type)
140
- class_or_module_definition = find_definition_by_fully_qualified_name(type)
216
+ class_or_module_definition = find_definition_by_qualified_name(type)
141
217
  return [] unless class_or_module_definition
142
218
 
143
- definitions = singleton_method_definitions
144
- [
145
- class_or_module_definition,
146
- *ancestor_definitions_of(class_or_module_definition)
147
- ].map(&:fully_qualified_name).flat_map do |fully_qualified_type_name|
148
- definitions.select do |definition|
149
- definition.namespace == fully_qualified_type_name
219
+ method_definitions = singleton_method_definitions
220
+ ancestors_of(class_or_module_definition).flat_map do |ancestor|
221
+ method_definitions.select do |method_definition|
222
+ method_definition.namespace == ancestor.qualified_name
150
223
  end
151
224
  end
152
225
  end
@@ -159,15 +232,27 @@ module Rucoa
159
232
  end
160
233
  end
161
234
 
235
+ # @param unqualified_name [Rucoa::UnqualifiedName]
236
+ # @return [String]
237
+ def resolve_constant(unqualified_name)
238
+ (
239
+ unqualified_name.module_nesting.map do |prefix|
240
+ "#{prefix}::#{unqualified_name.chained_name}"
241
+ end + [unqualified_name.chained_name]
242
+ ).find do |candidate|
243
+ find_definition_by_qualified_name(candidate)
244
+ end || unqualified_name.chained_name
245
+ end
246
+
162
247
  private
163
248
 
164
249
  # @param source [Rucoa::Source]
165
250
  # @return [void]
166
- def delete_definitions_about(source)
167
- @fully_qualified_names_by_uri[source.uri].each do |fully_qualified_name|
168
- @definition_by_full_qualified_name.delete(fully_qualified_name)
251
+ def delete_definitions_in(source)
252
+ @qualified_names_by_uri[source.uri].each do |qualified_name|
253
+ @definition_by_qualified_name.delete(qualified_name)
169
254
  end
170
- @fully_qualified_names_by_uri.delete(source.uri)
255
+ @qualified_names_by_uri.delete(source.uri)
171
256
  end
172
257
 
173
258
  # @param type [String]
@@ -176,25 +261,49 @@ module Rucoa
176
261
  type[/singleton<(\w+)>/, 1]
177
262
  end
178
263
 
179
- # @param class_or_module_definition [Rucoa::Definitions::Class, Rucoa::Definitions::Module]
180
- # @return [Array<Rucoa::Definitions::Class>]
181
- def ancestor_definitions_of(class_or_module_definition)
182
- return [] unless class_or_module_definition.is_a?(Definitions::ClassDefinition)
264
+ # @param definition [Rucoa::Definitions::Class, Rucoa::Definitions::Module]
265
+ # @return [Array<Rucoa::Definitions::Class>] The classes and modules that are traced in method search (as `Module#ancestors` in Ruby)
266
+ def ancestors_of(definition)
267
+ if definition.is_a?(Rucoa::Definitions::ClassDefinition)
268
+ [definition, *super_class_definitions_of(definition)]
269
+ else
270
+ [definition]
271
+ end.flat_map do |base|
272
+ module_ancestors_of(base)
273
+ end
274
+ end
275
+
276
+ # @param definition [Rucoa::Definitions::Class, Rucoa::Definitions::Module]
277
+ # @return [Array<Rucoa::Definitions::Class, Rucoa::Definitions::Module>] An array of prepended, itself, and included definitions
278
+ def module_ancestors_of(definition)
279
+ [
280
+ *definition.prepended_module_qualified_names.filter_map do |qualified_name|
281
+ find_definition_by_qualified_name(qualified_name)
282
+ end.reverse,
283
+ definition,
284
+ *definition.included_module_qualified_names.filter_map do |qualified_name|
285
+ find_definition_by_qualified_name(qualified_name)
286
+ end.reverse
287
+ ]
288
+ end
183
289
 
290
+ # @param definition [Rucoa::Definitions::Class]
291
+ # @return [Array<Rucoa::Definitions::Class>] super "class"es (not including modules) in closest-first order
292
+ def super_class_definitions_of(definition)
184
293
  result = []
185
- class_definition = class_or_module_definition
186
- while (super_class_fully_qualified_name = class_definition.super_class_fully_qualified_name)
187
- class_definition = find_definition_by_fully_qualified_name(super_class_fully_qualified_name)
188
- break unless class_definition
294
+ while (super_class_qualified_name = definition.super_class_qualified_name)
295
+ super_definition = find_definition_by_qualified_name(super_class_qualified_name)
296
+ break unless super_definition
189
297
 
190
- result << class_definition
298
+ result << super_definition
299
+ definition = super_definition
191
300
  end
192
301
  result
193
302
  end
194
303
 
195
304
  # @return [Array<Rucoa::Definitions::Base>]
196
305
  def definitions
197
- @definition_by_full_qualified_name.values
306
+ @definition_by_qualified_name.values
198
307
  end
199
308
 
200
309
  # @return [Array<Rucoa::Definition::MethodDefinition>]
@@ -217,14 +326,38 @@ module Rucoa
217
326
  definitions.grep(Definitions::ConstantDefinition)
218
327
  end
219
328
 
220
- # @param class_definition [Rucoa::Definitions::ClassDefinition]
221
- # @return [String]
222
- def resolve_super_class_of(class_definition)
223
- return 'Object' unless class_definition.super_class_chained_name
329
+ # @param source [Rucoa::Source]
330
+ # @return [void]
331
+ def add_definitions_in(source)
332
+ source.definitions.group_by do |definition|
333
+ definition.location.uri
334
+ end.each do |uri, definitions|
335
+ @qualified_names_by_uri[uri] += definitions.map(&:qualified_name)
336
+ definitions.each do |definition|
337
+ @definition_by_qualified_name[definition.qualified_name] = definition
338
+ end
339
+ end
340
+ end
224
341
 
225
- class_definition.super_class_candidates.find do |candidate|
226
- find_definition_by_fully_qualified_name(candidate)
227
- end || class_definition.super_class_chained_name
342
+ # @param source [Rucoa::Source]
343
+ # @return [void]
344
+ def resolve_constants_in(source)
345
+ source.definitions.each do |definition|
346
+ next unless definition.is_a?(Definitions::ClassDefinition)
347
+
348
+ definition.super_class_qualified_name = resolve_constant(definition.super_class_unqualified_name)
349
+ definition.super_class_unqualified_name = nil
350
+
351
+ definition.included_module_qualified_names = definition.included_module_unqualified_names.map do |unqualified_name|
352
+ resolve_constant(unqualified_name)
353
+ end
354
+ definition.included_module_unqualified_names = []
355
+
356
+ definition.prepended_module_qualified_names = definition.prepended_module_unqualified_names.map do |unqualified_name|
357
+ resolve_constant(unqualified_name)
358
+ end
359
+ definition.prepended_module_unqualified_names = []
360
+ end
228
361
  end
229
362
  end
230
363
  end
@@ -3,9 +3,20 @@
3
3
  module Rucoa
4
4
  module Definitions
5
5
  class Base
6
- # @return [String]
7
- def source_path
8
- raise ::NotImplementedError
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
@@ -3,79 +3,29 @@
3
3
  module Rucoa
4
4
  module Definitions
5
5
  class ClassDefinition < ModuleDefinition
6
- # @return [Arra<String>, nil]
7
- attr_reader :module_nesting
8
-
9
6
  # @return [String, nil]
10
- attr_reader :super_class_chained_name
7
+ attr_accessor :super_class_qualified_name
11
8
 
12
- # @return [String, nil]
13
- attr_accessor :super_class_fully_qualified_name
9
+ # @return [Rucoa::UnqualifiedName, nil]
10
+ attr_accessor :super_class_unqualified_name
14
11
 
15
- # @param module_nesting [Array<String>, nil]
16
- # @param super_class_chained_name [String, nil]
17
- # @param super_class_fully_qualified_name [String, nil]
12
+ # @param super_class_qualified_name [String, nil]
13
+ # @param super_class_unqualified_name [Rucoa::UnqualifiedName, nil]
18
14
  def initialize(
19
- module_nesting: nil,
20
- super_class_chained_name: nil,
21
- super_class_fully_qualified_name: nil,
15
+ super_class_qualified_name: nil,
16
+ super_class_unqualified_name: nil,
22
17
  **keyword_arguments
23
18
  )
24
19
  super(**keyword_arguments)
25
- @module_nesting = module_nesting
26
- @super_class_chained_name = super_class_chained_name
27
- @super_class_fully_qualified_name = super_class_fully_qualified_name
20
+ @super_class_qualified_name = super_class_qualified_name
21
+ @super_class_unqualified_name = super_class_unqualified_name
28
22
  end
29
23
 
30
- # @return [Boolean]
31
- # @example returns false on not-resolved case
32
- # definition = Rucoa::Definitions::ClassDefinition.new(
33
- # fully_qualified_name: 'Foo',
34
- # source_path: '/path/to/foo.rb',
35
- # super_class_chained_name: 'Bar'
36
- # )
37
- # expect(definition).not_to be_super_class_resolved
38
- # @example returns true on resolved case
39
- # definition = Rucoa::Definitions::ClassDefinition.new(
40
- # fully_qualified_name: 'Foo',
41
- # source_path: '/path/to/foo.rb',
42
- # super_class_chained_name: 'Bar',
43
- # super_class_fully_qualified_name: 'Bar'
44
- # )
45
- # expect(definition).to be_super_class_resolved
46
- def super_class_resolved?
47
- !@super_class_fully_qualified_name.nil?
48
- end
49
-
50
- # @return [Array<String>]
51
- # @example returns candidates of super class fully qualified name
52
- # class_definition = Rucoa::Definitions::ClassDefinition.new(
53
- # fully_qualified_name: nil,
54
- # module_nesting: %w[B::A B],
55
- # source_path: '/path/to/b/a/c.rb',
56
- # super_class_chained_name: 'C'
57
- # )
58
- # expect(class_definition.super_class_candidates).to eq(
59
- # %w[B::A::C B::C C]
60
- # )
61
- # @example returns only correct answer if it's already resolved
62
- # class_definition = Rucoa::Definitions::ClassDefinition.new(
63
- # fully_qualified_name: 'B::A::C',
64
- # source_path: '/path/to/b/a/c.rb',
65
- # super_class_fully_qualified_name: 'B::A::C'
66
- # )
67
- # expect(class_definition.super_class_candidates).to eq(
68
- # %w[B::A::C]
69
- # )
70
- def super_class_candidates
71
- return [super_class_fully_qualified_name] if super_class_resolved?
72
-
73
- module_nesting.map do |chained_name|
74
- [
75
- chained_name,
76
- super_class_chained_name
77
- ].join('::')
78
- end + [super_class_chained_name]
24
+ # @param other [Rucoa::Definitions::ClassDefinition]
25
+ def merge!(other)
26
+ self.super_class_qualified_name ||= other.super_class_qualified_name
27
+ self.super_class_unqualified_name ||= other.super_class_unqualified_name
28
+ super
79
29
  end
80
30
  end
81
31
  end