class YARD::Handlers::Base

@see #parse_block
@see #register
@see #owner
@see #namespace
@see handles
@see CodeObjects::NamespaceObject
@see CodeObjects::Base
during the processing phase.
@abstract Subclass this class to provide a handler for YARD to use
invoked explicitly out of efficiency sake.
even if statements. For this reason, the block parsing method must be
YARD has the ability to continue into any block: class, module, method,
the namespace now pointing to the class object the handler created.
{#parse_block} method to continue parsing code inside the block, with
the class. For a class handler, the programmer would execute the
would be a list of statements including the method definitions inside
For example, a class statement would be “class MyClass” and the block
statement or classic ‘Ruby block’.
of any statement, be it class definition, module definition, if
block (if there is one). In this context, a block means the inside
handlers may wish to continue parsing the code inside the statement’s
In addition to parsing a statement and creating new objects, some
== Parsing Blocks in Statements
of the current parsing position.
refer to the public/protected/private and class/instance values (respectively)
Mainly needed for parsing methods, the visibility and scope attributes
=== visibility and scope Attributes
second-class Ruby objects (methods).
of as the difference between first-class Ruby objects (namespaces) and
In summary, the distinction between namespace and owner can be thought
to the correct namespace (the class, not the method).
definitions set inside a method (def x; def y; 2 end end) by adding them
set to the class. This would allow the developer to process any method
the owner would be set to the method object but the namespace would remain
handler was added to the mix and decided to parse inside the method body,
To put this into context, the example from above will be used. If a method
so the owner attribute would not be limited to modules and classes.
to parse beyond module and class blocks (inside methods, for instance),
object is loosely defined as a module or class and YARD has the ability
it also follows the scope of the code during parsing. However, a namespace
The owner attribute is similar to the namespace attribute in that
=== owner Attribute
code object.
called on the method, the namespace would be set to the ‘MyClass’
a statement. If the class was then entered and another handler was
This is the value that namespace would return when processing such
be necessary to know that it belonged inside the SomeModule module.
If a handler was to parse the ‘class MyClass’ statement, it would
end
end
def mymethod; end
class MyClass
module SomeModule
which represents the current namespace that the parser is in. For instance:
The namespace attribute is a {CodeObjects::NamespaceObject namespace object}
=== namespace Attribute
regular expressions (or other text processing mechanisms), if needed.
can be converted to a String using #to_s to parse the data with
the data to be processed will live in the tokens attribute. This list
can be accessed by the {Parser::Ruby::Legacy::Statement#comments} method, but generally
of data to be analyzed and processed. The comments attached to the statement
containing a set of tokens parsed in by the parser. This is the main set
The statement attribute pertains to the {Parser::Ruby::Legacy::Statement} object
=== statement Attribute
it.
it is important to know where the data is coming from to be able to use
such there is no real guideline on how to process the data. However,
The goal of a specific handler is really up to the developer, and as
== Processing Handler Data
end
end
# do something
def process
handles TkMODULE
class MyModuleHandler < YARD::Handlers::Base
Here is a simple example which processes module statements.
declaration, taking either a {Parser::Ruby::Legacy::RubyToken}, {String} or ‘Regexp`.
which statement the handler will process. This is done with the handles
base class. The only other thing that needs to be done is to specify
A Handler is automatically registered when it is subclassed from the
== Setting up a Handler for Use
and register a new object or add new attributes to the current namespace.
Handlers are usually simple and take up to a page of code to process
sets some basic attributes for the new objects.
which case they should be registered by {#register}, a method that
{CodeObjects::Base code objects} or the creation of new ones, in
usually involve the manipulation of the {#namespace}, {#owner}
implement the {#process} method to do the work. The processing would
it will handle using the {handles} class declaration. It will then
Generally, a handler class will declare a set of statements which
== Overview of a Typical Handler Scenario
class objects in any outputted documentation.
documentation in a very explicit format by treating them as first-
takes advantage of class level declarations could add these to the
adding a handler for such a keyword. Similarly, any Ruby API that
the ’describe’ declaration of the RSpec testing framework by simply
of this would be the ability to document and generate meta data for
any Ruby DSLs that a customized framework may use. A good example
generated by YARD, giving them the ability to, for instance, document
phase. They allow developers to control what information gets
Handlers are pluggable semantic parsers for YARD’s code generation

def abort!

Other tags:
    Since: - 0.8.4
def abort!
  raise Handlers::HandlerAborted
end

def call_params

Returns:
  • (Array) - a list of argument names

Other tags:
    Abstract: - Implement this method to return the parameters in a method call
def call_params
  raise NotImplementedError
end

def caller_method

Returns:
  • (nil) - if the statement is not a method call
  • (String) - the method name being called

Other tags:
    Abstract: - Implement this method to return the method being called in
def caller_method
  raise NotImplementedError
end

def clear_subclasses

Returns:
  • (void) -
def clear_subclasses
  @@subclasses = []
end

def ensure_loaded!(object, max_retries = 1)

Raises:
  • (NamespaceMissingError) - if the object is not resolved within

Parameters:
  • max_retries (Integer) -- the number of times to defer the handler
  • object (Proxy, CodeObjects::Base) -- the object to resolve.

Other tags:
    Example: Adding a mixin to the String class programmatically -
def ensure_loaded!(object, max_retries = 1)
  return if object.root?
  return object unless object.is_a?(Proxy)
  retries = 0
  while object.is_a?(Proxy)
    raise NamespaceMissingError, object if retries > max_retries
    log.debug "Missing object #{object} in file `#{parser.file}', moving it to the back of the line."
    parser.parse_remaining_files
    retries += 1
  end
  object
end

def extra_state; parser.extra_state end

def extra_state; parser.extra_state end

def globals; parser.globals end

def globals; parser.globals end

def handlers

Other tags:
    See: handles? -

Returns:
  • (Array) - a list of matchers for the handler object.
def handlers
  @handlers ||= []
end

def handles(*matches)

Parameters:
  • matches (Parser::Ruby::Legacy::RubyToken, Symbol, String, Regexp) --
def handles(*matches)
  (@handlers ||= []).concat(matches)
end

def handles?(statement) # rubocop:disable Lint/UnusedMethodArgument

Returns:
  • (Boolean) - whether or not this handler object should process

Parameters:
  • statement () -- a statement object or node (depends on language type)
def handles?(statement) # rubocop:disable Lint/UnusedMethodArgument
  raise NotImplementedError, "override #handles? in a subclass"
end

def in_file(filename)

Other tags:
    Since: - 0.6.2

Returns:
  • (void) -

Parameters:
  • filename (String, Regexp) -- a matching filename or regex
def in_file(filename)
  (@in_files ||= []) << filename
end

def inherited(subclass)

def inherited(subclass)
  @@subclasses ||= []
  @@subclasses << subclass
end

def initialize(source_parser, stmt)

def initialize(source_parser, stmt)
  @parser = source_parser
  @statement = stmt
end

def matches_file?(filename)

Other tags:
    Since: - 0.6.2

Returns:
  • (Boolean) - whether the filename matches the declared file
def matches_file?(filename)
  @in_files ||= nil # avoid ruby warnings
  return true unless @in_files
  @in_files.any? do |in_file|
    case in_file
    when String
      File.basename(filename) == in_file
    when Regexp
      filename =~ in_file
    else
      true
    end
  end
end

def namespace; parser.namespace end

def namespace; parser.namespace end

def namespace=(v); parser.namespace = v end

def namespace=(v); parser.namespace = v end

def namespace_only

Returns:
  • (void) -
def namespace_only
  @namespace_only = true
end

def namespace_only?

Returns:
  • (Boolean) - whether the handler should only be processed inside
def namespace_only?
  @namespace_only ||= false
end

def owner; parser.owner end

def owner; parser.owner end

def owner=(v) parser.owner = v end

def owner=(v) parser.owner = v end

def parse_block(*)

Other tags:
    Abstract: - Subclasses should call {Processor#process parser.process}
def parse_block(*)
  raise NotImplementedError, "#{self} did not implement a #parse_block method for handling"
end

def process(&block)

Other tags:
    Since: - 0.5.4

Returns:
  • (void) -
  • (void) -

Other tags:
    See: #process -
def process(&block)
  mod = Module.new
  mod.send(:define_method, :process, &block)
  include mod
end

def process

Other tags:
    See: #register -
    See: handles -

Returns:
  • (Array, CodeObjects::Base, Object) -
def process
  raise NotImplementedError, "#{self} did not implement a #process method for handling."
end

def push_state(opts = {})

Other tags:
    Yield: - a block to execute with the given state values.

Options Hash: (**opts)
  • :owner (CodeObjects::Base) --
  • :scope (Symbol) --
  • :namespace (CodeObjects::NamespaceObject) --
def push_state(opts = {})
  opts = {
    :namespace => namespace,
    :scope => :instance,
    :owner => owner || namespace,
    :visibility => nil
  }.update(opts)
  ns = namespace
  vis = visibility
  sc = scope
  oo = owner
  self.namespace = opts[:namespace]
  self.visibility = opts[:visibility] || :public
  self.scope = opts[:scope]
  self.owner = opts[:owner]
  yield
  self.namespace = ns
  self.visibility = vis
  self.scope = sc
  self.owner = oo
end

def register(*objects)

Returns:
  • (CodeObjects::Base, Array) -

Parameters:
  • objects (Array) --
def register(*objects)
  objects.flatten.each do |object|
    next unless object.is_a?(CodeObjects::Base)
    register_ensure_loaded(object)
    yield(object) if block_given?
    register_file_info(object)
    register_source(object)
    register_visibility(object)
    register_docstring(object)
    register_group(object)
    register_dynamic(object)
    register_module_function(object)
  end
  objects.size == 1 ? objects.first : objects
end

def register_docstring(object, docstring = statement.comments, stmt = statement)

Other tags:
    Since: - 0.8.0

Returns:
  • (void) -

Parameters:
  • object (CodeObjects::Base) -- the object to register
def register_docstring(object, docstring = statement.comments, stmt = statement)
  docstring = docstring.join("\n") if Array === docstring
  parser = Docstring.parser
  parser.parse(docstring || "", object, self)
  if object && docstring
    object.docstring = parser.to_docstring
    # Add hash_flag/line_range
    if stmt
      object.docstring.hash_flag = stmt.comments_hash_flag
      object.docstring.line_range = stmt.comments_range
    end
  end
  register_transitive_tags(object)
end

def register_dynamic(object)

Other tags:
    Since: - 0.8.0

Returns:
  • (void) -

Parameters:
  • object (CodeObjects::Base) -- the object to register
def register_dynamic(object)
  object.dynamic = true if owner != namespace
end

def register_ensure_loaded(object)

Other tags:
    Since: - 0.8.0

Returns:
  • (void) -

Parameters:
  • object (CodeObjects::Base) -- the object to register
def register_ensure_loaded(object)
  ensure_loaded!(object.namespace)
  object.namespace.children << object
rescue NamespaceMissingError
  nil # noop
end

def register_file_info(object, file = parser.file, line = statement.line, comments = statement.comments)

Other tags:
    Since: - 0.8.0

Returns:
  • (void) -

Parameters:
  • object (CodeObjects::Base) -- the object to register
def register_file_info(object, file = parser.file, line = statement.line, comments = statement.comments)
  object.add_file(file, line, comments)
end

def register_group(object, group = extra_state.group)

Other tags:
    Since: - 0.8.0

Returns:
  • (void) -

Parameters:
  • object (CodeObjects::Base) -- the object to register
def register_group(object, group = extra_state.group)
  if group
    unless object.namespace.is_a?(Proxy)
      object.namespace.groups |= [group]
    end
    object.group = group
  end
end

def register_module_function(object)

Other tags:
    Since: - 0.8.0

Parameters:
  • object (CodeObjects::Base) -- the possible module function object
def register_module_function(object)
  return unless object.is_a?(MethodObject)
  return unless object.module_function?
  modobj = MethodObject.new(object.namespace, object.name)
  object.copy_to(modobj)
  modobj.visibility = :private # rubocop:disable Lint/UselessSetterCall
end

def register_source(object, source = statement, type = parser.parser_type)

Other tags:
    Since: - 0.8.0

Returns:
  • (void) -

Parameters:
  • object (CodeObjects::Base) -- the object to register
def register_source(object, source = statement, type = parser.parser_type)
  return unless object.is_a?(MethodObject)
  object.source ||= source
  object.source_type = type
end

def register_transitive_tags(object)

Other tags:
    Since: - 0.8.0

Returns:
  • (void) -

Parameters:
  • object (CodeObjects::Base, nil) -- the object to register
def register_transitive_tags(object)
  return unless object && !object.namespace.is_a?(Proxy)
  Tags::Library.transitive_tags.each do |tag|
    next unless object.namespace.has_tag?(tag)
    next if object.has_tag?(tag)
    object.add_tag(*object.namespace.tags(tag))
  end
end

def register_visibility(object, visibility = self.visibility)

Other tags:
    Since: - 0.8.0

Parameters:
  • visibility (Symbol) -- the visibility to set on the object
  • object (#visibility=) -- the object to register
def register_visibility(object, visibility = self.visibility)
  return unless object.respond_to?(:visibility=)
  return if object.is_a?(NamespaceObject)
  object.visibility = visibility
end

def scope; parser.scope end

def scope; parser.scope end

def scope=(v); parser.scope = v end

def scope=(v); parser.scope = v end

def subclasses

Returns:
  • (Array) - a list of handlers
def subclasses
  @@subclasses ||= []
end

def visibility; parser.visibility end

def visibility; parser.visibility end

def visibility=(v); parser.visibility = v end

def visibility=(v); parser.visibility = v end