lib/liquid/template.rb in liquid-3.0.0.rc1 vs lib/liquid/template.rb in liquid-3.0.0
- old
+ new
@@ -49,17 +49,25 @@
def lookup_class(name)
name.split("::").reject(&:empty?).reduce(Object) { |scope, const| scope.const_get(const) }
end
end
+ attr_reader :profiler
+
class << self
# Sets how strict the parser should be.
# :lax acts like liquid 2.5 and silently ignores malformed tags in most cases.
# :warn is the default and will give deprecation warnings when invalid syntax is used.
# :strict will enforce correct syntax.
attr_writer :error_mode
+ # Sets how strict the taint checker should be.
+ # :lax is the default, and ignores the taint flag completely
+ # :warn adds a warning, but does not interrupt the rendering
+ # :error raises an error when tainted output is used
+ attr_writer :taint_mode
+
def file_system
@@file_system
end
def file_system=(obj)
@@ -76,31 +84,43 @@
def error_mode
@error_mode || :lax
end
+ def taint_mode
+ @taint_mode || :lax
+ end
+
# Pass a module with filter methods which should be available
# to all liquid views. Good for registering the standard library
def register_filter(mod)
Strainer.global_filter(mod)
end
+ def default_resource_limits
+ @default_resource_limits ||= {}
+ end
+
# creates a new <tt>Template</tt> object from liquid source code
+ # To enable profiling, pass in <tt>profile: true</tt> as an option.
+ # See Liquid::Profiler for more information
def parse(source, options = {})
template = Template.new
template.parse(source, options)
end
end
- # creates a new <tt>Template</tt> from an array of tokens. Use <tt>Template.parse</tt> instead
def initialize
- @resource_limits = {}
+ @resource_limits = self.class.default_resource_limits.dup
end
# Parse source code.
# Returns self for easy chaining
def parse(source, options = {})
+ @options = options
+ @profiling = options[:profile]
+ @line_numbers = options[:line_numbers] || @profiling
@root = Document.parse(tokenize(source), DEFAULT_OPTIONS.merge(options))
@warnings = nil
self
end
@@ -128,10 +148,13 @@
# Render takes a hash with local variables.
#
# if you use the same filters over and over again consider registering them globally
# with <tt>Template.register_filter</tt>
#
+ # if profiling was enabled in <tt>Template#parse</tt> then the resulting profiling information
+ # will be available via <tt>Template#profiler</tt>
+ #
# Following options can be passed:
#
# * <tt>filters</tt> : array with local filters
# * <tt>registers</tt> : hash with register variables. Those can be accessed from
# filters and tags and might be useful to integrate liquid more with its host application
@@ -181,11 +204,13 @@
end
begin
# render the nodelist.
# for performance reasons we get an array back here. join will make a string out of it.
- result = @root.render(context)
+ result = with_profiling do
+ @root.render(context)
+ end
result.respond_to?(:join) ? result.join : result
rescue Liquid::MemoryError => e
context.handle_error(e)
ensure
@errors = context.errors
@@ -201,15 +226,41 @@
# Uses the <tt>Liquid::TemplateParser</tt> regexp to tokenize the passed source
def tokenize(source)
source = source.source if source.respond_to?(:source)
return [] if source.to_s.empty?
- tokens = source.split(TemplateParser)
+ tokens = calculate_line_numbers(source.split(TemplateParser))
+
# removes the rogue empty element at the beginning of the array
tokens.shift if tokens[0] and tokens[0].empty?
tokens
end
+ def calculate_line_numbers(raw_tokens)
+ return raw_tokens unless @line_numbers
+
+ current_line = 1
+ raw_tokens.map do |token|
+ Token.new(token, current_line).tap do
+ current_line += token.count("\n")
+ end
+ end
+ end
+
+ def with_profiling
+ if @profiling && !@options[:included]
+ @profiler = Profiler.new
+ @profiler.start
+
+ begin
+ yield
+ ensure
+ @profiler.stop
+ end
+ else
+ yield
+ end
+ end
end
end