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 +4 -4
- data/.travis.yml +1 -0
- data/CHANGELOG.md +12 -0
- data/lib/parlour/rbi_generator/namespace.rb +19 -10
- data/lib/parlour/type_loader.rb +9 -2
- data/lib/parlour/type_parser.rb +38 -17
- data/lib/parlour/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 889d6730ffefc764887706e5dadc4441e66cdf32e4567e809f7e634f511b7dfc
|
4
|
+
data.tar.gz: 9e9ab14b6618c209c8d194bf6e5557398689f0656247cac9561064dbcd541a6a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ea57b34b827ced92fdd1d28387217c0a5bc7027d94319cac6ffb238847a2820e9c164df86c9b2c43e60826cb1b362000c7c2bfc7f1f63b9b998959c70a3be377
|
7
|
+
data.tar.gz: fb10c8c783aea69e412d1a6eb67dd736f3db377168a21f8025e28fdb76acfc94ed20f1f7b9a17dafbac39ebcc2d36846b350d04c3e59882b546143df374b9f41
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -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
|
-
|
620
|
-
|
621
|
-
|
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
|
|
data/lib/parlour/type_loader.rb
CHANGED
@@ -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
|
|
data/lib/parlour/type_parser.rb
CHANGED
@@ -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
|
data/lib/parlour/version.rb
CHANGED
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.
|
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-
|
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.
|
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
|