parlour 5.0.0.beta.3 → 6.0.0
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/workflows/ruby.yml +46 -0
- data/CHANGELOG.md +73 -18
- data/README.md +2 -0
- data/ci/check_rbi.sh +9 -0
- data/lib/parlour/conversion/rbi_to_rbs.rb +6 -0
- data/lib/parlour/rbi_generator/class_namespace.rb +4 -2
- data/lib/parlour/rbi_generator/enum_class_namespace.rb +4 -2
- data/lib/parlour/rbi_generator/module_namespace.rb +19 -7
- data/lib/parlour/rbi_generator/namespace.rb +46 -23
- data/lib/parlour/rbi_generator/parameter.rb +3 -3
- data/lib/parlour/rbi_generator/struct_class_namespace.rb +4 -2
- data/lib/parlour/rbi_generator/struct_prop.rb +2 -2
- data/lib/parlour/rbi_generator/type_alias.rb +1 -1
- data/lib/parlour/rbs_generator/method.rb +1 -1
- data/lib/parlour/type_parser.rb +51 -16
- data/lib/parlour/types.rb +46 -7
- data/lib/parlour/version.rb +1 -1
- data/parlour.gemspec +2 -1
- metadata +21 -7
- data/.travis.yml +0 -28
- data/rbi/parlour.rbi +0 -1856
@@ -39,7 +39,7 @@ module Parlour
|
|
39
39
|
@name = name
|
40
40
|
|
41
41
|
prefix = /^(\*\*|\*|\&)?/.match(name)&.captures&.first || ''
|
42
|
-
@kind = PREFIXES.rassoc(prefix).first
|
42
|
+
@kind = T.must(PREFIXES.rassoc(prefix)).first
|
43
43
|
|
44
44
|
@kind = :keyword if kind == :normal && name.end_with?(':')
|
45
45
|
|
@@ -123,12 +123,12 @@ module Parlour
|
|
123
123
|
end
|
124
124
|
|
125
125
|
# A mapping of {kind} values to the characteristic prefixes each kind has.
|
126
|
-
PREFIXES = {
|
126
|
+
PREFIXES = T.let({
|
127
127
|
normal: '',
|
128
128
|
splat: '*',
|
129
129
|
double_splat: '**',
|
130
130
|
block: '&'
|
131
|
-
}.freeze
|
131
|
+
}.freeze, T::Hash[Symbol, String])
|
132
132
|
|
133
133
|
sig { void }
|
134
134
|
def generalize_from_rbi!
|
@@ -11,6 +11,7 @@ module Parlour
|
|
11
11
|
generator: Generator,
|
12
12
|
name: String,
|
13
13
|
final: T::Boolean,
|
14
|
+
sealed: T::Boolean,
|
14
15
|
props: T::Array[StructProp],
|
15
16
|
abstract: T::Boolean,
|
16
17
|
block: T.nilable(T.proc.params(x: StructClassNamespace).void)
|
@@ -22,12 +23,13 @@ module Parlour
|
|
22
23
|
# @param generator [RbiGenerator] The current RbiGenerator.
|
23
24
|
# @param name [String] The name of this class.
|
24
25
|
# @param final [Boolean] Whether this namespace is final.
|
26
|
+
# @param sealed [Boolean] Whether this namespace is sealed.
|
25
27
|
# @param props [Array<StructProp>] The props of the struct.
|
26
28
|
# @param abstract [Boolean] A boolean indicating whether this class is abstract.
|
27
29
|
# @param block A block which the new instance yields itself to.
|
28
30
|
# @return [void]
|
29
|
-
def initialize(generator, name, final, props, abstract, &block)
|
30
|
-
super(generator, name, final, 'T::Struct', abstract, &block)
|
31
|
+
def initialize(generator, name, final, sealed, props, abstract, &block)
|
32
|
+
super(generator, name, final, sealed, 'T::Struct', abstract, &block)
|
31
33
|
@props = props
|
32
34
|
end
|
33
35
|
|
@@ -112,9 +112,9 @@ module Parlour
|
|
112
112
|
attr_reader :redaction
|
113
113
|
|
114
114
|
# The optional properties available on instances of this class.
|
115
|
-
EXTRA_PROPERTIES = %i{
|
115
|
+
EXTRA_PROPERTIES = T.let(%i{
|
116
116
|
optional enum dont_store foreign default factory immutable array override redaction
|
117
|
-
}
|
117
|
+
}, T::Array[Symbol])
|
118
118
|
|
119
119
|
sig { returns(String) }
|
120
120
|
# Returns the +prop+ call required to create this property.
|
@@ -89,7 +89,7 @@ module Parlour
|
|
89
89
|
|
90
90
|
# Merge the first signature line, and indent & concat the rest
|
91
91
|
first_line, *rest_lines = *partial_sig_lines
|
92
|
-
this_sig_lines[0]
|
92
|
+
this_sig_lines[0] = T.unsafe(this_sig_lines[0]) + first_line
|
93
93
|
rest_lines&.each do |line|
|
94
94
|
this_sig_lines << ' ' * definition.length + options.indented(indent_level, line)
|
95
95
|
end
|
data/lib/parlour/type_parser.rb
CHANGED
@@ -158,6 +158,7 @@ module Parlour
|
|
158
158
|
|
159
159
|
name, superclass, body = *node
|
160
160
|
final = body_has_modifier?(body, :final!)
|
161
|
+
sealed = body_has_modifier?(body, :sealed!)
|
161
162
|
abstract = body_has_modifier?(body, :abstract!)
|
162
163
|
includes, extends = body ? body_includes_and_extends(body) : [[], []]
|
163
164
|
|
@@ -170,6 +171,7 @@ module Parlour
|
|
170
171
|
generator,
|
171
172
|
n.to_s,
|
172
173
|
false,
|
174
|
+
false,
|
173
175
|
)
|
174
176
|
target.children << new_obj if target
|
175
177
|
target = new_obj
|
@@ -233,6 +235,7 @@ module Parlour
|
|
233
235
|
generator,
|
234
236
|
this_name.to_s,
|
235
237
|
final,
|
238
|
+
sealed,
|
236
239
|
props,
|
237
240
|
abstract,
|
238
241
|
)
|
@@ -256,6 +259,7 @@ module Parlour
|
|
256
259
|
generator,
|
257
260
|
this_name.to_s,
|
258
261
|
final,
|
262
|
+
sealed,
|
259
263
|
enums,
|
260
264
|
abstract,
|
261
265
|
)
|
@@ -264,6 +268,7 @@ module Parlour
|
|
264
268
|
generator,
|
265
269
|
this_name.to_s,
|
266
270
|
final,
|
271
|
+
sealed,
|
267
272
|
node_to_s(superclass),
|
268
273
|
abstract,
|
269
274
|
)
|
@@ -275,7 +280,7 @@ module Parlour
|
|
275
280
|
|
276
281
|
if target
|
277
282
|
target.children << final_obj
|
278
|
-
[top_level]
|
283
|
+
[T.must(top_level)]
|
279
284
|
else
|
280
285
|
[final_obj]
|
281
286
|
end
|
@@ -283,7 +288,9 @@ module Parlour
|
|
283
288
|
parse_err 'cannot declare modules in an eigenclass', node if is_within_eigenclass
|
284
289
|
|
285
290
|
name, body = *node
|
291
|
+
abstract = body_has_modifier?(body, :abstract!)
|
286
292
|
final = body_has_modifier?(body, :final!)
|
293
|
+
sealed = body_has_modifier?(body, :sealed!)
|
287
294
|
interface = body_has_modifier?(body, :interface!)
|
288
295
|
includes, extends = body ? body_includes_and_extends(body) : [[], []]
|
289
296
|
|
@@ -296,6 +303,7 @@ module Parlour
|
|
296
303
|
generator,
|
297
304
|
n.to_s,
|
298
305
|
false,
|
306
|
+
false,
|
299
307
|
)
|
300
308
|
target.children << new_obj if target
|
301
309
|
target = new_obj
|
@@ -306,7 +314,9 @@ module Parlour
|
|
306
314
|
generator,
|
307
315
|
this_name.to_s,
|
308
316
|
final,
|
317
|
+
sealed,
|
309
318
|
interface,
|
319
|
+
abstract,
|
310
320
|
) do |m|
|
311
321
|
m.children.concat(parse_path_to_object(path.child(1))) if body
|
312
322
|
m.create_includes(includes)
|
@@ -315,7 +325,7 @@ module Parlour
|
|
315
325
|
|
316
326
|
if target
|
317
327
|
target.children << final_obj
|
318
|
-
[top_level]
|
328
|
+
[T.must(top_level)]
|
319
329
|
else
|
320
330
|
[final_obj]
|
321
331
|
end
|
@@ -345,11 +355,28 @@ module Parlour
|
|
345
355
|
end.flatten
|
346
356
|
when :casgn
|
347
357
|
_, name, body = *node
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
358
|
+
|
359
|
+
# Determine whether this is a constant or a type alias
|
360
|
+
# A type alias looks like:
|
361
|
+
# (block (send (const nil :T) :type_alias) (args) (type_to_alias))
|
362
|
+
if body.type == :block &&
|
363
|
+
body.to_a[0].type == :send &&
|
364
|
+
body.to_a[0].to_a[0].type == :const &&
|
365
|
+
body.to_a[0].to_a[0].to_a == [nil, :T] &&
|
366
|
+
body.to_a[0].to_a[1] == :type_alias
|
367
|
+
|
368
|
+
[Parlour::RbiGenerator::TypeAlias.new(
|
369
|
+
generator,
|
370
|
+
name: T.must(name).to_s,
|
371
|
+
type: T.must(node_to_s(body.to_a[2])),
|
372
|
+
)]
|
373
|
+
else
|
374
|
+
[Parlour::RbiGenerator::Constant.new(
|
375
|
+
generator,
|
376
|
+
name: T.must(name).to_s,
|
377
|
+
value: T.must(node_to_s(body)),
|
378
|
+
)]
|
379
|
+
end
|
353
380
|
else
|
354
381
|
if unknown_node_errors
|
355
382
|
parse_err "don't understand node type #{node.type}", node
|
@@ -704,7 +731,7 @@ module Parlour
|
|
704
731
|
end
|
705
732
|
|
706
733
|
sig { params(node: Parser::AST::Node).returns(Types::Type) }
|
707
|
-
# Given an AST node representing an RBI type (such as 'T::Array[String]'),
|
734
|
+
# Given an AST node representing an RBI type (such as 'T::Array[String]'),
|
708
735
|
# parses it into a generic type.
|
709
736
|
#
|
710
737
|
# @param [Parser::AST::Node] node
|
@@ -719,9 +746,9 @@ module Parlour
|
|
719
746
|
names = constant_names(target)
|
720
747
|
known_single_element_collections = [:Array, :Set, :Range, :Enumerator, :Enumerable]
|
721
748
|
|
722
|
-
if names.length == 2 && names[0] == :T &&
|
749
|
+
if names.length == 2 && names[0] == :T &&
|
723
750
|
known_single_element_collections.include?(names[1])
|
724
|
-
|
751
|
+
|
725
752
|
parse_err "no type in T::#{names[1]}[...]", node if args.nil? || args.empty?
|
726
753
|
parse_err "too many types in T::#{names[1]}[...]", node unless args.length == 1
|
727
754
|
return T.must(Types.const_get(T.must(names[1]))).new(parse_node_to_type(T.must(args.first)))
|
@@ -732,9 +759,17 @@ module Parlour
|
|
732
759
|
parse_node_to_type(args[0]), parse_node_to_type(args[1])
|
733
760
|
)
|
734
761
|
else
|
735
|
-
|
736
|
-
|
737
|
-
|
762
|
+
type = names.join('::')
|
763
|
+
if args.nil?
|
764
|
+
parse_err(
|
765
|
+
"user defined generic '#{type}' requires at least one type parameter",
|
766
|
+
node
|
767
|
+
)
|
768
|
+
end
|
769
|
+
return Types::Generic.new(
|
770
|
+
type,
|
771
|
+
args.map { |arg| parse_node_to_type(arg) }
|
772
|
+
)
|
738
773
|
end
|
739
774
|
end
|
740
775
|
|
@@ -743,7 +778,7 @@ module Parlour
|
|
743
778
|
# something pretty cursed with procs to break this
|
744
779
|
# This checks for (send (send (send (const nil :T) :proc) ...) ...)
|
745
780
|
# That's the right amount of nesting for T.proc.params(...).returns(...)
|
746
|
-
if node.to_a[0].type == :send &&
|
781
|
+
if node.to_a[0].type == :send &&
|
747
782
|
node.to_a[0].to_a[0].type == :send &&
|
748
783
|
node.to_a[0].to_a[0].to_a[1] == :proc &&
|
749
784
|
node.to_a[0].to_a[0].to_a[0].type == :const &&
|
@@ -780,7 +815,7 @@ module Parlour
|
|
780
815
|
# The other options for a valid call are all "T.something" methods
|
781
816
|
parse_err "unexpected call #{node_to_s(node).inspect} in type", node \
|
782
817
|
unless target.type == :const && target.to_a == [nil, :T]
|
783
|
-
|
818
|
+
|
784
819
|
case message
|
785
820
|
when :nilable
|
786
821
|
parse_err 'no argument to T.nilable', node if args.nil? || args.empty?
|
@@ -811,7 +846,7 @@ module Parlour
|
|
811
846
|
else
|
812
847
|
warning "unknown method T.#{message}, treating as untyped", node
|
813
848
|
Types::Untyped.new
|
814
|
-
end
|
849
|
+
end
|
815
850
|
when :const
|
816
851
|
# Special case: T::Boolean
|
817
852
|
if constant_names(node) == [:T, :Boolean]
|
data/lib/parlour/types.rb
CHANGED
@@ -196,6 +196,45 @@ module Parlour
|
|
196
196
|
end
|
197
197
|
end
|
198
198
|
|
199
|
+
# A user-defined generic class with an arbitrary number of type
|
200
|
+
# parameters. This class assumes at least one type_param is
|
201
|
+
# provided, otherwise output will have empty type param lists.
|
202
|
+
class Generic < Type
|
203
|
+
sig { params(type: TypeLike, type_params: T::Array[TypeLike]).void }
|
204
|
+
def initialize(type, type_params)
|
205
|
+
@type = to_type(type)
|
206
|
+
@type_params = type_params.map { |p| to_type(p) }
|
207
|
+
end
|
208
|
+
|
209
|
+
sig { params(other: Object).returns(T::Boolean) }
|
210
|
+
def ==(other)
|
211
|
+
self.class === other &&
|
212
|
+
type == other.type &&
|
213
|
+
type_params == other.type_params
|
214
|
+
end
|
215
|
+
|
216
|
+
sig { returns(Type) }
|
217
|
+
attr_reader :type
|
218
|
+
|
219
|
+
sig { returns(T::Array[Type]) }
|
220
|
+
attr_reader :type_params
|
221
|
+
|
222
|
+
sig { override.returns(String) }
|
223
|
+
def generate_rbi
|
224
|
+
"#{type.generate_rbi}[#{type_params.map(&:generate_rbi).join(', ')}]"
|
225
|
+
end
|
226
|
+
|
227
|
+
sig { override.returns(String) }
|
228
|
+
def generate_rbs
|
229
|
+
"#{type.generate_rbs}[#{type_params.map(&:generate_rbs).join(', ')}]"
|
230
|
+
end
|
231
|
+
|
232
|
+
sig { override.returns(String) }
|
233
|
+
def describe
|
234
|
+
"#{type.describe}<#{type_params.map(&:describe).join(', ')}>"
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
199
238
|
class SingleElementCollection < Type
|
200
239
|
abstract!
|
201
240
|
|
@@ -217,7 +256,7 @@ module Parlour
|
|
217
256
|
|
218
257
|
sig { override.returns(String) }
|
219
258
|
def generate_rbs
|
220
|
-
"
|
259
|
+
"::#{collection_name}[#{element.generate_rbs}]"
|
221
260
|
end
|
222
261
|
|
223
262
|
sig { override.returns(String) }
|
@@ -317,7 +356,7 @@ module Parlour
|
|
317
356
|
|
318
357
|
sig { override.returns(String) }
|
319
358
|
def generate_rbs
|
320
|
-
"Hash[#{key.generate_rbs}, #{value.generate_rbs}]"
|
359
|
+
"::Hash[#{key.generate_rbs}, #{value.generate_rbs}]"
|
321
360
|
end
|
322
361
|
|
323
362
|
sig { override.returns(String) }
|
@@ -436,9 +475,9 @@ module Parlour
|
|
436
475
|
def describe
|
437
476
|
"self"
|
438
477
|
end
|
439
|
-
end
|
478
|
+
end
|
440
479
|
|
441
|
-
# The explicit lack of a type.
|
480
|
+
# The explicit lack of a type.
|
442
481
|
class Untyped < Type
|
443
482
|
sig { params(other: Object).returns(T::Boolean) }
|
444
483
|
def ==(other)
|
@@ -487,9 +526,9 @@ module Parlour
|
|
487
526
|
def ==(other)
|
488
527
|
Parameter === other && name == other.name && type == other.type &&
|
489
528
|
default == other.default
|
490
|
-
end
|
529
|
+
end
|
491
530
|
end
|
492
|
-
|
531
|
+
|
493
532
|
sig { params(parameters: T::Array[Parameter], return_type: T.nilable(TypeLike)).void }
|
494
533
|
def initialize(parameters, return_type)
|
495
534
|
@parameters = parameters
|
@@ -536,4 +575,4 @@ module Parlour
|
|
536
575
|
end
|
537
576
|
end
|
538
577
|
end
|
539
|
-
|
578
|
+
|
data/lib/parlour/version.rb
CHANGED
data/parlour.gemspec
CHANGED
@@ -16,7 +16,7 @@ Gem::Specification.new do |spec|
|
|
16
16
|
# Specify which files should be added to the gem when it is released.
|
17
17
|
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
18
18
|
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
19
|
-
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features|sorbet)/}) }
|
19
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features|sorbet|rbi)/}) }
|
20
20
|
end
|
21
21
|
spec.bindir = "exe"
|
22
22
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
@@ -32,4 +32,5 @@ Gem::Specification.new do |spec|
|
|
32
32
|
spec.add_development_dependency "rspec", "~> 3.0"
|
33
33
|
spec.add_development_dependency "sorbet"
|
34
34
|
spec.add_development_dependency "simplecov"
|
35
|
+
spec.add_development_dependency "yard"
|
35
36
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: parlour
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 6.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Aaron Christiansen
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-02-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: sorbet-runtime
|
@@ -136,6 +136,20 @@ dependencies:
|
|
136
136
|
- - ">="
|
137
137
|
- !ruby/object:Gem::Version
|
138
138
|
version: '0'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: yard
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ">="
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0'
|
139
153
|
description:
|
140
154
|
email:
|
141
155
|
- hello@aaronc.cc
|
@@ -146,16 +160,17 @@ extra_rdoc_files: []
|
|
146
160
|
files:
|
147
161
|
- ".github/ISSUE_TEMPLATE/bug-report.md"
|
148
162
|
- ".github/ISSUE_TEMPLATE/feature-request.md"
|
163
|
+
- ".github/workflows/ruby.yml"
|
149
164
|
- ".gitignore"
|
150
165
|
- ".parlour"
|
151
166
|
- ".rspec"
|
152
|
-
- ".travis.yml"
|
153
167
|
- CHANGELOG.md
|
154
168
|
- CODE_OF_CONDUCT.md
|
155
169
|
- Gemfile
|
156
170
|
- LICENSE.txt
|
157
171
|
- README.md
|
158
172
|
- Rakefile
|
173
|
+
- ci/check_rbi.sh
|
159
174
|
- exe/parlour
|
160
175
|
- lib/parlour.rb
|
161
176
|
- lib/parlour/conflict_resolver.rb
|
@@ -208,7 +223,6 @@ files:
|
|
208
223
|
- lib/parlour/version.rb
|
209
224
|
- parlour.gemspec
|
210
225
|
- plugin_examples/foobar_plugin.rb
|
211
|
-
- rbi/parlour.rbi
|
212
226
|
homepage: https://github.com/AaronC81/parlour
|
213
227
|
licenses:
|
214
228
|
- MIT
|
@@ -224,11 +238,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
224
238
|
version: '0'
|
225
239
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
226
240
|
requirements:
|
227
|
-
- - "
|
241
|
+
- - ">="
|
228
242
|
- !ruby/object:Gem::Version
|
229
|
-
version:
|
243
|
+
version: '0'
|
230
244
|
requirements: []
|
231
|
-
rubygems_version: 3.0.
|
245
|
+
rubygems_version: 3.2.0.rc.1
|
232
246
|
signing_key:
|
233
247
|
specification_version: 4
|
234
248
|
summary: A type information generator, merger and parser for Sorbet and Ruby 3/Steep
|