parlour 5.0.0.beta.3 → 6.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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