parlour 4.0.0 → 5.0.0.beta.4

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 +0 -0
  6. data/.rspec +0 -0
  7. data/.travis.yml +0 -0
  8. data/CHANGELOG.md +52 -0
  9. data/CODE_OF_CONDUCT.md +0 -0
  10. data/Gemfile +0 -0
  11. data/LICENSE.txt +0 -0
  12. data/README.md +208 -20
  13. data/Rakefile +0 -0
  14. data/exe/parlour +45 -6
  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 +229 -0
  19. data/lib/parlour/debugging.rb +0 -0
  20. data/lib/parlour/detached_rbi_generator.rb +0 -0
  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 +0 -0
  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 +17 -6
  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 +40 -13
  38. data/lib/parlour/rbi_generator/parameter.rb +11 -5
  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 +0 -0
  60. data/lib/parlour/type_parser.rb +174 -5
  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 +1404 -441
  67. metadata +33 -10
  68. data/lib/parlour/rbi_generator/options.rb +0 -74
File without changes
@@ -0,0 +1,71 @@
1
+ # typed: true
2
+ module Parlour
3
+ # A set of immutable formatting options.
4
+ class Options
5
+ extend T::Sig
6
+
7
+ sig { params(break_params: Integer, tab_size: Integer, sort_namespaces: T::Boolean).void }
8
+ # Creates a new set of formatting options.
9
+ #
10
+ # @example Create Options with +break_params+ of +4+ and +tab_size+ of +2+.
11
+ # Parlour::Options.new(break_params: 4, tab_size: 2)
12
+ #
13
+ # @param break_params [Integer] If there are at least this many parameters in a
14
+ # signature, then it is broken onto separate lines.
15
+ # @param tab_size [Integer] The number of spaces to use per indent.
16
+ # @param sort_namespaces [Boolean] Whether to sort all items within a
17
+ # namespace alphabetically.
18
+ # @return [void]
19
+ def initialize(break_params:, tab_size:, sort_namespaces:)
20
+ @break_params = break_params
21
+ @tab_size = tab_size
22
+ @sort_namespaces = sort_namespaces
23
+ end
24
+
25
+ sig { returns(Integer) }
26
+ # If there are at least this many parameters in a signature, then it
27
+ # is broken onto separate lines.
28
+ #
29
+ # # With break_params: 5
30
+ # sig { params(name: String, age: Integer, hobbies: T::Array(String), country: Symbol).void }
31
+ #
32
+ # # With break_params: 4
33
+ # sig do
34
+ # params(
35
+ # name: String,
36
+ # age: Integer,
37
+ # hobbies: T::Array(String),
38
+ # country: Symbol
39
+ # ).void
40
+ # end
41
+ #
42
+ # @return [Integer]
43
+ attr_reader :break_params
44
+
45
+ sig { returns(Integer) }
46
+ # The number of spaces to use per indent.
47
+ # @return [Integer]
48
+ attr_reader :tab_size
49
+
50
+ sig { returns(T::Boolean) }
51
+ # Whether to sort all items within a namespace alphabetically.
52
+ # Items which are typically grouped together, such as "include" or
53
+ # "extend" calls, will remain grouped together when sorted.
54
+ # If true, items are sorted by their name when the RBI is generated.
55
+ # If false, items are generated in the order they are added to the
56
+ # namespace.
57
+ # @return [Boolean]
58
+ attr_reader :sort_namespaces
59
+
60
+ sig { params(level: Integer, str: String).returns(String) }
61
+ # Returns a string indented to the given indent level, according to the
62
+ # set {tab_size}.
63
+ #
64
+ # @param level [Integer] The indent level, as an integer. 0 is totally unindented.
65
+ # @param str [String] The string to indent.
66
+ # @return [String] The indented string.
67
+ def indented(level, str)
68
+ " " * (level * tab_size) + str
69
+ end
70
+ end
71
+ end
File without changes
File without changes
@@ -1,55 +1,42 @@
1
1
  # typed: true
2
2
  module Parlour
3
3
  # The RBI generator.
4
- class RbiGenerator
5
- extend T::Sig
4
+ class RbiGenerator < Generator
5
+ # For backwards compatibility.
6
+ # Before Parlour 5.0, Parlour::Options was Parlour::RbiGenerator::Options.
7
+ Options = Parlour::Options
6
8
 
7
- sig { params(break_params: Integer, tab_size: Integer, sort_namespaces: T::Boolean).void }
8
- # Creates a new RBI generator.
9
- #
10
- # @example Create a default generator.
11
- # generator = Parlour::RbiGenerator.new
12
- #
13
- # @example Create a generator with a custom +tab_size+ of 3.
14
- # generator = Parlour::RbiGenerator.new(tab_size: 3)
15
- #
16
- # @param break_params [Integer] If there are at least this many parameters in a
17
- # Sorbet +sig+, then it is broken onto separate lines.
18
- # @param tab_size [Integer] The number of spaces to use per indent.
19
- # @param sort_namespaces [Boolean] Whether to sort all items within a
20
- # namespace alphabetically.
21
- # @return [void]
22
- def initialize(break_params: 4, tab_size: 2, sort_namespaces: false)
23
- @options = Options.new(
24
- break_params: break_params,
25
- tab_size: tab_size,
26
- sort_namespaces: sort_namespaces
27
- )
28
- @root = Namespace.new(self)
9
+ def initialize(**hash)
10
+ super
11
+ @root = RbiGenerator::Namespace.new(self)
29
12
  end
30
13
 
31
- sig { overridable.returns(Options) }
32
- # The formatting options for this generator.
33
- # @return [Options]
34
- attr_reader :options
35
-
36
- sig { overridable.returns(Namespace) }
14
+ sig { overridable.returns(RbiGenerator::Namespace) }
37
15
  # The root {Namespace} of this generator.
38
16
  # @return [Namespace]
39
17
  attr_reader :root
40
18
 
41
- sig { overridable.returns(T.nilable(Plugin)) }
42
- # The plugin which is currently generating new definitions.
43
- # {Plugin#run_plugins} controls this value.
44
- # @return [Plugin, nil]
45
- attr_accessor :current_plugin
46
-
47
19
  sig { overridable.params(strictness: String).returns(String) }
48
20
  # Returns the complete contents of the generated RBI file as a string.
49
21
  #
50
22
  # @return [String] The generated RBI file
51
23
  def rbi(strictness = 'strong')
52
- "# typed: #{strictness}\n" + root.generate_rbi(0, options).join("\n") + "\n"
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
53
40
  end
54
41
  end
55
42
  end
@@ -1,11 +1,11 @@
1
1
  # typed: true
2
2
  module Parlour
3
- class RbiGenerator
3
+ class RbiGenerator < Generator
4
4
  # Represents miscellaneous Ruby code.
5
5
  class Arbitrary < RbiObject
6
6
  sig do
7
7
  params(
8
- generator: RbiGenerator,
8
+ generator: Generator,
9
9
  code: String,
10
10
  block: T.nilable(T.proc.params(x: Arbitrary).void)
11
11
  ).void
@@ -87,6 +87,9 @@ module Parlour
87
87
  def describe
88
88
  "Arbitrary code (#{code})"
89
89
  end
90
+
91
+ sig { override.void }
92
+ def generalize_from_rbi!; end # Nothing to do
90
93
  end
91
94
  end
92
95
  end
@@ -1,14 +1,14 @@
1
1
  # typed: true
2
2
  module Parlour
3
- class RbiGenerator
3
+ class RbiGenerator < Generator
4
4
  # Represents an attribute reader, writer or accessor.
5
5
  class Attribute < Method
6
6
  sig do
7
7
  params(
8
- generator: RbiGenerator,
8
+ generator: Generator,
9
9
  name: String,
10
10
  kind: Symbol,
11
- type: String,
11
+ type: Types::TypeLike,
12
12
  class_attribute: T::Boolean,
13
13
  block: T.nilable(T.proc.params(x: Attribute).void)
14
14
  ).void
@@ -20,8 +20,7 @@ module Parlour
20
20
  # @param name [String] The name of this attribute.
21
21
  # @param kind [Symbol] The kind of attribute this is; one of :writer, :reader or
22
22
  # :accessor.
23
- # @param type [String] A Sorbet string of this attribute's type, such as
24
- # +"String"+ or +"T.untyped"+.
23
+ # @param type [String, Types::Type] This attribute's type.
25
24
  # @param class_attribute [Boolean] Whether this attribute belongs to the
26
25
  # singleton class.
27
26
  # @param block A block which the new instance yields itself to.
@@ -32,6 +31,7 @@ module Parlour
32
31
  # attr_accessor and attr_reader should have: sig { returns(X) }
33
32
  # attr_writer :foo should have: sig { params(foo: X).returns(X) }
34
33
 
34
+ @type = type
35
35
  @kind = kind
36
36
  @class_attribute = class_attribute
37
37
  case kind
@@ -55,6 +55,10 @@ module Parlour
55
55
  # Whether this attribute belongs to the singleton class.
56
56
  attr_reader :class_attribute
57
57
 
58
+ sig { returns(Types::TypeLike) }
59
+ # The type of this attribute.
60
+ attr_reader :type
61
+
58
62
  sig { override.params(other: Object).returns(T::Boolean) }
59
63
  # Returns true if this instance is equal to another attribute.
60
64
  #
@@ -69,6 +73,11 @@ module Parlour
69
73
  )
70
74
  end
71
75
 
76
+ sig { override.void }
77
+ def generalize_from_rbi!
78
+ @type = TypeParser.parse_single_type(@type) if String === @type
79
+ end
80
+
72
81
  private
73
82
 
74
83
  sig do
@@ -1,13 +1,13 @@
1
1
  # typed: true
2
2
  module Parlour
3
- class RbiGenerator
3
+ class RbiGenerator < Generator
4
4
  # Represents a class definition.
5
5
  class ClassNamespace < Namespace
6
6
  extend T::Sig
7
7
 
8
8
  sig do
9
9
  params(
10
- generator: RbiGenerator,
10
+ generator: Generator,
11
11
  name: String,
12
12
  final: T::Boolean,
13
13
  superclass: T.nilable(String),
@@ -47,7 +47,7 @@ module Parlour
47
47
  class_definition = superclass.nil? \
48
48
  ? "class #{name}"
49
49
  : "class #{name} < #{superclass}"
50
-
50
+
51
51
  lines = generate_comments(indent_level, options)
52
52
  lines << options.indented(indent_level, class_definition)
53
53
  lines += [options.indented(indent_level + 1, "abstract!"), ""] if abstract
@@ -116,6 +116,11 @@ module Parlour
116
116
  "#{"abstract, " if abstract}#{children.length} children, " +
117
117
  "#{includes.length} includes, #{extends.length} extends"
118
118
  end
119
+
120
+ sig { override.void }
121
+ def generalize_from_rbi!
122
+ super
123
+ end
119
124
  end
120
125
  end
121
126
  end
@@ -1,13 +1,13 @@
1
1
  # typed: true
2
2
  module Parlour
3
- class RbiGenerator
3
+ class RbiGenerator < Generator
4
4
  # Represents a constant definition.
5
5
  class Constant < RbiObject
6
6
  sig do
7
7
  params(
8
- generator: RbiGenerator,
8
+ generator: Generator,
9
9
  name: String,
10
- value: String,
10
+ value: Types::TypeLike,
11
11
  eigen_constant: T::Boolean,
12
12
  block: T.nilable(T.proc.params(x: Constant).void)
13
13
  ).void
@@ -25,8 +25,8 @@ module Parlour
25
25
  yield_self(&block) if block
26
26
  end
27
27
 
28
- # @return [String] The value of the constant, as a Ruby code string.
29
- sig { returns(String) }
28
+ # @return [String] The value or type of the constant.
29
+ sig { returns(Types::TypeLike) }
30
30
  attr_reader :value
31
31
 
32
32
  # @return [Boolean] Whether this constant is defined on the eigenclass
@@ -56,7 +56,11 @@ module Parlour
56
56
  # @param options [Options] The formatting options to use.
57
57
  # @return [Array<String>] The RBI lines, formatted as specified.
58
58
  def generate_rbi(indent_level, options)
59
- [options.indented(indent_level, "#{name} = #{value}")]
59
+ if String === @value
60
+ [options.indented(indent_level, "#{name} = #{@value}")]
61
+ else
62
+ [options.indented(indent_level, "#{name} = T.let(nil, #{@value.generate_rbi})")]
63
+ end
60
64
  end
61
65
 
62
66
  sig do
@@ -98,6 +102,13 @@ module Parlour
98
102
  def describe
99
103
  "Constant (#{name} = #{value})"
100
104
  end
105
+
106
+ sig { override.void }
107
+ def generalize_from_rbi!
108
+ # There's a good change this is an untyped constant, so rescue
109
+ # ParseError and use untyped
110
+ @value = (TypeParser.parse_single_type(@value) if String === @value) rescue Types::Untyped.new
111
+ end
101
112
  end
102
113
  end
103
114
  end
@@ -1,13 +1,13 @@
1
1
  # typed: true
2
2
  module Parlour
3
- class RbiGenerator
3
+ class RbiGenerator < Generator
4
4
  # Represents an enum definition; that is, a class with an +enum+ call.
5
5
  class EnumClassNamespace < ClassNamespace
6
6
  extend T::Sig
7
7
 
8
8
  sig do
9
9
  params(
10
- generator: RbiGenerator,
10
+ generator: Generator,
11
11
  name: String,
12
12
  final: T::Boolean,
13
13
  enums: T::Array[T.any([String, String], String)],
@@ -38,7 +38,7 @@ module Parlour
38
38
  sig do
39
39
  override.params(
40
40
  indent_level: Integer,
41
- options: Options
41
+ options: Options,
42
42
  ).returns(T::Array[String])
43
43
  end
44
44
  # Generates the RBI lines for the body of this enum. This consists of
@@ -107,6 +107,11 @@ module Parlour
107
107
  @enums = other.enums if enums.empty?
108
108
  end
109
109
  end
110
+
111
+ sig { override.void }
112
+ def generalize_from_rbi!
113
+ super
114
+ end
110
115
  end
111
116
  end
112
117
  end
@@ -1,11 +1,11 @@
1
1
  # typed: true
2
2
  module Parlour
3
- class RbiGenerator
3
+ class RbiGenerator < Generator
4
4
  # Represents an +extend+ call.
5
5
  class Extend < RbiObject
6
6
  sig do
7
7
  params(
8
- generator: RbiGenerator,
8
+ generator: Generator,
9
9
  name: String,
10
10
  block: T.nilable(T.proc.params(x: Extend).void)
11
11
  ).void
@@ -82,6 +82,9 @@ module Parlour
82
82
  def describe
83
83
  "Extend (#{name})"
84
84
  end
85
+
86
+ sig { override.void }
87
+ def generalize_from_rbi!; end # Nothing to do
85
88
  end
86
89
  end
87
90
  end
@@ -1,11 +1,11 @@
1
1
  # typed: true
2
2
  module Parlour
3
- class RbiGenerator
3
+ class RbiGenerator < Generator
4
4
  # Represents an +include+ call.
5
5
  class Include < RbiObject
6
6
  sig do
7
7
  params(
8
- generator: RbiGenerator,
8
+ generator: Generator,
9
9
  name: String,
10
10
  block: T.nilable(T.proc.params(x: Include).void)
11
11
  ).void
@@ -82,6 +82,9 @@ module Parlour
82
82
  def describe
83
83
  "Include (#{name})"
84
84
  end
85
+
86
+ sig { override.void }
87
+ def generalize_from_rbi!; end # Nothing to do
85
88
  end
86
89
  end
87
90
  end
@@ -1,16 +1,16 @@
1
1
  # typed: true
2
2
  module Parlour
3
- class RbiGenerator
3
+ class RbiGenerator < Generator
4
4
  # Represents a method definition.
5
5
  class Method < RbiObject
6
6
  extend T::Sig
7
7
 
8
8
  sig do
9
9
  params(
10
- generator: RbiGenerator,
10
+ generator: Generator,
11
11
  name: String,
12
12
  parameters: T::Array[Parameter],
13
- return_type: T.nilable(String),
13
+ return_type: T.nilable(Types::TypeLike),
14
14
  abstract: T::Boolean,
15
15
  implementation: T::Boolean,
16
16
  override: T::Boolean,
@@ -29,8 +29,7 @@ module Parlour
29
29
  # this - use the +class_method+ parameter instead.
30
30
  # @param parameters [Array<Parameter>] An array of {Parameter} instances representing this
31
31
  # method's parameters.
32
- # @param return_type [String, nil] A Sorbet string of what this method returns, such as
33
- # +"String"+ or +"T.untyped"+. Passing nil denotes a void return.
32
+ # @param return_type [Types::TypeLike, nil] What this method returns. Passing nil denotes a void return.
34
33
  # @param abstract [Boolean] Whether this method is abstract.
35
34
  # @param implementation [Boolean] DEPRECATED: Whether this method is an
36
35
  # implementation of a parent abstract method.
@@ -82,10 +81,9 @@ module Parlour
82
81
  # @return [Array<Parameter>]
83
82
  attr_reader :parameters
84
83
 
85
- sig { returns(T.nilable(String)) }
86
- # A Sorbet string of what this method returns, such as "String" or
87
- # "T.untyped". Passing nil denotes a void return.
88
- # @return [String, nil]
84
+ sig { returns(T.nilable(Types::TypeLike)) }
85
+ # What this method returns. Passing nil denotes a void return.
86
+ # @return [Types::TypeLike, nil]
89
87
  attr_reader :return_type
90
88
 
91
89
  sig { returns(T::Boolean) }
@@ -140,7 +138,7 @@ module Parlour
140
138
  # @param options [Options] The formatting options to use.
141
139
  # @return [Array<String>] The RBI lines, formatted as specified.
142
140
  def generate_rbi(indent_level, options)
143
- return_call = return_type ? "returns(#{return_type})" : 'void'
141
+ return_call = @return_type ? "returns(#{String === @return_type ? @return_type : @return_type.generate_rbi})" : 'void'
144
142
  sig_args = final ? '(:final)' : ''
145
143
 
146
144
  sig_params = parameters.map(&:to_sig_param)
@@ -218,6 +216,13 @@ module Parlour
218
216
  " returns #{return_type}"
219
217
  end
220
218
 
219
+ sig { override.void }
220
+ def generalize_from_rbi!
221
+ @return_type = TypeParser.parse_single_type(@return_type) if String === @return_type
222
+
223
+ parameters.each(&:generalize_from_rbi!)
224
+ end
225
+
221
226
  private
222
227
 
223
228
  sig do