class YARD::CodeObjects::Base
Base
is the superclass of all code objects recognized by YARD
. A code object is any entity in the Ruby language (class, method, module). A DSL might subclass Base
to create a new custom object representing a new entity type.
Registry
Integration¶ ↑
Any created object associated with a namespace is immediately registered with the registry. This allows the Registry
to act as an identity map to ensure that no object is represented by more than one Ruby object in memory. A unique {#path} is essential for this identity map to work correctly.
Custom Attributes¶ ↑
Code objects allow arbitrary custom attributes to be set using the {#[]=} assignment method.
Namespaces¶ ↑
There is a special type of object called a “namespace”. These are subclasses of the {NamespaceObject} and represent Ruby entities that can have objects defined within them. Classically these are modules and classes, though a DSL might create a custom {NamespaceObject} to describe a specific set of objects.
Separators¶ ↑
Custom classes with different separator tokens should define their own separators using the {NamespaceMapper.register_separator} method. The standard Ruby separators have already been defined (‘::’, ‘#’, ‘.’, etc).
@abstract This class should not be used directly. Instead, create a
subclass that implements {#path}, {#sep} or {#type}. You might also need to register custom separators if {#sep} uses alternate separator tokens.
@see Registry
@see path
@see []=
@see NamespaceObject
@see NamespaceMapper.register_separator
Attributes
The non-localized documentation string associated with the object @return [Docstring] the documentation string @since 0.8.4
Marks whether or not the method is conditionally defined at runtime @return [Boolean] true if the method is conditionally defined at runtime
@return [String] the group this object is associated with @since 0.6.0
The namespace the object is defined in. If the object is in the top level namespace, this is {Registry.root} @return [NamespaceObject] the namespace object
The namespace the object is defined in. If the object is in the top level namespace, this is {Registry.root} @return [NamespaceObject] the namespace object
The one line signature representing an object. For a method, this will be of the form “def meth(arguments…)”. This is usually the first source line.
@return [String] a line of source
The source code associated with the object @return [String, nil] source, if present, or nil
Language of the source code associated with the object. Defaults to :ruby
.
@return [Symbol] the language type
@return [Symbol] the visibility of an object (:public, :private, :protected)
Public Class Methods
Compares the class with subclasses
@param [Object] other the other object to compare classes with @return [Boolean] true if other is a subclass of self
# File lib/yard/code_objects/base.rb, line 219 def ===(other) other.is_a?(self) end
Allocates a new code object @return [Base] @see initialize
# File lib/yard/code_objects/base.rb, line 189 def new(namespace, name, *args, &block) raise ArgumentError, "invalid empty object name" if name.to_s.empty? if namespace.is_a?(ConstantObject) unless namespace.value =~ /\A#{NAMESPACEMATCH}\Z/ raise Parser::UndocumentableError, "constant mapping" end namespace = Proxy.new(namespace.namespace, namespace.value) end if name.to_s[0, 2] == NSEP name = name.to_s[2..-1] namespace = Registry.root end if name =~ /(?:#{NSEPQ})([^:]+)$/ return new(Proxy.new(namespace, $`), $1, *args, &block) end obj = super(namespace, name, *args) existing_obj = Registry.at(obj.path) obj = existing_obj if existing_obj && existing_obj.class == self yield(obj) if block_given? obj end
Creates a new code object
@example Create a method in the root namespace
CodeObjects::Base.new(:root, '#method') # => #<yardoc method #method>
@example Create class Z inside namespace X::Y
CodeObjects::Base.new(P("X::Y"), :Z) # or CodeObjects::Base.new(Registry.root, "X::Y")
@param [NamespaceObject] namespace the namespace the object belongs in,
{Registry.root} or :root should be provided if it is associated with the top level namespace.
@param [Symbol, String] name the name (or complex path) of the object. @yield [self] a block to perform any extra initialization on the object @yieldparam [Base] self the newly initialized code object @return [Base] the newly created object
# File lib/yard/code_objects/base.rb, line 238 def initialize(namespace, name, *) if namespace && namespace != :root && !namespace.is_a?(NamespaceObject) && !namespace.is_a?(Proxy) raise ArgumentError, "Invalid namespace object: #{namespace}" end @files = [] @current_file_has_comments = false @name = name.to_sym @source_type = :ruby @visibility = :public @tags = [] @docstrings = {} @docstring = Docstring.new!('', [], self) @namespace = nil self.namespace = namespace yield(self) if block_given? end
Public Instance Methods
Accesses a custom attribute on the object @param [#to_s] key the name of the custom attribute @return [Object, nil] the custom attribute or nil if not found. @see []=
# File lib/yard/code_objects/base.rb, line 343 def [](key) if respond_to?(key) send(key) elsif instance_variable_defined?("@#{key}") instance_variable_get("@#{key}") end end
Sets a custom attribute on the object @param [#to_s] key the name of the custom attribute @param [Object] value the value to associate @return [void] @see []
# File lib/yard/code_objects/base.rb, line 356 def []=(key, value) if respond_to?("#{key}=") send("#{key}=", value) else instance_variable_set("@#{key}", value) end end
Associates a file with a code object, optionally adding the line where it was defined. By convention, ‘<stdin>’ should be used to associate code that comes form standard input.
@param [String] file the filename (‘<stdin>’ for standard input) @param [Fixnum, nil] line the line number where the object lies in the file @param [Boolean] has_comments whether or not the definition has comments associated. This
will allow {#file} to return the definition where the comments were made instead of any empty definitions that might have been parsed before (module namespaces for instance).
# File lib/yard/code_objects/base.rb, line 290 def add_file(file, line = nil, has_comments = false) raise(ArgumentError, "file cannot be nil or empty") if file.nil? || file == '' obj = [file.to_s, line] return if files.include?(obj) if has_comments && !@current_file_has_comments @current_file_has_comments = true @files.unshift(obj) else @files << obj # back of the line end end
Add tags to the {#docstring} @see Docstring#add_tag
@since 0.8.4
# File lib/yard/code_objects/base.rb, line 561 def add_tag(*tags) @docstrings.clear @docstring.add_tag(*tags) end
Copies all data in this object to another code object, except for uniquely identifying information (path, namespace, name, scope).
@param [Base] other the object to copy data to @return [Base] the other object @since 0.8.0
# File lib/yard/code_objects/base.rb, line 263 def copy_to(other) copyable_attributes.each do |ivar| ivar = "@#{ivar}" other.instance_variable_set(ivar, instance_variable_get(ivar)) end other.docstring = @docstring.to_raw other end
The documentation string associated with the object
@param [String, I18n::Locale
] locale (I18n::Locale.default
)
the locale of the documentation string.
@return [Docstring] the documentation string
# File lib/yard/code_objects/base.rb, line 405 def docstring(locale = I18n::Locale.default) if locale.nil? @docstring.resolve_reference return @docstring end if locale.is_a?(String) locale_name = locale locale = nil else locale_name = locale.name end @docstrings[locale_name] ||= translate_docstring(locale || Registry.locale(locale_name)) end
Attaches a docstring to a code object by parsing the comments attached to the statement and filling the {#tags} and {#docstring} methods with the parsed information.
@param [String, Array
<String>, Docstring] comments
the comments attached to the code object to be parsed into a docstring and meta tags.
# File lib/yard/code_objects/base.rb, line 427 def docstring=(comments) @docstrings.clear @docstring = Docstring === comments ? comments : Docstring.new(comments, self) end
Is the object defined conditionally at runtime? @see dynamic
# File lib/yard/code_objects/base.rb, line 178 def dynamic?; @dynamic end
Tests if another object is equal to this, including a proxy @param [Base, Proxy] other if other is a {Proxy}, tests if
the paths are equal
@return [Boolean] whether or not the objects are considered the same
# File lib/yard/code_objects/base.rb, line 323 def equal?(other) if other.is_a?(Base) || other.is_a?(Proxy) path == other.path else super end end
Returns the filename the object was first parsed at, taking definitions with docstrings first.
@return [String] a filename @return [nil] if there is no file associated with the object
# File lib/yard/code_objects/base.rb, line 307 def file @files.first ? @files.first[0] : nil end
Renders the object using the {Templates::Engine templating system}.
@example Formats a class in plaintext
puts P('MyClass').format
@example Formats a method in html with rdoc markup
puts P('MyClass#meth').format(:format => :html, :markup => :rdoc)
@param [Hash] options a set of options to pass to the template @option options [Symbol] :format (:text) :html, :text or another output format @option options [Symbol] :template (:default) a specific template to use @option options [Symbol] :markup (nil) the markup type (:rdoc, :markdown, :textile) @option options [Serializers::Base] :serializer (nil) see Serializers
@return [String] the rendered template @see Templates::Engine#render
# File lib/yard/code_objects/base.rb, line 505 def format(options = {}) options = options.merge(:object => self) options = options.merge(:type => type) unless options[:type] Templates::Engine.render(options) end
Tests if the {#docstring} has a tag @see Docstring#has_tag?
# File lib/yard/code_objects/base.rb, line 556 def has_tag?(name); docstring.has_tag?(name) end
@return [Integer] the object’s hash value (for equality checking)
# File lib/yard/code_objects/base.rb, line 334 def hash; path.hash end
Inspects the object, returning the type and path @return [String] a string describing the object
# File lib/yard/code_objects/base.rb, line 513 def inspect "#<yardoc #{type} #{path}>" end
Returns the line the object was first parsed at (or nil)
@return [Fixnum] the line where the object was first defined. @return [nil] if there is no line associated with the object
# File lib/yard/code_objects/base.rb, line 315 def line @files.first ? @files.first[1] : nil end
@overload dynamic_attr_name
@return the value of attribute named by the method attribute name @raise [NoMethodError] if no method or custom attribute exists by the attribute name @see #[]
@overload dynamic_attr_name=(value)
@param value a value to set @return +value+ @see #[]=
# File lib/yard/code_objects/base.rb, line 373 def method_missing(meth, *args, &block) if meth.to_s =~ /=$/ self[meth.to_s[0..-2]] = args.first elsif instance_variable_get("@#{meth}") self[meth] else super end end
The name of the object @param [Boolean] prefix whether to show a prefix. Implement
this in a subclass to define how the prefix is showed.
@return [Symbol] if prefix is false, the symbolized name @return [String] if prefix is true, prefix + the name as a String
.
This must be implemented by the subclass.
# File lib/yard/code_objects/base.rb, line 278 def name(prefix = false) prefix ? @name.to_s : (defined?(@name) && @name) end
Sets the namespace the object is defined in.
@param [NamespaceObject, :root, nil] obj the new namespace (:root
for {Registry.root}). If obj is nil, the object is unregistered from the Registry.
# File lib/yard/code_objects/base.rb, line 522 def namespace=(obj) if @namespace @namespace.children.delete(self) Registry.delete(self) end @namespace = (obj == :root ? Registry.root : obj) if @namespace reg_obj = Registry.at(path) return if reg_obj && reg_obj.class == self.class unless @namespace.is_a?(Proxy) # remove prior objects from obj's children that match this one @namespace.children.delete_if {|o| o.path == path } @namespace.children << self end Registry.register(self) end end
Represents the unique path of the object. The default implementation joins the path of {#namespace} with {#name} via the value of {#sep}. Custom code objects should ensure that the path is unique to the code object by either overriding {#sep} or this method.
@example The path of an instance method
MethodObject.new(P("A::B"), :c).path # => "A::B#c"
@return [String] the unique path of the object @see sep
# File lib/yard/code_objects/base.rb, line 453 def path @path ||= if parent && !parent.root? [parent.path, name.to_s].join(sep) else name.to_s end end
@param [Base, String] other another code object (or object path) @return [String] the shortest relative path from this object to other
@since 0.5.3
# File lib/yard/code_objects/base.rb, line 475 def relative_path(other) other = Registry.at(other) if String === other && Registry.at(other) same_parent = false if other.respond_to?(:path) same_parent = other.parent == parent other = other.path end return other unless namespace common = [path, other].join(" ").match(/^(\S*)\S*(?: \1\S*)*$/)[1] common = path unless common =~ /(\.|::|#)$/ common = common.sub(/(\.|::|#)[^:#\.]*?$/, '') if same_parent suffix = %w(. :).include?(common[-1, 1]) || other[common.size, 1] == '#' ? '' : '(::|\.)' result = other.sub(/^#{Regexp.quote common}#{suffix}/, '') result.empty? ? other : result end
@return whether or not this object is a RootObject
# File lib/yard/code_objects/base.rb, line 567 def root?; false end
Override this method with a custom component separator. For instance, {MethodObject} implements sep as ‘#’ or ‘.’ (depending on if the method is instance or class respectively). {#path} depends on this value to generate the full path in the form: namespace.path + sep + name
@return [String] the component that separates the namespace path
and the name (default is {NSEP})
# File lib/yard/code_objects/base.rb, line 576 def sep; NSEP end
Attaches source code to a code object with an optional file location
@param [#source, String] statement
the +Parser::Statement+ holding the source code or the raw source as a +String+ for the definition of the code object only (not the block)
# File lib/yard/code_objects/base.rb, line 388 def source=(statement) if statement.respond_to?(:source) @source = format_source(statement.source.strip) else @source = format_source(statement.to_s) end if statement.respond_to?(:signature) self.signature = statement.signature end end
Gets a tag from the {#docstring} @see Docstring#tag
# File lib/yard/code_objects/base.rb, line 548 def tag(name); docstring.tag(name) end
@note
Override this method if your object has a special title that does not match the {#path} attribute value. This title will be used when linking or displaying the object.
@return [String] the display title for an object @see 0.8.4
# File lib/yard/code_objects/base.rb, line 468 def title path end
@return [nil] this object does not turn into an array
# File lib/yard/code_objects/base.rb, line 337 def to_ary; nil end
Default type is the lowercase class name without the “Object” suffix. Override this method to provide a custom object type
@return [Symbol] the type of code object this represents
# File lib/yard/code_objects/base.rb, line 437 def type obj_name = self.class.name.split('::').last obj_name.gsub!(/Object$/, '') obj_name.downcase! obj_name.to_sym end
# File lib/yard/code_objects/base.rb, line 183 def visibility=(v) @visibility = v.to_sym end
Protected Instance Methods
Override this method if your code object subclass does not allow copying of certain attributes.
@return [Array<String>] the list of instance variable names (without
"@" prefix) that should be copied when {#copy_to} is called
@see copy_to
@since 0.8.0
# File lib/yard/code_objects/base.rb, line 587 def copyable_attributes vars = instance_variables.map {|ivar| ivar.to_s[1..-1] } vars -= %w(docstring docstrings namespace name path) vars end
Private Instance Methods
Formats source code by removing leading indentation
@param [String] source the source code to format @return [String] formatted source
# File lib/yard/code_objects/base.rb, line 599 def format_source(source) source = source.chomp last = source.split(/\r?\n/).last indent = last ? last[/^([ \t]*)/, 1].length : 0 source.gsub(/^[ \t]{#{indent}}/, '') end
# File lib/yard/code_objects/base.rb, line 606 def translate_docstring(locale) @docstring.resolve_reference return @docstring if locale.nil? text = I18n::Text.new(@docstring) localized_text = text.translate(locale) docstring = Docstring.new(localized_text, self) @docstring.tags.each do |tag| if tag.is_a?(Tags::Tag) localized_tag = tag.clone localized_tag.text = I18n::Text.new(tag.text).translate(locale) docstring.add_tag(localized_tag) else docstring.add_tag(tag) end end docstring end