lib/glyph/macro.rb in glyph-0.4.2 vs lib/glyph/macro.rb in glyph-0.5.0
- old
+ new
@@ -6,18 +6,18 @@
# The Macro class contains shortcut methods to access the current node and document, as well as other
# useful methods to be used in macro definitions.
class Macro
include Validators
- include Helpers
include Utils
- attr_reader :node, :source_name, :source_file, :source_topic
+ attr_reader :node, :source_name, :source_file, :source_topic, :name
# Creates a new macro instance from a Node
# @param [Node] node a node populated with macro data
def initialize(node)
+ @data = {}
@node = node
@name = @node[:name]
@updated_source = nil
@source_name = @node[:source][:name] || nil rescue "--"
@source_topic = @node[:source][:topic] || nil rescue "--"
@@ -32,11 +32,11 @@
# @since 0.3.0
def update_source(name, file=nil, topic=nil)
file ||= @node[:source][:file] rescue nil
@updated_source = {:name => name, :file => file, :topic => topic}
end
-
+
# Returns a Glyph code representation of the specified parameter
# @param [Fixnum] n the index of the parameter
# @return [String, nil] the string representation of the parameter
# @since 0.3.0
def raw_parameter(n)
@@ -107,12 +107,12 @@
def parameters(options={:strip => true, :null_if_blank => true})
return @parameters if @parameters
@parameters = []
@node.parameters.each do |value|
@parameters << value.evaluate(@node, :params => true)
- @parameters.last.strip! if options[:strip]
- @parameters.last = nil if @parameters.last.blank? && options[:null_if_blank]
+ @parameters[@parameters.length-1].strip! if options[:strip]
+ @parameters[@parameters.length-1] = nil if @parameters.last.blank? && options[:null_if_blank]
end
@parameters
end
alias params parameters
@@ -161,11 +161,11 @@
end
macros << name
end
macros.reverse.compact.join('/')
end
-
+
# Returns a todo message to include in the document in case of errors.
# @param [String] message the message to include in the document
# @return [String] the resulting todo message
# @since 0.2.0
def macro_todo(message)
@@ -207,27 +207,14 @@
# Instantiates a Glyph::Interpreter and interprets a string
# @param [String] string the string to interpret
# @return [String] the interpreted output
def interpret(string)
- if @node[:escape] then
- result = string
- else
- context = {}
- context[:source] = @updated_source || @node[:source]
- context[:embedded] = true
- context[:document] = @node[:document]
- interpreter = Glyph::Interpreter.new string, context
- subtree = interpreter.parse
- subtree[:source] = context[:source]
- @node << subtree
- result = interpreter.document.output
- end
- result
+ @node[:escape] ? string : inject(string).document.output
end
- # @see Glyph::Document#placeholder
+ # @see Glyph::Document#placeholder
def placeholder(&block)
@node[:document].placeholder &block
end
# @see Glyph::Document#bookmark
@@ -248,16 +235,101 @@
# @see Glyph::Document#header
def header(hash)
@node[:document].header hash
end
+ # @see Glyph::Document#snippet
+ def snippet(key, value)
+ @node[:document].snippet key, value
+ end
+
+ # @see Glyph::Document#snippet?
+ def snippet?(ident)
+ @node[:document].snippet? ident
+ end
+
+ # @since 0.5.0
+ # Renders a macro representation
+ # @param [Symbol, String] rep the representation to render
+ # @param [Hash] data the data to pass to the representation
+ def render(rep=nil, data=nil)
+ rep ||= @name
+ data ||= @data
+ block = Glyph::REPS[rep.to_sym]
+ macro_error "No macro representation for '#{rep}'", e unless block
+ instance_exec(data, &block).to_s
+ end
+
+ # Stores a block of code to be "dispatched" via macro composition
+ # @since 0.5.0
+ # @example
+ # # Macro definition (Ruby)
+ # macro :greet do
+ # dispatch do |node|
+ # "#{node[:name]}, #{node.param 0}!"
+ # end
+ # end
+ #
+ # # macro usage (Glyph)
+ # greet/Hello[World] --[Outputs: Hello, World!]
+ # greet/GoodBye[John] --[Outputs: Goodbye, John!]
+ def dispatch(&block)
+ @node[:dispatch] = block
+ value
+ end
+
+ # Performs parameter/attribute substitution and interprets text
+ # @since 0.5.0
+ # @param [String] text the text to interpret
+ # @return [String] the interpreted output
+ def apply(text)
+ body = text.dup
+ # Parameters
+ body.gsub!(/\{\{(\d+)\}\}/) do
+ raw_param($1.to_i).to_s.strip
+ end
+ # Attributes
+ body.gsub!(/\{\{([^\[\]\|\\\s]+)\}\}/) do
+ raw_attr($1.to_sym).to_s.strip
+ end
+ interpret body
+ end
+
+ # Parses text and injects the syntax tree into the current node
+ # @since 0.5.0
+ # @param [String] text the text to parse
+ # @return [Glyph::Interpreter] the interpreter instance used to parse text
+ def inject(text)
+ context = create_context
+ interpreter = Glyph::Interpreter.new text, context
+ subtree = interpreter.parse
+ subtree[:source] = context[:source]
+ @node << subtree
+ interpreter
+ end
+
+ # Parses text
+ # @since 0.5.0
+ # @param [String] text the text to parse
+ # @return [Glyph::Node] the syntax tree generated by parsing
+ def parse(text)
+ Glyph::Interpreter.new(text, create_context).parse
+ end
+
# Executes a macro definition in the context of self
def expand
block = Glyph::MACROS[@name]
- macro_error "Undefined macro '#@name'}" unless block
- res = instance_exec(@node, &block).to_s
- res.gsub!(/\\?([\[\]\|])/){"\\#$1"}
- res
+ macro_error "Undefined macro '#@name'" unless block
+ instance_exec(@node, &block).to_s.gsub(/\\?([\[\]\|])/){"\\#$1"}
end
+ private
+
+ def create_context
+ context = {}
+ context[:source] = @updated_source || @node[:source]
+ context[:embedded] = true
+ context[:document] = @node[:document]
+ context
+ end
end
end