parlour 2.0.0 → 2.1.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 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