parlour 3.0.0 → 5.0.0.beta.3

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 (68) hide show
  1. checksums.yaml +4 -4
  2. data/.github/ISSUE_TEMPLATE/bug-report.md +0 -0
  3. data/.github/ISSUE_TEMPLATE/feature-request.md +0 -0
  4. data/.gitignore +1 -1
  5. data/.parlour +5 -0
  6. data/.rspec +0 -0
  7. data/.travis.yml +0 -0
  8. data/CHANGELOG.md +57 -0
  9. data/CODE_OF_CONDUCT.md +0 -0
  10. data/Gemfile +0 -0
  11. data/LICENSE.txt +0 -0
  12. data/README.md +233 -19
  13. data/Rakefile +0 -0
  14. data/exe/parlour +109 -4
  15. data/lib/parlour.rb +27 -1
  16. data/lib/parlour/conflict_resolver.rb +31 -9
  17. data/lib/parlour/conversion/converter.rb +34 -0
  18. data/lib/parlour/conversion/rbi_to_rbs.rb +223 -0
  19. data/lib/parlour/debugging.rb +0 -0
  20. data/lib/parlour/detached_rbi_generator.rb +1 -6
  21. data/lib/parlour/detached_rbs_generator.rb +25 -0
  22. data/lib/parlour/generator.rb +34 -0
  23. data/lib/parlour/kernel_hack.rb +0 -0
  24. data/lib/parlour/options.rb +71 -0
  25. data/lib/parlour/parse_error.rb +0 -0
  26. data/lib/parlour/plugin.rb +1 -1
  27. data/lib/parlour/rbi_generator.rb +24 -37
  28. data/lib/parlour/rbi_generator/arbitrary.rb +5 -2
  29. data/lib/parlour/rbi_generator/attribute.rb +14 -5
  30. data/lib/parlour/rbi_generator/class_namespace.rb +8 -3
  31. data/lib/parlour/rbi_generator/constant.rb +28 -8
  32. data/lib/parlour/rbi_generator/enum_class_namespace.rb +8 -3
  33. data/lib/parlour/rbi_generator/extend.rb +5 -2
  34. data/lib/parlour/rbi_generator/include.rb +5 -2
  35. data/lib/parlour/rbi_generator/method.rb +15 -10
  36. data/lib/parlour/rbi_generator/module_namespace.rb +7 -2
  37. data/lib/parlour/rbi_generator/namespace.rb +68 -18
  38. data/lib/parlour/rbi_generator/parameter.rb +13 -7
  39. data/lib/parlour/rbi_generator/rbi_object.rb +19 -78
  40. data/lib/parlour/rbi_generator/struct_class_namespace.rb +9 -2
  41. data/lib/parlour/rbi_generator/struct_prop.rb +12 -9
  42. data/lib/parlour/rbi_generator/type_alias.rb +101 -0
  43. data/lib/parlour/rbs_generator.rb +24 -0
  44. data/lib/parlour/rbs_generator/arbitrary.rb +92 -0
  45. data/lib/parlour/rbs_generator/attribute.rb +82 -0
  46. data/lib/parlour/rbs_generator/block.rb +49 -0
  47. data/lib/parlour/rbs_generator/class_namespace.rb +106 -0
  48. data/lib/parlour/rbs_generator/constant.rb +95 -0
  49. data/lib/parlour/rbs_generator/extend.rb +92 -0
  50. data/lib/parlour/rbs_generator/include.rb +92 -0
  51. data/lib/parlour/rbs_generator/interface_namespace.rb +34 -0
  52. data/lib/parlour/rbs_generator/method.rb +146 -0
  53. data/lib/parlour/rbs_generator/method_signature.rb +104 -0
  54. data/lib/parlour/rbs_generator/module_namespace.rb +35 -0
  55. data/lib/parlour/rbs_generator/namespace.rb +627 -0
  56. data/lib/parlour/rbs_generator/parameter.rb +146 -0
  57. data/lib/parlour/rbs_generator/rbs_object.rb +78 -0
  58. data/lib/parlour/rbs_generator/type_alias.rb +96 -0
  59. data/lib/parlour/type_loader.rb +25 -12
  60. data/lib/parlour/type_parser.rb +174 -17
  61. data/lib/parlour/typed_object.rb +87 -0
  62. data/lib/parlour/types.rb +539 -0
  63. data/lib/parlour/version.rb +1 -1
  64. data/parlour.gemspec +1 -1
  65. data/plugin_examples/foobar_plugin.rb +0 -0
  66. data/rbi/parlour.rbi +1856 -0
  67. metadata +35 -10
  68. data/lib/parlour/rbi_generator/options.rb +0 -74
@@ -9,12 +9,17 @@ require 'parlour/kernel_hack'
9
9
 
10
10
  require 'parlour/plugin'
11
11
 
12
+ require 'parlour/types'
13
+
14
+ require 'parlour/options'
15
+ require 'parlour/typed_object'
16
+ require 'parlour/generator'
12
17
  require 'parlour/rbi_generator/parameter'
13
18
  require 'parlour/rbi_generator/rbi_object'
19
+ require 'parlour/rbi_generator/type_alias'
14
20
  require 'parlour/rbi_generator/method'
15
21
  require 'parlour/rbi_generator/attribute'
16
22
  require 'parlour/rbi_generator/arbitrary'
17
- require 'parlour/rbi_generator/options'
18
23
  require 'parlour/rbi_generator/include'
19
24
  require 'parlour/rbi_generator/extend'
20
25
  require 'parlour/rbi_generator/constant'
@@ -27,6 +32,27 @@ require 'parlour/rbi_generator/struct_class_namespace'
27
32
  require 'parlour/rbi_generator'
28
33
  require 'parlour/detached_rbi_generator'
29
34
 
35
+ require 'parlour/rbs_generator/rbs_object'
36
+ require 'parlour/rbs_generator/type_alias'
37
+ require 'parlour/rbs_generator/namespace'
38
+ require 'parlour/rbs_generator/method'
39
+ require 'parlour/rbs_generator/arbitrary'
40
+ require 'parlour/rbs_generator/attribute'
41
+ require 'parlour/rbs_generator/block'
42
+ require 'parlour/rbs_generator/class_namespace'
43
+ require 'parlour/rbs_generator/constant'
44
+ require 'parlour/rbs_generator/extend'
45
+ require 'parlour/rbs_generator/include'
46
+ require 'parlour/rbs_generator/method_signature'
47
+ require 'parlour/rbs_generator/module_namespace'
48
+ require 'parlour/rbs_generator/interface_namespace'
49
+ require 'parlour/rbs_generator/parameter'
50
+ require 'parlour/rbs_generator'
51
+ require 'parlour/detached_rbs_generator'
52
+
53
+ require 'parlour/conversion/converter'
54
+ require 'parlour/conversion/rbi_to_rbs'
55
+
30
56
  require 'parlour/conflict_resolver'
31
57
 
32
58
  require 'parlour/parse_error'
@@ -13,7 +13,7 @@ module Parlour
13
13
  resolver: T.proc.params(
14
14
  desc: String,
15
15
  choices: T::Array[RbiGenerator::RbiObject]
16
- ).returns(RbiGenerator::RbiObject)
16
+ ).returns(T.nilable(RbiGenerator::RbiObject))
17
17
  ).void
18
18
  end
19
19
  # Given a namespace, attempts to automatically resolve conflicts in the
@@ -23,13 +23,13 @@ module Parlour
23
23
  # All children of the given namespace which are also namespaces are
24
24
  # processed recursively, so passing {RbiGenerator#root} will eliminate all
25
25
  # conflicts in the entire object tree.
26
- #
26
+ #
27
27
  # If automatic resolution is not possible, the block passed to this method
28
28
  # is invoked and passed two arguments: a message on what the conflict is,
29
29
  # and an array of candidate objects. The block should return one of these
30
30
  # candidate objects, which will be kept, and all other definitions are
31
31
  # deleted. Alternatively, the block may return nil, which will delete all
32
- # definitions. The block may be invoked many times from one call to
32
+ # definitions. The block may be invoked many times from one call to
33
33
  # {resolve_conflicts}, one for each unresolvable conflict.
34
34
  #
35
35
  # @param namespace [RbiGenerator::Namespace] The starting namespace to
@@ -52,14 +52,14 @@ module Parlour
52
52
  child.name
53
53
  end
54
54
  end
55
-
55
+
56
56
  grouped_by_name_children.each do |name, children|
57
57
  Debugging.debug_puts(self, Debugging::Tree.begin("Checking children named #{name}..."))
58
58
 
59
59
  if children.length > 1
60
60
  Debugging.debug_puts(self, Debugging::Tree.here("Possible conflict between #{children.length} objects"))
61
61
 
62
- # Special case: do we have two methods, one of which is a class method
62
+ # Special case: do we have two methods, one of which is a class method
63
63
  # and the other isn't? If so, do nothing - this is fine
64
64
  if children.length == 2 &&
65
65
  children.all? { |c| c.is_a?(RbiGenerator::Method) } &&
@@ -78,12 +78,13 @@ module Parlour
78
78
  c.is_a?(RbiGenerator::Include) || c.is_a?(RbiGenerator::Extend)
79
79
  end
80
80
  end
81
-
81
+ deduplicate_mixins_of_name(namespace, name)
82
+
82
83
  Debugging.debug_puts(self, Debugging::Tree.end("Includes/extends do not conflict with namespaces; no resolution required"))
83
84
  next
84
85
  end
85
86
 
86
- # Special case: do we have two attributes, one of which is a class
87
+ # Special case: do we have two attributes, one of which is a class
87
88
  # attribute and the other isn't? If so, do nothing - this is fine
88
89
  if children.length == 2 &&
89
90
  children.all? { |c| c.is_a?(RbiGenerator::Attribute) } &&
@@ -93,13 +94,13 @@ module Parlour
93
94
  next
94
95
  end
95
96
 
96
- # Special case: are they all clearly equal? If so, remove all but one
97
+ # Optimization for Special case: are they all clearly equal? If so, remove all but one
97
98
  if all_eql?(children)
98
99
  Debugging.debug_puts(self, Debugging::Tree.end("All children are identical"))
99
100
 
100
101
  # All of the children are the same, so this deletes all of them
101
102
  namespace.children.delete(T.must(children.first))
102
-
103
+
103
104
  # Re-add one child
104
105
  namespace.children << T.must(children.first)
105
106
  next
@@ -239,5 +240,26 @@ module Parlour
239
240
  def all_eql?(arr)
240
241
  arr.each_cons(2).all? { |x, y| x == y }
241
242
  end
243
+
244
+ sig { params(namespace: RbiGenerator::Namespace, name: T.nilable(String)).void }
245
+ # Given a namespace and a child name, removes all duplicate children that are mixins
246
+ # and that have the given name, except the first found instance.
247
+ #
248
+ # @param namespace [RbiGenerator::Namespace] The namespace to deduplicate mixins in.
249
+ # @param name [String] The name of the mixin modules to deduplicate.
250
+ # @return [void]
251
+ def deduplicate_mixins_of_name(namespace, name)
252
+ found_map = {}
253
+ namespace.children.delete_if do |x|
254
+ # ignore children whose names don't match
255
+ next unless x.name == name
256
+ # ignore children that are not mixins
257
+ next unless x.is_a?(RbiGenerator::Include) || x.is_a?(RbiGenerator::Extend)
258
+
259
+ delete = found_map.key?(x.class)
260
+ found_map[x.class] = true
261
+ delete
262
+ end
263
+ end
242
264
  end
243
265
  end
@@ -0,0 +1,34 @@
1
+ # typed: true
2
+ require 'rainbow'
3
+
4
+ module Parlour
5
+ module Conversion
6
+ # An abstract class which converts between the node trees of two type
7
+ # systems.
8
+ class Converter
9
+ extend T::Sig
10
+ extend T::Helpers
11
+ abstract!
12
+
13
+ def initialize
14
+ @warnings = []
15
+ end
16
+
17
+ sig { returns(T::Array[[String, TypedObject]]) }
18
+ attr_reader :warnings
19
+
20
+ sig { params(msg: String, node: RbiGenerator::RbiObject).void }
21
+ def add_warning(msg, node)
22
+ warnings << [msg, node]
23
+
24
+ return if $VERBOSE.nil?
25
+ class_name = T.must(self.class.name).split('::').last
26
+ print Rainbow("Parlour warning: ").yellow.dark.bold
27
+ print Rainbow("#{class_name}: ").magenta.bright.bold
28
+ puts msg
29
+ print Rainbow(" └ at object: ").blue.bright.bold
30
+ puts node.describe
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,223 @@
1
+ # typed: true
2
+ module Parlour
3
+ module Conversion
4
+ # Converts RBI types to RBS types.
5
+ class RbiToRbs < Converter
6
+ extend T::Sig
7
+
8
+ sig { params(rbs_gen: RbsGenerator).void }
9
+ def initialize(rbs_gen)
10
+ super()
11
+ @rbs_gen = rbs_gen
12
+ end
13
+
14
+ sig { returns(RbsGenerator) }
15
+ attr_reader :rbs_gen
16
+
17
+ sig { params(from: RbiGenerator::Namespace, to: RbsGenerator::Namespace).void }
18
+ def convert_all(from, to)
19
+ from.children.each do |child|
20
+ convert_object(child, to)
21
+ end
22
+ end
23
+
24
+ sig do
25
+ params(
26
+ node: RbiGenerator::RbiObject,
27
+ new_parent: RbsGenerator::Namespace,
28
+ ).void
29
+ end
30
+ def convert_object(node, new_parent)
31
+ case node
32
+ when RbiGenerator::StructClassNamespace
33
+ add_warning 'performing a one-way conversion of an RBI struct to RBS', node
34
+
35
+ klass = new_parent.create_class(node.name)
36
+ klass.add_comments(node.comments)
37
+
38
+ # Create a constructor
39
+ klass.create_method('initialize', [
40
+ RbsGenerator::MethodSignature.new(
41
+ node.props.map do |prop|
42
+ RbsGenerator::Parameter.new(
43
+ "#{prop.name}:",
44
+ type: prop.type,
45
+ required: !prop.optional,
46
+ )
47
+ end,
48
+ nil,
49
+ )
50
+ ])
51
+
52
+ # Make each prop a getter (and setter, if not immutable) attribute
53
+ node.props.each do |prop|
54
+ klass.create_attribute(
55
+ prop.name,
56
+ kind: prop.immutable ? :reader : :accessor,
57
+ type: prop.type,
58
+ )
59
+ end
60
+
61
+ klass
62
+
63
+ when RbiGenerator::EnumClassNamespace
64
+ add_warning 'performing a one-way conversion of an RBI enum to RBS', node
65
+
66
+ klass = new_parent.create_class(node.name)
67
+ klass.add_comments(node.comments)
68
+
69
+ # Define .values
70
+ klass.create_method('values', [
71
+ RbsGenerator::MethodSignature.new([], Types::Array.new(node.name))
72
+ ], class_method: true)
73
+
74
+ # Define each enum variant
75
+ node.enums.each do |variant|
76
+ # We don't care about any extra value
77
+ variant = variant[0] if Array === variant
78
+
79
+ klass.create_constant(variant, type: node.name)
80
+ end
81
+
82
+ klass
83
+
84
+ when RbiGenerator::Arbitrary
85
+ add_warning 'converting type of Arbitrary is likely to cause syntax errors; doing it anyway', node
86
+ new_parent.create_arbitrary(
87
+ code: node.code,
88
+ ).add_comments(node.comments)
89
+
90
+ when RbiGenerator::Attribute
91
+ if node.class_attribute
92
+ add_warning 'RBS does not support class attributes; dropping', node
93
+ return
94
+ end
95
+ new_parent.create_attribute(
96
+ node.name,
97
+ kind: node.kind,
98
+ type: node.type,
99
+ ).add_comments(node.comments)
100
+
101
+ when RbiGenerator::ClassNamespace
102
+ if node.abstract
103
+ add_warning 'RBS does not support abstract classes', node
104
+ end
105
+ klass = new_parent.create_class(
106
+ node.name,
107
+ superclass: node.superclass
108
+ )
109
+ klass.add_comments(node.comments)
110
+ node.children.each do |child|
111
+ convert_object(child, klass)
112
+ end
113
+
114
+ when RbiGenerator::Constant
115
+ if node.eigen_constant
116
+ add_warning 'RBS does not support constants on eigenclasses; dropping', node
117
+ return
118
+ end
119
+ new_parent.create_constant(
120
+ node.name,
121
+ type: node.value,
122
+ ).add_comments(node.comments)
123
+
124
+ when RbiGenerator::Extend
125
+ new_parent.create_extend(node.name).add_comments(node.comments)
126
+
127
+ when RbiGenerator::Include
128
+ new_parent.create_include(node.name).add_comments(node.comments)
129
+
130
+ when RbiGenerator::Method
131
+ # Convert parameters
132
+ parameters = node.parameters
133
+ .reject { |param| param.kind == :block }
134
+ .map do |param|
135
+ RbsGenerator::Parameter.new(
136
+ param.name,
137
+ type: param.type,
138
+ required: param.default.nil?
139
+ )
140
+ end
141
+
142
+ # Find block if there is one
143
+ block_param = node.parameters.find { |param| param.kind == :block }
144
+ if block_param
145
+ if String === block_param.type
146
+ add_warning "block must have a Types::Type for conversion; dropping block", node
147
+ block = nil
148
+ else
149
+ # A nilable proc is an optional block
150
+ block_param_type = block_param.type
151
+ if Types::Nilable === block_param_type && Types::Proc === block_param_type.type
152
+ t = T.cast(block_param_type.type, Types::Proc)
153
+ required = false
154
+ block = RbsGenerator::Block.new(t, required)
155
+ elsif Types::Proc === block_param_type
156
+ t = block_param_type
157
+ required = true
158
+ block = RbsGenerator::Block.new(t, required)
159
+ elsif Types::Untyped === block_param_type
160
+ # Consider there to be a block of unknown types
161
+ block = RbsGenerator::Block.new(
162
+ Types::Proc.new(
163
+ [
164
+ Types::Proc::Parameter.new('*args', Types::Untyped.new),
165
+ Types::Proc::Parameter.new('**kwargs', Types::Untyped.new),
166
+ ],
167
+ Types::Untyped.new,
168
+ ),
169
+ false,
170
+ )
171
+ else
172
+ add_warning 'block type must be a Types::Proc (or nilable one); dropping block', node
173
+ end
174
+ end
175
+ else
176
+ block = nil
177
+ end
178
+
179
+ new_parent.create_method(
180
+ node.name,
181
+ [
182
+ RbsGenerator::MethodSignature.new(
183
+ parameters,
184
+ node.return_type,
185
+ block: block,
186
+ type_parameters: node.type_parameters,
187
+ )
188
+ ],
189
+ class_method: node.class_method,
190
+ ).add_comments(node.comments)
191
+
192
+ when RbiGenerator::ModuleNamespace
193
+ if node.interface
194
+ rbs_node = new_parent.create_interface(
195
+ node.name,
196
+ )
197
+ else
198
+ rbs_node = new_parent.create_module(
199
+ node.name,
200
+ )
201
+ end
202
+ rbs_node.add_comments(node.comments)
203
+ node.children.each do |child|
204
+ convert_object(child, rbs_node)
205
+ end
206
+
207
+ when RbiGenerator::Namespace
208
+ add_warning 'unspecialized namespaces are not supposed to be in the tree; you may run into issues', node
209
+ namespace = RbsGenerator::Namespace.new(rbs_gen)
210
+ namespace.add_comments(node.comments)
211
+ node.children.each do |child|
212
+ convert_object(child, namespace)
213
+ end
214
+ new_parent.children << namespace
215
+
216
+ else
217
+ raise "missing conversion for #{node.describe}"
218
+ # TODO: stick a T.absurd here
219
+ end
220
+ end
221
+ end
222
+ end
223
+ end
File without changes
@@ -6,17 +6,12 @@ module Parlour
6
6
  def detached!
7
7
  raise "cannot call methods on a detached RBI generator"
8
8
  end
9
-
9
+
10
10
  sig { override.returns(Options) }
11
11
  def options
12
12
  detached!
13
13
  end
14
14
 
15
- sig { override.returns(Namespace) }
16
- def root
17
- detached!
18
- end
19
-
20
15
  sig { override.returns(T.nilable(Plugin)) }
21
16
  def current_plugin
22
17
  nil
@@ -0,0 +1,25 @@
1
+ # typed: true
2
+
3
+ module Parlour
4
+ class DetachedRbsGenerator < RbsGenerator
5
+ sig { returns(T.untyped) }
6
+ def detached!
7
+ raise "cannot call methods on a detached RBS generator"
8
+ end
9
+
10
+ sig { override.returns(Options) }
11
+ def options
12
+ detached!
13
+ end
14
+
15
+ sig { override.returns(T.nilable(Plugin)) }
16
+ def current_plugin
17
+ nil
18
+ end
19
+
20
+ sig { override.returns(String) }
21
+ def rbs
22
+ detached!
23
+ end
24
+ end
25
+ end