Class: Parlour::RbsGenerator::Parameter

Inherits:
Object
  • Object
show all
Extended by:
T::Sig
Defined in:
lib/parlour/rbs_generator/parameter.rb

Overview

Represents a method parameter with a Sorbet type signature.

Constant Summary collapse

RBS_KEYWORDS =

An array of reserved keywords in RBS which may be used as parameter names in standard Ruby. TODO: probably incomplete

[
  'type', 'interface', 'out', 'in', 'instance', 'extension', 'top', 'bot',
  'self', 'nil', 'void'
]
PREFIXES =

A mapping of #kind values to the characteristic prefixes each kind has.

{
  normal: '',
  splat: '*',
  double_splat: '**',
}.freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name, type: nil, required: true) ⇒ void

Create a new method parameter. Note that, in RBS, blocks are not parameters. Use a Block instead.

Examples:

Create a simple Integer parameter named num.

Parlour::RbsGenerator::Parameter.new('num', type: 'Integer')

Create a nilable array parameter.

Parlour::RbsGenerator::Parameter.new('array_of_strings_or_symbols', type:
  Parlour::Types::Nilable.new(
    Parlour::Types::Array.new(
      Parlour::Types::Union.new('String', 'Symbol')
    )
  )
)

Create an optional parameter.

Parlour::RbsGenerator::Parameter.new('name', type: 'String', default: 'Parlour')

Parameters:

  • name (String)

    The name of this parameter. This may start with * or **, ,or end with :, which will infer the #kind of this parameter. (If it contains none of those, #kind will be :normal.)

  • type (Types::TypeLike, nil) (defaults to: nil)

    This type of this parameter.

  • required (Boolean) (defaults to: true)

    Whether this parameter is required.



37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/parlour/rbs_generator/parameter.rb', line 37

def initialize(name, type: nil, required: true)
  name = T.must(name)
  @name = name

  prefix = /^(\*\*|\*|\&)?/.match(name)&.captures&.first || ''
  @kind = PREFIXES.rassoc(prefix).first

  @kind = :keyword if kind == :normal && name.end_with?(':')

  @type = type || Parlour::Types::Untyped.new
  @required = required
end

Instance Attribute Details

#kindSymbol (readonly)

The kind of parameter that this is. This will be one of :normal, :splat, :double_splat, or :keyword.

Returns:

  • (Symbol)


98
99
100
# File 'lib/parlour/rbs_generator/parameter.rb', line 98

def kind
  @kind
end

#nameString (readonly)

The name of this parameter, including any prefixes or suffixes such as *.

Returns:

  • (String)


68
69
70
# File 'lib/parlour/rbs_generator/parameter.rb', line 68

def name
  @name
end

#requiredBoolean (readonly)

Whether this parameter is required.

Returns:

  • (Boolean)


92
93
94
# File 'lib/parlour/rbs_generator/parameter.rb', line 92

def required
  @required
end

#typeString (readonly)

This parameter’s type.

Returns:

  • (String)


87
88
89
# File 'lib/parlour/rbs_generator/parameter.rb', line 87

def type
  @type
end

Instance Method Details

#==(other) ⇒ Boolean

Returns true if this instance is equal to another method.

Parameters:

Returns:

  • (Boolean)


56
57
58
59
60
61
62
# File 'lib/parlour/rbs_generator/parameter.rb', line 56

def ==(other)
  Parameter === other &&
    name    == other.name &&
    kind    == other.kind &&
    type    == other.type &&
    required == other.required
end

#name_without_kindString

The name of this parameter, stripped of any prefixes or suffixes. For example, *rest would become rest, or foo: would become foo.

Returns:

  • (String)


75
76
77
78
79
80
81
82
# File 'lib/parlour/rbs_generator/parameter.rb', line 75

def name_without_kind
  return T.must(name[0..-2]) if kind == :keyword

  prefix_match = /^(\*\*|\*|\&)?[a-zA-Z_]/.match(name)
  raise 'unknown prefix' unless prefix_match
  prefix = prefix_match.captures.first || ''
  T.must(name[prefix.length..-1])
end

#to_rbs_paramString

A string of how this parameter should be defined in an RBS signature.

Returns:

  • (String)


119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/parlour/rbs_generator/parameter.rb', line 119

def to_rbs_param
  raise 'blocks are not parameters in RBS' if kind == :block

  t = String === @type ? @type : @type.generate_rbs
  t = "^#{t}" if Types::Proc === @type

  if RBS_KEYWORDS.include? name_without_kind
    unless $VERBOSE.nil?
      print Rainbow("Parlour warning: ").yellow.dark.bold
      print Rainbow("RBS generation: ").magenta.bright.bold
      puts "'#{name_without_kind}' is a keyword in RBS, renaming method parameter to '_#{name_without_kind}'"
    end
    
    n = "_#{name_without_kind}"
  else
    n = name_without_kind
  end

  # Extra check because "?*something" is invalid
  ((required || (kind != :normal && kind != :keyword)) ? '' : '?') + if kind == :keyword
    "#{n}: #{t}"
  else
    "#{PREFIXES[kind]}#{t} #{n}"
  end
end