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.
@@ -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.
@@ -21,7 +21,7 @@ module Parlour
21
21
  yield_self(&block) if block
22
22
  end
23
23
 
24
- # @return [String] The type to alias to.
24
+ # @return [Types::TypeLike] The type to alias to.
25
25
  sig { returns(Types::TypeLike) }
26
26
  attr_reader :type
27
27
 
@@ -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] += first_line
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
@@ -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
- [Parlour::RbiGenerator::Constant.new(
349
- generator,
350
- name: T.must(name).to_s,
351
- value: T.must(node_to_s(body)),
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
- # TODO
736
- warning "user-defined generic types not implemented, treating #{names.last} as untyped", node
737
- return Types::Untyped.new
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
- "#{collection_name}[#{element.generate_rbs}]"
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
+
@@ -1,5 +1,5 @@
1
1
  # typed: strong
2
2
  module Parlour
3
3
  # The library version.
4
- VERSION = '5.0.0.beta.3'
4
+ VERSION = '6.0.0'
5
5
  end
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: 5.0.0.beta.3
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: 2020-09-15 00:00:00.000000000 Z
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: 1.3.1
243
+ version: '0'
230
244
  requirements: []
231
- rubygems_version: 3.0.3
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