class YARD::Tags::MacroDirective

@since 0.7.0
end
property :view_count, Integer
# Macro will expand on this definition too
property :title, String
# @return [$2] the $1 property
# @!macro [attach] property
class Post < Resource
@example Attaching a macro directly to a DSL method
end
property :view_count, Integer
property :title, String
class Post < Resource
end
def self.property(name, type) end
# @return [$2] the $1 property
# @!macro [attach] property
# @param [Class] type the property’s type
# @param [String] name the property name
# Defines a new property
class Resource
@example Attaching a macro to a class method (for DSL usage)
def filter; end
# @macro returnself
# …
# Documentation for filter
def map; end
# @macro returnself
# …
# Documentation for map
@example Using a simple macro in multiple docstrings
# @return [self] returns itself
# @!macro [new] returnself
@example Defining a simple macro
# I have $2.00 USD.
# @!macro foo
Interpolation can be escaped by prefixing the +$+ with +\+, like so:
=== Escaping Interpolation
so it would be safe to list $1 $2 ... $10, for example.
if the token cannot be expanded, it will return the empty string (not an error),
If you want to separate them with spaces, use $1 $2 $3 $4 .... Note that
$0-1 # => Interpolates to “create_method_with_args, foo”
!!!plain
with commas. Note that this includes using $0:
type from the last argument, String. When using ranges, tokens are joined
As described, the method is using the signature foo(a, b, c) and the return
create_method_with_args :foo, :a, :b, :c, String
# @return [${-1}] the return value of $0
# @!method $1(${2–2})
# @!macro dsl_method
could be documented as:
argument names following, ending with the return type of the method. This
Consider a DSL method that creates a method using the first argument with
on either N or M are valid, and refer to indexes from the end of the list.
Ranges are also acceptable with the syntax ${N-M}. Negative values
=== Ranges
# $& => “property :foo, :a, :b, :c, String”
# $2 => “a”
# $1 => “foo”
# $0 => “property”
property :foo, :a, :b, :c, String
DSL method call:
The following example shows what the expansion variables might hold for a given
* $& - the full source line
* $1, $2, $3, … - the Nth argument in the method call
* $0 - the method name being called
similar in syntax to Ruby’s global variables, are as follows:
variables can be used for interpolation inside of the macro data. The variables,
In the case of using macros on DSL-style method calls, a number of expansion
== Macro Expansion Variables
is the same.
that provides the DSL method to its subclasses. The syntax in either case
Attached macros can also be attached directly on the class method declaration
in the type specifier list (“new” is implied).
define a macro to be auto expanded in this way, use the “attach” keyword
Macros can be defined to auto-expand on DSL-style class method calls. To
== Attaching a Macro to a DSL Method
data will be expanded in place.
@!macro the_name with no indented block of macro data. The resulting
To re-use a macro in another docstring after it is defined, simply use
== Using a Macro
to take advantage of the macro expansion variables (described below).
but they will expand in the first definition. This is useful when needing
no name is given. In this case, they can not be re-used in future docstrings,
In addition to standard named macros, macros can be defined anonymously if
=== Anonymous Macros
indented macro data block is given, so the keywords are not strictly needed.
types specifier list. A macro will also automatically be created if an
comment). To define a macro, use the “new” or “attach” identifier in the
method, class, module or constant object as opposed to a free standing
expanded upon definition if it defined on an object (the docstring of a
A macro must first be defined in order to be used. Note that a macro is also
== Defining a Macro
it regular documentation, meta-data tags or directives.
in subsequent docstrings. The macro data can be any arbitrary text data, be
Defines a block of text to be expanded whenever the macro is called by name

def anonymous?

def anonymous?
  tag.name.nil? || tag.name.empty?
end

def attach?

def attach?
  new? && # must have data or there is nothing to attach
    class_method? || # always attach to class methods
    (tag.types && tag.types.include?('attach'))
end

def call

def call
  raise TagFormatError if tag.name.nil? && tag.text.to_s.empty?
  macro_data = find_or_create
  unless macro_data
    warn
    return
  end
  self.expanded_text = expand(macro_data)
end

def class_method?

def class_method?
  object && object.is_a?(CodeObjects::MethodObject) &&
    object.scope == :class
end

def expand(macro_data)

def expand(macro_data)
  return if attach? && class_method?
  return if !anonymous? && new? &&
            (!handler || handler.statement.source.empty?)
  call_params = []
  caller_method = nil
  full_source = ''
  if handler
    call_params = handler.call_params
    caller_method = handler.caller_method
    full_source = handler.statement.source
  end
  all_params = ([caller_method] + call_params).compact
  CodeObjects::MacroObject.expand(macro_data, all_params, full_source)
end

def find_or_create

def find_or_create
  if new? || attach?
    if handler && attach?
      if object && object.is_a?(CodeObjects::NamespaceObject)
        log.warn "Attaching macros to non-methods is unsupported, ignoring: " \
                 "#{object.path} (#{handler.parser.file}:#{handler.statement.line})"
        obj = nil
      else
        obj = object ? object :
          P("#{handler.namespace}.#{handler.caller_method}")
      end
    else
      obj = nil
    end
    return tag.text || "" if anonymous? # anonymous macro
    macro = CodeObjects::MacroObject.create(tag.name, tag.text, obj)
  else
    macro = CodeObjects::MacroObject.find(tag.name)
  end
  macro ? macro.macro_data : nil
end

def new?

def new?
  (tag.types && tag.types.include?('new')) ||
    (tag.text && !tag.text.strip.empty?)
end

def warn

def warn
  if object && handler
    log.warn "Invalid/missing macro name for " \
             "#{object.path} (#{handler.parser.file}:#{handler.statement.line})"
  end
end