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