parlour 4.0.0 → 5.0.0.beta.4

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