lib/yard/code_objects/macro_object.rb in yard-0.7.5 vs lib/yard/code_objects/macro_object.rb in yard-0.8.0

- old
+ new

@@ -1,29 +1,31 @@ +require 'ostruct' + module YARD module CodeObjects - # A MacroObject represents a docstring defined through +@macro NAME+ and can be - # reused by specifying the tag +@macro NAME+. You can also provide the + # A MacroObject represents a docstring defined through +@!macro NAME+ and can be + # reused by specifying the tag +@!macro NAME+. You can also provide the # +attached+ type flag to the macro definition to have it attached to the # specific DSL method so it will be implicitly reused. - # - # Macros are fully described in the {file:docs/Tags.md#macros Tags Overview} + # + # Macros are fully described in the {file:docs/Tags.md#macro Tags Overview} # document. - # + # # @example Creating a basic named macro - # # @macro prop - # # @method $1(${3-}) - # # @return [$2] the value of the $0 + # # @!macro prop + # # @!method $1(${3-}) + # # @return [$2] the value of the $0 # property :foo, String, :a, :b - # - # # @macro prop + # + # # @!macro prop # property :bar, Numeric, :value - # + # # @example Creating a macro that is attached to the method call - # # @macro [attach] prop2 - # # @method $1(value) + # # @!macro [attach] prop2 + # # @!method $1(value) # property :foo - # + # # # Extra data added to docstring # property :bar class MacroObject < Base MACRO_MATCH = /(\\)?\$(?:\{(-?\d+|\*)(-)?(-?\d+)?\}|(-?\d+|\*))/ @@ -38,60 +40,58 @@ obj = new(:root, macro_name) obj.macro_data = data obj.method_object = method_object obj end - + # Finds a macro using +macro_name+ + # @param [#to_s] macro_name the name of the macro # @return [MacroObject] if a macro is found # @return [nil] if there is no registered macro by that name def find(macro_name) Registry.at('.macro.' + macro_name.to_s) end - + # Parses a given docstring and determines if the macro is "new" or - # not. If the macro has $variable names or if it has a @macro tag - # with the [new] or [attached] flag, it is considered new. - # + # not. If the macro has $variable names or if it has a @!macro tag + # with the [new] or [attached] flag, it is considered new. + # # If a new macro is found, the macro is created and registered. Otherwise # the macro name is searched and returned. If a macro is not found, # nil is returned. - # + # + # @param [#to_s] macro_name the name of the macro # @param [CodeObjects::Base] method_object an optional method to attach # the macro to. Only used if the macro is being created, otherwise # this argument is ignored. # @return [MacroObject] the newly created or existing macro, depending - # on whether the @macro tag was a new tag or not. + # on whether the @!macro tag was a new tag or not. # @return [nil] if the +data+ has no macro tag or if the macro is # not new and no macro by the macro name is found. - def find_or_create(data, method_object = nil) - docstring = Docstring === data ? data : Docstring.new(data) - return unless docstring.tag(:macro) - return unless name = macro_name(docstring) - if new_macro?(docstring) - method_object = nil unless attached_macro?(docstring, method_object) - create(name, macro_data(docstring), method_object) + def find_or_create(macro_name, data, method_object = nil) + if macro = find(name) + macro else - find(name) + create(macro_name, data, method_object) end end alias create_docstring find_or_create - + # Expands +macro_data+ using the interpolation parameters. - # + # # Interpolation rules: # * $0, $1, $2, ... = the Nth parameter in +call_params+ # * $* = the full statement source (excluding block) # * Also supports $!{N-M} ranges, as well as negative indexes on N or M # * Use \$ to escape the variable name in a macro. - # - # @macro [new] macro.expand + # + # @!macro [new] macro.expand # @param [Array<String>] call_params the method name and parameters # to the method call. These arguments will fill \$0-N - # @param [String] full_source the full source line (excluding block) + # @param [String] full_source the full source line (excluding block) # interpolated as \$* - # @param [String] block_source Currently unused. Will support + # @param [String] block_source Currently unused. Will support # interpolating the block data as a variable. # @return [String] the expanded macro data # @param [String] macro_data the macro data to expand (taken from {#macro_data}) def expand(macro_data, call_params = [], full_source = '', block_source = '') macro_data = macro_data.all if macro_data.is_a?(Docstring) @@ -111,94 +111,51 @@ end # Applies a macro on a docstring by creating any macro data inside of # the docstring first. Equivalent to calling {find_or_create} and {apply_macro} # on the new macro object. - # + # # @param [Docstring] docstring the docstring to create a macro out of - # @macro macro.expand + # @!macro macro.expand # @see find_or_create def apply(docstring, call_params = [], full_source = '', block_source = '', method_object = nil) - macro = find_or_create(docstring, method_object) - apply_macro(macro, docstring, call_params, full_source, block_source) + docstring = docstring.all if Docstring === docstring + parser = DocstringParser.new + handler = OpenStruct.new + handler.call_params = call_params[1..-1] + handler.caller_method = call_params.first + handler.statement = OpenStruct.new(:source => full_source) + parser.parse(docstring, nil, handler).to_docstring.to_raw end # Applies a macro to a docstring, interpolating the macro's data on the # docstring and appending any extra local docstring data that was in # the original +docstring+ object. - # + # # @param [MacroObject] macro the macro object - # @macro macro.expand + # @!macro macro.expand def apply_macro(macro, docstring, call_params = [], full_source = '', block_source = '') - docstring = Docstring.new(docstring) unless Docstring === docstring - data = [] - data << macro.expand(call_params, full_source, block_source) if macro - if !macro && new_macro?(docstring) - data << expand(macro_data(docstring), call_params, full_source, block_source) - end - data << nonmacro_data(docstring) - data.join("\n").strip + apply(docstring, call_params, full_source, block_source) end - - private - - def new_macro?(docstring) - if docstring.tag(:macro) - if types = docstring.tag(:macro).types - return true if types.include?('new') || types.include?('attach') - end - if docstring.all =~ MACRO_MATCH - return true - end - end - false - end - - def attached_macro?(docstring, method_object) - return false if method_object.nil? - return false if docstring.tag(:macro).types.nil? - docstring.tag(:macro).types.include?('attach') - end - - def macro_name(docstring) - docstring.tag(:macro).name - end - - def macro_data(docstring) - new_docstring = docstring.dup - new_docstring.delete_tags(:macro) - tag_text = docstring.tag(:macro).text - if !tag_text || tag_text.strip.empty? - new_docstring.to_raw.strip - else - tag_text - end - end - - def nonmacro_data(docstring) - if new_macro?(docstring) - text = docstring.tag(:macro).text - return '' if !text || text.strip.empty? - end - new_docstring = docstring.dup - new_docstring.delete_tags(:macro) - new_docstring.to_raw - end end - + # @return [String] the macro data stored on the object attr_accessor :macro_data - + # @return [CodeObjects::Base] the method object that this macro is # attached to. attr_accessor :method_object - + # @return [Boolean] whether this macro is attached to a method def attached?; method_object ? true : false end + + # Overrides {Base#path} so the macro path is ".macro.MACRONAME" def path; '.macro.' + name.to_s end + + # Overrides the separator to be '.' def sep; '.' end - - # Expands the macro using + + # Expands the macro using # @param [Array<String>] call_params a list of tokens that are passed # to the method call # @param [String] full_source the full method call (not including the block) # @param [String] block_source the source passed in the block of the method # call, if there is a block. \ No newline at end of file