class Parlour::RbsGenerator::Namespace
A generic namespace. This shouldn't be used, except as the type of {RbsGenerator#root}.
Attributes
The child {RbsObject} instances inside this namespace. @return [Array<RbsObject>]
Public Class Methods
Creates a new namespace. @note Unless you're doing something impressively hacky, this shouldn't
be invoked outside of {RbsGenerator#initialize}.
@param generator [RbsGenerator] The current RbsGenerator
. @param name [String, nil] The name of this module. @param final [Boolean] Whether this namespace is final. @param block A block which the new instance yields itself to. @return [void]
# File lib/parlour/rbs_generator/namespace.rb, line 41 def initialize(generator, name = nil, &block) super(generator, name || '<anonymous namespace>') @children = [] @next_comments = [] yield_self(&block) if block end
Public Instance Methods
Adds one or more comments to the next child RBS object to be created.
@example Creating a module with a comment.
namespace.add_comment_to_next_child('This is a module') namespace.create_module('M')
@example 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')
@param comment [String, Array<String>] The new comment(s). @return [void]
# File lib/parlour/rbs_generator/namespace.rb, line 135 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
The {RbsGenerator::TypeAlias} objects from {children}. @return [Array<RbsGenerator::TypeAlias>]
# File lib/parlour/rbs_generator/namespace.rb, line 76 def aliases T.cast( children.select { |c| c.is_a?(RbsGenerator::TypeAlias) }, T::Array[RbsGenerator::TypeAlias] ) end
The {RbsGenerator::Constant} objects from {children}. @return [Array<RbsGenerator::Constant>]
# File lib/parlour/rbs_generator/namespace.rb, line 87 def constants T.cast( children.select { |c| c.is_a?(RbsGenerator::Constant) }, T::Array[RbsGenerator::Constant] ) end
Creates a new arbitrary code section. You should rarely have to use this!
@param code [String] The code to insert. @param block A block which the new instance yields itself to. @return [RbsGenerator::Arbitrary]
# File lib/parlour/rbs_generator/namespace.rb, line 353 def create_arbitrary(code:, &block) new_arbitrary = RbsGenerator::Arbitrary.new( generator, code: code, &block ) move_next_comments(new_arbitrary) children << new_arbitrary new_arbitrary end
Creates a new read and write attribute (attr_accessor
).
@param name [String] The name of this attribute. @param type [Types::TypeLike] This attribute's type. @param class_attribute [Boolean] Whether this attribute belongs to the
singleton class.
@param block A block which the new instance yields itself to. @return [RbsGenerator::Attribute]
# File lib/parlour/rbs_generator/namespace.rb, line 343 def create_attr_accessor(name, type:, &block) create_attribute(name, kind: :accessor, type: type, &block) end
Creates a new read-only attribute (attr_reader
).
@param name [String] The name of this attribute. @param type [Types::TypeLike] This attribute's type. @param class_attribute [Boolean] Whether this attribute belongs to the
singleton class.
@param block A block which the new instance yields itself to. @return [RbsGenerator::Attribute]
# File lib/parlour/rbs_generator/namespace.rb, line 305 def create_attr_reader(name, type:, &block) create_attribute(name, kind: :reader, type: type, &block) end
Creates a new write-only attribute (attr_writer
).
@param name [String] The name of this attribute. @param type [Types::TypeLike] This attribute's type. @param class_attribute [Boolean] Whether this attribute belongs to the
singleton class.
@param block A block which the new instance yields itself to. @return [RbsGenerator::Attribute]
# File lib/parlour/rbs_generator/namespace.rb, line 324 def create_attr_writer(name, type:, &block) create_attribute(name, kind: :writer, type: type, &block) end
Creates a new attribute.
@example Create an attr_reader
.
module.create_attribute('readable', kind: :reader, type: 'String') # #=> attr_reader readable: String
@example Create an attr_writer
.
module.create_attribute('writable', kind: :writer, type: 'Integer') # #=> attr_writer writable: Integer
@example Create an attr_accessor
.
module.create_attribute('accessible', kind: :accessor, type: Types::Boolean.new) # #=> attr_accessor accessible: bool
@param name [String] The name of this attribute. @param kind [Symbol] The kind of attribute this is; one of :writer
, :reader
, or
+:accessor+.
@param type [Types::TypeLike] This attribute's type. @param class_attribute [Boolean] Whether this attribute belongs to the
singleton class.
@param block A block which the new instance yields itself to. @return [RbsGenerator::Attribute]
# File lib/parlour/rbs_generator/namespace.rb, line 276 def create_attribute(name, kind:, type:, &block) new_attribute = RbsGenerator::Attribute.new( generator, name, kind, type, &block ) move_next_comments(new_attribute) children << new_attribute new_attribute end
Creates a new class definition as a child of this namespace.
@example Create a class with a nested module.
namespace.create_class('Foo') do |foo| foo.create_module('Bar') end
@example Create a class that is the child of another class.
namespace.create_class('Bar', superclass: 'Foo') #=> class Bar < Foo
@param name [String] The name of this class. @param superclass [String, nil] The superclass of this class, or nil if it doesn't
have one.
@param block A block which the new instance yields itself to. @return [ClassNamespace]
# File lib/parlour/rbs_generator/namespace.rb, line 165 def create_class(name, superclass: nil, &block) new_class = ClassNamespace.new(generator, name, superclass, &block) move_next_comments(new_class) children << new_class new_class end
Adds a new constant definition to this namespace.
@example Add an Elem
constant to the class.
class.create_constant('FOO', type: 'String') #=> FOO: String
@param name [String] The name of the constant. @param type [Types::TypeLike] The type of the constant, as a Ruby code string. @param block A block which the new instance yields itself to. @return [RbsGenerator::Constant]
# File lib/parlour/rbs_generator/namespace.rb, line 446 def create_constant(name, type:, &block) new_constant = RbsGenerator::Constant.new( generator, name, type: type, &block ) move_next_comments(new_constant) children << new_constant new_constant end
Adds a new extend
to this namespace.
@example Add an extend
to a class.
class.create_extend('ExtendableClass') #=> extend ExtendableClass
@param type [Types::TypeLike] The type to extend. @param block A block which the new instance yields itself to. @return [RbsGenerator::Extend]
# File lib/parlour/rbs_generator/namespace.rb, line 373 def create_extend(type, &block) new_extend = RbsGenerator::Extend.new( generator, type: type, &block ) move_next_comments(new_extend) children << new_extend new_extend end
Adds new +extend+s to this namespace.
@example Add +extend+s to a class.
class.create_extends(['Foo', 'Bar'])
@param [Array<Types::TypeLike>] extendables An array of types to extend. @return [Array<RbsGenerator::Extend>]
# File lib/parlour/rbs_generator/namespace.rb, line 392 def create_extends(extendables) returned_extendables = [] extendables.each do |extendable| returned_extendables << create_extend(extendable) end returned_extendables end
Adds a new include
to this namespace.
@example Add an include
to a class.
class.create_include('IncludableClass') #=> include IncludableClass
@param type [Types::TypeLike] The type to extend. @param block A block which the new instance yields itself to. @return [RbsGenerator::Include]
# File lib/parlour/rbs_generator/namespace.rb, line 409 def create_include(type, &block) new_include = RbsGenerator::Include.new( generator, type: type, &block ) move_next_comments(new_include) children << new_include new_include end
Adds new +include+s to this namespace.
@example Add +include+s to a class.
class.create_includes(['Foo', 'Bar'])
@param [Array<Types::TypeLike>] includables An array of types to extend. @return [Array<RbsGenerator::Include>]
# File lib/parlour/rbs_generator/namespace.rb, line 428 def create_includes(includables) returned_includables = [] includables.each do |includable| returned_includables << create_include(includable) end returned_includables end
Creates a new interface definition as a child of this namespace.
@example Create a basic interface.
namespace.create_interface('Foo')
@param name [String] The name of this interface. @param block A block which the new instance yields itself to. @return [InterfaceNamespace]
# File lib/parlour/rbs_generator/namespace.rb, line 207 def create_interface(name, &block) new_interface = InterfaceNamespace.new(generator, name, &block) move_next_comments(new_interface) children << new_interface new_interface end
Creates a new method definition as a child of this namespace.
@param name [String] The name of this method. You should not specify self.
in
this - use the +class_method+ parameter instead.
@param signatures [Array<MethodSignature>] The signatures for each
overload of this method.
@param class_method [Boolean] Whether this method is a class method; that is, it
it is defined using +self.+.
@param block A block which the new instance yields itself to. @return [Method]
# File lib/parlour/rbs_generator/namespace.rb, line 232 def create_method(name, signatures = nil, class_method: false, &block) raise 'cannot have a method with no signatures' if signatures&.empty? new_method = RbsGenerator::Method.new( generator, name, signatures || [MethodSignature.new([], nil)], class_method: class_method, &block ) move_next_comments(new_method) children << new_method new_method end
Creates a new module definition as a child of this namespace.
@example Create a basic module.
namespace.create_module('Foo')
@param name [String] The name of this module. @param block A block which the new instance yields itself to. @return [ModuleNamespace]
# File lib/parlour/rbs_generator/namespace.rb, line 186 def create_module(name, &block) new_module = ModuleNamespace.new(generator, name, &block) move_next_comments(new_module) children << new_module new_module end
Adds a new type alias, in the form of a constant, to this namespace.
@example Add a MyType
type alias, to Integer
, to the class.
class.create_type_alias('MyType', type: 'Integer') #=> type MyType = Integer
@param name [String] The name of the type alias. @param value [Types::TypeLike] The type to alias. @param block A block which the new instance yields itself to. @return [RbsGenerator::TypeAlias]
# File lib/parlour/rbs_generator/namespace.rb, line 468 def create_type_alias(name, type:, &block) new_type_alias = TypeAlias.new( generator, name: name, type: type, &block ) move_next_comments(new_type_alias) children << new_type_alias new_type_alias end
Returns a human-readable brief string description of this namespace.
@return [String]
# File lib/parlour/rbs_generator/namespace.rb, line 524 def describe "Namespace #{name} - #{children.length} children, #{includes.length} " + "includes, #{extends.length} extends, #{constants.length} constants" end
The {RbsGenerator::Extend} objects from {children}. @return [Array<RbsGenerator::Extend>]
# File lib/parlour/rbs_generator/namespace.rb, line 56 def extends T.cast( children.select { |c| c.is_a?(RbsGenerator::Extend) }, T::Array[RbsGenerator::Extend] ) end
Generates the RBS lines for this namespace.
@param indent_level [Integer] The indentation level to generate the lines at. @param options [Options] The formatting options to use. @return [Array<String>] The RBS lines, formatted as specified.
# File lib/parlour/rbs_generator/namespace.rb, line 20 def generate_rbs(indent_level, options) generate_comments(indent_level, options) + generate_body(indent_level, options) end
The {RbsGenerator::Include} objects from {children}. @return [Array<RbsGenerator::Include>]
# File lib/parlour/rbs_generator/namespace.rb, line 66 def includes T.cast( children.select { |c| c.is_a?(RbsGenerator::Include) }, T::Array[RbsGenerator::Include] ) end
Given an array of {Namespace} instances, merges them into this one. All children, constants, extends and includes are copied into this instance.
There may also be {RbsGenerator::Method} instances in the stream, which are ignored.
@param others [Array<RbsGenerator::RbsObject>] An array of other {Namespace} instances. @return [void]
# File lib/parlour/rbs_generator/namespace.rb, line 511 def merge_into_self(others) others.each do |other| next if other.is_a?(RbsGenerator::Method) other = T.cast(other, Namespace) other.children.each { |c| children << c } end end
Given an array of {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}.)
@param others [Array<RbsGenerator::RbsObject>] An array of other {Namespace} instances. @return [true] Always true.
# File lib/parlour/rbs_generator/namespace.rb, line 493 def mergeable?(others) true end
Given a Class or Module object, generates all classes and modules in the path to that object, then executes the given block on the last {Namespace}. This should only be executed on the root namespace. @param [Class, Module] object @param block A block which the new {Namespace} yields itself to.
# File lib/parlour/rbs_generator/namespace.rb, line 100 def path(object, &block) raise 'only call #path on root' if is_a?(ClassNamespace) || is_a?(ModuleNamespace) parts = object.to_s.split('::') parts_with_types = parts.size.times.map do |i| [parts[i], Module.const_get(parts[0..i].join('::')).class] end current_part = self parts_with_types.each do |(name, type)| if type == Class current_part = current_part.create_class(name) elsif type == Module current_part = current_part.create_module(name) else raise "unexpected type: path part #{name} is a #{type}" end end block.call(current_part) end
Private Instance Methods
Generates the RBS lines for the body of this namespace. This consists of {includes}, {extends} and {children}.
@param indent_level [Integer] The indentation level to generate the lines at. @param options [Options] The formatting options to use. @param mode [Symbol] The symbol to send to generate children: one of
:generate_rbs or :generate_rbs.
@return [Array<String>] The RBS lines for the body, formatted as specified.
# File lib/parlour/rbs_generator/namespace.rb, line 545 def generate_body(indent_level, options) result = [] if includes.any? || extends.any? || aliases.any? || constants.any? result += (options.sort_namespaces \ ? includes.sort_by { |x| t = x.type; String === t ? t : t.generate_rbs } : includes) .flat_map { |x| x.generate_rbs(indent_level, options) } .reject { |x| x.strip == '' } result += (options.sort_namespaces \ ? extends.sort_by { |x| t = x.type; String === t ? t : t.generate_rbs } : extends) .flat_map { |x| x.generate_rbs(indent_level, options) } .reject { |x| x.strip == '' } result += (options.sort_namespaces \ ? aliases.sort_by { |x| t = x.type; String === t ? t : t.generate_rbs } : aliases) .flat_map { |x| x.generate_rbs(indent_level, options) } .reject { |x| x.strip == '' } result += (options.sort_namespaces \ ? constants.sort_by { |x| t = x.type; String === t ? t : t.generate_rbs } : constants) .flat_map { |x| x.generate_rbs(indent_level, options) } .reject { |x| x.strip == '' } result << "" end # Sort children sorted_children = ( if options.sort_namespaces # sort_by can be unstable (and is in current MRI). # Use the this work around to preserve order for ties children.sort_by.with_index { |child, i| [child.name, i] } else children end ) first, *rest = sorted_children.reject do |child| # We already processed these kinds of children child.is_a?(Include) || child.is_a?(Extend) || child.is_a?(Constant) || child.is_a?(TypeAlias) end.reject do |child| next if is_a?(ClassNamespace) || is_a?(ModuleNamespace) # next if this is not root if child.is_a?(RbsGenerator::Method) unless $VERBOSE.nil? print Rainbow("Parlour warning: ").yellow.dark.bold print Rainbow("RBS generation: ").magenta.bright.bold puts "RBS does not support top-level method definitions, ignoring #{child.name}" print Rainbow(" └ at object: ").blue.bright.bold puts describe end next true end false end unless first # Remove any trailing whitespace due to includes or class attributes result.pop while result.last == '' return result end result += first.generate_rbs(indent_level, options) + T.must(rest) .map { |obj| obj.generate_rbs(indent_level, options) } .map { |lines| [""] + lines } .flatten result end
Copies the comments added with {#add_comment_to_next_child} into the given object, and clears the list of pending comments. @param object [RbsObject] The object to move the comments into. @return [void]
# File lib/parlour/rbs_generator/namespace.rb, line 621 def move_next_comments(object) object.comments.unshift(*@next_comments) @next_comments.clear end