parlour 2.0.0 → 5.0.0.beta.1

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 (68) hide show
  1. checksums.yaml +4 -4
  2. data/.github/ISSUE_TEMPLATE/bug-report.md +0 -0
  3. data/.github/ISSUE_TEMPLATE/feature-request.md +0 -0
  4. data/.gitignore +1 -1
  5. data/.parlour +5 -0
  6. data/.rspec +0 -0
  7. data/.travis.yml +3 -3
  8. data/CHANGELOG.md +64 -0
  9. data/CODE_OF_CONDUCT.md +0 -0
  10. data/Gemfile +0 -0
  11. data/LICENSE.txt +0 -0
  12. data/README.md +233 -19
  13. data/Rakefile +0 -0
  14. data/exe/parlour +109 -4
  15. data/lib/parlour.rb +29 -1
  16. data/lib/parlour/conflict_resolver.rb +75 -27
  17. data/lib/parlour/conversion/converter.rb +34 -0
  18. data/lib/parlour/conversion/rbi_to_rbs.rb +223 -0
  19. data/lib/parlour/debugging.rb +0 -0
  20. data/lib/parlour/detached_rbi_generator.rb +1 -6
  21. data/lib/parlour/detached_rbs_generator.rb +25 -0
  22. data/lib/parlour/generator.rb +34 -0
  23. data/lib/parlour/kernel_hack.rb +0 -0
  24. data/lib/parlour/options.rb +71 -0
  25. data/lib/parlour/parse_error.rb +0 -0
  26. data/lib/parlour/plugin.rb +1 -1
  27. data/lib/parlour/rbi_generator.rb +24 -37
  28. data/lib/parlour/rbi_generator/arbitrary.rb +5 -2
  29. data/lib/parlour/rbi_generator/attribute.rb +14 -5
  30. data/lib/parlour/rbi_generator/class_namespace.rb +8 -3
  31. data/lib/parlour/rbi_generator/constant.rb +28 -8
  32. data/lib/parlour/rbi_generator/enum_class_namespace.rb +32 -5
  33. data/lib/parlour/rbi_generator/extend.rb +5 -2
  34. data/lib/parlour/rbi_generator/include.rb +5 -2
  35. data/lib/parlour/rbi_generator/method.rb +15 -10
  36. data/lib/parlour/rbi_generator/module_namespace.rb +7 -2
  37. data/lib/parlour/rbi_generator/namespace.rb +115 -27
  38. data/lib/parlour/rbi_generator/parameter.rb +13 -7
  39. data/lib/parlour/rbi_generator/rbi_object.rb +19 -78
  40. data/lib/parlour/rbi_generator/struct_class_namespace.rb +110 -0
  41. data/lib/parlour/rbi_generator/struct_prop.rb +139 -0
  42. data/lib/parlour/rbi_generator/type_alias.rb +101 -0
  43. data/lib/parlour/rbs_generator.rb +24 -0
  44. data/lib/parlour/rbs_generator/arbitrary.rb +92 -0
  45. data/lib/parlour/rbs_generator/attribute.rb +82 -0
  46. data/lib/parlour/rbs_generator/block.rb +49 -0
  47. data/lib/parlour/rbs_generator/class_namespace.rb +106 -0
  48. data/lib/parlour/rbs_generator/constant.rb +95 -0
  49. data/lib/parlour/rbs_generator/extend.rb +92 -0
  50. data/lib/parlour/rbs_generator/include.rb +92 -0
  51. data/lib/parlour/rbs_generator/interface_namespace.rb +34 -0
  52. data/lib/parlour/rbs_generator/method.rb +146 -0
  53. data/lib/parlour/rbs_generator/method_signature.rb +104 -0
  54. data/lib/parlour/rbs_generator/module_namespace.rb +35 -0
  55. data/lib/parlour/rbs_generator/namespace.rb +627 -0
  56. data/lib/parlour/rbs_generator/parameter.rb +145 -0
  57. data/lib/parlour/rbs_generator/rbs_object.rb +78 -0
  58. data/lib/parlour/rbs_generator/type_alias.rb +96 -0
  59. data/lib/parlour/type_loader.rb +30 -10
  60. data/lib/parlour/type_parser.rb +440 -43
  61. data/lib/parlour/typed_object.rb +87 -0
  62. data/lib/parlour/types.rb +445 -0
  63. data/lib/parlour/version.rb +1 -1
  64. data/parlour.gemspec +2 -2
  65. data/plugin_examples/foobar_plugin.rb +0 -0
  66. data/rbi/parlour.rbi +1799 -0
  67. metadata +42 -15
  68. data/lib/parlour/rbi_generator/options.rb +0 -74
@@ -0,0 +1,35 @@
1
+ # typed: true
2
+ module Parlour
3
+ class RbsGenerator < Generator
4
+ # Represents a module definition.
5
+ class ModuleNamespace < Namespace
6
+ extend T::Sig
7
+
8
+ sig do
9
+ override.params(
10
+ indent_level: Integer,
11
+ options: Options
12
+ ).returns(T::Array[String])
13
+ end
14
+ # Generates the RBS lines for this module.
15
+ #
16
+ # @param indent_level [Integer] The indentation level to generate the lines at.
17
+ # @param options [Options] The formatting options to use.
18
+ # @return [Array<String>] The RBS lines, formatted as specified.
19
+ def generate_rbs(indent_level, options)
20
+ lines = generate_comments(indent_level, options)
21
+ lines << options.indented(indent_level, "module #{name}")
22
+ lines += generate_body(indent_level + 1, options)
23
+ lines << options.indented(indent_level, "end")
24
+ end
25
+
26
+ sig { override.returns(String) }
27
+ # Returns a human-readable brief string description of this module.
28
+ # @return [String]
29
+ def describe
30
+ "Module #{name} - #{children.length} " +
31
+ "children, #{includes.length} includes, #{extends.length} extends"
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,627 @@
1
+ # typed: true
2
+ module Parlour
3
+ class RbsGenerator < Generator
4
+ # A generic namespace. This shouldn't be used, except as the type of
5
+ # {RbsGenerator#root}.
6
+ class Namespace < RbsObject
7
+ extend T::Sig
8
+
9
+ sig do
10
+ override.overridable.params(
11
+ indent_level: Integer,
12
+ options: Options
13
+ ).returns(T::Array[String])
14
+ end
15
+ # Generates the RBS lines for this namespace.
16
+ #
17
+ # @param indent_level [Integer] The indentation level to generate the lines at.
18
+ # @param options [Options] The formatting options to use.
19
+ # @return [Array<String>] The RBS lines, formatted as specified.
20
+ def generate_rbs(indent_level, options)
21
+ generate_comments(indent_level, options) +
22
+ generate_body(indent_level, options)
23
+ end
24
+
25
+ sig do
26
+ params(
27
+ generator: Generator,
28
+ name: T.nilable(String),
29
+ block: T.nilable(T.proc.params(x: Namespace).void)
30
+ ).void
31
+ end
32
+ # Creates a new namespace.
33
+ # @note Unless you're doing something impressively hacky, this shouldn't
34
+ # be invoked outside of {RbsGenerator#initialize}.
35
+ #
36
+ # @param generator [RbsGenerator] The current RbsGenerator.
37
+ # @param name [String, nil] The name of this module.
38
+ # @param final [Boolean] Whether this namespace is final.
39
+ # @param block A block which the new instance yields itself to.
40
+ # @return [void]
41
+ def initialize(generator, name = nil, &block)
42
+ super(generator, name || '<anonymous namespace>')
43
+ @children = []
44
+ @next_comments = []
45
+ yield_self(&block) if block
46
+ end
47
+
48
+ sig { returns(T::Array[RbsObject]) }
49
+ # The child {RbsObject} instances inside this namespace.
50
+ # @return [Array<RbsObject>]
51
+ attr_reader :children
52
+
53
+ sig { returns(T::Array[RbsGenerator::Extend]) }
54
+ # The {RbsGenerator::Extend} objects from {children}.
55
+ # @return [Array<RbsGenerator::Extend>]
56
+ def extends
57
+ T.cast(
58
+ children.select { |c| c.is_a?(RbsGenerator::Extend) },
59
+ T::Array[RbsGenerator::Extend]
60
+ )
61
+ end
62
+
63
+ sig { returns(T::Array[RbsGenerator::Include]) }
64
+ # The {RbsGenerator::Include} objects from {children}.
65
+ # @return [Array<RbsGenerator::Include>]
66
+ def includes
67
+ T.cast(
68
+ children.select { |c| c.is_a?(RbsGenerator::Include) },
69
+ T::Array[RbsGenerator::Include]
70
+ )
71
+ end
72
+
73
+ sig { returns(T::Array[RbsGenerator::TypeAlias]) }
74
+ # The {RbsGenerator::TypeAlias} objects from {children}.
75
+ # @return [Array<RbsGenerator::TypeAlias>]
76
+ def aliases
77
+ T.cast(
78
+ children.select { |c| c.is_a?(RbsGenerator::TypeAlias) },
79
+ T::Array[RbsGenerator::TypeAlias]
80
+ )
81
+ end
82
+ alias type_aliases aliases
83
+
84
+ sig { returns(T::Array[RbsGenerator::Constant]) }
85
+ # The {RbsGenerator::Constant} objects from {children}.
86
+ # @return [Array<RbsGenerator::Constant>]
87
+ def constants
88
+ T.cast(
89
+ children.select { |c| c.is_a?(RbsGenerator::Constant) },
90
+ T::Array[RbsGenerator::Constant]
91
+ )
92
+ end
93
+
94
+ sig { params(object: T.untyped, block: T.proc.params(x: Namespace).void).void }
95
+ # Given a Class or Module object, generates all classes and modules in the
96
+ # path to that object, then executes the given block on the last
97
+ # {Namespace}. This should only be executed on the root namespace.
98
+ # @param [Class, Module] object
99
+ # @param block A block which the new {Namespace} yields itself to.
100
+ def path(object, &block)
101
+ raise 'only call #path on root' if is_a?(ClassNamespace) || is_a?(ModuleNamespace)
102
+
103
+ parts = object.to_s.split('::')
104
+ parts_with_types = parts.size.times.map do |i|
105
+ [parts[i], Module.const_get(parts[0..i].join('::')).class]
106
+ end
107
+
108
+ current_part = self
109
+ parts_with_types.each do |(name, type)|
110
+ if type == Class
111
+ current_part = current_part.create_class(name)
112
+ elsif type == Module
113
+ current_part = current_part.create_module(name)
114
+ else
115
+ raise "unexpected type: path part #{name} is a #{type}"
116
+ end
117
+ end
118
+
119
+ block.call(current_part)
120
+ end
121
+
122
+ sig { params(comment: T.any(String, T::Array[String])).void }
123
+ # Adds one or more comments to the next child RBS object to be created.
124
+ #
125
+ # @example Creating a module with a comment.
126
+ # namespace.add_comment_to_next_child('This is a module')
127
+ # namespace.create_module('M')
128
+ #
129
+ # @example Creating a class with a multi-line comment.
130
+ # namespace.add_comment_to_next_child(['This is a multi-line comment!', 'It can be as long as you want!'])
131
+ # namespace.create_class('C')
132
+ #
133
+ # @param comment [String, Array<String>] The new comment(s).
134
+ # @return [void]
135
+ def add_comment_to_next_child(comment)
136
+ if comment.is_a?(String)
137
+ @next_comments << comment
138
+ elsif comment.is_a?(Array)
139
+ @next_comments.concat(comment)
140
+ end
141
+ end
142
+
143
+ sig do
144
+ params(
145
+ name: String,
146
+ superclass: T.nilable(Types::TypeLike),
147
+ block: T.nilable(T.proc.params(x: ClassNamespace).void)
148
+ ).returns(ClassNamespace)
149
+ end
150
+ # Creates a new class definition as a child of this namespace.
151
+ #
152
+ # @example Create a class with a nested module.
153
+ # namespace.create_class('Foo') do |foo|
154
+ # foo.create_module('Bar')
155
+ # end
156
+ #
157
+ # @example Create a class that is the child of another class.
158
+ # namespace.create_class('Bar', superclass: 'Foo') #=> class Bar < Foo
159
+ #
160
+ # @param name [String] The name of this class.
161
+ # @param superclass [String, nil] The superclass of this class, or nil if it doesn't
162
+ # have one.
163
+ # @param block A block which the new instance yields itself to.
164
+ # @return [ClassNamespace]
165
+ def create_class(name, superclass: nil, &block)
166
+ new_class = ClassNamespace.new(generator, name, superclass, &block)
167
+ move_next_comments(new_class)
168
+ children << new_class
169
+ new_class
170
+ end
171
+
172
+ sig do
173
+ params(
174
+ name: String,
175
+ block: T.nilable(T.proc.params(x: Namespace).void)
176
+ ).returns(ModuleNamespace)
177
+ end
178
+ # Creates a new module definition as a child of this namespace.
179
+ #
180
+ # @example Create a basic module.
181
+ # namespace.create_module('Foo')
182
+ #
183
+ # @param name [String] The name of this module.
184
+ # @param block A block which the new instance yields itself to.
185
+ # @return [ModuleNamespace]
186
+ def create_module(name, &block)
187
+ new_module = ModuleNamespace.new(generator, name, &block)
188
+ move_next_comments(new_module)
189
+ children << new_module
190
+ new_module
191
+ end
192
+
193
+ sig do
194
+ params(
195
+ name: String,
196
+ block: T.nilable(T.proc.params(x: Namespace).void)
197
+ ).returns(InterfaceNamespace)
198
+ end
199
+ # Creates a new interface definition as a child of this namespace.
200
+ #
201
+ # @example Create a basic interface.
202
+ # namespace.create_interface('Foo')
203
+ #
204
+ # @param name [String] The name of this interface.
205
+ # @param block A block which the new instance yields itself to.
206
+ # @return [InterfaceNamespace]
207
+ def create_interface(name, &block)
208
+ new_interface = InterfaceNamespace.new(generator, name, &block)
209
+ move_next_comments(new_interface)
210
+ children << new_interface
211
+ new_interface
212
+ end
213
+
214
+ sig do
215
+ params(
216
+ name: String,
217
+ signatures: T.nilable(T::Array[MethodSignature]),
218
+ class_method: T::Boolean,
219
+ block: T.nilable(T.proc.params(x: Method).void)
220
+ ).returns(Method)
221
+ end
222
+ # Creates a new method definition as a child of this namespace.
223
+ #
224
+ # @param name [String] The name of this method. You should not specify +self.+ in
225
+ # this - use the +class_method+ parameter instead.
226
+ # @param signatures [Array<MethodSignature>] The signatures for each
227
+ # overload of this method.
228
+ # @param class_method [Boolean] Whether this method is a class method; that is, it
229
+ # it is defined using +self.+.
230
+ # @param block A block which the new instance yields itself to.
231
+ # @return [Method]
232
+ def create_method(name, signatures = nil, class_method: false, &block)
233
+ raise 'cannot have a method with no signatures' if signatures&.empty?
234
+ new_method = RbsGenerator::Method.new(
235
+ generator,
236
+ name,
237
+ signatures || [MethodSignature.new([], nil)],
238
+ class_method: class_method,
239
+ &block
240
+ )
241
+ move_next_comments(new_method)
242
+ children << new_method
243
+ new_method
244
+ end
245
+
246
+ sig do
247
+ params(
248
+ name: String,
249
+ kind: Symbol,
250
+ type: Types::TypeLike,
251
+ block: T.nilable(T.proc.params(x: Attribute).void)
252
+ ).returns(Attribute)
253
+ end
254
+ # Creates a new attribute.
255
+ #
256
+ # @example Create an +attr_reader+.
257
+ # module.create_attribute('readable', kind: :reader, type: 'String')
258
+ # # #=> attr_reader readable: String
259
+ #
260
+ # @example Create an +attr_writer+.
261
+ # module.create_attribute('writable', kind: :writer, type: 'Integer')
262
+ # # #=> attr_writer writable: Integer
263
+ #
264
+ # @example Create an +attr_accessor+.
265
+ # module.create_attribute('accessible', kind: :accessor, type: Types::Boolean.new)
266
+ # # #=> attr_accessor accessible: bool
267
+ #
268
+ # @param name [String] The name of this attribute.
269
+ # @param kind [Symbol] The kind of attribute this is; one of +:writer+, +:reader+, or
270
+ # +:accessor+.
271
+ # @param type [Types::TypeLike] This attribute's type.
272
+ # @param class_attribute [Boolean] Whether this attribute belongs to the
273
+ # singleton class.
274
+ # @param block A block which the new instance yields itself to.
275
+ # @return [RbsGenerator::Attribute]
276
+ def create_attribute(name, kind:, type:, &block)
277
+ new_attribute = RbsGenerator::Attribute.new(
278
+ generator,
279
+ name,
280
+ kind,
281
+ type,
282
+ &block
283
+ )
284
+ move_next_comments(new_attribute)
285
+ children << new_attribute
286
+ new_attribute
287
+ end
288
+ alias_method :create_attr, :create_attribute
289
+
290
+ sig do
291
+ params(
292
+ name: String,
293
+ type: Types::TypeLike,
294
+ block: T.nilable(T.proc.params(x: Attribute).void)
295
+ ).returns(Attribute)
296
+ end
297
+ # Creates a new read-only attribute (+attr_reader+).
298
+ #
299
+ # @param name [String] The name of this attribute.
300
+ # @param type [Types::TypeLike] This attribute's type.
301
+ # @param class_attribute [Boolean] Whether this attribute belongs to the
302
+ # singleton class.
303
+ # @param block A block which the new instance yields itself to.
304
+ # @return [RbsGenerator::Attribute]
305
+ def create_attr_reader(name, type:, &block)
306
+ create_attribute(name, kind: :reader, type: type, &block)
307
+ end
308
+
309
+ sig do
310
+ params(
311
+ name: String,
312
+ type: Types::TypeLike,
313
+ block: T.nilable(T.proc.params(x: Attribute).void)
314
+ ).returns(Attribute)
315
+ end
316
+ # Creates a new write-only attribute (+attr_writer+).
317
+ #
318
+ # @param name [String] The name of this attribute.
319
+ # @param type [Types::TypeLike] This attribute's type.
320
+ # @param class_attribute [Boolean] Whether this attribute belongs to the
321
+ # singleton class.
322
+ # @param block A block which the new instance yields itself to.
323
+ # @return [RbsGenerator::Attribute]
324
+ def create_attr_writer(name, type:, &block)
325
+ create_attribute(name, kind: :writer, type: type, &block)
326
+ end
327
+
328
+ sig do
329
+ params(
330
+ name: String,
331
+ type: Types::TypeLike,
332
+ block: T.nilable(T.proc.params(x: Attribute).void)
333
+ ).returns(Attribute)
334
+ end
335
+ # Creates a new read and write attribute (+attr_accessor+).
336
+ #
337
+ # @param name [String] The name of this attribute.
338
+ # @param type [Types::TypeLike] This attribute's type.
339
+ # @param class_attribute [Boolean] Whether this attribute belongs to the
340
+ # singleton class.
341
+ # @param block A block which the new instance yields itself to.
342
+ # @return [RbsGenerator::Attribute]
343
+ def create_attr_accessor(name, type:, &block)
344
+ create_attribute(name, kind: :accessor, type: type, &block)
345
+ end
346
+
347
+ # Creates a new arbitrary code section.
348
+ # You should rarely have to use this!
349
+ #
350
+ # @param code [String] The code to insert.
351
+ # @param block A block which the new instance yields itself to.
352
+ # @return [RbsGenerator::Arbitrary]
353
+ def create_arbitrary(code:, &block)
354
+ new_arbitrary = RbsGenerator::Arbitrary.new(
355
+ generator,
356
+ code: code,
357
+ &block
358
+ )
359
+ move_next_comments(new_arbitrary)
360
+ children << new_arbitrary
361
+ new_arbitrary
362
+ end
363
+
364
+ sig { params(type: Types::TypeLike, block: T.nilable(T.proc.params(x: Extend).void)).returns(RbsGenerator::Extend) }
365
+ # Adds a new +extend+ to this namespace.
366
+ #
367
+ # @example Add an +extend+ to a class.
368
+ # class.create_extend('ExtendableClass') #=> extend ExtendableClass
369
+ #
370
+ # @param type [Types::TypeLike] The type to extend.
371
+ # @param block A block which the new instance yields itself to.
372
+ # @return [RbsGenerator::Extend]
373
+ def create_extend(type, &block)
374
+ new_extend = RbsGenerator::Extend.new(
375
+ generator,
376
+ type: type,
377
+ &block
378
+ )
379
+ move_next_comments(new_extend)
380
+ children << new_extend
381
+ new_extend
382
+ end
383
+
384
+ sig { params(extendables: T::Array[Types::TypeLike]).returns(T::Array[Extend]) }
385
+ # Adds new +extend+s to this namespace.
386
+ #
387
+ # @example Add +extend+s to a class.
388
+ # class.create_extends(['Foo', 'Bar'])
389
+ #
390
+ # @param [Array<Types::TypeLike>] extendables An array of types to extend.
391
+ # @return [Array<RbsGenerator::Extend>]
392
+ def create_extends(extendables)
393
+ returned_extendables = []
394
+ extendables.each do |extendable|
395
+ returned_extendables << create_extend(extendable)
396
+ end
397
+ returned_extendables
398
+ end
399
+
400
+ sig { params(type: Types::TypeLike, block: T.nilable(T.proc.params(x: Include).void)).returns(Include) }
401
+ # Adds a new +include+ to this namespace.
402
+ #
403
+ # @example Add an +include+ to a class.
404
+ # class.create_include('IncludableClass') #=> include IncludableClass
405
+ #
406
+ # @param type [Types::TypeLike] The type to extend.
407
+ # @param block A block which the new instance yields itself to.
408
+ # @return [RbsGenerator::Include]
409
+ def create_include(type, &block)
410
+ new_include = RbsGenerator::Include.new(
411
+ generator,
412
+ type: type,
413
+ &block
414
+ )
415
+ move_next_comments(new_include)
416
+ children << new_include
417
+ new_include
418
+ end
419
+
420
+ sig { params(includables: T::Array[Types::TypeLike]).returns(T::Array[Include]) }
421
+ # Adds new +include+s to this namespace.
422
+ #
423
+ # @example Add +include+s to a class.
424
+ # class.create_includes(['Foo', 'Bar'])
425
+ #
426
+ # @param [Array<Types::TypeLike>] includables An array of types to extend.
427
+ # @return [Array<RbsGenerator::Include>]
428
+ def create_includes(includables)
429
+ returned_includables = []
430
+ includables.each do |includable|
431
+ returned_includables << create_include(includable)
432
+ end
433
+ returned_includables
434
+ end
435
+
436
+ sig { params(name: String, type: Types::TypeLike, block: T.nilable(T.proc.params(x: Constant).void)).returns(Constant) }
437
+ # Adds a new constant definition to this namespace.
438
+ #
439
+ # @example Add an +Elem+ constant to the class.
440
+ # class.create_constant('FOO', type: 'String') #=> FOO: String
441
+ #
442
+ # @param name [String] The name of the constant.
443
+ # @param type [Types::TypeLike] The type of the constant, as a Ruby code string.
444
+ # @param block A block which the new instance yields itself to.
445
+ # @return [RbsGenerator::Constant]
446
+ def create_constant(name, type:, &block)
447
+ new_constant = RbsGenerator::Constant.new(
448
+ generator,
449
+ name,
450
+ type: type,
451
+ &block
452
+ )
453
+ move_next_comments(new_constant)
454
+ children << new_constant
455
+ new_constant
456
+ end
457
+
458
+ sig { params(name: String, type: Types::TypeLike, block: T.nilable(T.proc.params(x: TypeAlias).void)).returns(TypeAlias) }
459
+ # Adds a new type alias, in the form of a constant, to this namespace.
460
+ #
461
+ # @example Add a +MyType+ type alias, to +Integer+, to the class.
462
+ # class.create_type_alias('MyType', type: 'Integer') #=> type MyType = Integer
463
+ #
464
+ # @param name [String] The name of the type alias.
465
+ # @param value [Types::TypeLike] The type to alias.
466
+ # @param block A block which the new instance yields itself to.
467
+ # @return [RbsGenerator::TypeAlias]
468
+ def create_type_alias(name, type:, &block)
469
+ new_type_alias = TypeAlias.new(
470
+ generator,
471
+ name: name,
472
+ type: type,
473
+ &block
474
+ )
475
+ move_next_comments(new_type_alias)
476
+ children << new_type_alias
477
+ new_type_alias
478
+ end
479
+
480
+ sig do
481
+ override.overridable.params(
482
+ others: T::Array[RbsGenerator::RbsObject]
483
+ ).returns(T::Boolean)
484
+ end
485
+ # Given an array of {Namespace} instances, returns true if they may be
486
+ # merged into this instance using {merge_into_self}. All bare namespaces
487
+ # can be merged into each other, as they lack definitions for themselves,
488
+ # so there is nothing to conflict. (This isn't the case for subclasses
489
+ # such as {ClassNamespace}.)
490
+ #
491
+ # @param others [Array<RbsGenerator::RbsObject>] An array of other {Namespace} instances.
492
+ # @return [true] Always true.
493
+ def mergeable?(others)
494
+ true
495
+ end
496
+
497
+ sig do
498
+ override.overridable.params(
499
+ others: T::Array[RbsGenerator::RbsObject]
500
+ ).void
501
+ end
502
+ # Given an array of {Namespace} instances, merges them into this one.
503
+ # All children, constants, extends and includes are copied into this
504
+ # instance.
505
+ #
506
+ # There may also be {RbsGenerator::Method} instances in the stream, which
507
+ # are ignored.
508
+ #
509
+ # @param others [Array<RbsGenerator::RbsObject>] An array of other {Namespace} instances.
510
+ # @return [void]
511
+ def merge_into_self(others)
512
+ others.each do |other|
513
+ next if other.is_a?(RbsGenerator::Method)
514
+ other = T.cast(other, Namespace)
515
+
516
+ other.children.each { |c| children << c }
517
+ end
518
+ end
519
+
520
+ sig { override.overridable.returns(String) }
521
+ # Returns a human-readable brief string description of this namespace.
522
+ #
523
+ # @return [String]
524
+ def describe
525
+ "Namespace #{name} - #{children.length} children, #{includes.length} " +
526
+ "includes, #{extends.length} extends, #{constants.length} constants"
527
+ end
528
+
529
+ private
530
+
531
+ sig do
532
+ overridable.params(
533
+ indent_level: Integer,
534
+ options: Options,
535
+ ).returns(T::Array[String])
536
+ end
537
+ # Generates the RBS lines for the body of this namespace. This consists of
538
+ # {includes}, {extends} and {children}.
539
+ #
540
+ # @param indent_level [Integer] The indentation level to generate the lines at.
541
+ # @param options [Options] The formatting options to use.
542
+ # @param mode [Symbol] The symbol to send to generate children: one of
543
+ # :generate_rbs or :generate_rbs.
544
+ # @return [Array<String>] The RBS lines for the body, formatted as specified.
545
+ def generate_body(indent_level, options)
546
+ result = []
547
+
548
+ if includes.any? || extends.any? || aliases.any? || constants.any?
549
+ result += (options.sort_namespaces \
550
+ ? includes.sort_by { |x| t = x.type; String === t ? t : t.generate_rbs }
551
+ : includes)
552
+ .flat_map { |x| x.generate_rbs(indent_level, options) }
553
+ .reject { |x| x.strip == '' }
554
+ result += (options.sort_namespaces \
555
+ ? extends.sort_by { |x| t = x.type; String === t ? t : t.generate_rbs }
556
+ : extends)
557
+ .flat_map { |x| x.generate_rbs(indent_level, options) }
558
+ .reject { |x| x.strip == '' }
559
+ result += (options.sort_namespaces \
560
+ ? aliases.sort_by { |x| t = x.type; String === t ? t : t.generate_rbs }
561
+ : aliases)
562
+ .flat_map { |x| x.generate_rbs(indent_level, options) }
563
+ .reject { |x| x.strip == '' }
564
+ result += (options.sort_namespaces \
565
+ ? constants.sort_by { |x| t = x.type; String === t ? t : t.generate_rbs }
566
+ : constants)
567
+ .flat_map { |x| x.generate_rbs(indent_level, options) }
568
+ .reject { |x| x.strip == '' }
569
+ result << ""
570
+ end
571
+
572
+ # Sort children
573
+ sorted_children = (
574
+ if options.sort_namespaces
575
+ # sort_by can be unstable (and is in current MRI).
576
+ # Use the this work around to preserve order for ties
577
+ children.sort_by.with_index { |child, i| [child.name, i] }
578
+ else
579
+ children
580
+ end
581
+ )
582
+
583
+ first, *rest = sorted_children.reject do |child|
584
+ # We already processed these kinds of children
585
+ child.is_a?(Include) || child.is_a?(Extend) || child.is_a?(Constant) || child.is_a?(TypeAlias)
586
+ end.reject do |child|
587
+ next if is_a?(ClassNamespace) || is_a?(ModuleNamespace) # next if this is not root
588
+
589
+ if child.is_a?(RbsGenerator::Method)
590
+ unless $VERBOSE.nil?
591
+ print Rainbow("Parlour warning: ").yellow.dark.bold
592
+ print Rainbow("RBS generation: ").magenta.bright.bold
593
+ puts "RBS does not support top-level method definitions, ignoring #{child.name}"
594
+ print Rainbow(" └ at object: ").blue.bright.bold
595
+ puts describe
596
+ end
597
+ next true
598
+ end
599
+
600
+ false
601
+ end
602
+ unless first
603
+ # Remove any trailing whitespace due to includes or class attributes
604
+ result.pop while result.last == ''
605
+ return result
606
+ end
607
+
608
+ result += first.generate_rbs(indent_level, options) + T.must(rest)
609
+ .map { |obj| obj.generate_rbs(indent_level, options) }
610
+ .map { |lines| [""] + lines }
611
+ .flatten
612
+
613
+ result
614
+ end
615
+
616
+ sig { params(object: RbsObject).void }
617
+ # Copies the comments added with {#add_comment_to_next_child} into the
618
+ # given object, and clears the list of pending comments.
619
+ # @param object [RbsObject] The object to move the comments into.
620
+ # @return [void]
621
+ def move_next_comments(object)
622
+ object.comments.unshift(*@next_comments)
623
+ @next_comments.clear
624
+ end
625
+ end
626
+ end
627
+ end