rucoa 0.8.0 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
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