Class: Parlour::RbiGenerator::Namespace

Inherits:
RbiObject show all
Extended by:
T::Generic, T::Sig
Includes:
Mixin::Searchable
Defined in:
lib/parlour/rbi_generator/namespace.rb

Overview

A generic namespace. This shouldn’t be used, except as the type of #root.

Direct Known Subclasses

ClassNamespace, ModuleNamespace

Constant Summary collapse

Child =
type_member {{ fixed: RbiObject }}

Instance Attribute Summary collapse

Attributes inherited from RbiObject

#generator

Attributes inherited from TypedObject

#comments, #generated_by, #name

Instance Method Summary collapse

Methods included from Mixin::Searchable

#find, #find_all

Methods inherited from TypedObject

#add_comment, #describe, #describe_tree

Constructor Details

#initialize(generator, name = nil, final = false, sealed = false, &block) ⇒ void

Note:

Unless you’re doing something impressively hacky, this shouldn’t be invoked outside of Parlour::RbiGenerator#initialize.

Creates a new namespace.

Parameters:

  • generator (RbiGenerator)

    The current RbiGenerator.

  • name (String, nil) (defaults to: nil)

    The name of this module.

  • final (Boolean) (defaults to: false)

    Whether this namespace is final.

  • final (Boolean) (defaults to: false)

    Whether this namespace is sealed.

  • block

    A block which the new instance yields itself to.



45
46
47
48
49
50
51
52
# File 'lib/parlour/rbi_generator/namespace.rb', line 45

def initialize(generator, name = nil, final = false, sealed = false, &block)
  super(generator, name || '<anonymous namespace>')
  @children = []
  @next_comments = []
  @final = final
  @sealed = sealed
  yield_self(&block) if block
end

Instance Attribute Details

#childrenArray<RbiObject> (readonly)

The child RbiObject instances inside this namespace.

Returns:



67
68
69
# File 'lib/parlour/rbi_generator/namespace.rb', line 67

def children
  @children
end

#finalBoolean (readonly)

Whether this namespace is final.

Returns:

  • (Boolean)


57
58
59
# File 'lib/parlour/rbi_generator/namespace.rb', line 57

def final
  @final
end

#sealedBoolean (readonly)

Whether this namespace is sealed.

Returns:

  • (Boolean)


62
63
64
# File 'lib/parlour/rbi_generator/namespace.rb', line 62

def sealed
  @sealed
end

Instance Method Details

#add_comment_to_next_child(comment) ⇒ void

This method returns an undefined value.

Adds one or more comments to the next child RBI object to be created.

Examples:

Creating a module with a comment.

namespace.add_comment_to_next_child('This is a module')
namespace.create_module('M')

Creating a class with a multi-line comment.

namespace.add_comment_to_next_child(['This is a multi-line comment!', 'It can be as long as you want!'])
namespace.create_class('C')

Parameters:

  • comment (String, Array<String>)

    The new comment(s).



157
158
159
160
161
162
163
# File 'lib/parlour/rbi_generator/namespace.rb', line 157

def add_comment_to_next_child(comment)
  if comment.is_a?(String)
    @next_comments << comment
  elsif comment.is_a?(Array)
    @next_comments.concat(comment)
  end
end

#aliasesArray<RbiGenerator::TypeAlias> Also known as: type_aliases

The TypeAlias objects from #children.

Returns:



95
96
97
98
99
100
# File 'lib/parlour/rbi_generator/namespace.rb', line 95

def aliases
  T.cast(
    children.select { |c| c.is_a?(RbiGenerator::TypeAlias) },
    T::Array[RbiGenerator::TypeAlias]
  )
end

#constantsArray<RbiGenerator::Constant>

The Constant objects from #children.

Returns:



106
107
108
109
110
111
# File 'lib/parlour/rbi_generator/namespace.rb', line 106

def constants
  T.cast(
    children.select { |c| c.is_a?(RbiGenerator::Constant) },
    T::Array[RbiGenerator::Constant]
  )
end

#create_arbitrary(code:, &block) ⇒ RbiGenerator::Arbitrary

Creates a new arbitrary code section. You should rarely have to use this!

Parameters:

  • code (String)

    The code to insert.

  • block

    A block which the new instance yields itself to.

Returns:



482
483
484
485
486
487
488
489
490
491
# File 'lib/parlour/rbi_generator/namespace.rb', line 482

def create_arbitrary(code:, &block)
  new_arbitrary = RbiGenerator::Arbitrary.new(
    generator,
    code: code,
    &block
  )
  move_next_comments(new_arbitrary)
  children << new_arbitrary
  new_arbitrary
end

#create_attr_accessor(name, type:, class_attribute: false, &block) ⇒ RbiGenerator::Attribute

Creates a new read and write attribute (attr_accessor).

Parameters:

  • name (String)

    The name of this attribute.

  • type (String)

    A Sorbet string of this attribute’s type, such as “String” or “T.untyped”.

  • class_attribute (Boolean) (defaults to: false)

    Whether this attribute belongs to the singleton class.

  • block

    A block which the new instance yields itself to.

Returns:



472
473
474
# File 'lib/parlour/rbi_generator/namespace.rb', line 472

def create_attr_accessor(name, type:, class_attribute: false, &block)
  create_attribute(name, kind: :accessor, type: type, class_attribute: class_attribute, &block)
end

#create_attr_reader(name, type:, class_attribute: false, &block) ⇒ RbiGenerator::Attribute

Creates a new read-only attribute (attr_reader).

Parameters:

  • name (String)

    The name of this attribute.

  • type (String)

    A Sorbet string of this attribute’s type, such as “String” or “T.untyped”.

  • class_attribute (Boolean) (defaults to: false)

    Whether this attribute belongs to the singleton class.

  • block

    A block which the new instance yields itself to.

Returns:



430
431
432
# File 'lib/parlour/rbi_generator/namespace.rb', line 430

def create_attr_reader(name, type:, class_attribute: false, &block)
  create_attribute(name, kind: :reader, type: type, class_attribute: class_attribute, &block)
end

#create_attr_writer(name, type:, class_attribute: false, &block) ⇒ RbiGenerator::Attribute

Creates a new write-only attribute (attr_writer).

Parameters:

  • name (String)

    The name of this attribute.

  • type (String)

    A Sorbet string of this attribute’s type, such as “String” or “T.untyped”.

  • class_attribute (Boolean) (defaults to: false)

    Whether this attribute belongs to the singleton class.

  • block

    A block which the new instance yields itself to.

Returns:



451
452
453
# File 'lib/parlour/rbi_generator/namespace.rb', line 451

def create_attr_writer(name, type:, class_attribute: false, &block)
  create_attribute(name, kind: :writer, type: type, class_attribute: class_attribute, &block)
end

#create_attribute(name, kind:, type:, class_attribute: false, &block) ⇒ RbiGenerator::Attribute Also known as: create_attr

Creates a new attribute.

Examples:

Create an attr_reader.

module.create_attribute('readable', kind: :reader, type: 'String')
# #=> sig { returns(String) }
#     attr_reader :readable

Create an attr_writer.

module.create_attribute('writable', kind: :writer, type: 'Integer')
# #=> sig { params(writable: Integer).returns(Integer) }
#     attr_writer :writable

Create an attr_accessor.

module.create_attribute('accessible', kind: :accessor, type: 'T::Boolean')
# #=> sig { returns(T::Boolean) }
#     attr_accessor :accessible

Create an attr_accessor on the singleton class.

module.create_attribute('singleton_attr', kind: :accessor, type: 'T::Boolean')
# #=> class << self
#       sig { returns(T::Boolean) }
#       attr_accessor :singleton_attr
#     end

Parameters:

  • name (String)

    The name of this attribute.

  • kind (Symbol)

    The kind of attribute this is; one of :writer, :reader, or :accessor.

  • type (String)

    A Sorbet string of this attribute’s type, such as “String” or “T.untyped”.

  • class_attribute (Boolean) (defaults to: false)

    Whether this attribute belongs to the singleton class.

  • block

    A block which the new instance yields itself to.

Returns:



398
399
400
401
402
403
404
405
406
407
408
409
410
# File 'lib/parlour/rbi_generator/namespace.rb', line 398

def create_attribute(name, kind:, type:, class_attribute: false, &block)
  new_attribute = RbiGenerator::Attribute.new(
    generator,
    name,
    kind,
    type,
    class_attribute: class_attribute,
    &block
  )
  move_next_comments(new_attribute)
  children << new_attribute
  new_attribute
end

#create_class(name, final: false, sealed: false, superclass: nil, abstract: false, &block) ⇒ ClassNamespace

Creates a new class definition as a child of this namespace.

Examples:

Create a class with a nested module.

namespace.create_class('Foo') do |foo|
  foo.create_module('Bar')
end

Create a class that is the child of another class.

namespace.create_class('Bar', superclass: 'Foo') #=> class Bar < Foo

Parameters:

  • name (String)

    The name of this class.

  • final (Boolean) (defaults to: false)

    Whether this namespace is final.

  • sealed (Boolean) (defaults to: false)

    Whether this namespace is sealed.

  • superclass (String, nil) (defaults to: nil)

    The superclass of this class, or nil if it doesn’t have one.

  • abstract (Boolean) (defaults to: false)

    A boolean indicating whether this class is abstract.

  • block

    A block which the new instance yields itself to.

Returns:



193
194
195
196
197
198
# File 'lib/parlour/rbi_generator/namespace.rb', line 193

def create_class(name, final: false, sealed: false, superclass: nil, abstract: false, &block)
  new_class = ClassNamespace.new(generator, name, final, sealed, superclass, abstract, &block)
  move_next_comments(new_class)
  children << new_class
  new_class
end

#create_constant(name, value:, eigen_constant: false, &block) ⇒ RbiGenerator::Constant

Adds a new constant definition to this namespace.

Examples:

Add an Elem constant to the class.

class.create_constant('Elem', value: 'String') #=> Elem = String

Parameters:

  • name (String)

    The name of the constant.

  • value (String)

    The value of the constant, as a Ruby code string.

  • eigen_constant (Boolean) (defaults to: false)

    Whether this constant is defined on the eigenclass of the current namespace.

  • block

    A block which the new instance yields itself to.

Returns:



579
580
581
582
583
584
585
586
587
588
589
590
# File 'lib/parlour/rbi_generator/namespace.rb', line 579

def create_constant(name, value:, eigen_constant: false, &block)
  new_constant = RbiGenerator::Constant.new(
    generator,
    name: name,
    value: value,
    eigen_constant: eigen_constant,
    &block
  )
  move_next_comments(new_constant)
  children << new_constant
  new_constant
end

#create_enum_class(name, final: false, sealed: false, enums: nil, abstract: false, &block) ⇒ EnumClassNamespace

Creates a new enum class definition as a child of this namespace.

Examples:

Create a compass direction enum.

namespace.create_class('Direction', enums: ['North', 'South', 'East', 'West'])

Parameters:

  • name (String)

    The name of this class.

  • final (Boolean) (defaults to: false)

    Whether this namespace is final.

  • sealed (Boolean) (defaults to: false)

    Whether this namespace is sealed.

  • enums (Array<(String, String), String>) (defaults to: nil)

    The values of the enumeration.

  • abstract (Boolean) (defaults to: false)

    A boolean indicating whether this class is abstract.

  • block

    A block which the new instance yields itself to.

Returns:



222
223
224
225
226
227
# File 'lib/parlour/rbi_generator/namespace.rb', line 222

def create_enum_class(name, final: false, sealed: false, enums: nil, abstract: false, &block)
  new_enum_class = EnumClassNamespace.new(generator, name, final, sealed, enums || [], abstract, &block)
  move_next_comments(new_enum_class)
  children << new_enum_class
  new_enum_class
end

#create_extend(name, &block) ⇒ RbiGenerator::Extend

Adds a new extend to this namespace.

Examples:

Add an extend to a class.

class.create_extend('ExtendableClass') #=> extend ExtendableClass

Parameters:

  • object (String)

    A code string for what is extended, for example “MyModule”.

  • block

    A block which the new instance yields itself to.

Returns:



503
504
505
506
507
508
509
510
511
512
# File 'lib/parlour/rbi_generator/namespace.rb', line 503

def create_extend(name, &block)
  new_extend = RbiGenerator::Extend.new(
    generator,
    name: name,
    &block
  )
  move_next_comments(new_extend)
  children << new_extend
  new_extend
end

#create_extends(extendables) ⇒ Array<RbiGenerator::Extend>

Adds new extends to this namespace.

Examples:

Add extends to a class.

class.create_extends(['Foo', 'Bar'])

Parameters:

  • extendables (Array<String>)

    An array of names for whatever is being extended.

Returns:



522
523
524
525
526
527
528
# File 'lib/parlour/rbi_generator/namespace.rb', line 522

def create_extends(extendables)
  returned_extendables = []
  extendables.each do |extendable|
    returned_extendables << create_extend(extendable)
  end
  returned_extendables
end

#create_include(name, &block) ⇒ RbiGenerator::Include

Adds a new include to this namespace.

Examples:

Add an include to a class.

class.create_include('IncludableClass') #=> include IncludableClass

Parameters:

  • name (String)

    A code string for what is included, for example “Enumerable”.

  • block

    A block which the new instance yields itself to.

Returns:



540
541
542
543
544
545
546
547
548
549
# File 'lib/parlour/rbi_generator/namespace.rb', line 540

def create_include(name, &block)
  new_include = RbiGenerator::Include.new(
    generator,
    name: name,
    &block
  )
  move_next_comments(new_include)
  children << new_include
  new_include
end

#create_includes(includables) ⇒ Array<RbiGenerator::Include>

Adds new includes to this namespace.

Examples:

Add includes to a class.

class.create_includes(['Foo', 'Bar'])

Parameters:

  • includables (Array<String>)

    An array of names for whatever is being included.

Returns:



559
560
561
562
563
564
565
# File 'lib/parlour/rbi_generator/namespace.rb', line 559

def create_includes(includables)
  returned_includables = []
  includables.each do |includable|
    returned_includables << create_include(includable)
  end
  returned_includables
end

#create_method(name, parameters: nil, return_type: nil, returns: nil, abstract: false, implementation: false, override: false, overridable: false, class_method: false, final: false, type_parameters: nil, &block) ⇒ Method

Creates a new method definition as a child of this namespace.

Parameters:

  • name (String)

    The name of this method. You should not specify self. in this - use the class_method parameter instead.

  • parameters (Array<Parameter>) (defaults to: nil)

    An array of Parameter instances representing this method’s parameters.

  • return_type (String, nil) (defaults to: nil)

    A Sorbet string of what this method returns, such as “String” or “T.untyped”. Passing nil denotes a void return.

  • returns (String, nil) (defaults to: nil)

    Same as return_type.

  • abstract (Boolean) (defaults to: false)

    Whether this method is abstract.

  • implementation (Boolean) (defaults to: false)

    DEPRECATED: Whether this method is an implementation of a parent abstract method.

  • override (Boolean) (defaults to: false)

    Whether this method is overriding a parent overridable method, or implementing a parent abstract method.

  • overridable (Boolean) (defaults to: false)

    Whether this method is overridable by subclasses.

  • class_method (Boolean) (defaults to: false)

    Whether this method is a class method; that is, it it is defined using self..

  • final (Boolean) (defaults to: false)

    Whether this method is final.

  • type_parameters (Array<Symbol>, nil) (defaults to: nil)

    This method’s type parameters.

  • block

    A block which the new instance yields itself to.

Returns:



333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
# File 'lib/parlour/rbi_generator/namespace.rb', line 333

def create_method(name, parameters: nil, return_type: nil, returns: nil, abstract: false, implementation: false, override: false, overridable: false, class_method: false, final: false, type_parameters: nil, &block)
  parameters = parameters || []
  raise 'cannot specify both return_type: and returns:' if return_type && returns
  return_type ||= returns
  new_method = RbiGenerator::Method.new(
    generator,
    name,
    parameters,
    return_type,
    abstract: abstract,
    implementation: implementation,
    override: override,
    overridable: overridable,
    class_method: class_method,
    final: final,
    type_parameters: type_parameters,
    &block
  )
  move_next_comments(new_method)
  children << new_method
  new_method
end

#create_module(name, final: false, sealed: false, interface: false, abstract: false, &block) ⇒ ModuleNamespace

Creates a new module definition as a child of this namespace.

Examples:

Create a basic module.

namespace.create_module('Foo')

Create a module with a method.

namespace.create_module('Foo') do |foo|
  foo.create_method('method_name', parameters: [], return_type: 'Integer')
end

Parameters:

  • name (String)

    The name of this module.

  • final (Boolean) (defaults to: false)

    Whether this namespace is final.

  • sealed (Boolean) (defaults to: false)

    Whether this namespace is sealed.

  • interface (Boolean) (defaults to: false)

    A boolean indicating whether this module is an interface.

  • abstract (Boolean) (defaults to: false)

    A boolean indicating whether this module is abstract.

  • block

    A block which the new instance yields itself to.

Returns:



289
290
291
292
293
294
# File 'lib/parlour/rbi_generator/namespace.rb', line 289

def create_module(name, final: false, sealed: false, interface: false, abstract: false, &block)
  new_module = ModuleNamespace.new(generator, name, final, sealed, interface, abstract, &block)
  move_next_comments(new_module)
  children << new_module
  new_module
end

#create_struct_class(name, final: false, sealed: false, props: nil, abstract: false, &block) ⇒ EnumClassNamespace

Creates a new struct class definition as a child of this namespace.

Examples:

Create a person struct.

namespace.create_class('Person', props: [
  Parlour::RbiGenerator::StructProp.new('name', 'String')
])

Parameters:

  • name (String)

    The name of this class.

  • final (Boolean) (defaults to: false)

    Whether this namespace is final.

  • sealed (Boolean) (defaults to: false)

    Whether this namespace is sealed.

  • props (Array<StructProp>) (defaults to: nil)

    The props of the struct.

  • abstract (Boolean) (defaults to: false)

    A boolean indicating whether this class is abstract.

  • block

    A block which the new instance yields itself to.

Returns:



253
254
255
256
257
258
# File 'lib/parlour/rbi_generator/namespace.rb', line 253

def create_struct_class(name, final: false, sealed: false, props: nil, abstract: false, &block)
  new_struct_class = StructClassNamespace.new(generator, name, final, sealed, props || [], abstract, &block)
  move_next_comments(new_struct_class)
  children << new_struct_class
  new_struct_class
end

#create_type_alias(name, type:, &block) ⇒ RbiGenerator::Constant

Adds a new type alias, in the form of a constant, to this namespace.

Examples:

Add a MyType type alias, to Integer, to the class.

class.create_type_alias('MyType', type: 'Integer') #=> MyType = T.type_alias { Integer }

Parameters:

  • name (String)

    The name of the type alias.

  • value (String)

    The type to alias, as a Ruby code string.

  • block

    A block which the new instance yields itself to.

Returns:



602
603
604
605
606
607
608
609
610
611
612
# File 'lib/parlour/rbi_generator/namespace.rb', line 602

def create_type_alias(name, type:, &block)
  new_type_alias = RbiGenerator::TypeAlias.new(
    generator,
    name: name,
    type: type,
    &block
  )
  move_next_comments(new_type_alias)
  children << new_type_alias
  new_type_alias
end

#describe_attrsObject



660
661
662
# File 'lib/parlour/rbi_generator/namespace.rb', line 660

def describe_attrs
  [:children, :final, :sealed]
end

#extendsArray<RbiGenerator::Extend>

The Extend objects from #children.

Returns:



75
76
77
78
79
80
# File 'lib/parlour/rbi_generator/namespace.rb', line 75

def extends
  T.cast(
    children.select { |c| c.is_a?(RbiGenerator::Extend) },
    T::Array[RbiGenerator::Extend]
  )
end

#generalize_from_rbi!Object



655
656
657
# File 'lib/parlour/rbi_generator/namespace.rb', line 655

def generalize_from_rbi!
  children.each(&:generalize_from_rbi!)
end

#generate_rbi(indent_level, options) ⇒ Array<String>

Generates the RBI lines for this namespace.

Parameters:

  • indent_level (Integer)

    The indentation level to generate the lines at.

  • options (Options)

    The formatting options to use.

Returns:

  • (Array<String>)

    The RBI lines, formatted as specified.



21
22
23
24
# File 'lib/parlour/rbi_generator/namespace.rb', line 21

def generate_rbi(indent_level, options)
  generate_comments(indent_level, options) +
    generate_body(indent_level, options)
end

#includesArray<RbiGenerator::Include>

The Include objects from #children.

Returns:



85
86
87
88
89
90
# File 'lib/parlour/rbi_generator/namespace.rb', line 85

def includes
  T.cast(
    children.select { |c| c.is_a?(RbiGenerator::Include) },
    T::Array[RbiGenerator::Include]
  )
end

#merge_into_self(others) ⇒ void

This method returns an undefined value.

Given an array of Parlour::RbiGenerator::Namespace instances, merges them into this one. All children, constants, extends and includes are copied into this instance.

There may also be Method instances in the stream, which are ignored.

Parameters:



645
646
647
648
649
650
651
652
# File 'lib/parlour/rbi_generator/namespace.rb', line 645

def merge_into_self(others)
  others.each do |other|
    next if other.is_a?(RbiGenerator::Method)
    other = T.cast(other, Namespace)

    other.children.each { |c| children << c }
  end
end

#mergeable?(others) ⇒ true

Given an array of Parlour::RbiGenerator::Namespace instances, returns true if they may be merged into this instance using #merge_into_self. All bare namespaces can be merged into each other, as they lack definitions for themselves, so there is nothing to conflict. (This isn’t the case for subclasses such as ClassNamespace.)

Parameters:

Returns:

  • (true)

    Always true.



627
628
629
# File 'lib/parlour/rbi_generator/namespace.rb', line 627

def mergeable?(others)
  true
end

#path(constant, &block) ⇒ Object

Given a constant (i.e. a Module instance), generates all classes and modules in the path to that object, then executes the given block on the last Parlour::RbiGenerator::Namespace. This should only be executed on the root namespace.

Parameters:



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

def path(constant, &block)
  raise 'only call #path on root' if is_a?(ClassNamespace) || is_a?(ModuleNamespace)

  constant_name = T.let(Module.instance_method(:name).bind(constant).call, T.nilable(String))
  raise 'given constant does not have a name' unless constant_name

  current_part = self
  constant_name.split('::').each_with_object([]) do |name, namespace|
    namespace << name
    instance = Module.const_get(namespace.join("::"))

    case instance
    when Class
      current_part = current_part.create_class(name)
    when Module
      current_part = current_part.create_module(name)
    else
      raise "unexpected type: path part #{name} is a #{instance.class}"
    end
  end

  block.call(current_part)
end