parlour 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,6 +1,7 @@
1
1
  # typed: true
2
2
  module Parlour
3
3
  class RbiGenerator
4
+ # Represents a method parameter with a Sorbet type signature.
4
5
  class Parameter
5
6
  extend T::Sig
6
7
 
@@ -11,6 +12,27 @@ module Parlour
11
12
  default: T.nilable(String)
12
13
  ).void
13
14
  end
15
+ # Create a new method parameter.
16
+ #
17
+ # @example Create a simple Integer parameter named +num+.
18
+ # Parlour::RbiGenerator::Parameter.new('num', type: 'Integer')
19
+ # @example Create a nilable array parameter.
20
+ # Parlour::RbiGenerator::Parameter.new('array_of_strings_or_symbols', type: 'T.nilable(T::Array(String, Symbol))')
21
+ # @example Create a block parameter.
22
+ # Parlour::RbiGenerator::Parameter.new('&blk', type: 'T.proc.void')
23
+ # @example Create a parameter with a default value.
24
+ # Parlour::RbiGenerator::Parameter.new('name', type: 'String', default: 'Parlour')
25
+ #
26
+ # @param name [String] The name of this parameter. This may start with +*+, +**+,
27
+ # or +&+, or end with +:+, which will infer the {kind} of this
28
+ # parameter. (If it contains none of those, {kind} will be +:normal+.)
29
+ # @param type [String, nil] A Sorbet string of this parameter's type, such as
30
+ # +"String"+ or +"T.untyped"+.
31
+ # @param default [String, nil] A string of Ruby code for this parameter's default value.
32
+ # For example, the default value of an empty string would be represented
33
+ # as +"\"\""+ (or +'""'+). The default value of the decimal +3.14+
34
+ # would be +"3.14"+.
35
+ # @return [void]
14
36
  def initialize(name, type: nil, default: nil)
15
37
  @name = name
16
38
 
@@ -24,6 +46,11 @@ module Parlour
24
46
  end
25
47
 
26
48
  sig { params(other: Object).returns(T::Boolean) }
49
+ # Returns true if this instance is equal to another method.
50
+ #
51
+ # @param other [Object] The other instance. If this is not a {Parameter} (or a
52
+ # subclass of it), this will always return false.
53
+ # @return [Boolean]
27
54
  def ==(other)
28
55
  Parameter === other &&
29
56
  name == other.name &&
@@ -33,9 +60,16 @@ module Parlour
33
60
  end
34
61
 
35
62
  sig { returns(String) }
63
+ # The name of this parameter, including any prefixes or suffixes such as
64
+ # +*+.
65
+ # @return [String]
36
66
  attr_reader :name
37
67
 
38
68
  sig { returns(String) }
69
+ # The name of this parameter, stripped of any prefixes or suffixes. For
70
+ # example, +*rest+ would become +rest+, or +foo:+ would become +foo+.
71
+ #
72
+ # @return [String]
39
73
  def name_without_kind
40
74
  return T.must(name[0..-2]) if kind == :keyword
41
75
 
@@ -46,15 +80,28 @@ module Parlour
46
80
  end
47
81
 
48
82
  sig { returns(T.nilable(String)) }
83
+ # A Sorbet string of this parameter's type, such as +"String"+ or
84
+ # +"T.untyped"+.
85
+ # @return [String, nil]
49
86
  attr_reader :type
50
87
 
51
88
  sig { returns(T.nilable(String)) }
89
+ # A string of Ruby code for this parameter's default value. For example,
90
+ # the default value of an empty string would be represented as +"\"\""+
91
+ # (or +'""'+). The default value of the decimal +3.14+ would be +"3.14"+.
92
+ # @return [String, nil]
52
93
  attr_reader :default
53
94
 
54
95
  sig { returns(Symbol) }
96
+ # The kind of parameter that this is. This will be one of +:normal+,
97
+ # +:splat+, +:double_splat+, +:block+ or +:keyword+.
98
+ # @return [Symbol]
55
99
  attr_reader :kind
56
100
 
57
101
  sig { returns(String) }
102
+ # A string of how this parameter should be defined in a method definition.
103
+ #
104
+ # @return [String]
58
105
  def to_def_param
59
106
  if default.nil?
60
107
  "#{name}"
@@ -66,10 +113,14 @@ module Parlour
66
113
  end
67
114
 
68
115
  sig { returns(String) }
116
+ # A string of how this parameter should be defined in a Sorbet +sig+.
117
+ #
118
+ # @return [String]
69
119
  def to_sig_param
70
120
  "#{name_without_kind}: #{type || 'T.untyped'}"
71
- end
121
+ end#
72
122
 
123
+ # A mapping of {kind} values to the characteristic prefixes each kind has.
73
124
  PREFIXES = {
74
125
  normal: '',
75
126
  splat: '*',
@@ -1,10 +1,76 @@
1
1
  # typed: true
2
2
  module Parlour
3
3
  class RbiGenerator
4
- module RbiObject
4
+ # An abstract class which is subclassed by any classes which can generate
5
+ # entire lines of an RBI, such as {Namespace} and {Method}. (As an example,
6
+ # {Parameter} is _not_ a subclass because it does not generate lines, only
7
+ # segments of definition and signature lines.)
8
+ # @abstract
9
+ class RbiObject
5
10
  extend T::Helpers
6
11
  extend T::Sig
7
- interface!
12
+ abstract!
13
+
14
+ sig { params(generator: RbiGenerator, name: String).void }
15
+ # Creates a new RBI object.
16
+ # @note Don't call this directly.
17
+ #
18
+ # @param generator [RbiGenerator] The current RbiGenerator.
19
+ # @param name [String] The name of this module.
20
+ # @return [void]
21
+ def initialize(generator, name)
22
+ @generator = generator
23
+ @generated_by = generator.current_plugin
24
+ @name = name
25
+ @comments = []
26
+ end
27
+
28
+ sig { returns(RbiGenerator) }
29
+ # The generator which this object belongs to.
30
+ # @return [RbiGenerator]
31
+ attr_reader :generator
32
+
33
+ sig { returns(T.nilable(Plugin)) }
34
+ # The {Plugin} which was controlling the {generator} when this object was
35
+ # created.
36
+ # @return [Plugin, nil]
37
+ attr_reader :generated_by
38
+
39
+ sig { returns(String) }
40
+ # The name of this object.
41
+ # @return [String]
42
+ attr_reader :name
43
+
44
+ sig { returns(T::Array[String]) }
45
+ # An array of comments which will be placed above the object in the RBI
46
+ # file.
47
+ # @return [Array<String>]
48
+ attr_reader :comments
49
+
50
+ sig { params(comment: T.any(String, T::Array[String])).void }
51
+ # Adds one or more comments to this RBI object.
52
+ #
53
+ # @example Creating a module with a comment.
54
+ # namespace.create_module('M') do |m|
55
+ # m.add_comment('This is a module')
56
+ # end
57
+ #
58
+ # @example Creating a class with a multi-line comment.
59
+ # namespace.create_class('C') do |c|
60
+ # c.add_comment(['This is a multi-line comment!', 'It can be as long as you want!'])
61
+ # end
62
+ #
63
+ # @param comment [String, Array<String>] The new comment(s).
64
+ # @return [void]
65
+ def add_comment(comment)
66
+ if comment.is_a?(String)
67
+ comments << comment
68
+ elsif comment.is_a?(Array)
69
+ comments.concat(comment)
70
+ end
71
+ end
72
+
73
+ alias_method :add_comments, :add_comment
8
74
 
9
75
  sig do
10
76
  abstract.params(
@@ -12,6 +78,12 @@ module Parlour
12
78
  options: Options
13
79
  ).returns(T::Array[String])
14
80
  end
81
+ # Generates the RBI lines for this object.
82
+ #
83
+ # @abstract
84
+ # @param indent_level [Integer] The indentation level to generate the lines at.
85
+ # @param options [Options] The formatting options to use.
86
+ # @return [Array<String>] The RBI lines, formatted as specified.
15
87
  def generate_rbi(indent_level, options); end
16
88
 
17
89
  sig do
@@ -19,6 +91,13 @@ module Parlour
19
91
  others: T::Array[RbiGenerator::RbiObject]
20
92
  ).returns(T::Boolean)
21
93
  end
94
+ # Given an array of other objects, returns true if they may be merged
95
+ # into this instance using {merge_into_self}. Each subclass will have its
96
+ # own criteria on what allows objects to be mergeable.
97
+ #
98
+ # @abstract
99
+ # @param others [Array<RbiGenerator::RbiObject>] An array of other {RbiObject} instances.
100
+ # @return [Boolean] Whether this instance may be merged with them.
22
101
  def mergeable?(others); end
23
102
 
24
103
  sig do
@@ -26,7 +105,41 @@ module Parlour
26
105
  others: T::Array[RbiGenerator::RbiObject]
27
106
  ).void
28
107
  end
108
+ # Given an array of other objects, merges them into this one. Each
109
+ # subclass will do this differently.
110
+ # You MUST ensure that {mergeable?} is true for those instances.
111
+ #
112
+ # @abstract
113
+ # @param others [Array<RbiGenerator::RbiObject>] An array of other {RbiObject} instances.
114
+ # @return [void]
29
115
  def merge_into_self(others); end
116
+
117
+ sig { abstract.returns(String) }
118
+ # Returns a human-readable brief string description of this object. This
119
+ # is displayed during manual conflict resolution with the +parlour+ CLI.
120
+ #
121
+ # @abstract
122
+ # @return [String]
123
+ def describe; end
124
+
125
+ private
126
+
127
+ sig do
128
+ params(
129
+ indent_level: Integer,
130
+ options: Options
131
+ ).returns(T::Array[String])
132
+ end
133
+ # Generates the RBI lines for this object's comments.
134
+ #
135
+ # @param indent_level [Integer] The indentation level to generate the lines at.
136
+ # @param options [Options] The formatting options to use.
137
+ # @return [Array<String>] The RBI lines for each comment, formatted as specified.
138
+ def generate_comments(indent_level, options)
139
+ comments.any? \
140
+ ? comments.map { |c| options.indented(indent_level, "# #{c}") }
141
+ : []
142
+ end
30
143
  end
31
144
  end
32
- end
145
+ end
@@ -1,4 +1,5 @@
1
1
  # typed: strong
2
2
  module Parlour
3
- VERSION = '0.1.1'
3
+ # The library version.
4
+ VERSION = '0.2.0'
4
5
  end
@@ -23,6 +23,7 @@ Gem::Specification.new do |spec|
23
23
  spec.require_paths = ["lib"]
24
24
 
25
25
  spec.add_dependency "sorbet-runtime"
26
+ spec.add_dependency "rainbow", "~> 3.0.0"
26
27
 
27
28
  spec.add_development_dependency "bundler", "~> 2.0"
28
29
  spec.add_development_dependency "rake", "~> 10.0"
@@ -0,0 +1,13 @@
1
+ require 'parlour'
2
+
3
+ module FooBar
4
+ class Plugin < Parlour::Plugin
5
+ def generate(root)
6
+ root.create_module('Foo') do |foo|
7
+ foo.add_comment('This is an example plugin!')
8
+ foo.create_module('Bar')
9
+ foo.create_module('Bar', interface: true)
10
+ end
11
+ end
12
+ end
13
+ end
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: 0.1.1
4
+ version: 0.2.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: 2019-07-05 00:00:00.000000000 Z
11
+ date: 2019-07-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sorbet-runtime
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rainbow
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 3.0.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 3.0.0
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: bundler
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -97,20 +111,28 @@ dependencies:
97
111
  description:
98
112
  email:
99
113
  - hello@aaronc.cc
100
- executables: []
114
+ executables:
115
+ - parlour
101
116
  extensions: []
102
117
  extra_rdoc_files: []
103
118
  files:
119
+ - ".github/ISSUE_TEMPLATE/bug-report.md"
120
+ - ".github/ISSUE_TEMPLATE/feature-request.md"
104
121
  - ".gitignore"
105
122
  - ".rspec"
123
+ - ".travis.yml"
106
124
  - CHANGELOG.md
107
125
  - CODE_OF_CONDUCT.md
108
126
  - Gemfile
109
127
  - LICENSE.txt
110
128
  - README.md
129
+ - Rakefile
130
+ - exe/parlour
111
131
  - lib/parlour.rb
112
132
  - lib/parlour/conflict_resolver.rb
133
+ - lib/parlour/plugin.rb
113
134
  - lib/parlour/rbi_generator.rb
135
+ - lib/parlour/rbi_generator/attribute.rb
114
136
  - lib/parlour/rbi_generator/class_namespace.rb
115
137
  - lib/parlour/rbi_generator/method.rb
116
138
  - lib/parlour/rbi_generator/module_namespace.rb
@@ -120,6 +142,7 @@ files:
120
142
  - lib/parlour/rbi_generator/rbi_object.rb
121
143
  - lib/parlour/version.rb
122
144
  - parlour.gemspec
145
+ - plugin_examples/foobar_plugin.rb
123
146
  - sorbet/config
124
147
  - sorbet/rbi/gems/rake.rbi
125
148
  - sorbet/rbi/gems/rspec-core.rbi