parlour 2.0.0 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 382331994bebd14df33b96b084d725b0375fa84e0a3aa263e944bad22bb5ef3f
4
- data.tar.gz: 33b9014173a85bc6dddec5aa3ad38cc7e23d869636694fbbe96d4e07c7e78886
3
+ metadata.gz: 889d6730ffefc764887706e5dadc4441e66cdf32e4567e809f7e634f511b7dfc
4
+ data.tar.gz: 9e9ab14b6618c209c8d194bf6e5557398689f0656247cac9561064dbcd541a6a
5
5
  SHA512:
6
- metadata.gz: 6ecd35a473c689909a7ef3b84af799cfa718b1901929743676c557d95f6dd717b3c9cd60dcec1c4274ce1ecc4e69310aa3213505c6f3ef479cfa580ccb39f187
7
- data.tar.gz: 7dddda7cb3a9d123e74f0ed218d62b17697f63451b7389d6d5c92bb4712d41b1cc920380eb8ee3b84c7916be5ad8c32c5d2bb0f3b46c7828acefa45fa0581683
6
+ metadata.gz: ea57b34b827ced92fdd1d28387217c0a5bc7027d94319cac6ffb238847a2820e9c164df86c9b2c43e60826cb1b362000c7c2bfc7f1f63b9b998959c70a3be377
7
+ data.tar.gz: fb10c8c783aea69e412d1a6eb67dd736f3db377168a21f8025e28fdb76acfc94ed20f1f7b9a17dafbac39ebcc2d36846b350d04c3e59882b546143df374b9f41
@@ -12,6 +12,7 @@ rvm:
12
12
  - ruby-head
13
13
  matrix:
14
14
  allow_failures:
15
+ - rvm: 2.3
15
16
  - rvm: ruby-head
16
17
 
17
18
  jobs:
@@ -3,6 +3,18 @@ All notable changes to this project will be documented in this file.
3
3
 
4
4
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
5
5
 
6
+ ## [2.1.0] - 2020-03-22
7
+ ### Added
8
+ - Files can now be excluded from the `TypeLoader`.
9
+
10
+ ### Changed
11
+ - A block argument in the definition but not in the signature no longer causes
12
+ an error in the `TypeParser`.
13
+ - Sorting of namespace children is now a stable sort.
14
+
15
+ ### Fixed
16
+ - Type parameters are now parsed by the `TypeParser`.
17
+
6
18
  ## [2.0.0] - 2020-02-10
7
19
  ### Added
8
20
  - Parlour can now load types back out of RBI files or Ruby source files by
@@ -247,13 +247,13 @@ module Parlour
247
247
  #
248
248
  # @param name [String] The name of this method. You should not specify +self.+ in
249
249
  # this - use the +class_method+ parameter instead.
250
- # @param parameters [Array<Parameter>] An array of {Parameter} instances representing this
250
+ # @param parameters [Array<Parameter>] An array of {Parameter} instances representing this
251
251
  # method's parameters.
252
252
  # @param return_type [String, nil] A Sorbet string of what this method returns, such as
253
253
  # +"String"+ or +"T.untyped"+. Passing nil denotes a void return.
254
254
  # @param returns [String, nil] Same as return_type.
255
255
  # @param abstract [Boolean] Whether this method is abstract.
256
- # @param implementation [Boolean] DEPRECATED: Whether this method is an
256
+ # @param implementation [Boolean] DEPRECATED: Whether this method is an
257
257
  # implementation of a parent abstract method.
258
258
  # @param override [Boolean] Whether this method is overriding a parent overridable
259
259
  # method, or implementing a parent abstract method.
@@ -544,25 +544,25 @@ module Parlour
544
544
  # can be merged into each other, as they lack definitions for themselves,
545
545
  # so there is nothing to conflict. (This isn't the case for subclasses
546
546
  # such as {ClassNamespace}.)
547
- #
547
+ #
548
548
  # @param others [Array<RbiGenerator::RbiObject>] An array of other {Namespace} instances.
549
549
  # @return [true] Always true.
550
550
  def mergeable?(others)
551
551
  true
552
552
  end
553
553
 
554
- sig do
554
+ sig do
555
555
  override.overridable.params(
556
556
  others: T::Array[RbiGenerator::RbiObject]
557
557
  ).void
558
558
  end
559
559
  # Given an array of {Namespace} instances, merges them into this one.
560
- # All children, constants, extends and includes are copied into this
560
+ # All children, constants, extends and includes are copied into this
561
561
  # instance.
562
562
  #
563
563
  # There may also be {RbiGenerator::Method} instances in the stream, which
564
564
  # are ignored.
565
- #
565
+ #
566
566
  # @param others [Array<RbiGenerator::RbiObject>] An array of other {Namespace} instances.
567
567
  # @return [void]
568
568
  def merge_into_self(others)
@@ -616,10 +616,19 @@ module Parlour
616
616
  end
617
617
 
618
618
  # Process singleton class attributes
619
- class_attributes, remaining_children = \
620
- (options.sort_namespaces ? children.sort_by(&:name) : children)
621
- .partition { |child| child.is_a?(Attribute) && child.class_attribute }
622
-
619
+ sorted_children = (
620
+ if options.sort_namespaces
621
+ # sort_by can be unstable (and is in current MRI).
622
+ # Use the this work around to preserve order for ties
623
+ children.sort_by.with_index { |child, i| [child.name, i] }
624
+ else
625
+ children
626
+ end
627
+ )
628
+ class_attributes, remaining_children = sorted_children.partition do |child|
629
+ child.is_a?(Attribute) && child.class_attribute
630
+ end
631
+
623
632
  if class_attributes.any?
624
633
  result << options.indented(indent_level, 'class << self')
625
634
 
@@ -30,7 +30,7 @@ module Parlour
30
30
  load_source(File.read(filename), filename)
31
31
  end
32
32
 
33
- sig { params(root: String).returns(RbiGenerator::Namespace) }
33
+ sig { params(root: String, exclusions: T::Array[String]).returns(RbiGenerator::Namespace) }
34
34
  # Loads an entire Sorbet project using Sorbet's file table, obeying any
35
35
  # "typed: ignore" sigils, into a tree of objects.
36
36
  #
@@ -39,8 +39,12 @@ module Parlour
39
39
  #
40
40
  # @param [String] root The root of the project; where the "sorbet" directory
41
41
  # and "Gemfile" are located.
42
+ # @param [Array<String>] exclusions A list of files to exclude when loading
43
+ # the project, relative to the given root.
42
44
  # @return [RbiGenerator::Namespace] The root of the object tree.
43
- def self.load_project(root)
45
+ def self.load_project(root, exclusions: [])
46
+ expanded_exclusions = exclusions.map { |e| File.expand_path(e, root) }
47
+
44
48
  stdin, stdout, stderr, wait_thr = T.unsafe(Open3).popen3(
45
49
  'bundle exec srb tc -p file-table-json',
46
50
  chdir: root
@@ -58,6 +62,9 @@ module Parlour
58
62
  next if rel_path.start_with?('./sorbet/rbi/hidden-definitions/')
59
63
  path = File.expand_path(rel_path, root)
60
64
 
65
+ # Skip this file if it was excluded
66
+ next if expanded_exclusions.include?(path)
67
+
61
68
  # There are some entries which are URLs to stdlib
62
69
  next unless File.exist?(path)
63
70
 
@@ -107,7 +107,7 @@ module Parlour
107
107
  def self.from_source(filename, source)
108
108
  buffer = Parser::Source::Buffer.new(filename)
109
109
  buffer.source = source
110
-
110
+
111
111
  TypeParser.new(Parser::CurrentRuby.new.parse(buffer))
112
112
  end
113
113
 
@@ -117,7 +117,7 @@ module Parlour
117
117
 
118
118
  sig { returns(T::Boolean) }
119
119
  # @return [Boolean] Whether to raise an error if a node of an unknown kind
120
- # is encountered.
120
+ # is encountered.
121
121
  attr_reader :unknown_node_errors
122
122
 
123
123
  # Parses the entire source file and returns the resulting root namespace.
@@ -134,7 +134,7 @@ module Parlour
134
134
  # represents and returns it, recursing to any child namespaces and parsing
135
135
  # any methods within.
136
136
  #
137
- # If the node directly represents several nodes, such as being a
137
+ # If the node directly represents several nodes, such as being a
138
138
  # (begin ...) node, they are all returned.
139
139
  #
140
140
  # @param [NodePath] path The path to the namespace definition. Do not pass
@@ -144,7 +144,7 @@ module Parlour
144
144
  sig { params(path: NodePath, is_within_eigenclass: T::Boolean).returns(T::Array[RbiGenerator::RbiObject]) }
145
145
  def parse_path_to_object(path, is_within_eigenclass: false)
146
146
  node = path.traverse(ast)
147
-
147
+
148
148
  case node.type
149
149
  when :class
150
150
  parse_err 'cannot declare classes in an eigenclass', node if is_within_eigenclass
@@ -158,7 +158,7 @@ module Parlour
158
158
  *parent_names, this_name = constant_names(name)
159
159
  target = T.let(nil, T.nilable(RbiGenerator::Namespace))
160
160
  top_level = T.let(nil, T.nilable(RbiGenerator::Namespace))
161
- parent_names.each do |n|
161
+ parent_names.each do |n|
162
162
  new_obj = RbiGenerator::Namespace.new(
163
163
  DetachedRbiGenerator.new,
164
164
  n.to_s,
@@ -199,7 +199,7 @@ module Parlour
199
199
  *parent_names, this_name = constant_names(name)
200
200
  target = T.let(nil, T.nilable(RbiGenerator::Namespace))
201
201
  top_level = T.let(nil, T.nilable(RbiGenerator::Namespace))
202
- parent_names.each do |n|
202
+ parent_names.each do |n|
203
203
  new_obj = RbiGenerator::Namespace.new(
204
204
  DetachedRbiGenerator.new,
205
205
  n.to_s,
@@ -236,7 +236,7 @@ module Parlour
236
236
  when :def, :defs
237
237
  # TODO: Support for defs without sigs
238
238
  # If so, we need some kind of state machine to determine whether
239
- # they've already been dealt with by the "when :send" clause and
239
+ # they've already been dealt with by the "when :send" clause and
240
240
  # #parse_sig_into_methods.
241
241
  # If not, just ignore this.
242
242
  []
@@ -246,7 +246,7 @@ module Parlour
246
246
  when :begin
247
247
  # Just map over all the things
248
248
  node.to_a.length.times.map do |c|
249
- parse_path_to_object(path.child(c), is_within_eigenclass: is_within_eigenclass)
249
+ parse_path_to_object(path.child(c), is_within_eigenclass: is_within_eigenclass)
250
250
  end.flatten
251
251
  else
252
252
  if unknown_node_errors
@@ -259,6 +259,7 @@ module Parlour
259
259
 
260
260
  # A parsed sig, not associated with a method.
261
261
  class IntermediateSig < T::Struct
262
+ prop :type_parameters, T.nilable(T::Array[Symbol])
262
263
  prop :overridable, T::Boolean
263
264
  prop :override, T::Boolean
264
265
  prop :abstract, T::Boolean
@@ -318,7 +319,18 @@ module Parlour
318
319
  arg.to_a
319
320
  end
320
321
 
322
+ # Find type parameters if they were used
323
+ type_parameters = sig_chain
324
+ .find { |(n, _)| n == :type_parameters }
325
+ &.then do |(_, a)|
326
+ a.map do |arg|
327
+ parse_err 'type parameter must be a symbol', arg if arg.type != :sym
328
+ arg.to_a[0]
329
+ end
330
+ end
331
+
321
332
  IntermediateSig.new(
333
+ type_parameters: type_parameters,
322
334
  overridable: overridable,
323
335
  override: override,
324
336
  abstract: abstract,
@@ -370,7 +382,7 @@ module Parlour
370
382
  || target != nil
371
383
 
372
384
  parse_err 'typed attribute should have at least one name', def_node if parameters&.length == 0
373
-
385
+
374
386
  kind = :attr
375
387
  attr_direction = method_name.to_s.gsub('attr_', '').to_sym
376
388
  def_names = T.must(parameters).map { |param| param.to_a[0].to_s }
@@ -389,6 +401,13 @@ module Parlour
389
401
  return_type = this_sig.return_type
390
402
 
391
403
  if kind == :def
404
+ # Sorbet allows a trailing blockarg that's not in the sig
405
+ if params &&
406
+ def_params.length == params.length + 1 &&
407
+ def_params[-1].type == :blockarg
408
+ def_params = def_params[0...-1]
409
+ end
410
+
392
411
  parse_err 'mismatching number of arguments in sig and def', sig_block_node \
393
412
  if params && def_params.length != params.length
394
413
 
@@ -399,6 +418,7 @@ module Parlour
399
418
  parameters = params \
400
419
  ? zip_by(params, ->x{ x.to_a[0].to_a[0] }, def_params, ->x{ x.to_a[0] })
401
420
  .map do |sig_arg, def_param|
421
+
402
422
  arg_name = def_param.to_a[0]
403
423
 
404
424
  # TODO: anonymous restarg
@@ -422,6 +442,7 @@ module Parlour
422
442
  def_name,
423
443
  parameters,
424
444
  return_type,
445
+ type_parameters: this_sig.type_parameters,
425
446
  override: this_sig.override,
426
447
  overridable: this_sig.overridable,
427
448
  abstract: this_sig.abstract,
@@ -437,7 +458,7 @@ module Parlour
437
458
 
438
459
  parse_err "attr_#{attr_direction} sig should have non-void return", sig_block_node \
439
460
  unless return_type
440
-
461
+
441
462
  attr_type = return_type
442
463
  when :writer
443
464
  # These are special and can only have one name
@@ -476,7 +497,7 @@ module Parlour
476
497
  # A::B::C), converts that node into an array of the constant names which
477
498
  # are accessed. For example, A::B::C would become [:A, :B, :C].
478
499
  #
479
- # @param [Parser::AST::Node, nil] node The node to convert. This must
500
+ # @param [Parser::AST::Node, nil] node The node to convert. This must
480
501
  # consist only of nested (:const) nodes.
481
502
  # @return [Array<Symbol>] The chain of constant names.
482
503
  def constant_names(node)
@@ -524,13 +545,13 @@ module Parlour
524
545
  def body_has_modifier?(node, modifier)
525
546
  return false unless node
526
547
 
527
- (node.type == :send && node.to_a == [nil, modifier]) ||
548
+ (node.type == :send && node.to_a == [nil, modifier]) ||
528
549
  (node.type == :begin &&
529
550
  node.to_a.any? { |c| c.type == :send && c.to_a == [nil, modifier] })
530
551
  end
531
552
 
532
553
  sig { params(node: Parser::AST::Node).returns([T::Array[String], T::Array[String]]) }
533
- # Given an AST node representing the body of a class or module, returns two
554
+ # Given an AST node representing the body of a class or module, returns two
534
555
  # arrays of the includes and extends contained within the body.
535
556
  #
536
557
  # @param [Parser::AST::Node] node The body of the namespace.
@@ -568,7 +589,7 @@ module Parlour
568
589
  raise ParseError.new(buffer, range), desc
569
590
  end
570
591
 
571
- sig do
592
+ sig do
572
593
  type_parameters(:A, :B)
573
594
  .params(
574
595
  a: T::Array[T.type_parameter(:A)],
@@ -580,7 +601,7 @@ module Parlour
580
601
  end
581
602
  # Given two arrays and functions to get a key for each item in the two
582
603
  # arrays, joins the two arrays into one array of pairs by that key.
583
- #
604
+ #
584
605
  # The arrays should both be the same length, and the key functions should
585
606
  # never return duplicate keys for two different items.
586
607
  #
@@ -588,7 +609,7 @@ module Parlour
588
609
  # @param [A -> Any] fa A function to obtain a key for any element in the
589
610
  # first array.
590
611
  # @param [Array<B>] b The second array.
591
- # @param [B -> Any] fb A function to obtain a key for any element in the
612
+ # @param [B -> Any] fb A function to obtain a key for any element in the
592
613
  # second array.
593
614
  # @return [Array<(A, B)>] An array of pairs, where the left of the pair is
594
615
  # an element from A and the right is the element from B with the
@@ -606,4 +627,4 @@ module Parlour
606
627
  end
607
628
  end
608
629
  end
609
- end
630
+ end
@@ -1,5 +1,5 @@
1
1
  # typed: strong
2
2
  module Parlour
3
3
  # The library version.
4
- VERSION = '2.0.0'
4
+ VERSION = '2.1.0'
5
5
  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: 2.0.0
4
+ version: 2.1.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-02-10 00:00:00.000000000 Z
11
+ date: 2020-03-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sorbet-runtime
@@ -201,7 +201,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
201
201
  - !ruby/object:Gem::Version
202
202
  version: '0'
203
203
  requirements: []
204
- rubygems_version: 3.1.2
204
+ rubygems_version: 3.0.3
205
205
  signing_key:
206
206
  specification_version: 4
207
207
  summary: An RBI generator, merger and parser for Sorbet