rucoa 0.10.0 → 0.12.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +8 -2
  3. data/Gemfile.lock +3 -3
  4. data/README.md +4 -1
  5. data/data/definitions_ruby_3_1 +6594 -6594
  6. data/lib/rucoa/configuration.rb +22 -12
  7. data/lib/rucoa/definition_store.rb +270 -158
  8. data/lib/rucoa/definitions/method_definition.rb +11 -11
  9. data/lib/rucoa/definitions/module_definition.rb +14 -0
  10. data/lib/rucoa/handler_concerns/configuration_requestable.rb +7 -7
  11. data/lib/rucoa/handler_concerns/diagnostics_publishable.rb +11 -11
  12. data/lib/rucoa/handler_concerns/text_document_position_parameters.rb +29 -0
  13. data/lib/rucoa/handler_concerns/text_document_uri_parameters.rb +21 -0
  14. data/lib/rucoa/handler_concerns.rb +2 -0
  15. data/lib/rucoa/handlers/base.rb +9 -9
  16. data/lib/rucoa/handlers/initialize_handler.rb +1 -0
  17. data/lib/rucoa/handlers/initialized_handler.rb +16 -16
  18. data/lib/rucoa/handlers/text_document_code_action_handler.rb +12 -12
  19. data/lib/rucoa/handlers/text_document_completion_handler.rb +85 -99
  20. data/lib/rucoa/handlers/text_document_definition_handler.rb +11 -30
  21. data/lib/rucoa/handlers/text_document_did_close_handler.rb +2 -8
  22. data/lib/rucoa/handlers/text_document_did_open_handler.rb +3 -7
  23. data/lib/rucoa/handlers/text_document_document_highlight_handler.rb +256 -0
  24. data/lib/rucoa/handlers/text_document_document_symbol_handler.rb +47 -76
  25. data/lib/rucoa/handlers/text_document_formatting_handler.rb +15 -23
  26. data/lib/rucoa/handlers/text_document_hover_handler.rb +24 -43
  27. data/lib/rucoa/handlers/text_document_range_formatting_handler.rb +17 -25
  28. data/lib/rucoa/handlers/text_document_selection_range_handler.rb +11 -19
  29. data/lib/rucoa/handlers/text_document_signature_help_handler.rb +17 -36
  30. data/lib/rucoa/handlers.rb +1 -0
  31. data/lib/rucoa/node_concerns/body.rb +1 -1
  32. data/lib/rucoa/node_concerns/qualified_name.rb +5 -5
  33. data/lib/rucoa/node_concerns/rescue.rb +21 -0
  34. data/lib/rucoa/node_concerns.rb +1 -0
  35. data/lib/rucoa/node_inspector.rb +17 -6
  36. data/lib/rucoa/nodes/base.rb +48 -48
  37. data/lib/rucoa/nodes/begin_node.rb +2 -0
  38. data/lib/rucoa/nodes/block_node.rb +24 -0
  39. data/lib/rucoa/nodes/case_node.rb +24 -0
  40. data/lib/rucoa/nodes/const_node.rb +26 -26
  41. data/lib/rucoa/nodes/def_node.rb +14 -13
  42. data/lib/rucoa/nodes/ensure_node.rb +19 -0
  43. data/lib/rucoa/nodes/for_node.rb +8 -0
  44. data/lib/rucoa/nodes/if_node.rb +32 -0
  45. data/lib/rucoa/nodes/resbody_node.rb +8 -0
  46. data/lib/rucoa/nodes/rescue_node.rb +17 -0
  47. data/lib/rucoa/nodes/send_node.rb +40 -0
  48. data/lib/rucoa/nodes/until_node.rb +8 -0
  49. data/lib/rucoa/nodes/when_node.rb +8 -0
  50. data/lib/rucoa/nodes/while_node.rb +8 -0
  51. data/lib/rucoa/nodes.rb +10 -1
  52. data/lib/rucoa/parser_builder.rb +16 -2
  53. data/lib/rucoa/range.rb +9 -3
  54. data/lib/rucoa/rbs/class_definition_mapper.rb +1 -0
  55. data/lib/rucoa/rbs/constant_definition_mapper.rb +5 -5
  56. data/lib/rucoa/rbs/method_definition_mapper.rb +18 -18
  57. data/lib/rucoa/rbs/module_definition_mapper.rb +17 -12
  58. data/lib/rucoa/rbs/ruby_definitions_loader.rb +5 -5
  59. data/lib/rucoa/rubocop/configuration_checker.rb +7 -7
  60. data/lib/rucoa/server.rb +25 -24
  61. data/lib/rucoa/source.rb +5 -5
  62. data/lib/rucoa/source_store.rb +8 -8
  63. data/lib/rucoa/version.rb +1 -1
  64. data/lib/rucoa/yard/definition_generators/attribute_reader_definition_generator.rb +17 -1
  65. data/lib/rucoa/yard/definition_generators/attribute_writer_definition_generator.rb +17 -1
  66. data/lib/rucoa/yard/definition_generators/class_definition_generator.rb +1 -0
  67. data/lib/rucoa/yard/definition_generators/method_definition_generator.rb +14 -1
  68. data/lib/rucoa/yard/definition_generators/module_definition_generator.rb +6 -0
  69. metadata +16 -3
  70. data/lib/rucoa/nodes/defs_node.rb +0 -33
@@ -36,6 +36,11 @@ module Rucoa
36
36
  disable_feature('formatting')
37
37
  end
38
38
 
39
+ # @return [void]
40
+ def disable_highlight
41
+ disable_feature('highlight')
42
+ end
43
+
39
44
  # @return [void]
40
45
  def disable_hover
41
46
  disable_feature('hover')
@@ -58,18 +63,6 @@ module Rucoa
58
63
  @settings['base']['debug'] = true
59
64
  end
60
65
 
61
- # @return [Boolean]
62
- # @example returns false if the configuration is empty
63
- # configuration = Rucoa::Configuration.new
64
- # expect(configuration).not_to be_enables_debug
65
- # @example returns true if the configuration enables debug
66
- # configuration = Rucoa::Configuration.new
67
- # configuration.update('base' => { 'debug' => true })
68
- # expect(configuration).to be_enables_debug
69
- def enables_debug?
70
- fetch('base', 'debug', default: false)
71
- end
72
-
73
66
  # @return [Boolean]
74
67
  # @example returns true if the configuration is empty
75
68
  # configuration = Rucoa::Configuration.new
@@ -87,6 +80,18 @@ module Rucoa
87
80
  enables_feature?('completion')
88
81
  end
89
82
 
83
+ # @return [Boolean]
84
+ # @example returns false if the configuration is empty
85
+ # configuration = Rucoa::Configuration.new
86
+ # expect(configuration).not_to be_enables_debug
87
+ # @example returns true if the configuration enables debug
88
+ # configuration = Rucoa::Configuration.new
89
+ # configuration.update('base' => { 'debug' => true })
90
+ # expect(configuration).to be_enables_debug
91
+ def enables_debug?
92
+ fetch('base', 'debug', default: false)
93
+ end
94
+
90
95
  # @return [Boolean]
91
96
  def enables_definition?
92
97
  enables_feature?('definition')
@@ -107,6 +112,11 @@ module Rucoa
107
112
  enables_feature?('formatting')
108
113
  end
109
114
 
115
+ # @return [Boolean]
116
+ def enables_highlight?
117
+ enables_feature?('highlight')
118
+ end
119
+
110
120
  # @return [Boolean]
111
121
  def enables_hover?
112
122
  enables_feature?('hover')
@@ -7,11 +7,6 @@ module Rucoa
7
7
  @qualified_names_by_uri = ::Hash.new { |hash, key| hash[key] = [] }
8
8
  end
9
9
 
10
- # @return [String]
11
- def inspect
12
- "#<#{self.class} definitions_count=#{@definition_by_qualified_name.count}>"
13
- end
14
-
15
10
  # @param definitions [Array<Rucoa::Definition::Base>]
16
11
  # @return [void]
17
12
  def bulk_add(definitions)
@@ -23,61 +18,12 @@ module Rucoa
23
18
  end
24
19
  end
25
20
 
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)
21
+ # @param namespace [String]
22
+ # @return [Array<Rucoa::Definitions::ConstantDefinition>] e.g. File::Separator, File::SEPARATOR, etc.
23
+ def constant_definitions_under(namespace)
24
+ constant_definitions.select do |constant_definition|
25
+ constant_definition.namespace == namespace
26
+ end
81
27
  end
82
28
 
83
29
  # @param qualified_name [String]
@@ -178,18 +124,83 @@ module Rucoa
178
124
  end
179
125
  end
180
126
 
127
+ # @return [String]
128
+ def inspect
129
+ "#<#{self.class} definitions_count=#{@definition_by_qualified_name.count}>"
130
+ end
131
+
181
132
  # @param type [String]
182
133
  # @return [Array<Rucoa::Definitions::MethodDefinition>]
183
- # @example includes ancestors' methods
134
+ # @example supports simple instance method
135
+ # source = Rucoa::Source.new(
136
+ # content: <<~RUBY,
137
+ # class A
138
+ # def foo
139
+ # end
140
+ # end
141
+ # RUBY
142
+ # uri: 'file:///path/to/example.rb'
143
+ # )
184
144
  # definition_store = Rucoa::DefinitionStore.new
185
- # definition_store.bulk_add(Rucoa::DefinitionArchiver.load)
186
- # subject = definition_store.instance_method_definitions_of('File')
187
- # expect(subject.map(&:qualified_name)).to include('IO#raw')
188
- # @example responds to `singleton<File>`
145
+ # definition_store.update_from(source)
146
+ # subject = definition_store.instance_method_definitions_of('A')
147
+ # expect(subject.map(&:qualified_name)).to eq(%w[A#foo])
148
+ # @example supports inheritance
149
+ # source = Rucoa::Source.new(
150
+ # content: <<~RUBY,
151
+ # class A
152
+ # def foo
153
+ # end
154
+ # end
155
+ #
156
+ # class B < A
157
+ # end
158
+ # RUBY
159
+ # uri: 'file:///path/to/example.rb'
160
+ # )
161
+ # definition_store = Rucoa::DefinitionStore.new
162
+ # definition_store.update_from(source)
163
+ # subject = definition_store.instance_method_definitions_of('B')
164
+ # expect(subject.map(&:qualified_name)).to eq(%w[A#foo])
165
+ # @example supports `include`
166
+ # source = Rucoa::Source.new(
167
+ # content: <<~RUBY,
168
+ # module A
169
+ # def foo
170
+ # end
171
+ # end
172
+ #
173
+ # class B
174
+ # include A
175
+ # end
176
+ # RUBY
177
+ # uri: 'file:///path/to/example.rb'
178
+ # )
179
+ # definition_store = Rucoa::DefinitionStore.new
180
+ # definition_store.update_from(source)
181
+ # subject = definition_store.instance_method_definitions_of('B')
182
+ # expect(subject.map(&:qualified_name)).to eq(%w[A#foo])
183
+ # @example supports `prepend`
184
+ # source = Rucoa::Source.new(
185
+ # content: <<~RUBY,
186
+ # module A
187
+ # def foo
188
+ # end
189
+ # end
190
+ #
191
+ # class B
192
+ # prepend A
193
+ #
194
+ # def foo
195
+ # end
196
+ # end
197
+ # RUBY
198
+ # uri: 'file:///path/to/example.rb'
199
+ # )
189
200
  # definition_store = Rucoa::DefinitionStore.new
190
- # definition_store.bulk_add(Rucoa::DefinitionArchiver.load)
191
- # subject = definition_store.instance_method_definitions_of('singleton<File>')
192
- # expect(subject.map(&:qualified_name)).to include('IO.write')
201
+ # definition_store.update_from(source)
202
+ # subject = definition_store.instance_method_definitions_of('B')
203
+ # expect(subject.map(&:qualified_name)).to eq(%w[A#foo])
193
204
  def instance_method_definitions_of(type)
194
205
  singleton_class_name = singleton_class_name_from(type)
195
206
  return singleton_method_definitions_of(singleton_class_name) if singleton_class_name
@@ -197,68 +208,172 @@ module Rucoa
197
208
  class_or_module_definition = find_definition_by_qualified_name(type)
198
209
  return [] unless class_or_module_definition
199
210
 
200
- method_definitions = instance_method_definitions
211
+ method_definitions = self.method_definitions
201
212
  ancestors_of(class_or_module_definition).flat_map do |ancestor|
202
213
  method_definitions.select do |method_definition|
203
- method_definition.namespace == ancestor.qualified_name
214
+ method_definition.namespace == ancestor.qualified_name &&
215
+ method_definition.instance_method?
204
216
  end
205
- end
217
+ end.uniq(&:method_name)
218
+ end
219
+
220
+ # @todo Search ancestors.
221
+ # @param unqualified_name [Rucoa::UnqualifiedName]
222
+ # @return [String]
223
+ def resolve_constant(unqualified_name)
224
+ (
225
+ unqualified_name.module_nesting.map do |prefix|
226
+ "#{prefix}::#{unqualified_name.chained_name}"
227
+ end + [unqualified_name.chained_name]
228
+ ).find do |candidate|
229
+ find_definition_by_qualified_name(candidate)
230
+ end || unqualified_name.chained_name
206
231
  end
207
232
 
208
233
  # @param type [String]
209
234
  # @return [Array<Rucoa::Definitions::MethodDefinition>]
210
- # @example returns singleton method definitions of File
235
+ # @example supports simple singleton method
236
+ # source = Rucoa::Source.new(
237
+ # content: <<~RUBY,
238
+ # class A
239
+ # def self.foo
240
+ # end
241
+ # end
242
+ # RUBY
243
+ # uri: 'file:///path/to/example.rb'
244
+ # )
211
245
  # definition_store = Rucoa::DefinitionStore.new
212
- # definition_store.bulk_add(Rucoa::DefinitionArchiver.load)
213
- # subject = definition_store.singleton_method_definitions_of('File')
214
- # expect(subject.map(&:qualified_name)).to include('IO.write')
246
+ # definition_store.update_from(source)
247
+ # subject = definition_store.singleton_method_definitions_of('A')
248
+ # expect(subject.map(&:qualified_name)).to include('A.foo')
249
+ # @example supports super class's singleton method
250
+ # source = Rucoa::Source.new(
251
+ # content: <<~RUBY,
252
+ # class A
253
+ # def self.foo
254
+ # end
255
+ # end
256
+ #
257
+ # class B < A
258
+ # end
259
+ # RUBY
260
+ # uri: 'file:///path/to/example.rb'
261
+ # )
262
+ # definition_store = Rucoa::DefinitionStore.new
263
+ # definition_store.update_from(source)
264
+ # subject = definition_store.singleton_method_definitions_of('B')
265
+ # expect(subject.map(&:qualified_name)).to include('A.foo')
266
+ # @example supports extended module's instance method
267
+ # source = Rucoa::Source.new(
268
+ # content: <<~RUBY,
269
+ # module A
270
+ # def foo
271
+ # end
272
+ # end
273
+ #
274
+ # class B
275
+ # def self.foo
276
+ # end
277
+ # end
278
+ #
279
+ # class C < B
280
+ # extend A
281
+ # end
282
+ # RUBY
283
+ # uri: 'file:///path/to/example.rb'
284
+ # )
285
+ # definition_store = Rucoa::DefinitionStore.new
286
+ # definition_store.update_from(source)
287
+ # subject = definition_store.singleton_method_definitions_of('C')
288
+ # expect(subject.map(&:qualified_name)).to eq(%w[A#foo])
215
289
  def singleton_method_definitions_of(type)
216
290
  class_or_module_definition = find_definition_by_qualified_name(type)
217
291
  return [] unless class_or_module_definition
218
292
 
219
- method_definitions = singleton_method_definitions
293
+ method_definitions = self.method_definitions
220
294
  ancestors_of(class_or_module_definition).flat_map do |ancestor|
221
295
  method_definitions.select do |method_definition|
222
- method_definition.namespace == ancestor.qualified_name
296
+ method_definition.namespace == ancestor.qualified_name &&
297
+ method_definition.singleton_method?
298
+ end + ancestor.extended_module_qualified_names.flat_map do |extended_module_qualified_name|
299
+ method_definitions.select do |method_definition|
300
+ method_definition.namespace == extended_module_qualified_name &&
301
+ method_definition.instance_method?
302
+ end
223
303
  end
224
- end
225
- end
226
-
227
- # @param namespace [String]
228
- # @return [Array<Rucoa::Definitions::ConstantDefinition>] e.g. File::Separator, File::SEPARATOR, etc.
229
- def constant_definitions_under(namespace)
230
- constant_definitions.select do |constant_definition|
231
- constant_definition.namespace == namespace
232
- end
304
+ end.uniq(&:method_name)
233
305
  end
234
306
 
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
307
+ # @param source [Rucoa::Source]
308
+ # @return [void]
309
+ # @example resolves super class name from definitions
310
+ # definition_store = Rucoa::DefinitionStore.new
311
+ # foo = Rucoa::Source.new(
312
+ # content: <<~RUBY,
313
+ # module A
314
+ # class Foo
315
+ # end
316
+ # end
317
+ # RUBY
318
+ # uri: 'file:///path/to/a/foo.rb',
319
+ # )
320
+ # definition_store.update_from(foo)
321
+ # bar = Rucoa::Source.new(
322
+ # content: <<~RUBY,
323
+ # module A
324
+ # class Bar < Foo
325
+ # end
326
+ # end
327
+ # RUBY
328
+ # uri: 'file:///path/to/a/bar.rb',
329
+ # )
330
+ # definition_store.update_from(bar)
331
+ # definition = definition_store.find_definition_by_qualified_name('A::Bar')
332
+ # expect(definition.super_class_qualified_name).to eq('A::Foo')
333
+ # @example resolves included module names from definitions
334
+ # definition_store = Rucoa::DefinitionStore.new
335
+ # foo = Rucoa::Source.new(
336
+ # content: <<~RUBY,
337
+ # module A
338
+ # module Foo
339
+ # end
340
+ # end
341
+ # RUBY
342
+ # uri: 'file:///path/to/a/foo.rb',
343
+ # )
344
+ # definition_store.update_from(foo)
345
+ # bar = Rucoa::Source.new(
346
+ # content: <<~RUBY,
347
+ # module A
348
+ # class Bar
349
+ # include Foo
350
+ # end
351
+ # end
352
+ # RUBY
353
+ # uri: 'file:///path/to/a/bar.rb',
354
+ # )
355
+ # definition_store.update_from(bar)
356
+ # definition = definition_store.find_definition_by_qualified_name('A::Bar')
357
+ # expect(definition.included_module_qualified_names).to eq(%w[A::Foo])
358
+ def update_from(source)
359
+ delete_definitions_in(source)
360
+ add_definitions_in(source)
361
+ resolve_constants_in(source)
245
362
  end
246
363
 
247
364
  private
248
365
 
249
366
  # @param source [Rucoa::Source]
250
367
  # @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)
368
+ def add_definitions_in(source)
369
+ source.definitions.group_by do |definition|
370
+ definition.location.uri
371
+ end.each do |uri, definitions|
372
+ @qualified_names_by_uri[uri] += definitions.map(&:qualified_name)
373
+ definitions.each do |definition|
374
+ @definition_by_qualified_name[definition.qualified_name] = definition
375
+ end
254
376
  end
255
- @qualified_names_by_uri.delete(source.uri)
256
- end
257
-
258
- # @param type [String]
259
- # @return [String, nil]
260
- def singleton_class_name_from(type)
261
- type[/singleton<(\w+)>/, 1]
262
377
  end
263
378
 
264
379
  # @param definition [Rucoa::Definitions::Class, Rucoa::Definitions::Module]
@@ -273,32 +388,9 @@ module Rucoa
273
388
  end
274
389
  end
275
390
 
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
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)
293
- result = []
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
297
-
298
- result << super_definition
299
- definition = super_definition
300
- end
301
- result
391
+ # @return [Array<Rucoa::Definition::ConstantDefinition>]
392
+ def constant_definitions
393
+ definitions.grep(Definitions::ConstantDefinition)
302
394
  end
303
395
 
304
396
  # @return [Array<Rucoa::Definitions::Base>]
@@ -306,37 +398,32 @@ module Rucoa
306
398
  @definition_by_qualified_name.values
307
399
  end
308
400
 
309
- # @return [Array<Rucoa::Definition::MethodDefinition>]
310
- def method_definitions
311
- definitions.grep(Definitions::MethodDefinition)
312
- end
313
-
314
- # @return [Array<Rucoa::Definition::MethodDefinition>]
315
- def instance_method_definitions
316
- method_definitions.select(&:instance_method?)
401
+ # @param source [Rucoa::Source]
402
+ # @return [void]
403
+ def delete_definitions_in(source)
404
+ @qualified_names_by_uri[source.uri].each do |qualified_name|
405
+ @definition_by_qualified_name.delete(qualified_name)
406
+ end
407
+ @qualified_names_by_uri.delete(source.uri)
317
408
  end
318
409
 
319
410
  # @return [Array<Rucoa::Definition::MethodDefinition>]
320
- def singleton_method_definitions
321
- method_definitions.select(&:singleton_method?)
322
- end
323
-
324
- # @return [Array<Rucoa::Definition::ConstantDefinition>]
325
- def constant_definitions
326
- definitions.grep(Definitions::ConstantDefinition)
411
+ def method_definitions
412
+ definitions.grep(Definitions::MethodDefinition)
327
413
  end
328
414
 
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
415
+ # @param definition [Rucoa::Definitions::Class, Rucoa::Definitions::Module]
416
+ # @return [Array<Rucoa::Definitions::Class, Rucoa::Definitions::Module>] An array of prepended, itself, and included definitions
417
+ def module_ancestors_of(definition)
418
+ [
419
+ *definition.prepended_module_qualified_names.filter_map do |qualified_name|
420
+ find_definition_by_qualified_name(qualified_name)
421
+ end.reverse,
422
+ definition,
423
+ *definition.included_module_qualified_names.filter_map do |qualified_name|
424
+ find_definition_by_qualified_name(qualified_name)
425
+ end.reverse
426
+ ]
340
427
  end
341
428
 
342
429
  # @param source [Rucoa::Source]
@@ -348,6 +435,11 @@ module Rucoa
348
435
  definition.super_class_qualified_name = resolve_constant(definition.super_class_unqualified_name)
349
436
  definition.super_class_unqualified_name = nil
350
437
 
438
+ definition.extended_module_qualified_names = definition.extended_module_unqualified_names.map do |unqualified_name|
439
+ resolve_constant(unqualified_name)
440
+ end
441
+ definition.extended_module_unqualified_names = []
442
+
351
443
  definition.included_module_qualified_names = definition.included_module_unqualified_names.map do |unqualified_name|
352
444
  resolve_constant(unqualified_name)
353
445
  end
@@ -359,5 +451,25 @@ module Rucoa
359
451
  definition.prepended_module_unqualified_names = []
360
452
  end
361
453
  end
454
+
455
+ # @param type [String]
456
+ # @return [String, nil]
457
+ def singleton_class_name_from(type)
458
+ type[/singleton<([\w:]+)>/, 1]
459
+ end
460
+
461
+ # @param definition [Rucoa::Definitions::Class]
462
+ # @return [Array<Rucoa::Definitions::Class>] super "class"es (not including modules) in closest-first order
463
+ def super_class_definitions_of(definition)
464
+ result = []
465
+ while (super_class_qualified_name = definition.super_class_qualified_name)
466
+ super_definition = find_definition_by_qualified_name(super_class_qualified_name)
467
+ break unless super_definition
468
+
469
+ result << super_definition
470
+ definition = super_definition
471
+ end
472
+ result
473
+ end
362
474
  end
363
475
  end
@@ -30,6 +30,17 @@ module Rucoa
30
30
  @types = types
31
31
  end
32
32
 
33
+ # @return [Boolean]
34
+ def instance_method?
35
+ @kind == :instance
36
+ end
37
+
38
+ # @todo
39
+ # @return [Array<Rucoa::Definitions::MethodParameter>]
40
+ def parameters
41
+ []
42
+ end
43
+
33
44
  # @return [String]
34
45
  # @example returns qualified name of method
35
46
  # definition = Rucoa::Source.new(
@@ -52,12 +63,6 @@ module Rucoa
52
63
  ].join
53
64
  end
54
65
 
55
- # @todo
56
- # @return [Array<Rucoa::Definitions::MethodParameter>]
57
- def parameters
58
- []
59
- end
60
-
61
66
  # @return [Array<String>]
62
67
  # @example returns return types
63
68
  # definition = Rucoa::Source.new(
@@ -105,11 +110,6 @@ module Rucoa
105
110
  end
106
111
  end
107
112
 
108
- # @return [Boolean]
109
- def instance_method?
110
- @kind == :instance
111
- end
112
-
113
113
  # @return [Boolean]
114
114
  def singleton_method?
115
115
  !instance_method?
@@ -3,6 +3,12 @@
3
3
  module Rucoa
4
4
  module Definitions
5
5
  class ModuleDefinition < ConstantDefinition
6
+ # @return [Array<String>]
7
+ attr_accessor :extended_module_qualified_names
8
+
9
+ # @return [Array<Rucoa::UnqualifiedName>]
10
+ attr_accessor :extended_module_unqualified_names
11
+
6
12
  # @return [Array<String>]
7
13
  attr_accessor :included_module_qualified_names
8
14
 
@@ -15,11 +21,15 @@ module Rucoa
15
21
  # @return [Array<Rucoa::UnqualifiedName>]
16
22
  attr_accessor :prepended_module_unqualified_names
17
23
 
24
+ # @param extended_module_qualified_names [Array<String>]
25
+ # @param extended_module_unqualified_names [Array<String>]
18
26
  # @param included_module_qualified_names [Array<String>]
19
27
  # @param included_module_unqualified_names [Array<String>]
20
28
  # @param prepended_module_qualified_names [Array<String>]
21
29
  # @param prepended_module_unqualified_names [Array<String>]
22
30
  def initialize(
31
+ extended_module_qualified_names: [],
32
+ extended_module_unqualified_names: [],
23
33
  included_module_qualified_names: [],
24
34
  included_module_unqualified_names: [],
25
35
  prepended_module_qualified_names: [],
@@ -27,6 +37,8 @@ module Rucoa
27
37
  **keyword_arguments
28
38
  )
29
39
  super(**keyword_arguments)
40
+ @extended_module_qualified_names = extended_module_qualified_names
41
+ @extended_module_unqualified_names = extended_module_unqualified_names
30
42
  @included_module_qualified_names = included_module_qualified_names
31
43
  @included_module_unqualified_names = included_module_unqualified_names
32
44
  @prepended_module_qualified_names = prepended_module_qualified_names
@@ -36,6 +48,8 @@ module Rucoa
36
48
  # @param other [Rucoa::Definitions::ModuleDefinition]
37
49
  # @return [Rucoa::Definitions::ModuleDefinition]
38
50
  def merge!(other)
51
+ self.extended_module_qualified_names |= other.extended_module_qualified_names
52
+ self.extended_module_unqualified_names |= other.extended_module_unqualified_names
39
53
  self.included_module_qualified_names |= other.included_module_qualified_names
40
54
  self.included_module_unqualified_names |= other.included_module_unqualified_names
41
55
  self.prepended_module_qualified_names |= other.prepended_module_qualified_names
@@ -7,6 +7,13 @@ module Rucoa
7
7
 
8
8
  private
9
9
 
10
+ # @return [void]
11
+ def publish_diagnostics_on_each_source
12
+ source_store.each_uri do |uri|
13
+ publish_diagnostics_on(uri)
14
+ end
15
+ end
16
+
10
17
  # @return [void]
11
18
  def request_workspace_configuration
12
19
  write(
@@ -23,13 +30,6 @@ module Rucoa
23
30
  publish_diagnostics_on_each_source
24
31
  end
25
32
  end
26
-
27
- # @return [void]
28
- def publish_diagnostics_on_each_source
29
- source_store.each_uri do |uri|
30
- publish_diagnostics_on(uri)
31
- end
32
- end
33
33
  end
34
34
  end
35
35
  end