module Liquid
# Templates are central to liquid.
# Interpretating templates is a two step process. First you compile the
# source code you got. During compile time some extensive error checking is performed.
# your code should expect to get some SyntaxErrors.
#
# After you have a compiled template you can then render it.
# You can use a compiled template over and over again and keep it cached.
#
# Example:
#
# template = Liquid::Template.parse(source)
# template.render('user_name' => 'bob')
#
class Template
attr_accessor :root
@@file_system = BlankFileSystem.new
def self.file_system
@@file_system
end
def self.file_system=(obj)
@@file_system = obj
end
def self.register_tag(name, klass)
tags[name.to_s] = klass
end
def self.tags
@tags ||= {}
end
# Pass a module with filter methods which should be available
# to all liquid views. Good for registering the standard library
def self.register_filter(mod)
Strainer.global_filter(mod)
end
# creates a new Template object from liquid source code
def self.parse(source)
self.new(tokenize(source))
end
# Uses the Liquid::TokenizationRegexp regexp to tokenize the passed source
def self.tokenize(source)
return [] if source.to_s.empty?
tokens = source.split(TokenizationRegexp)
# removes the rogue empty element at the beginning of the array
tokens.shift if tokens[0] and tokens[0].empty?
tokens
end
# creates a new Template from an array of tokens. Use Template.parse instead
def initialize(tokens = [])
@root = Document.new(tokens)
end
# Render takes a hash with local variables.
#
# if you use the same filters over and over again consider registering them globally
# with Template.register_filter
#
# Following options can be passed:
#
# * filters : array with local filters
# * registers : hash with register variables. Those can be accessed from
# filters and tags and might be useful to integrate liquid more with its host application
#
def render(assigns = {}, options = nil)
options = { :filters => options } unless options.is_a?(Hash)
context = Context.new(assigns, options[:registers])
# Apply all filters
[options[:filters]].flatten.each do |filter|
context.add_filters(filter)
end
# render the nodelist.
# for performance reasons we get a array back here. to_s will make a string out of it
@root.render(context).to_s
end
end
end