parlour 4.0.1 → 5.0.0.beta.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +24 -0
  3. data/README.md +208 -20
  4. data/exe/parlour +45 -6
  5. data/lib/parlour.rb +27 -1
  6. data/lib/parlour/conversion/converter.rb +34 -0
  7. data/lib/parlour/conversion/rbi_to_rbs.rb +223 -0
  8. data/lib/parlour/detached_rbs_generator.rb +25 -0
  9. data/lib/parlour/generator.rb +34 -0
  10. data/lib/parlour/options.rb +71 -0
  11. data/lib/parlour/rbi_generator.rb +24 -37
  12. data/lib/parlour/rbi_generator/arbitrary.rb +5 -2
  13. data/lib/parlour/rbi_generator/attribute.rb +14 -5
  14. data/lib/parlour/rbi_generator/class_namespace.rb +8 -3
  15. data/lib/parlour/rbi_generator/constant.rb +17 -6
  16. data/lib/parlour/rbi_generator/enum_class_namespace.rb +8 -3
  17. data/lib/parlour/rbi_generator/extend.rb +5 -2
  18. data/lib/parlour/rbi_generator/include.rb +5 -2
  19. data/lib/parlour/rbi_generator/method.rb +15 -10
  20. data/lib/parlour/rbi_generator/module_namespace.rb +7 -2
  21. data/lib/parlour/rbi_generator/namespace.rb +39 -12
  22. data/lib/parlour/rbi_generator/parameter.rb +11 -5
  23. data/lib/parlour/rbi_generator/rbi_object.rb +19 -78
  24. data/lib/parlour/rbi_generator/struct_class_namespace.rb +9 -2
  25. data/lib/parlour/rbi_generator/struct_prop.rb +12 -9
  26. data/lib/parlour/rbi_generator/type_alias.rb +101 -0
  27. data/lib/parlour/rbs_generator.rb +24 -0
  28. data/lib/parlour/rbs_generator/arbitrary.rb +92 -0
  29. data/lib/parlour/rbs_generator/attribute.rb +82 -0
  30. data/lib/parlour/rbs_generator/block.rb +49 -0
  31. data/lib/parlour/rbs_generator/class_namespace.rb +106 -0
  32. data/lib/parlour/rbs_generator/constant.rb +95 -0
  33. data/lib/parlour/rbs_generator/extend.rb +92 -0
  34. data/lib/parlour/rbs_generator/include.rb +92 -0
  35. data/lib/parlour/rbs_generator/interface_namespace.rb +34 -0
  36. data/lib/parlour/rbs_generator/method.rb +146 -0
  37. data/lib/parlour/rbs_generator/method_signature.rb +104 -0
  38. data/lib/parlour/rbs_generator/module_namespace.rb +35 -0
  39. data/lib/parlour/rbs_generator/namespace.rb +627 -0
  40. data/lib/parlour/rbs_generator/parameter.rb +145 -0
  41. data/lib/parlour/rbs_generator/rbs_object.rb +78 -0
  42. data/lib/parlour/rbs_generator/type_alias.rb +96 -0
  43. data/lib/parlour/type_parser.rb +152 -0
  44. data/lib/parlour/typed_object.rb +87 -0
  45. data/lib/parlour/types.rb +445 -0
  46. data/lib/parlour/version.rb +1 -1
  47. data/parlour.gemspec +1 -1
  48. data/rbi/parlour.rbi +982 -76
  49. metadata +30 -7
  50. data/lib/parlour/rbi_generator/options.rb +0 -74
@@ -0,0 +1,87 @@
1
+ # typed: true
2
+ module Parlour
3
+ # A generic superclass of all objects which form part of type definitions in,
4
+ # specific formats, such as RbiObject and RbsObject.
5
+ class TypedObject
6
+ extend T::Sig
7
+ extend T::Helpers
8
+ abstract!
9
+
10
+ sig { params(name: String).void }
11
+ # Create a new typed object.
12
+ def initialize(name)
13
+ @name = name
14
+ @comments = []
15
+ end
16
+
17
+ sig { returns(T.nilable(Plugin)) }
18
+ # The {Plugin} which was controlling the {generator} when this object was
19
+ # created.
20
+ # @return [Plugin, nil]
21
+ attr_reader :generated_by
22
+
23
+ sig { returns(String) }
24
+ # The name of this object.
25
+ # @return [String]
26
+ attr_reader :name
27
+
28
+ sig { returns(T::Array[String]) }
29
+ # An array of comments which will be placed above the object in the RBS
30
+ # file.
31
+ # @return [Array<String>]
32
+ attr_reader :comments
33
+
34
+ sig { params(comment: T.any(String, T::Array[String])).void }
35
+ # Adds one or more comments to this RBS object. Comments always go above
36
+ # the definition for this object, not in the definition's body.
37
+ #
38
+ # @example Creating a module with a comment.
39
+ # namespace.create_module('M') do |m|
40
+ # m.add_comment('This is a module')
41
+ # end
42
+ #
43
+ # @example Creating a class with a multi-line comment.
44
+ # namespace.create_class('C') do |c|
45
+ # c.add_comment(['This is a multi-line comment!', 'It can be as long as you want!'])
46
+ # end
47
+ #
48
+ # @param comment [String, Array<String>] The new comment(s).
49
+ # @return [void]
50
+ def add_comment(comment)
51
+ if comment.is_a?(String)
52
+ comments << comment
53
+ elsif comment.is_a?(Array)
54
+ comments.concat(comment)
55
+ end
56
+ end
57
+
58
+ alias_method :add_comments, :add_comment
59
+
60
+ sig { abstract.returns(String) }
61
+ # Returns a human-readable brief string description of this object. This
62
+ # is displayed during manual conflict resolution with the +parlour+ CLI.
63
+ #
64
+ # @abstract
65
+ # @return [String]
66
+ def describe; end
67
+
68
+ protected
69
+
70
+ sig do
71
+ params(
72
+ indent_level: Integer,
73
+ options: Options
74
+ ).returns(T::Array[String])
75
+ end
76
+ # Generates the RBS lines for this object's comments.
77
+ #
78
+ # @param indent_level [Integer] The indentation level to generate the lines at.
79
+ # @param options [Options] The formatting options to use.
80
+ # @return [Array<String>] The RBS lines for each comment, formatted as specified.
81
+ def generate_comments(indent_level, options)
82
+ comments.any? \
83
+ ? comments.map { |c| options.indented(indent_level, "# #{c}") }
84
+ : []
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,445 @@
1
+ # typed: true
2
+
3
+ module Parlour
4
+ # Contains structured types which can be used in type signatures.
5
+ module Types
6
+ TypeLike = T.type_alias { T.any(String, Type) }
7
+
8
+ # The top-level, abstract class for a generalised type. All of the other
9
+ # types inherit from this. Do not instantiate.
10
+ class Type
11
+ extend T::Sig
12
+ extend T::Helpers
13
+
14
+ abstract!
15
+
16
+ sig { abstract.returns(String) }
17
+ def generate_rbi; end
18
+
19
+ sig { abstract.returns(String) }
20
+ def generate_rbs; end
21
+
22
+ sig { params(type_like: TypeLike).returns(Type) }
23
+ def self.to_type(type_like)
24
+ if type_like.is_a?(String)
25
+ Raw.new(type_like)
26
+ else
27
+ type_like
28
+ end
29
+ end
30
+
31
+ sig { params(type_like: TypeLike).returns(Type) }
32
+ def to_type(type_like)
33
+ Type.to_type(type_like)
34
+ end
35
+ end
36
+
37
+ # A basic type as a raw string.
38
+ class Raw < Type
39
+ sig { params(str: String).void }
40
+ def initialize(str)
41
+ @str = str
42
+ end
43
+
44
+ sig { returns(String) }
45
+ attr_reader :str
46
+
47
+ sig { params(other: Object).returns(T::Boolean) }
48
+ def ==(other)
49
+ Raw === other && str == other.str
50
+ end
51
+
52
+ sig { override.returns(String) }
53
+ def generate_rbi
54
+ str
55
+ end
56
+
57
+ sig { override.returns(String) }
58
+ def generate_rbs
59
+ str
60
+ end
61
+ end
62
+
63
+ # A type which can be either the wrapped type, or nil.
64
+ class Nilable < Type
65
+ sig { params(type: TypeLike).void }
66
+ def initialize(type)
67
+ @type = to_type(type)
68
+ end
69
+
70
+ sig { params(other: Object).returns(T::Boolean) }
71
+ def ==(other)
72
+ Nilable === other && type == other.type
73
+ end
74
+
75
+ sig { returns(Type) }
76
+ attr_reader :type
77
+
78
+ sig { override.returns(String) }
79
+ def generate_rbi
80
+ "T.nilable(#{type.generate_rbi})"
81
+ end
82
+
83
+ sig { override.returns(String) }
84
+ def generate_rbs
85
+ "#{type.generate_rbs}?"
86
+ end
87
+ end
88
+
89
+ # A type which is (at least) one of the wrapped types.
90
+ class Union < Type
91
+ sig { params(types: T::Array[TypeLike]).void }
92
+ def initialize(types)
93
+ @types = types.map(&method(:to_type))
94
+ end
95
+
96
+ sig { params(other: Object).returns(T::Boolean) }
97
+ def ==(other)
98
+ Union === other && types == other.types
99
+ end
100
+
101
+ sig { returns(T::Array[Type]) }
102
+ attr_reader :types
103
+
104
+ sig { override.returns(String) }
105
+ def generate_rbi
106
+ "T.any(#{types.map(&:generate_rbi).join(', ')})"
107
+ end
108
+
109
+ sig { override.returns(String) }
110
+ def generate_rbs
111
+ "(#{types.map(&:generate_rbs).join(' | ')})"
112
+ end
113
+ end
114
+
115
+ # A type which matches all of the wrapped types.
116
+ class Intersection < Type
117
+ sig { params(types: T::Array[TypeLike]).void }
118
+ def initialize(types)
119
+ @types = types.map(&method(:to_type))
120
+ end
121
+
122
+ sig { params(other: Object).returns(T::Boolean) }
123
+ def ==(other)
124
+ Intersection === other && types == other.types
125
+ end
126
+
127
+ sig { returns(T::Array[Type]) }
128
+ attr_reader :types
129
+
130
+ sig { override.returns(String) }
131
+ def generate_rbi
132
+ "T.all(#{types.map(&:generate_rbi).join(', ')})"
133
+ end
134
+
135
+ sig { override.returns(String) }
136
+ def generate_rbs
137
+ "(#{types.map(&:generate_rbs).join(' & ')})"
138
+ end
139
+ end
140
+
141
+ # A fixed-length array of items, each with a known type.
142
+ class Tuple < Type
143
+ sig { params(types: T::Array[TypeLike]).void }
144
+ def initialize(types)
145
+ @types = types.map(&method(:to_type))
146
+ end
147
+
148
+ sig { params(other: Object).returns(T::Boolean) }
149
+ def ==(other)
150
+ Tuple === other && types == other.types
151
+ end
152
+
153
+ sig { returns(T::Array[Type]) }
154
+ attr_reader :types
155
+
156
+ sig { override.returns(String) }
157
+ def generate_rbi
158
+ "[#{types.map(&:generate_rbi).join(', ')}]"
159
+ end
160
+
161
+ sig { override.returns(String) }
162
+ def generate_rbs
163
+ "[#{types.map(&:generate_rbs).join(', ')}]"
164
+ end
165
+ end
166
+
167
+ class SingleElementCollection < Type
168
+ abstract!
169
+
170
+ sig { params(element: TypeLike).void }
171
+ def initialize(element)
172
+ @element = to_type(element)
173
+ end
174
+
175
+ sig { returns(Type) }
176
+ attr_reader :element
177
+
178
+ sig { abstract.returns(String) }
179
+ def collection_name; end
180
+
181
+ sig { override.returns(String) }
182
+ def generate_rbi
183
+ "T::#{collection_name}[#{element.generate_rbi}]"
184
+ end
185
+
186
+ sig { override.returns(String) }
187
+ def generate_rbs
188
+ "#{collection_name}[#{element.generate_rbs}]"
189
+ end
190
+ end
191
+
192
+ # An array with known element types.
193
+ class Array < SingleElementCollection
194
+ sig { override.returns(String) }
195
+ def collection_name
196
+ 'Array'
197
+ end
198
+
199
+ sig { params(other: Object).returns(T::Boolean) }
200
+ def ==(other)
201
+ Array === other && element == other.element
202
+ end
203
+ end
204
+
205
+ # A set with known element types.
206
+ class Set < SingleElementCollection
207
+ sig { override.returns(String) }
208
+ def collection_name
209
+ 'Set'
210
+ end
211
+
212
+ sig { params(other: Object).returns(T::Boolean) }
213
+ def ==(other)
214
+ Set === other && element == other.element
215
+ end
216
+ end
217
+
218
+ # A range with known element types.
219
+ class Range < SingleElementCollection
220
+ sig { override.returns(String) }
221
+ def collection_name
222
+ 'Range'
223
+ end
224
+
225
+ sig { params(other: Object).returns(T::Boolean) }
226
+ def ==(other)
227
+ Range === other && element == other.element
228
+ end
229
+ end
230
+
231
+ # An enumerable with known element types.
232
+ class Enumerable < SingleElementCollection
233
+ sig { override.returns(String) }
234
+ def collection_name
235
+ 'Enumerable'
236
+ end
237
+
238
+ sig { params(other: Object).returns(T::Boolean) }
239
+ def ==(other)
240
+ Enumerable === other && element == other.element
241
+ end
242
+ end
243
+
244
+ # An enumerator with known element types.
245
+ class Enumerator < SingleElementCollection
246
+ sig { override.returns(String) }
247
+ def collection_name
248
+ 'Enumerator'
249
+ end
250
+
251
+ sig { params(other: Object).returns(T::Boolean) }
252
+ def ==(other)
253
+ Enumerator === other && element == other.element
254
+ end
255
+ end
256
+
257
+ # A hash with known key and value types.
258
+ class Hash < Type
259
+ sig { params(key: TypeLike, value: TypeLike).void }
260
+ def initialize(key, value)
261
+ @key = to_type(key)
262
+ @value = to_type(value)
263
+ end
264
+
265
+ sig { params(other: Object).returns(T::Boolean) }
266
+ def ==(other)
267
+ Hash === other && key == other.key && value == other.value
268
+ end
269
+
270
+ sig { returns(Type) }
271
+ attr_reader :key
272
+
273
+ sig { returns(Type) }
274
+ attr_reader :value
275
+
276
+ sig { override.returns(String) }
277
+ def generate_rbi
278
+ "T::Hash[#{key.generate_rbi}, #{value.generate_rbi}]"
279
+ end
280
+
281
+ sig { override.returns(String) }
282
+ def generate_rbs
283
+ "Hash[#{key.generate_rbs}, #{value.generate_rbs}]"
284
+ end
285
+ end
286
+
287
+ # A record/shape; a hash with a fixed set of keys with given types.
288
+ class Record < Type
289
+ sig { params(keys_to_types: T::Hash[Symbol, TypeLike]).void }
290
+ def initialize(keys_to_types)
291
+ @keys_to_types = keys_to_types.map do |k, v|
292
+ [k, to_type(v)]
293
+ end.to_h
294
+ end
295
+
296
+ sig { params(other: Object).returns(T::Boolean) }
297
+ def ==(other)
298
+ Record === other && keys_to_types == other.keys_to_types
299
+ end
300
+
301
+ sig { returns(T::Hash[Symbol, Type]) }
302
+ attr_reader :keys_to_types
303
+
304
+ sig { override.returns(String) }
305
+ def generate_rbi
306
+ "{ #{keys_to_types.map { |k, v| "#{k}: #{v.generate_rbi}" }.join(', ')} }"
307
+ end
308
+
309
+ sig { override.returns(String) }
310
+ def generate_rbs
311
+ "{ #{keys_to_types.map { |k, v| "#{k}: #{v.generate_rbs}" }.join(', ')} }"
312
+ end
313
+ end
314
+
315
+ # A type which represents the class of a type, rather than an instance.
316
+ # For example, "String" means an instance of String, but "Class(String)"
317
+ # means the actual String class.
318
+ class Class < Type
319
+ sig { params(type: TypeLike).void }
320
+ def initialize(type)
321
+ @type = to_type(type)
322
+ end
323
+
324
+ sig { params(other: Object).returns(T::Boolean) }
325
+ def ==(other)
326
+ Class === other && type == other.type
327
+ end
328
+
329
+ sig { returns(Type) }
330
+ attr_reader :type
331
+
332
+ sig { override.returns(String) }
333
+ def generate_rbi
334
+ "T.class_of(#{type.generate_rbi})"
335
+ end
336
+
337
+ sig { override.returns(String) }
338
+ def generate_rbs
339
+ "singleton(#{type.generate_rbs})"
340
+ end
341
+ end
342
+
343
+ # Generic type for a boolean.
344
+ class Boolean < Type
345
+ sig { params(other: Object).returns(T::Boolean) }
346
+ def ==(other)
347
+ Boolean === other
348
+ end
349
+
350
+ sig { override.returns(String) }
351
+ def generate_rbi
352
+ "T::Boolean"
353
+ end
354
+
355
+ sig { override.returns(String) }
356
+ def generate_rbs
357
+ "bool"
358
+ end
359
+ end
360
+
361
+ # The explicit lack of a type.
362
+ class Untyped < Type
363
+ sig { params(other: Object).returns(T::Boolean) }
364
+ def ==(other)
365
+ Untyped === other
366
+ end
367
+
368
+ sig { override.returns(String) }
369
+ def generate_rbi
370
+ "T.untyped"
371
+ end
372
+
373
+ sig { override.returns(String) }
374
+ def generate_rbs
375
+ "untyped"
376
+ end
377
+ end
378
+
379
+ # A type which can be called as a function.
380
+ class Proc < Type
381
+ # A parameter to a proc.
382
+ class Parameter
383
+ extend T::Sig
384
+
385
+ sig { params(name: String, type: TypeLike, default: T.nilable(String)).void }
386
+ def initialize(name, type, default = nil)
387
+ @name = name
388
+ @type = Type.to_type(type)
389
+ @default = default
390
+ end
391
+
392
+ sig { returns(String) }
393
+ attr_reader :name
394
+
395
+ sig { returns(Type) }
396
+ attr_reader :type
397
+
398
+ sig { returns(T.nilable(String)) }
399
+ attr_reader :default
400
+
401
+ sig { params(other: Object).returns(T::Boolean) }
402
+ def ==(other)
403
+ Parameter === other && name == other.name && type == other.type &&
404
+ default == other.default
405
+ end
406
+ end
407
+
408
+ sig { params(parameters: T::Array[Parameter], return_type: T.nilable(TypeLike)).void }
409
+ def initialize(parameters, return_type)
410
+ @parameters = parameters
411
+ @return_type = return_type && to_type(return_type)
412
+ end
413
+
414
+ sig { params(other: Object).returns(T::Boolean) }
415
+ def ==(other)
416
+ Proc === other && parameters == other.parameters && return_type == other.return_type
417
+ end
418
+
419
+ sig { returns(T::Array[Parameter]) }
420
+ attr_reader :parameters
421
+
422
+ sig { returns(T.nilable(Type)) }
423
+ attr_reader :return_type
424
+
425
+ sig { override.returns(String) }
426
+ def generate_rbi
427
+ rbi_params = parameters.map do |param|
428
+ RbiGenerator::Parameter.new(param.name, type: param.type, default: param.default)
429
+ end
430
+ "T.proc.params(#{rbi_params.map(&:to_sig_param).join(', ')}).#{
431
+ @return_type ? "returns(#{@return_type.generate_rbi})" : 'void'
432
+ }"
433
+ end
434
+
435
+ sig { override.returns(String) }
436
+ def generate_rbs
437
+ rbs_params = parameters.map do |param|
438
+ RbsGenerator::Parameter.new(param.name, type: param.type, required: param.default.nil?)
439
+ end
440
+ "(#{rbs_params.map(&:to_rbs_param).join(', ')}) -> #{return_type&.generate_rbs || 'void'}"
441
+ end
442
+ end
443
+ end
444
+ end
445
+