Skip to content

Instantly share code, notes, and snippets.

@ernie
Created May 14, 2013 18:22
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ernie/5578218 to your computer and use it in GitHub Desktop.
Save ernie/5578218 to your computer and use it in GitHub Desktop.
Multistache! A multipass rendering example for Mustache.
class DotContext < String
def initialize(val = '.')
val = '.' # Ensure we're always a dot
super
freeze
end
def to_s
self
end
alias :to_str :to_s
def has_key?(key)
true
end
def [](key)
key == :to_s ? self : LaterContext.new(key)
end
end
class LaterContext
def initialize(prefix)
@prefix = prefix
end
def has_key?(key)
true
end
def to_s
@prefix.to_s
end
def [](key)
LaterContext.new([@prefix, key].join('.'))
end
end
class Multistache < Mustache
def self.templateify(obj)
if obj.is_a?(MultistacheTemplate)
obj
else
MultistacheTemplate.new(obj.to_s)
end
end
def self.later(prefix)
LaterContext.new(prefix)
end
end
class MultistacheGenerator < Mustache::Generator
def on_section(name, content, raw, delims)
code = compile(content)
ev(<<-compiled)
if v = #{compile!(name)}
if v == true
#{code}
elsif v.is_a?(Proc)
t = MultistacheTemplate.new(v.call(#{raw.inspect}).to_s)
def t.tokens(src=@source)
p = Parser.new
p.otag, p.ctag = #{delims.inspect}
p.compile(src)
end
t.render(ctx.dup)
elsif v.is_a?(LaterContext)
outside = v.to_s
ctx.push(DotContext.new)
inside = #{code}
ctx.pop
"{{##\{outside}}}#\{inside}{{/#\{outside}}}"
else
# Shortcut when passed non-array
v = [v] unless v.is_a?(Array) || defined?(Enumerator) && v.is_a?(Enumerator)
v.map { |h| ctx.push(h); r = #{code}; ctx.pop; r }.join
end
end
compiled
end
def on_inverted_section(name, content, raw, _)
code = compile(content)
ev(<<-compiled)
v = #{compile!(name)}
if v.is_a?(LaterContext)
outside = v.to_s
inside = #{code}
"{{^#\{outside}}}#\{inside}{{/#\{outside}}}"
elsif v.nil? || v == false || v.respond_to?(:empty?) && v.empty?
#{code}
end
compiled
end
def on_etag(name)
ev(<<-compiled)
v = #{compile!(name)}
if v.is_a?(Proc)
v = MultistacheTemplate.new(v.call.to_s).render(ctx.dup)
end
case v
when LaterContext, DotContext
"{{#\{v.to_s}}}"
else
ctx.escapeHTML(v.to_s)
end
compiled
end
def on_utag(name)
ev(<<-compiled)
v = #{compile!(name)}
if v.is_a?(Proc)
v = MultistacheTemplate.new(v.call.to_s).render(ctx.dup)
end
case v
when LaterContext, DotContext
"{{{#\{v.to_s}}}}"
else
v.to_s
end
compiled
end
end
class MultistacheTemplate < Mustache::Template
def compile(src = @source)
MultistacheGenerator.new.compile(tokens(src))
end
alias_method :to_s, :compile
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment