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.
- checksums.yaml +4 -4
- data/.github/ISSUE_TEMPLATE/bug-report.md +0 -0
- data/.github/ISSUE_TEMPLATE/feature-request.md +0 -0
- data/.gitignore +1 -1
- data/.parlour +5 -0
- data/.rspec +0 -0
- data/.travis.yml +3 -3
- data/CHANGELOG.md +64 -0
- data/CODE_OF_CONDUCT.md +0 -0
- data/Gemfile +0 -0
- data/LICENSE.txt +0 -0
- data/README.md +233 -19
- data/Rakefile +0 -0
- data/exe/parlour +109 -4
- data/lib/parlour.rb +29 -1
- data/lib/parlour/conflict_resolver.rb +75 -27
- data/lib/parlour/conversion/converter.rb +34 -0
- data/lib/parlour/conversion/rbi_to_rbs.rb +223 -0
- data/lib/parlour/debugging.rb +0 -0
- data/lib/parlour/detached_rbi_generator.rb +1 -6
- data/lib/parlour/detached_rbs_generator.rb +25 -0
- data/lib/parlour/generator.rb +34 -0
- data/lib/parlour/kernel_hack.rb +0 -0
- data/lib/parlour/options.rb +71 -0
- data/lib/parlour/parse_error.rb +0 -0
- data/lib/parlour/plugin.rb +1 -1
- data/lib/parlour/rbi_generator.rb +24 -37
- data/lib/parlour/rbi_generator/arbitrary.rb +5 -2
- data/lib/parlour/rbi_generator/attribute.rb +14 -5
- data/lib/parlour/rbi_generator/class_namespace.rb +8 -3
- data/lib/parlour/rbi_generator/constant.rb +28 -8
- data/lib/parlour/rbi_generator/enum_class_namespace.rb +32 -5
- data/lib/parlour/rbi_generator/extend.rb +5 -2
- data/lib/parlour/rbi_generator/include.rb +5 -2
- data/lib/parlour/rbi_generator/method.rb +15 -10
- data/lib/parlour/rbi_generator/module_namespace.rb +7 -2
- data/lib/parlour/rbi_generator/namespace.rb +115 -27
- data/lib/parlour/rbi_generator/parameter.rb +13 -7
- data/lib/parlour/rbi_generator/rbi_object.rb +19 -78
- data/lib/parlour/rbi_generator/struct_class_namespace.rb +110 -0
- data/lib/parlour/rbi_generator/struct_prop.rb +139 -0
- data/lib/parlour/rbi_generator/type_alias.rb +101 -0
- data/lib/parlour/rbs_generator.rb +24 -0
- data/lib/parlour/rbs_generator/arbitrary.rb +92 -0
- data/lib/parlour/rbs_generator/attribute.rb +82 -0
- data/lib/parlour/rbs_generator/block.rb +49 -0
- data/lib/parlour/rbs_generator/class_namespace.rb +106 -0
- data/lib/parlour/rbs_generator/constant.rb +95 -0
- data/lib/parlour/rbs_generator/extend.rb +92 -0
- data/lib/parlour/rbs_generator/include.rb +92 -0
- data/lib/parlour/rbs_generator/interface_namespace.rb +34 -0
- data/lib/parlour/rbs_generator/method.rb +146 -0
- data/lib/parlour/rbs_generator/method_signature.rb +104 -0
- data/lib/parlour/rbs_generator/module_namespace.rb +35 -0
- data/lib/parlour/rbs_generator/namespace.rb +627 -0
- data/lib/parlour/rbs_generator/parameter.rb +145 -0
- data/lib/parlour/rbs_generator/rbs_object.rb +78 -0
- data/lib/parlour/rbs_generator/type_alias.rb +96 -0
- data/lib/parlour/type_loader.rb +30 -10
- data/lib/parlour/type_parser.rb +440 -43
- data/lib/parlour/typed_object.rb +87 -0
- data/lib/parlour/types.rb +445 -0
- data/lib/parlour/version.rb +1 -1
- data/parlour.gemspec +2 -2
- data/plugin_examples/foobar_plugin.rb +0 -0
- data/rbi/parlour.rbi +1799 -0
- metadata +42 -15
- 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
|