class Mustache::Template
You shouldn’t use this class directly.
Ruby.
a Ruby string by transforming Mustache tags into interpolated
The idea is this: when handed a Mustache template, convert it into
A Template is a compiled version of a Mustache template.
def compile(src = @source)
Does the dirty work of transforming a Mustache template into an
def compile(src = @source) "\"#{compile_sections(src)}\"" end
def compile_partial(name)
def compile_partial(name) klass = Mustache.classify(name) if Object.const_defined?(klass) ev("#{klass}.render") else src = File.read("#{@template_path}/#{name}.#{@template_extension}") compile(src)[1..-2] end end
def compile_sections(src)
If false, the section is not displayed.
If true, the section is displayed.
Sections can return true, false, or an enumerable.
{{#sections}}okay{{/sections}}
def compile_sections(src) res = "" while src =~ /#{otag}\#([^\}]*)#{ctag}\s*(.+?)#{otag}\/\1#{ctag}\s*/m # $` = The string to the left of the last successful match res << compile_tags($`) name = $1.strip.to_sym.inspect code = compile($2) ctxtmp = "ctx#{tmpid}" res << ev(<<-compiled) if v = ctx[#{name}] v = [v] if v.is_a?(Hash) # shortcut when passed a single hash if v.respond_to?(:each) #{ctxtmp} = ctx.dup begin r = v.map { |h| ctx.update(h); #{code} }.join rescue TypeError => e raise TypeError, "All elements in {{#{name.to_s[1..-1]}}} are not hashes!" end ctx.replace(#{ctxtmp}) r else #{code} end end compiled # $' = The string to the right of the last successful match src = $' end res << compile_tags(src) end
def compile_tags(src)
3. Comment variable tags - {{! comment}
2. Unescaped variable tags - {{{var}}}
1. Escaped variable tags - {{var}}
In particular we look for four types of tags:
Find and replace all non-section tags.
def compile_tags(src) res = "" while src =~ /#{otag}(=|!|<|\{)?(.+?)\1?#{ctag}+/ res << str($`) case $1 when '!' # ignore comments when '=' self.otag, self.ctag = $2.strip.split(' ', 2) when '<' res << compile_partial($2.strip) when '{' res << utag($2.strip) else res << etag($2.strip) end src = $' end res << str(src) end
def ctag
def ctag @ctag ||= Regexp.escape('}}') end
def ctag=(tag)
def ctag=(tag) @ctag = Regexp.escape(tag) end
def etag(s)
def etag(s) ev("CGI.escapeHTML(ctx[#{s.strip.to_sym.inspect}].to_s)") end
def ev(s)
An interpolation-friendly version of a string, for use within a
def ev(s) "#\{#{s}}" end
def initialize(source, template_path = '.', template_extension = 'html')
Expects a Mustache template as a string along with a template
def initialize(source, template_path = '.', template_extension = 'html') @source = source @template_path = template_path @template_extension = template_extension @tmpid = 0 end
def otag
def otag @otag ||= Regexp.escape('{{') end
def otag=(tag)
def otag=(tag) @otag = Regexp.escape(tag) end
def render(context)
Renders the `@source` Mustache template using the given
def render(context) # Compile our Mustache template into a Ruby string compiled = "def render(ctx) #{compile} end" # Here we rewrite ourself with the interpolated Ruby version of # our Mustache template so subsequent calls are very fast and # can skip the compilation stage. instance_eval(compiled, __FILE__, __LINE__ - 1) # Call the newly rewritten version of #render render(context) end
def str(s)
def str(s) s.inspect[1..-2] end
def tmpid
def tmpid @tmpid += 1 end
def utag(s)
def utag(s) ev("ctx[#{s.strip.to_sym.inspect}]") end