parlour 6.0.1 → 7.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.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/.parlour +4 -2
  3. data/CHANGELOG.md +18 -0
  4. data/exe/parlour +2 -3
  5. data/lib/parlour/conflict_resolver.rb +18 -14
  6. data/lib/parlour/debugging.rb +29 -16
  7. data/lib/parlour/mixin/searchable.rb +54 -0
  8. data/lib/parlour/rbi_generator/arbitrary.rb +3 -6
  9. data/lib/parlour/rbi_generator/attribute.rb +9 -0
  10. data/lib/parlour/rbi_generator/class_namespace.rb +6 -7
  11. data/lib/parlour/rbi_generator/constant.rb +3 -6
  12. data/lib/parlour/rbi_generator/enum_class_namespace.rb +7 -0
  13. data/lib/parlour/rbi_generator/extend.rb +5 -8
  14. data/lib/parlour/rbi_generator/include.rb +5 -8
  15. data/lib/parlour/rbi_generator/method.rb +15 -10
  16. data/lib/parlour/rbi_generator/module_namespace.rb +7 -9
  17. data/lib/parlour/rbi_generator/namespace.rb +10 -10
  18. data/lib/parlour/rbi_generator/parameter.rb +12 -0
  19. data/lib/parlour/rbi_generator/rbi_object.rb +0 -5
  20. data/lib/parlour/rbi_generator/struct_class_namespace.rb +7 -0
  21. data/lib/parlour/rbi_generator/type_alias.rb +5 -8
  22. data/lib/parlour/rbi_generator.rb +1 -16
  23. data/lib/parlour/rbs_generator/arbitrary.rb +3 -6
  24. data/lib/parlour/rbs_generator/attribute.rb +8 -0
  25. data/lib/parlour/rbs_generator/class_namespace.rb +5 -9
  26. data/lib/parlour/rbs_generator/constant.rb +3 -6
  27. data/lib/parlour/rbs_generator/extend.rb +3 -6
  28. data/lib/parlour/rbs_generator/include.rb +3 -6
  29. data/lib/parlour/rbs_generator/interface_namespace.rb +5 -5
  30. data/lib/parlour/rbs_generator/method.rb +6 -7
  31. data/lib/parlour/rbs_generator/method_signature.rb +13 -0
  32. data/lib/parlour/rbs_generator/module_namespace.rb +5 -6
  33. data/lib/parlour/rbs_generator/namespace.rb +8 -8
  34. data/lib/parlour/rbs_generator/rbs_object.rb +0 -5
  35. data/lib/parlour/rbs_generator/type_alias.rb +3 -6
  36. data/lib/parlour/type_loader.rb +6 -1
  37. data/lib/parlour/type_parser.rb +2 -2
  38. data/lib/parlour/typed_object.rb +88 -3
  39. data/lib/parlour/version.rb +1 -1
  40. data/lib/parlour.rb +2 -0
  41. metadata +4 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 55378d16bdfdd7b027be168f8ed8bc0e78a49ba2ec42150692ba4e864c1f12eb
4
- data.tar.gz: 21a92ac404908f7c8ea99975ac3be11486d8335ce6b0b0d329b1d3eb70a9c906
3
+ metadata.gz: cc5c6c8baabe95bbc999a4143264b1dad8b84260bdc156d2a35526244322db2f
4
+ data.tar.gz: 580430b0cfe37f80b60f9dd47f8673f4d1d973e6ef6abca44efa299355d19fed
5
5
  SHA512:
6
- metadata.gz: 0cf8085a865e7865b1291b1cfde385cd3d9aff648f06c8ab7ea47d85161cc988faba165bae14bb450a979f27ef6687482105abe9a875781aea41d84a8b3f164e
7
- data.tar.gz: 0a660369feb37945261fa7720034d8c48721b03ee1b8b71eaa121fd6f9c72070a20e32360fcba8109cc8dcb10dbeb7f471b24c8d80900ca6938b411756128e61
6
+ metadata.gz: ae2fd0263a3d955ff7904a28e69bf16eb21b413bda3e71be42636e0829e730a33ee0eb477712fc45dffbce948de3a4c3d6ae6e19147e21b114cd58fe93679676
7
+ data.tar.gz: 549cd5f91736b8aa5c1f5e1ebaa69fd2d8e4e9f905f1d4aa9ed799677e2d2367a573548d6a9ea220f3c6c6dbf268cc2679c8d0e26516c52224574563974070b6
data/.parlour CHANGED
@@ -1,5 +1,7 @@
1
- excluded_paths:
2
- - lib/parlour/kernel_hack.rb
1
+ parser:
2
+ excluded_paths:
3
+ - lib/parlour/kernel_hack.rb
3
4
 
4
5
  excluded_modules:
5
6
  - Parlour::DetachedRbiGenerator
7
+ - Parlour::DetachedRbsGenerator
data/CHANGELOG.md CHANGED
@@ -3,6 +3,24 @@ 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
+ ## [7.0.0] - 2022-04-18
7
+ ### Added
8
+ - `#describe` now uses a new, clearer format.
9
+ - Added `#describe_tree`, which produces `#describe` output for a node and all
10
+ of its children.
11
+ - Added `#find` and `#find_all` for retrieving a node's children based on
12
+ criteria.
13
+
14
+ ### Changed
15
+ - Parlour now uses the new block-based `type_member` syntax internally.
16
+ **Potentially breaking** if you pin an older version of Sorbet which doesn't
17
+ support this syntax!
18
+ - Improved error message when unable to retrieve the file table from Sorbet.
19
+ - `#inspect` and `#to_s` now call `#describe`.
20
+
21
+ ## Fixed
22
+ - Fixed some incorrect YARD documentation tags.
23
+
6
24
  ## [6.0.1] - 2021-02-28
7
25
  ### Changed
8
26
  - Disabled runtime type checking for `TypedObject#name`, resulting in a
data/exe/parlour CHANGED
@@ -11,9 +11,8 @@ program :description, 'An RBI generator and plugin system'
11
11
 
12
12
  default_command :run
13
13
  command :run do |c|
14
- # TODO: re-add support for flags and figure out how to merge them with .parlour
15
- c.syntax = 'parlour run <plugins...> <output-file> [options]'
16
- c.description = 'Generates an RBI file from your .parlour file'
14
+ c.syntax = 'parlour run'
15
+ c.description = 'Generates a signature file from your .parlour file'
17
16
 
18
17
  c.action do |args, options|
19
18
  working_dir = Dir.pwd
@@ -7,6 +7,10 @@ module Parlour
7
7
  class ConflictResolver
8
8
  extend T::Sig
9
9
 
10
+ def initialize
11
+ @debugging_tree = Debugging::Tree.new(colour: true)
12
+ end
13
+
10
14
  sig do
11
15
  params(
12
16
  namespace: RbiGenerator::Namespace,
@@ -41,7 +45,7 @@ module Parlour
41
45
  # will be kept, or nil to keep none of them.
42
46
  # @return [void]
43
47
  def resolve_conflicts(namespace, &resolver)
44
- Debugging.debug_puts(self, Debugging::Tree.begin("Resolving conflicts for #{namespace.name}..."))
48
+ Debugging.debug_puts(self, @debugging_tree.begin("Resolving conflicts for #{namespace.name}..."))
45
49
 
46
50
  # Check for multiple definitions with the same name
47
51
  # (Special case here: writer attributes get an "=" appended to their name)
@@ -54,10 +58,10 @@ module Parlour
54
58
  end
55
59
 
56
60
  grouped_by_name_children.each do |name, children|
57
- Debugging.debug_puts(self, Debugging::Tree.begin("Checking children named #{name}..."))
61
+ Debugging.debug_puts(self, @debugging_tree.begin("Checking children named #{name}..."))
58
62
 
59
63
  if children.length > 1
60
- Debugging.debug_puts(self, Debugging::Tree.here("Possible conflict between #{children.length} objects"))
64
+ Debugging.debug_puts(self, @debugging_tree.here("Possible conflict between #{children.length} objects"))
61
65
 
62
66
  # Special case: do we have two methods, one of which is a class method
63
67
  # and the other isn't? If so, do nothing - this is fine
@@ -65,7 +69,7 @@ module Parlour
65
69
  children.all? { |c| c.is_a?(RbiGenerator::Method) } &&
66
70
  children.count { |c| T.cast(c, RbiGenerator::Method).class_method } == 1
67
71
 
68
- Debugging.debug_puts(self, Debugging::Tree.end("One is an instance method and one is a class method; no resolution required"))
72
+ Debugging.debug_puts(self, @debugging_tree.end("One is an instance method and one is a class method; no resolution required"))
69
73
  next
70
74
  end
71
75
 
@@ -80,7 +84,7 @@ module Parlour
80
84
  end
81
85
  deduplicate_mixins_of_name(namespace, name)
82
86
 
83
- Debugging.debug_puts(self, Debugging::Tree.end("Includes/extends do not conflict with namespaces; no resolution required"))
87
+ Debugging.debug_puts(self, @debugging_tree.end("Includes/extends do not conflict with namespaces; no resolution required"))
84
88
  next
85
89
  end
86
90
 
@@ -90,13 +94,13 @@ module Parlour
90
94
  children.all? { |c| c.is_a?(RbiGenerator::Attribute) } &&
91
95
  children.count { |c| T.cast(c, RbiGenerator::Attribute).class_attribute } == 1
92
96
 
93
- Debugging.debug_puts(self, Debugging::Tree.end("One is an instance attribute and one is a class attribute; no resolution required"))
97
+ Debugging.debug_puts(self, @debugging_tree.end("One is an instance attribute and one is a class attribute; no resolution required"))
94
98
  next
95
99
  end
96
100
 
97
101
  # Optimization for Special case: are they all clearly equal? If so, remove all but one
98
102
  if all_eql?(children)
99
- Debugging.debug_puts(self, Debugging::Tree.end("All children are identical"))
103
+ Debugging.debug_puts(self, @debugging_tree.end("All children are identical"))
100
104
 
101
105
  # All of the children are the same, so this deletes all of them
102
106
  namespace.children.delete(T.must(children.first))
@@ -116,7 +120,7 @@ module Parlour
116
120
  # and get the strategy to use
117
121
  strategy = merge_strategy(children)
118
122
  unless strategy
119
- Debugging.debug_puts(self, Debugging::Tree.end("Children are unmergeable types; requesting manual resolution"))
123
+ Debugging.debug_puts(self, @debugging_tree.end("Children are unmergeable types; requesting manual resolution"))
120
124
  # The types aren't the same, so ask the resolver what to do, and
121
125
  # insert that (if not nil)
122
126
  choice = resolver.call("Different kinds of definition for the same name", children)
@@ -135,7 +139,7 @@ module Parlour
135
139
  # a single method
136
140
  if non_namespaces.length != 0
137
141
  unless non_namespaces.length == 1 && RbiGenerator::Method === non_namespaces.first
138
- Debugging.debug_puts(self, Debugging::Tree.end("Non-namespace item in a differing namespace conflict is not a single method; requesting manual resolution"))
142
+ Debugging.debug_puts(self, @debugging_tree.end("Non-namespace item in a differing namespace conflict is not a single method; requesting manual resolution"))
139
143
  # The types aren't the same, so ask the resolver what to do, and
140
144
  # insert that (if not nil)
141
145
  choice = resolver.call("Non-namespace item in a differing namespace conflict is not a single method", non_namespaces)
@@ -167,29 +171,29 @@ module Parlour
167
171
  # Can the children merge themselves automatically? If so, let them
168
172
  first, rest = T.must(first), T.must(rest)
169
173
  if T.must(first).mergeable?(T.must(rest))
170
- Debugging.debug_puts(self, Debugging::Tree.end("Children are all mergeable; resolving automatically"))
174
+ Debugging.debug_puts(self, @debugging_tree.end("Children are all mergeable; resolving automatically"))
171
175
  first.merge_into_self(rest)
172
176
  namespace.children << first
173
177
  next
174
178
  end
175
179
 
176
180
  # I give up! Let it be resolved manually somehow
177
- Debugging.debug_puts(self, Debugging::Tree.end("Unable to resolve automatically; requesting manual resolution"))
181
+ Debugging.debug_puts(self, @debugging_tree.end("Unable to resolve automatically; requesting manual resolution"))
178
182
  choice = resolver.call("Can't automatically resolve", children)
179
183
  namespace.children << choice if choice
180
184
  else
181
- Debugging.debug_puts(self, Debugging::Tree.end("No conflicts"))
185
+ Debugging.debug_puts(self, @debugging_tree.end("No conflicts"))
182
186
  end
183
187
  end
184
188
 
185
- Debugging.debug_puts(self, Debugging::Tree.here("Resolving children..."))
189
+ Debugging.debug_puts(self, @debugging_tree.here("Resolving children..."))
186
190
 
187
191
  # Recurse to child namespaces
188
192
  namespace.children.each do |child|
189
193
  resolve_conflicts(child, &resolver) if RbiGenerator::Namespace === child
190
194
  end
191
195
 
192
- Debugging.debug_puts(self, Debugging::Tree.end("All children done"))
196
+ Debugging.debug_puts(self, @debugging_tree.end("All children done"))
193
197
  end
194
198
 
195
199
  private
@@ -17,7 +17,7 @@ module Parlour
17
17
  @debug_mode = value
18
18
  end
19
19
 
20
- # Whether debug messages sent by {#debug_puts} should be printed.
20
+ # Whether debug messages sent by {.debug_puts} should be printed.
21
21
  # Defaults to true if the PARLOUR_DEBUG environment variable is set.
22
22
  # @return [Boolean] True if debug messages will be printed, false otherwise.
23
23
  sig { returns(T::Boolean) }
@@ -25,11 +25,11 @@ module Parlour
25
25
  @debug_mode
26
26
  end
27
27
 
28
- # Prints a message with a debugging prefix to STDOUT if {#debug_mode?} is
28
+ # Prints a message with a debugging prefix to STDOUT if {.debug_mode?} is
29
29
  # true.
30
- # @params [Object] object The object which is printing this debug message.
30
+ # @param [Object] object The object which is printing this debug message.
31
31
  # Callers should pass +self+.
32
- # @params [String] message The message to print. It should not contain
32
+ # @param [String] message The message to print. It should not contain
33
33
  # newlines.
34
34
  # @return [void]
35
35
  sig { params(object: T.untyped, message: String).void }
@@ -45,7 +45,7 @@ module Parlour
45
45
  # "conflict resolver". If the object type is unknown, this returns its class
46
46
  # name.
47
47
  # @param [Object] object The object to convert.
48
- # @return [String] A string describing the object for {#debug_puts}.
48
+ # @return [String] A string describing the object for {.debug_puts}.
49
49
  sig { params(object: T.untyped).returns(String) }
50
50
  def self.name_for_debug_caller(object)
51
51
  case object
@@ -63,24 +63,32 @@ module Parlour
63
63
 
64
64
  # A module for generating a globally-consistent, nicely-formatted tree of
65
65
  # output using Unicode block characters.
66
- module Tree
66
+ class Tree
67
67
  extend T::Sig
68
68
 
69
69
  # The number of spaces to indent each layer of the tree by. Should be at
70
70
  # least 1.
71
71
  INDENT_SPACES = 2
72
72
 
73
- # The current indent level of the tree.
74
- @indent_level = 0
73
+ # Whether to colour output or not.
74
+ sig { returns(T::Boolean) }
75
+ attr_reader :colour
76
+
77
+ sig { params(colour: T::Boolean).void }
78
+ def initialize(colour: false)
79
+ @colour = colour
80
+ @indent_level = 0
81
+ end
75
82
 
76
83
  # Returns a new heading, and then decents the tree one level into it.
77
84
  # (That is, future output will go under the new heading.)
78
85
  # @param [String] message The heading.
79
86
  # @return [String] The line of this tree which should be printed.
80
87
  sig { params(message: String).returns(String) }
81
- def self.begin(message)
82
- result = line_prefix + '├' + text_prefix + Rainbow(message).green.bright.bold
83
- @indent_level += 1
88
+ def begin(message)
89
+ result = line_prefix + '├' + text_prefix +
90
+ (colour ? Rainbow(message).green.bright.bold : message)
91
+ indent!(1)
84
92
  result
85
93
  end
86
94
 
@@ -88,7 +96,7 @@ module Parlour
88
96
  # @param [String] message The element.
89
97
  # @return [String] The line of this tree which should be printed.
90
98
  sig { params(message: String).returns(String) }
91
- def self.here(message)
99
+ def here(message)
92
100
  line_prefix + '├' + text_prefix + message
93
101
  end
94
102
 
@@ -97,16 +105,16 @@ module Parlour
97
105
  # @param [String] message The element.
98
106
  # @return [String] The line of this tree which should be printed.
99
107
  sig { params(message: String).returns(String) }
100
- def self.end(message)
108
+ def end(message)
101
109
  result = line_prefix + '└' + text_prefix + message
102
- @indent_level = [0, @indent_level - 1].max
110
+ indent!(-1)
103
111
  result
104
112
  end
105
113
 
106
114
  # The prefix which should be printed before anything else on this line of
107
115
  # the tree, based on the current indent level.
108
116
  # @return [String]
109
- def self.line_prefix
117
+ def line_prefix
110
118
  @indent_level.times.map { '│' + ' ' * INDENT_SPACES }.join
111
119
  end
112
120
 
@@ -114,9 +122,14 @@ module Parlour
114
122
  # the current element and its text, based on the specified number of
115
123
  # spaces to use for indents.
116
124
  # @return [String]
117
- def self.text_prefix
125
+ def text_prefix
118
126
  '─' * (INDENT_SPACES - 1) + " "
119
127
  end
128
+
129
+ # Modifies the current indent level by the given offset.
130
+ def indent!(offset)
131
+ @indent_level = [0, @indent_level + offset].max
132
+ end
120
133
  end
121
134
  end
122
135
  end
@@ -0,0 +1,54 @@
1
+ # typed: true
2
+
3
+ module Parlour
4
+ module Mixin
5
+ # Extends a particular type system's Namespace class to provide searchable
6
+ # children.
7
+ module Searchable
8
+ extend T::Sig
9
+ extend T::Generic
10
+
11
+ Child = type_member
12
+
13
+ abstract!
14
+
15
+ sig { abstract.returns(T::Array[Child]) }
16
+ def children; end
17
+
18
+ sig { params(name: T.nilable(String), type: T.nilable(Class)).returns(Child) }
19
+ # Finds the first child matching the given predicates.
20
+ #
21
+ # @param [String, nil] name The name of the child to filter on, or nil.
22
+ # @param [Class, nil] type The type of the child to filter on, or nil. The
23
+ # type is compared using #is_a?.
24
+ def find(name: nil, type: nil)
25
+ T.unsafe(children).find { |c| searchable_child_matches(c, name, type) }
26
+ end
27
+
28
+ sig { params(name: T.nilable(String), type: T.nilable(Class)).returns(T::Array[Child]) }
29
+ # Finds the first child matching the given predicates.
30
+ #
31
+ # @param [String, nil] name The name of the child to filter on, or nil.
32
+ # @param [Class, nil] type The type of the child to filter on, or nil. The
33
+ # type is compared using #is_a?.
34
+ def find_all(name: nil, type: nil)
35
+ T.unsafe(children).select { |c| searchable_child_matches(c, name, type) }
36
+ end
37
+
38
+ private
39
+
40
+ sig do
41
+ params(
42
+ child: Child,
43
+ name: T.nilable(String),
44
+ type: T.nilable(Class)
45
+ )
46
+ .returns(T::Boolean)
47
+ end
48
+ def searchable_child_matches(child, name, type)
49
+ (name.nil? ? true : child.name == name) \
50
+ && (type.nil? ? true : child.is_a?(type))
51
+ end
52
+ end
53
+ end
54
+ end
@@ -80,12 +80,9 @@ module Parlour
80
80
  raise 'arbitrary code is never mergeable'
81
81
  end
82
82
 
83
- sig { override.returns(String) }
84
- # Returns a human-readable brief string description of this code.
85
- #
86
- # @return [String]
87
- def describe
88
- "Arbitrary code (#{code})"
83
+ sig { override.returns(T::Array[T.any(Symbol, T::Hash[Symbol, String])]) }
84
+ def describe_attrs
85
+ [:code]
89
86
  end
90
87
 
91
88
  sig { override.void }
@@ -78,6 +78,15 @@ module Parlour
78
78
  @type = TypeParser.parse_single_type(@type) if String === @type
79
79
  end
80
80
 
81
+ sig { override.returns(T::Array[T.any(Symbol, T::Hash[Symbol, String])]) }
82
+ def describe_attrs
83
+ [
84
+ :kind,
85
+ {type: type}, # avoid quotes
86
+ :class_attribute
87
+ ]
88
+ end
89
+
81
90
  private
82
91
 
83
92
  sig do
@@ -5,6 +5,8 @@ module Parlour
5
5
  class ClassNamespace < Namespace
6
6
  extend T::Sig
7
7
 
8
+ Child = type_member {{ fixed: RbiObject }}
9
+
8
10
  sig do
9
11
  params(
10
12
  generator: Generator,
@@ -110,13 +112,10 @@ module Parlour
110
112
  end
111
113
  end
112
114
 
113
- sig { override.returns(String) }
114
- # Returns a human-readable brief string description of this class.
115
- # @return [String]
116
- def describe
117
- "Class #{name} - #{"superclass #{superclass}, " if superclass}" +
118
- "#{"abstract, " if abstract}#{children.length} children, " +
119
- "#{includes.length} includes, #{extends.length} extends"
115
+ sig { override.returns(T::Array[T.any(Symbol, T::Hash[Symbol, String])]) }
116
+ def describe_attrs
117
+ (superclass ? [:superclass] : []) \
118
+ + [:children, :abstract, :final, :sealed]
120
119
  end
121
120
 
122
121
  sig { override.void }
@@ -95,12 +95,9 @@ module Parlour
95
95
  # We don't need to change anything! We only merge identical constants
96
96
  end
97
97
 
98
- sig { override.returns(String) }
99
- # Returns a human-readable brief string description of this code.
100
- #
101
- # @return [String]
102
- def describe
103
- "Constant (#{name} = #{value})"
98
+ sig { override.returns(T::Array[T.any(Symbol, T::Hash[Symbol, String])]) }
99
+ def describe_attrs
100
+ [:value, :eigen_constant]
104
101
  end
105
102
 
106
103
  sig { override.void }
@@ -5,6 +5,8 @@ module Parlour
5
5
  class EnumClassNamespace < ClassNamespace
6
6
  extend T::Sig
7
7
 
8
+ Child = type_member {{ fixed: RbiObject }}
9
+
8
10
  sig do
9
11
  params(
10
12
  generator: Generator,
@@ -114,6 +116,11 @@ module Parlour
114
116
  def generalize_from_rbi!
115
117
  super
116
118
  end
119
+
120
+ sig { override.returns(T::Array[T.any(Symbol, T::Hash[Symbol, String])]) }
121
+ def describe_attrs
122
+ super + [{enums: enums.inspect}]
123
+ end
117
124
  end
118
125
  end
119
126
  end
@@ -75,16 +75,13 @@ module Parlour
75
75
  # We don't need to change anything! We only merge identical extends
76
76
  end
77
77
 
78
- sig { override.returns(String) }
79
- # Returns a human-readable brief string description of this code.
80
- #
81
- # @return [String]
82
- def describe
83
- "Extend (#{name})"
84
- end
85
-
86
78
  sig { override.void }
87
79
  def generalize_from_rbi!; end # Nothing to do
80
+
81
+ sig { override.returns(T::Array[T.any(Symbol, T::Hash[Symbol, String])]) }
82
+ def describe_attrs
83
+ []
84
+ end
88
85
  end
89
86
  end
90
87
  end
@@ -75,16 +75,13 @@ module Parlour
75
75
  # We don't need to change anything! We only merge identical includes
76
76
  end
77
77
 
78
- sig { override.returns(String) }
79
- # Returns a human-readable brief string description of this code.
80
- #
81
- # @return [String]
82
- def describe
83
- "Include (#{name})"
84
- end
85
-
86
78
  sig { override.void }
87
79
  def generalize_from_rbi!; end # Nothing to do
80
+
81
+ sig { override.returns(T::Array[T.any(Symbol, T::Hash[Symbol, String])]) }
82
+ def describe_attrs
83
+ []
84
+ end
88
85
  end
89
86
  end
90
87
  end
@@ -206,16 +206,6 @@ module Parlour
206
206
  # We don't need to change anything! We only merge identical methods
207
207
  end
208
208
 
209
- sig { override.returns(String) }
210
- # Returns a human-readable brief string description of this method.
211
- #
212
- # @return [String]
213
- def describe
214
- # TODO: more info
215
- "Method #{name} - #{parameters.length} parameters, " +
216
- " returns #{return_type}"
217
- end
218
-
219
209
  sig { override.void }
220
210
  def generalize_from_rbi!
221
211
  @return_type = TypeParser.parse_single_type(@return_type) if String === @return_type
@@ -223,6 +213,21 @@ module Parlour
223
213
  parameters.each(&:generalize_from_rbi!)
224
214
  end
225
215
 
216
+ sig { override.returns(T::Array[T.any(Symbol, T::Hash[Symbol, String])]) }
217
+ def describe_attrs
218
+ (type_parameters.any? ? [{ type_parameters: type_parameters.join(", ")}] : []) \
219
+ + [
220
+ {parameters: "(#{parameters.map(&:describe_in_method).join(", ")})"},
221
+ {return_type: return_type || '(void)'}, # avoid quotes
222
+ :class_method,
223
+ :abstract,
224
+ :implementation,
225
+ :override,
226
+ :overridable,
227
+ :final,
228
+ ]
229
+ end
230
+
226
231
  private
227
232
 
228
233
  sig do
@@ -5,6 +5,8 @@ module Parlour
5
5
  class ModuleNamespace < Namespace
6
6
  extend T::Sig
7
7
 
8
+ Child = type_member {{ fixed: RbiObject }}
9
+
8
10
  sig do
9
11
  params(
10
12
  generator: Generator,
@@ -100,19 +102,15 @@ module Parlour
100
102
  super
101
103
  end
102
104
 
103
- sig { override.returns(String) }
104
- # Returns a human-readable brief string description of this module.
105
- # @return [String]
106
- def describe
107
- "Module #{name} - #{"interface, " if interface}" +
108
- "#{"abstract, " if abstract}#{children.length} " +
109
- "children, #{includes.length} includes, #{extends.length} extends"
110
- end
111
-
112
105
  sig { override.void }
113
106
  def generalize_from_rbi!
114
107
  super
115
108
  end
109
+
110
+ sig { override.returns(T::Array[T.any(Symbol, T::Hash[Symbol, String])]) }
111
+ def describe_attrs
112
+ [:children, :abstract, :interface, :final, :sealed]
113
+ end
116
114
  end
117
115
  end
118
116
  end
@@ -5,6 +5,7 @@ module Parlour
5
5
  # {RbiGenerator#root}.
6
6
  class Namespace < RbiObject
7
7
  extend T::Sig
8
+ extend T::Generic
8
9
 
9
10
  sig do
10
11
  override.overridable.params(
@@ -60,11 +61,14 @@ module Parlour
60
61
  # @return [Boolean]
61
62
  attr_reader :sealed
62
63
 
63
- sig { returns(T::Array[RbiObject]) }
64
+ sig { override.returns(T::Array[RbiObject]).checked(:never) }
64
65
  # The child {RbiObject} instances inside this namespace.
65
66
  # @return [Array<RbiObject>]
66
67
  attr_reader :children
67
68
 
69
+ include Mixin::Searchable
70
+ Child = type_member {{ fixed: RbiObject }}
71
+
68
72
  sig { returns(T::Array[RbiGenerator::Extend]) }
69
73
  # The {RbiGenerator::Extend} objects from {children}.
70
74
  # @return [Array<RbiGenerator::Extend>]
@@ -647,20 +651,16 @@ module Parlour
647
651
  end
648
652
  end
649
653
 
650
- sig { override.overridable.returns(String) }
651
- # Returns a human-readable brief string description of this namespace.
652
- #
653
- # @return [String]
654
- def describe
655
- "Namespace #{name} - #{children.length} children, #{includes.length} " +
656
- "includes, #{extends.length} extends, #{constants.length} constants"
657
- end
658
-
659
654
  sig { override.void }
660
655
  def generalize_from_rbi!
661
656
  children.each(&:generalize_from_rbi!)
662
657
  end
663
658
 
659
+ sig { override.returns(T::Array[T.any(Symbol, T::Hash[Symbol, String])]) }
660
+ def describe_attrs
661
+ [:children, :final, :sealed]
662
+ end
663
+
664
664
  private
665
665
 
666
666
  sig do
@@ -134,6 +134,18 @@ module Parlour
134
134
  def generalize_from_rbi!
135
135
  @type = TypeParser.parse_single_type(@type) if String === @type
136
136
  end
137
+
138
+ sig { returns(String) }
139
+ def describe_in_method
140
+ t = type
141
+ t = t.is_a?(String) ? t : t.describe
142
+
143
+ if default
144
+ "#{name}: #{t} = #{default}"
145
+ else
146
+ "#{name}: #{t}"
147
+ end
148
+ end
137
149
  end
138
150
  end
139
151
  end
@@ -69,11 +69,6 @@ module Parlour
69
69
  # @return [void]
70
70
  def merge_into_self(others); end
71
71
 
72
- sig { override.overridable.returns(String) }
73
- def describe
74
- 'RBI object'
75
- end
76
-
77
72
  sig { abstract.void }
78
73
  # Assuming that the types throughout this object and its children have
79
74
  # been specified as RBI-style types, generalises them into type instances
@@ -6,6 +6,8 @@ module Parlour
6
6
  class StructClassNamespace < ClassNamespace
7
7
  extend T::Sig
8
8
 
9
+ Child = type_member {{ fixed: RbiObject }}
10
+
9
11
  sig do
10
12
  params(
11
13
  generator: Generator,
@@ -107,6 +109,11 @@ module Parlour
107
109
 
108
110
  props.each(&:generalize_from_rbi!)
109
111
  end
112
+
113
+ sig { override.returns(T::Array[T.any(Symbol, T::Hash[Symbol, String])]) }
114
+ def describe_attrs
115
+ super + [{props: "(#{props.map(&:name)})"}]
116
+ end
110
117
  end
111
118
  end
112
119
  end
@@ -84,18 +84,15 @@ module Parlour
84
84
  # We don't need to change anything! We only merge identical type alias
85
85
  end
86
86
 
87
- sig { override.returns(String) }
88
- # Returns a human-readable brief string description of this code.
89
- #
90
- # @return [String]
91
- def describe
92
- "Type Alias (#{name} = #{type})"
93
- end
94
-
95
87
  sig { override.void }
96
88
  def generalize_from_rbi!
97
89
  @type = TypeParser.parse_single_type(@type) if String === @type
98
90
  end
91
+
92
+ sig { override.returns(T::Array[T.any(Symbol, T::Hash[Symbol, String])]) }
93
+ def describe_attrs
94
+ [{type: type}] # avoid quotes
95
+ end
99
96
  end
100
97
  end
101
98
  end
@@ -21,22 +21,7 @@ module Parlour
21
21
  #
22
22
  # @return [String] The generated RBI file
23
23
  def rbi(strictness = 'strong')
24
- # TODO: Early test option - convert to RBS if requested
25
- # Absolutely remove this later on
26
- if ENV['PARLOUR_CONVERT_TO_RBS']
27
- # Perform conversion
28
- root.generalize_from_rbi!
29
- rbs_gen = Parlour::RbsGenerator.new
30
- converter = Parlour::Conversion::RbiToRbs.new(rbs_gen)
31
- root.children.each do |child|
32
- converter.convert_object(child, rbs_gen.root)
33
- end
34
-
35
- # Write the final RBS
36
- rbs_gen.rbs
37
- else
38
- "# typed: #{strictness}\n" + root.generate_rbi(0, options).join("\n") + "\n"
39
- end
24
+ "# typed: #{strictness}\n" + root.generate_rbi(0, options).join("\n") + "\n"
40
25
  end
41
26
  end
42
27
  end
@@ -80,12 +80,9 @@ module Parlour
80
80
  raise 'arbitrary code is never mergeable'
81
81
  end
82
82
 
83
- sig { override.returns(String) }
84
- # Returns a human-readable brief string description of this code.
85
- #
86
- # @return [String]
87
- def describe
88
- "Arbitrary code (#{code})"
83
+ sig { override.returns(T::Array[T.any(Symbol, T::Hash[Symbol, String])]) }
84
+ def describe_attrs
85
+ [:code]
89
86
  end
90
87
  end
91
88
  end
@@ -77,6 +77,14 @@ module Parlour
77
77
  super(other) && Attribute === other && kind == other.kind
78
78
  )
79
79
  end
80
+
81
+ sig { override.returns(T::Array[T.any(Symbol, T::Hash[Symbol, String])]) }
82
+ def describe_attrs
83
+ [
84
+ :kind,
85
+ :class_attribute
86
+ ]
87
+ end
80
88
  end
81
89
  end
82
90
  end
@@ -5,6 +5,8 @@ module Parlour
5
5
  class ClassNamespace < Namespace
6
6
  extend T::Sig
7
7
 
8
+ Child = type_member {{ fixed: RbsObject }}
9
+
8
10
  sig do
9
11
  params(
10
12
  generator: Generator,
@@ -18,10 +20,8 @@ module Parlour
18
20
  #
19
21
  # @param generator [RbsGenerator] The current RbsGenerator.
20
22
  # @param name [String] The name of this class.
21
- # @param final [Boolean] Whether this namespace is final.
22
23
  # @param superclass [String, nil] The superclass of this class, or nil if it doesn't
23
24
  # have one.
24
- # @param abstract [Boolean] A boolean indicating whether this class is abstract.
25
25
  # @param block A block which the new instance yields itself to.
26
26
  # @return [void]
27
27
  def initialize(generator, name, superclass, &block)
@@ -93,13 +93,9 @@ module Parlour
93
93
  end
94
94
  end
95
95
 
96
- sig { override.returns(String) }
97
- # Returns a human-readable brief string description of this class.
98
- # @return [String]
99
- def describe
100
- "Class #{name} - #{"superclass #{superclass}, " if superclass}" +
101
- "#{children.length} children, " +
102
- "#{includes.length} includes, #{extends.length} extends"
96
+ sig { override.returns(T::Array[T.any(Symbol, T::Hash[Symbol, String])]) }
97
+ def describe_attrs
98
+ (superclass ? [:superclass] : []) + [:children]
103
99
  end
104
100
  end
105
101
  end
@@ -83,12 +83,9 @@ module Parlour
83
83
  # We don't need to change anything! We only merge identical constants
84
84
  end
85
85
 
86
- sig { override.returns(String) }
87
- # Returns a human-readable brief string description of this code.
88
- #
89
- # @return [String]
90
- def describe
91
- "Constant (#{name} = #{type})"
86
+ sig { override.returns(T::Array[T.any(Symbol, T::Hash[Symbol, String])]) }
87
+ def describe_attrs
88
+ [{type: type}] # avoid quotes
92
89
  end
93
90
  end
94
91
  end
@@ -80,12 +80,9 @@ module Parlour
80
80
  # We don't need to change anything! We only merge identical extends
81
81
  end
82
82
 
83
- sig { override.returns(String) }
84
- # Returns a human-readable brief string description of this code.
85
- #
86
- # @return [String]
87
- def describe
88
- "Extend (#{@type})"
83
+ sig { override.returns(T::Array[T.any(Symbol, T::Hash[Symbol, String])]) }
84
+ def describe_attrs
85
+ [{type: type}] # avoid quotes
89
86
  end
90
87
  end
91
88
  end
@@ -80,12 +80,9 @@ module Parlour
80
80
  # We don't need to change anything! We only merge identical includes
81
81
  end
82
82
 
83
- sig { override.returns(String) }
84
- # Returns a human-readable brief string description of this code.
85
- #
86
- # @return [String]
87
- def describe
88
- "Include (#{@type})"
83
+ sig { override.returns(T::Array[T.any(Symbol, T::Hash[Symbol, String])]) }
84
+ def describe_attrs
85
+ [{type: type}] # avoid quotes
89
86
  end
90
87
  end
91
88
  end
@@ -5,6 +5,8 @@ module Parlour
5
5
  class InterfaceNamespace < Namespace
6
6
  extend T::Sig
7
7
 
8
+ Child = type_member {{ fixed: RbsObject }}
9
+
8
10
  sig do
9
11
  override.params(
10
12
  indent_level: Integer,
@@ -23,11 +25,9 @@ module Parlour
23
25
  lines << options.indented(indent_level, "end")
24
26
  end
25
27
 
26
- sig { override.returns(String) }
27
- # Returns a human-readable brief string description of this interface.
28
- # @return [String]
29
- def describe
30
- "Interface #{name} - #{children.length}"
28
+ sig { override.returns(T::Array[T.any(Symbol, T::Hash[Symbol, String])]) }
29
+ def describe_attrs
30
+ [:children]
31
31
  end
32
32
  end
33
33
  end
@@ -133,13 +133,12 @@ module Parlour
133
133
  # TODO: merge signatures of different definitions
134
134
  end
135
135
 
136
- sig { override.returns(String) }
137
- # Returns a human-readable brief string description of this method.
138
- #
139
- # @return [String]
140
- def describe
141
- # TODO: more info
142
- "Method #{name} - #{signatures.length} signatures"
136
+ sig { override.returns(T::Array[T.any(Symbol, T::Hash[Symbol, String])]) }
137
+ def describe_attrs
138
+ [
139
+ {signatures: "(#{signatures.map(&:describe_in_method).join(", ")})"},
140
+ :class_method,
141
+ ]
143
142
  end
144
143
  end
145
144
  end
@@ -99,6 +99,19 @@ module Parlour
99
99
 
100
100
  generated_params
101
101
  end
102
+
103
+ sig { returns(String) }
104
+ def describe_in_method
105
+ # RBS is terse enough that just describing using the RBS is probably
106
+ # fine. (Unfortunately, this doesn't allow any differentiation between
107
+ # string types and Parlour::Types types.)
108
+ # (#describe is supposed to be one line, but this will break if you
109
+ # have than 10000 parameters. Honestly, if you do have more than 10000
110
+ # parameters, you deserve this...)
111
+ generate_rbs(Parlour::Options.new(
112
+ break_params: 10000, tab_size: 2, sort_namespaces: false
113
+ )).join("\n")
114
+ end
102
115
  end
103
116
  end
104
117
  end
@@ -5,6 +5,8 @@ module Parlour
5
5
  class ModuleNamespace < Namespace
6
6
  extend T::Sig
7
7
 
8
+ Child = type_member {{ fixed: RbsObject }}
9
+
8
10
  sig do
9
11
  override.params(
10
12
  indent_level: Integer,
@@ -23,12 +25,9 @@ module Parlour
23
25
  lines << options.indented(indent_level, "end")
24
26
  end
25
27
 
26
- sig { override.returns(String) }
27
- # Returns a human-readable brief string description of this module.
28
- # @return [String]
29
- def describe
30
- "Module #{name} - #{children.length} " +
31
- "children, #{includes.length} includes, #{extends.length} extends"
28
+ sig { override.returns(T::Array[T.any(Symbol, T::Hash[Symbol, String])]) }
29
+ def describe_attrs
30
+ [:children]
32
31
  end
33
32
  end
34
33
  end
@@ -5,6 +5,7 @@ module Parlour
5
5
  # {RbsGenerator#root}.
6
6
  class Namespace < RbsObject
7
7
  extend T::Sig
8
+ extend T::Generic
8
9
 
9
10
  sig do
10
11
  override.overridable.params(
@@ -45,11 +46,14 @@ module Parlour
45
46
  yield_self(&block) if block
46
47
  end
47
48
 
48
- sig { returns(T::Array[RbsObject]) }
49
+ sig { override.returns(T::Array[RbsObject]).checked(:never) }
49
50
  # The child {RbsObject} instances inside this namespace.
50
51
  # @return [Array<RbsObject>]
51
52
  attr_reader :children
52
53
 
54
+ include Mixin::Searchable
55
+ Child = type_member {{ fixed: RbsObject }}
56
+
53
57
  sig { returns(T::Array[RbsGenerator::Extend]) }
54
58
  # The {RbsGenerator::Extend} objects from {children}.
55
59
  # @return [Array<RbsGenerator::Extend>]
@@ -517,13 +521,9 @@ module Parlour
517
521
  end
518
522
  end
519
523
 
520
- sig { override.overridable.returns(String) }
521
- # Returns a human-readable brief string description of this namespace.
522
- #
523
- # @return [String]
524
- def describe
525
- "Namespace #{name} - #{children.length} children, #{includes.length} " +
526
- "includes, #{extends.length} extends, #{constants.length} constants"
524
+ sig { override.returns(T::Array[T.any(Symbol, T::Hash[Symbol, String])]) }
525
+ def describe_attrs
526
+ [:children]
527
527
  end
528
528
 
529
529
  private
@@ -68,11 +68,6 @@ module Parlour
68
68
  # @param others [Array<RbsGenerator::RbsObject>] An array of other {RbsObject} instances.
69
69
  # @return [void]
70
70
  def merge_into_self(others); end
71
-
72
- sig { overridable.override.returns(String) }
73
- def describe
74
- 'RBS object'
75
- end
76
71
  end
77
72
  end
78
73
  end
@@ -84,12 +84,9 @@ module Parlour
84
84
  # We don't need to change anything! We only merge identical type alias
85
85
  end
86
86
 
87
- sig { override.returns(String) }
88
- # Returns a human-readable brief string description of this code.
89
- #
90
- # @return [String]
91
- def describe
92
- "Type Alias (#{name} = #{type})"
87
+ sig { override.returns(T::Array[T.any(Symbol, T::Hash[Symbol, String])]) }
88
+ def describe_attrs
89
+ [{type: type}] # avoid quotes
93
90
  end
94
91
  end
95
92
  end
@@ -60,7 +60,12 @@ module Parlour
60
60
  chdir: root
61
61
  )
62
62
 
63
- file_table_hash = JSON.parse(T.must(stdout.read))
63
+ stdout = T.must(stdout.read)
64
+ if stdout == ''
65
+ raise 'unable to get Sorbet file table; the project may be empty or not have Sorbet initialised'
66
+ end
67
+
68
+ file_table_hash = JSON.parse(stdout)
64
69
  file_table_entries = file_table_hash['files']
65
70
 
66
71
  namespaces = T.let([], T::Array[Parlour::RbiGenerator::Namespace])
@@ -361,8 +361,8 @@ module Parlour
361
361
  # (block (send (const nil :T) :type_alias) (args) (type_to_alias))
362
362
  if body.type == :block &&
363
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] &&
364
+ body.to_a[0].to_a[0]&.type == :const &&
365
+ body.to_a[0].to_a[0]&.to_a == [nil, :T] &&
366
366
  body.to_a[0].to_a[1] == :type_alias
367
367
 
368
368
  [Parlour::RbiGenerator::TypeAlias.new(
@@ -57,16 +57,101 @@ module Parlour
57
57
 
58
58
  alias_method :add_comments, :add_comment
59
59
 
60
- sig { abstract.returns(String) }
60
+ sig { returns(String) }
61
61
  # Returns a human-readable brief string description of this object. This
62
62
  # is displayed during manual conflict resolution with the +parlour+ CLI.
63
63
  #
64
- # @abstract
65
64
  # @return [String]
66
- def describe; end
65
+ def describe
66
+ if is_a?(RbiGenerator::RbiObject)
67
+ type_system = 'RBI'
68
+ elsif is_a?(RbsGenerator::RbsObject)
69
+ type_system = 'RBS'
70
+ else
71
+ raise 'unknown type system'
72
+ end
73
+
74
+ attr_strings = describe_attrs.map do |a|
75
+ case a
76
+ when Symbol
77
+ key = a
78
+ value = send(a)
79
+
80
+ case value
81
+ when Array, Hash
82
+ value = value.length
83
+ next nil if value == 0
84
+ when String
85
+ value = value.inspect
86
+ when Parlour::Types::Type
87
+ value = value.describe
88
+ when true
89
+ next key
90
+ when false
91
+ next nil
92
+ end
93
+ when Hash
94
+ raise 'describe_attrs Hash must have one key' unless a.length == 1
95
+
96
+ key = a.keys[0]
97
+ value = a.values[0]
98
+ end
99
+
100
+ "#{key}=#{value}"
101
+ end.compact
102
+
103
+ class_name = T.must(self.class.name).split('::').last
104
+ if attr_strings.empty?
105
+ "<#{type_system}:#{class_name}:#{name}>"
106
+ else
107
+ "<#{type_system}:#{class_name}:#{name} #{attr_strings.join(" ")}>"
108
+ end
109
+ end
110
+
111
+ sig { params(tree: T.nilable(Debugging::Tree)).returns(String) }
112
+ # Returns a human-readable multi-line string description of this object and
113
+ # its children recursively.
114
+ #
115
+ # @return [String]
116
+ def describe_tree(tree: nil)
117
+ if tree.nil?
118
+ tree = Debugging::Tree.new
119
+ result = "#{describe}\n"
120
+ else
121
+ result = ""
122
+ end
123
+
124
+ if is_a?(RbiGenerator::Namespace) || is_a?(RbsGenerator::Namespace)
125
+ children.each do |child|
126
+ result += "#{tree.begin(child.describe)}\n"
127
+ result += child.describe_tree(tree: tree)
128
+ tree.indent!(-1)
129
+ end
130
+ else
131
+ "#{describe}\n"
132
+ end
133
+
134
+ result
135
+ end
136
+
137
+ alias inspect describe
138
+ alias to_s describe
67
139
 
68
140
  protected
69
141
 
142
+ sig { abstract.returns(T::Array[T.any(Symbol, T::Hash[Symbol, String])]) }
143
+ # The attributes for an instance of this object which should be included in
144
+ # its string form generated by +#describe+.
145
+ # For each element in the returned array:
146
+ # - If it is a symbol, this symbol will be called on +self+ and the
147
+ # returned object will be dynamically converted into a string.
148
+ # - If it is a hash, it must be of the format { Symbol => String }. The
149
+ # given string will be used instead of calling the symbol.
150
+ #
151
+ # @abstract
152
+ # @return [<Symbol, String>]
153
+ def describe_attrs; end
154
+
70
155
  sig do
71
156
  params(
72
157
  indent_level: Integer,
@@ -1,5 +1,5 @@
1
1
  # typed: strong
2
2
  module Parlour
3
3
  # The library version.
4
- VERSION = '6.0.1'
4
+ VERSION = '7.0.0'
5
5
  end
data/lib/parlour.rb CHANGED
@@ -14,6 +14,8 @@ require 'parlour/types'
14
14
  require 'parlour/options'
15
15
  require 'parlour/typed_object'
16
16
  require 'parlour/generator'
17
+ require 'parlour/mixin/searchable'
18
+
17
19
  require 'parlour/rbi_generator/parameter'
18
20
  require 'parlour/rbi_generator/rbi_object'
19
21
  require 'parlour/rbi_generator/type_alias'
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: 6.0.1
4
+ version: 7.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: 2021-07-05 00:00:00.000000000 Z
11
+ date: 2022-04-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sorbet-runtime
@@ -181,6 +181,7 @@ files:
181
181
  - lib/parlour/detached_rbs_generator.rb
182
182
  - lib/parlour/generator.rb
183
183
  - lib/parlour/kernel_hack.rb
184
+ - lib/parlour/mixin/searchable.rb
184
185
  - lib/parlour/options.rb
185
186
  - lib/parlour/parse_error.rb
186
187
  - lib/parlour/plugin.rb
@@ -242,7 +243,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
242
243
  - !ruby/object:Gem::Version
243
244
  version: '0'
244
245
  requirements: []
245
- rubygems_version: 3.2.0.rc.1
246
+ rubygems_version: 3.2.22
246
247
  signing_key:
247
248
  specification_version: 4
248
249
  summary: A type information generator, merger and parser for Sorbet and Ruby 3/Steep