parlour 6.0.1 → 7.0.0

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