rucoa 0.8.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) 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 +268 -75
  7. data/lib/rucoa/definitions/base.rb +14 -3
  8. data/lib/rucoa/definitions/class_definition.rb +20 -4
  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/initialized_handler.rb +33 -5
  16. data/lib/rucoa/handlers/text_document_completion_handler.rb +1 -1
  17. data/lib/rucoa/handlers/text_document_definition_handler.rb +3 -99
  18. data/lib/rucoa/handlers/text_document_did_open_handler.rb +1 -4
  19. data/lib/rucoa/handlers/text_document_hover_handler.rb +21 -13
  20. data/lib/rucoa/handlers/text_document_selection_range_handler.rb +8 -2
  21. data/lib/rucoa/location.rb +37 -0
  22. data/lib/rucoa/node_concerns/body.rb +24 -0
  23. data/lib/rucoa/node_concerns/{name_full_qualifiable.rb → qualified_name.rb} +2 -2
  24. data/lib/rucoa/node_concerns.rb +2 -1
  25. data/lib/rucoa/node_inspector.rb +22 -26
  26. data/lib/rucoa/nodes/base.rb +51 -10
  27. data/lib/rucoa/nodes/begin_node.rb +8 -0
  28. data/lib/rucoa/nodes/casgn_node.rb +1 -1
  29. data/lib/rucoa/nodes/cbase_node.rb +8 -0
  30. data/lib/rucoa/nodes/class_node.rb +63 -1
  31. data/lib/rucoa/nodes/const_node.rb +64 -5
  32. data/lib/rucoa/nodes/def_node.rb +11 -9
  33. data/lib/rucoa/nodes/defs_node.rb +21 -0
  34. data/lib/rucoa/nodes/lvar_node.rb +2 -1
  35. data/lib/rucoa/nodes/module_node.rb +2 -1
  36. data/lib/rucoa/nodes/send_node.rb +14 -10
  37. data/lib/rucoa/nodes.rb +3 -1
  38. data/lib/rucoa/parse_result.rb +29 -0
  39. data/lib/rucoa/parser.rb +40 -8
  40. data/lib/rucoa/parser_builder.rb +7 -1
  41. data/lib/rucoa/position.rb +10 -1
  42. data/lib/rucoa/range.rb +11 -1
  43. data/lib/rucoa/rbs/class_definition_mapper.rb +13 -28
  44. data/lib/rucoa/rbs/constant_definition_mapper.rb +12 -6
  45. data/lib/rucoa/rbs/method_definition_mapper.rb +12 -6
  46. data/lib/rucoa/rbs/module_definition_mapper.rb +34 -6
  47. data/lib/rucoa/rubocop/autocorrector.rb +2 -2
  48. data/lib/rucoa/rubocop/investigator.rb +6 -3
  49. data/lib/rucoa/server.rb +9 -3
  50. data/lib/rucoa/source.rb +57 -27
  51. data/lib/rucoa/source_store.rb +0 -13
  52. data/lib/rucoa/unqualified_name.rb +9 -0
  53. data/lib/rucoa/version.rb +1 -1
  54. data/lib/rucoa/yard/definition_generators/attribute_reader_definition_generator.rb +60 -0
  55. data/lib/rucoa/yard/definition_generators/attribute_writer_definition_generator.rb +60 -0
  56. data/lib/rucoa/yard/definition_generators/base.rb +117 -0
  57. data/lib/rucoa/yard/definition_generators/class_definition_generator.rb +66 -0
  58. data/lib/rucoa/yard/definition_generators/constant_assignment_definition_generator.rb +29 -0
  59. data/lib/rucoa/yard/definition_generators/method_definition_generator.rb +47 -0
  60. data/lib/rucoa/yard/definition_generators/module_definition_generator.rb +62 -0
  61. data/lib/rucoa/yard/definition_generators.rb +15 -0
  62. data/lib/rucoa/yard/definitions_loader.rb +44 -65
  63. data/lib/rucoa/yard/type.rb +46 -0
  64. data/lib/rucoa/yard.rb +2 -1
  65. data/lib/rucoa.rb +4 -1
  66. metadata +18 -4
  67. data/lib/rucoa/yard/method_definition_mapper.rb +0 -215
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 26c4a8d526acb34d3722fc4b78e4c8fa0a1bac7bfc11d72af4b5962afdbc01c9
4
- data.tar.gz: b49e5bdca272898e10870fbad7f99b2ba5cf63e0d1acef074d3af1928b69058b
3
+ metadata.gz: 3344309136313473ea6d4fecd4c57745fb4bc8fc1404c40f7126c0a5d5eef440
4
+ data.tar.gz: 1bfb57eee21c860f54b8c82452717d987a31bc977a5a7853b6e08b0d486fd5ac
5
5
  SHA512:
6
- metadata.gz: 4de0736efd9d7b44d7756bfe5aedf6fc60d0b3a9ce9ab55cb0e3c6b83ca0525017e0ddb629d612ec4c05a8cae97f1d902bf33a3090c00570765c344821393bf6
7
- data.tar.gz: 8228a81e3b4408274d2e51f2c339e724e4c4615f4af2a311bad68c48b74d32a09773cf5a0caaa780135780d7510b95aa64579ec6d009bf7fe711cb590660bde8
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.8.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
@@ -2,48 +2,179 @@
2
2
 
3
3
  module Rucoa
4
4
  class DefinitionStore
5
- # @return [Array<Rucoa::Definition::Base>]
6
- attr_accessor :definitions
7
-
8
5
  def initialize
9
- @definitions = []
6
+ @definition_by_qualified_name = {}
7
+ @qualified_names_by_uri = ::Hash.new { |hash, key| hash[key] = [] }
10
8
  end
11
9
 
12
- # @param source_path [String]
13
- # @return [Array<Rucoa::Definition::Base>]
14
- def update_definitions_defined_in(source_path, definitions:)
15
- delete_definitions_defined_in(source_path)
16
- @definitions += definitions
10
+ # @return [String]
11
+ def inspect
12
+ "#<#{self.class} definitions_count=#{@definition_by_qualified_name.count}>"
17
13
  end
18
14
 
19
- # @param full_qualified_name [String]
20
- # @return [Array<Rucoa::Definitions::Base>]
21
- def select_by_full_qualified_name(full_qualified_name)
22
- @definitions.select do |definition|
23
- definition.full_qualified_name == full_qualified_name
15
+ # @param definitions [Array<Rucoa::Definition::Base>]
16
+ # @return [void]
17
+ def bulk_add(definitions)
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
24
23
  end
25
24
  end
26
25
 
26
+ # @param source [Rucoa::Source]
27
+ # @return [void]
28
+ # @example resolves super class name from definitions
29
+ # definition_store = Rucoa::DefinitionStore.new
30
+ # foo = Rucoa::Source.new(
31
+ # content: <<~RUBY,
32
+ # module A
33
+ # class Foo
34
+ # end
35
+ # end
36
+ # RUBY
37
+ # uri: 'file:///path/to/a/foo.rb',
38
+ # )
39
+ # definition_store.update_from(foo)
40
+ # bar = Rucoa::Source.new(
41
+ # content: <<~RUBY,
42
+ # module A
43
+ # class Bar < Foo
44
+ # end
45
+ # end
46
+ # RUBY
47
+ # uri: 'file:///path/to/a/bar.rb',
48
+ # )
49
+ # definition_store.update_from(bar)
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])
77
+ def update_from(source)
78
+ delete_definitions_in(source)
79
+ add_definitions_in(source)
80
+ resolve_constants_in(source)
81
+ end
82
+
83
+ # @param qualified_name [String]
84
+ # @return [Rucoa::Definitions::Base, nil]
85
+ def find_definition_by_qualified_name(qualified_name)
86
+ @definition_by_qualified_name[qualified_name]
87
+ end
88
+
27
89
  # @param method_name [String]
28
90
  # @param namespace [String]
29
91
  # @param singleton [Boolean]
30
92
  # @return [Rucoa::Definition::MethodDefinition, nil]
31
- # @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
+ # )
32
106
  # definition_store = Rucoa::DefinitionStore.new
33
- # definition_store.definitions += Rucoa::DefinitionArchiver.load
107
+ # definition_store.update_from(source)
34
108
  # subject = definition_store.find_method_definition_by(
35
- # method_name: 'write',
36
- # namespace: 'File',
37
- # singleton: true
109
+ # method_name: 'foo',
110
+ # namespace: 'B',
111
+ # singleton: false
38
112
  # )
39
- # expect(subject.full_qualified_name).to eq('IO.write')
40
- def find_method_definition_by(method_name:, namespace:, singleton: false)
41
- if singleton
42
- singleton_method_definitions_of(namespace)
43
- else
44
- instance_method_definitions_of(namespace)
45
- end.find do |method_definition|
46
- method_definition.method_name == method_name
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)
167
+ return unless definition
168
+
169
+ ancestors_of(definition).find do |ancestor|
170
+ method_marker = singleton ? '.' : '#'
171
+ qualified_method_name = [
172
+ ancestor.qualified_name,
173
+ method_marker,
174
+ method_name
175
+ ].join
176
+ method_definition = find_definition_by_qualified_name(qualified_method_name)
177
+ break method_definition if method_definition
47
178
  end
48
179
  end
49
180
 
@@ -51,28 +182,25 @@ module Rucoa
51
182
  # @return [Array<Rucoa::Definitions::MethodDefinition>]
52
183
  # @example includes ancestors' methods
53
184
  # definition_store = Rucoa::DefinitionStore.new
54
- # definition_store.definitions += Rucoa::DefinitionArchiver.load
185
+ # definition_store.bulk_add(Rucoa::DefinitionArchiver.load)
55
186
  # subject = definition_store.instance_method_definitions_of('File')
56
- # expect(subject.map(&:full_qualified_name)).to include('IO#raw')
187
+ # expect(subject.map(&:qualified_name)).to include('IO#raw')
57
188
  # @example responds to `singleton<File>`
58
189
  # definition_store = Rucoa::DefinitionStore.new
59
- # definition_store.definitions += Rucoa::DefinitionArchiver.load
190
+ # definition_store.bulk_add(Rucoa::DefinitionArchiver.load)
60
191
  # subject = definition_store.instance_method_definitions_of('singleton<File>')
61
- # expect(subject.map(&:full_qualified_name)).to include('IO.write')
192
+ # expect(subject.map(&:qualified_name)).to include('IO.write')
62
193
  def instance_method_definitions_of(type)
63
194
  singleton_class_name = singleton_class_name_from(type)
64
195
  return singleton_method_definitions_of(singleton_class_name) if singleton_class_name
65
196
 
66
- class_or_module_definition = find_class_or_module_definition(type)
197
+ class_or_module_definition = find_definition_by_qualified_name(type)
67
198
  return [] unless class_or_module_definition
68
199
 
69
- definitions = instance_method_definitions
70
- [
71
- class_or_module_definition,
72
- *ancestor_definitions_of(class_or_module_definition)
73
- ].map(&:full_qualified_name).flat_map do |full_qualified_type_name|
74
- definitions.select do |definition|
75
- definition.namespace == full_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
76
204
  end
77
205
  end
78
206
  end
@@ -81,29 +209,21 @@ module Rucoa
81
209
  # @return [Array<Rucoa::Definitions::MethodDefinition>]
82
210
  # @example returns singleton method definitions of File
83
211
  # definition_store = Rucoa::DefinitionStore.new
84
- # definition_store.definitions += Rucoa::DefinitionArchiver.load
212
+ # definition_store.bulk_add(Rucoa::DefinitionArchiver.load)
85
213
  # subject = definition_store.singleton_method_definitions_of('File')
86
- # expect(subject.map(&:full_qualified_name)).to include('IO.write')
214
+ # expect(subject.map(&:qualified_name)).to include('IO.write')
87
215
  def singleton_method_definitions_of(type)
88
- class_or_module_definition = find_class_or_module_definition(type)
216
+ class_or_module_definition = find_definition_by_qualified_name(type)
89
217
  return [] unless class_or_module_definition
90
218
 
91
- definitions = singleton_method_definitions
92
- [
93
- class_or_module_definition,
94
- *ancestor_definitions_of(class_or_module_definition)
95
- ].map(&:full_qualified_name).flat_map do |full_qualified_type_name|
96
- definitions.select do |definition|
97
- definition.namespace == full_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
98
223
  end
99
224
  end
100
225
  end
101
226
 
102
- # @return [Array<Rucoa::Definition::ConstantDefinition>]
103
- def constant_definitions
104
- @definitions.grep(Definitions::ConstantDefinition)
105
- end
106
-
107
227
  # @param namespace [String]
108
228
  # @return [Array<Rucoa::Definitions::ConstantDefinition>] e.g. File::Separator, File::SEPARATOR, etc.
109
229
  def constant_definitions_under(namespace)
@@ -112,41 +232,83 @@ module Rucoa
112
232
  end
113
233
  end
114
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
+
115
247
  private
116
248
 
249
+ # @param source [Rucoa::Source]
250
+ # @return [void]
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)
254
+ end
255
+ @qualified_names_by_uri.delete(source.uri)
256
+ end
257
+
117
258
  # @param type [String]
118
259
  # @return [String, nil]
119
260
  def singleton_class_name_from(type)
120
261
  type[/singleton<(\w+)>/, 1]
121
262
  end
122
263
 
123
- # @param class_or_module_definition [Rucoa::Definitions::Class, Rucoa::Definitions::Module]
124
- # @return [Array<Rucoa::Definitions::Class>]
125
- def ancestor_definitions_of(class_or_module_definition)
126
- 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
127
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)
128
293
  result = []
129
- class_definition = class_or_module_definition
130
- while (super_class_name = class_definition.super_class_name)
131
- class_definition = find_class_or_module_definition(super_class_name)
132
- 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
133
297
 
134
- result << class_definition
298
+ result << super_definition
299
+ definition = super_definition
135
300
  end
136
301
  result
137
302
  end
138
303
 
139
- # @param type [String]
140
- # @return [Rucoa::Definitions::Class, Rucoa::Definitions::Module, nil]
141
- def find_class_or_module_definition(type)
142
- @definitions.find do |definition|
143
- definition.full_qualified_name == type
144
- end
304
+ # @return [Array<Rucoa::Definitions::Base>]
305
+ def definitions
306
+ @definition_by_qualified_name.values
145
307
  end
146
308
 
147
309
  # @return [Array<Rucoa::Definition::MethodDefinition>]
148
310
  def method_definitions
149
- @definitions.grep(Definitions::MethodDefinition)
311
+ definitions.grep(Definitions::MethodDefinition)
150
312
  end
151
313
 
152
314
  # @return [Array<Rucoa::Definition::MethodDefinition>]
@@ -159,11 +321,42 @@ module Rucoa
159
321
  method_definitions.select(&:singleton_method?)
160
322
  end
161
323
 
162
- # @param source_path [String]
163
- # @return [Array<Rucoa::Definition::Base>]
164
- def delete_definitions_defined_in(source_path)
165
- @definitions.delete_if do |definition|
166
- definition.source_path == source_path
324
+ # @return [Array<Rucoa::Definition::ConstantDefinition>]
325
+ def constant_definitions
326
+ definitions.grep(Definitions::ConstantDefinition)
327
+ end
328
+
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
341
+
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 = []
167
360
  end
168
361
  end
169
362
  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
@@ -4,12 +4,28 @@ module Rucoa
4
4
  module Definitions
5
5
  class ClassDefinition < ModuleDefinition
6
6
  # @return [String, nil]
7
- attr_reader :super_class_name
7
+ attr_accessor :super_class_qualified_name
8
8
 
9
- # @param super_class_name [String, nil]
10
- def initialize(super_class_name:, **keyword_arguments)
9
+ # @return [Rucoa::UnqualifiedName, nil]
10
+ attr_accessor :super_class_unqualified_name
11
+
12
+ # @param super_class_qualified_name [String, nil]
13
+ # @param super_class_unqualified_name [Rucoa::UnqualifiedName, nil]
14
+ def initialize(
15
+ super_class_qualified_name: nil,
16
+ super_class_unqualified_name: nil,
17
+ **keyword_arguments
18
+ )
11
19
  super(**keyword_arguments)
12
- @super_class_name = super_class_name
20
+ @super_class_qualified_name = super_class_qualified_name
21
+ @super_class_unqualified_name = super_class_unqualified_name
22
+ end
23
+
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
13
29
  end
14
30
  end
15
31
  end
@@ -5,25 +5,30 @@ module Rucoa
5
5
  # Represents class definition, module definition, or constant assignment.
6
6
  class ConstantDefinition < Base
7
7
  # @return [String]
8
- attr_reader :full_qualified_name
8
+ attr_reader :qualified_name
9
9
 
10
- # @return [String]
11
- attr_reader :source_path
12
-
13
- # @param full_qualified_name [String]
14
- # @param source_path [String]
15
- def initialize(full_qualified_name:, source_path:)
16
- super()
17
- @full_qualified_name = full_qualified_name
18
- @source_path = source_path
10
+ # @param qualified_name [String]
11
+ def initialize(
12
+ qualified_name:,
13
+ **keyword_arguments
14
+ )
15
+ super(**keyword_arguments)
16
+ @qualified_name = qualified_name
19
17
  end
20
18
 
21
19
  # @return [String]
22
20
  # @example returns non-full-qualified name
23
- # definition = Rucoa::Definitions::ConstantDefinition.new(
24
- # full_qualified_name: 'Foo::Bar::Baz',
25
- # source_path: '/path/to/foo/bar/baz.rb'
26
- # )
21
+ # definition = Rucoa::Source.new(
22
+ # content: <<~RUBY,
23
+ # module Foo
24
+ # module Bar
25
+ # class Baz
26
+ # end
27
+ # end
28
+ # end
29
+ # RUBY
30
+ # uri: 'file:///path/to/foo/bar/baz.rb',
31
+ # ).definitions[2]
27
32
  # expect(definition.name).to eq('Baz')
28
33
  def name
29
34
  names.last
@@ -31,10 +36,17 @@ module Rucoa
31
36
 
32
37
  # @return [String]
33
38
  # @example returns namespace
34
- # definition = Rucoa::Definitions::ConstantDefinition.new(
35
- # full_qualified_name: 'Foo::Bar::Baz',
36
- # source_path: '/path/to/foo/bar/baz.rb'
37
- # )
39
+ # definition = Rucoa::Source.new(
40
+ # content: <<~RUBY,
41
+ # module Foo
42
+ # module Bar
43
+ # class Baz
44
+ # end
45
+ # end
46
+ # end
47
+ # RUBY
48
+ # uri: 'file:///path/to/foo/bar/baz.rb',
49
+ # ).definitions[2]
38
50
  # expect(definition.namespace).to eq('Foo::Bar')
39
51
  def namespace
40
52
  names[..-2].join('::')
@@ -44,7 +56,7 @@ module Rucoa
44
56
 
45
57
  # @return [Array<String>]
46
58
  def names
47
- @names ||= full_qualified_name.split('::')
59
+ @names ||= qualified_name.split('::')
48
60
  end
49
61
  end
50
62
  end