mirror of
https://github.com/Shopify/liquid.git
synced 2026-09-16 17:30:43 -07:00
Merge remote-tracking branch 'upstream/master' into correct-if-nodelists
Conflicts: test/liquid/tags/for_tag_test.rb test/liquid/tags/if_else_tag_test.rb
This commit is contained in:
+1
-1
@@ -135,7 +135,7 @@ module Liquid
|
||||
end
|
||||
|
||||
token_output = (token.respond_to?(:render) ? token.render(context) : token)
|
||||
context.resource_limits[:render_length_current] += (token_output.respond_to?(:length) ? token_output.length : 1)
|
||||
context.increment_used_resources(:render_length_current, token_output)
|
||||
if context.resource_limits_reached?
|
||||
context.resource_limits[:reached] = true
|
||||
raise MemoryError.new("Memory limits exceeded")
|
||||
|
||||
+21
-3
@@ -25,6 +25,15 @@ module Liquid
|
||||
squash_instance_assigns_with_environments
|
||||
|
||||
@interrupts = []
|
||||
@filters = []
|
||||
end
|
||||
|
||||
def increment_used_resources(key, obj)
|
||||
@resource_limits[key] += if obj.class.ancestors & [ String, Array, Hash ] != []
|
||||
obj.length
|
||||
else
|
||||
1
|
||||
end
|
||||
end
|
||||
|
||||
def resource_limits_reached?
|
||||
@@ -34,7 +43,7 @@ module Liquid
|
||||
end
|
||||
|
||||
def strainer
|
||||
@strainer ||= Strainer.create(self)
|
||||
@strainer ||= Strainer.create(self, @filters)
|
||||
end
|
||||
|
||||
# Adds filters to this context.
|
||||
@@ -43,11 +52,20 @@ module Liquid
|
||||
# for that
|
||||
def add_filters(filters)
|
||||
filters = [filters].flatten.compact
|
||||
|
||||
filters.each do |f|
|
||||
raise ArgumentError, "Expected module but got: #{f.class}" unless f.is_a?(Module)
|
||||
Strainer.add_known_filter(f)
|
||||
strainer.extend(f)
|
||||
end
|
||||
|
||||
# If strainer is already setup then there's no choice but to use a runtime
|
||||
# extend call. If strainer is not yet created, we can utilize strainers
|
||||
# cached class based API, which avoids busting the method cache.
|
||||
if @strainer
|
||||
filters.each do |f|
|
||||
strainer.extend(f)
|
||||
end
|
||||
else
|
||||
@filters.concat filters
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
+4
-5
@@ -59,13 +59,12 @@ module Liquid
|
||||
# Check for method existence without invoking respond_to?, which creates symbols
|
||||
def self.invokable?(method_name)
|
||||
unless @invokable_methods
|
||||
# Ruby 1.8 compatibility: call to_s on method names (which are strings in 1.8, but already symbols in 1.9)
|
||||
blacklist = (Liquid::Drop.public_instance_methods + [:each]).map(&:to_s)
|
||||
blacklist = Liquid::Drop.public_instance_methods + [:each]
|
||||
if include?(Enumerable)
|
||||
blacklist += Enumerable.public_instance_methods.map(&:to_s)
|
||||
blacklist -= [:sort, :count, :first, :min, :max, :include?].map(&:to_s)
|
||||
blacklist += Enumerable.public_instance_methods
|
||||
blacklist -= [:sort, :count, :first, :min, :max, :include?]
|
||||
end
|
||||
whitelist = [:to_liquid] + (public_instance_methods.map(&:to_s) - blacklist.map(&:to_s))
|
||||
whitelist = [:to_liquid] + (public_instance_methods - blacklist)
|
||||
@invokable_methods = Set.new(whitelist.map(&:to_s))
|
||||
end
|
||||
@invokable_methods.include?(method_name.to_s)
|
||||
|
||||
@@ -31,11 +31,22 @@ module Liquid
|
||||
# file_system.full_path("mypartial") # => "/some/path/_mypartial.liquid"
|
||||
# file_system.full_path("dir/mypartial") # => "/some/path/dir/_mypartial.liquid"
|
||||
#
|
||||
# Optionally in the second argument you can specify a custom pattern for template filenames.
|
||||
# The Kernel::sprintf format specification is used.
|
||||
# Default pattern is "_%s.liquid".
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# file_system = Liquid::LocalFileSystem.new("/some/path", "%s.html")
|
||||
#
|
||||
# file_system.full_path("index") # => "/some/path/index.html"
|
||||
#
|
||||
class LocalFileSystem
|
||||
attr_accessor :root
|
||||
|
||||
def initialize(root)
|
||||
def initialize(root, pattern = "_%s.liquid")
|
||||
@root = root
|
||||
@pattern = pattern
|
||||
end
|
||||
|
||||
def read_template_file(template_path, context)
|
||||
@@ -49,9 +60,9 @@ module Liquid
|
||||
raise FileSystemError, "Illegal template name '#{template_path}'" unless template_path =~ /^[^.\/][a-zA-Z0-9_\/]+$/
|
||||
|
||||
full_path = if template_path.include?('/')
|
||||
File.join(root, File.dirname(template_path), "_#{File.basename(template_path)}.liquid")
|
||||
File.join(root, File.dirname(template_path), @pattern % File.basename(template_path))
|
||||
else
|
||||
File.join(root, "_#{template_path}.liquid")
|
||||
File.join(root, @pattern % template_path)
|
||||
end
|
||||
|
||||
raise FileSystemError, "Illegal template path '#{File.expand_path(full_path)}'" unless File.expand_path(full_path) =~ /^#{File.expand_path(root)}/
|
||||
|
||||
@@ -23,7 +23,7 @@ module Liquid
|
||||
from = @attributes['offset'] ? context[@attributes['offset']].to_i : 0
|
||||
to = @attributes['limit'] ? from + context[@attributes['limit']].to_i : nil
|
||||
|
||||
collection = Utils.slice_collection_using_each(collection, from, to)
|
||||
collection = Utils.slice_collection(collection, from, to)
|
||||
|
||||
length = collection.length
|
||||
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@ module Liquid
|
||||
|
||||
private
|
||||
def interpolate(name, vars)
|
||||
name.gsub(/%{(\w+)}/) {
|
||||
name.gsub(/%\{(\w+)\}/) {
|
||||
# raise TranslationError, "Undefined key #{$1} for interpolation in translation #{name}" unless vars[$1.to_sym]
|
||||
"#{vars[$1.to_sym]}"
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ module Liquid
|
||||
SINGLE_STRING_LITERAL = /'[^\']*'/
|
||||
DOUBLE_STRING_LITERAL = /"[^\"]*"/
|
||||
NUMBER_LITERAL = /-?\d+(\.\d+)?/
|
||||
DOTDOT = /\.\./
|
||||
COMPARISON_OPERATOR = /==|!=|<>|<=?|>=?|contains/
|
||||
|
||||
def initialize(input)
|
||||
@@ -32,6 +33,7 @@ module Liquid
|
||||
when t = @ss.scan(DOUBLE_STRING_LITERAL) then [:string, t]
|
||||
when t = @ss.scan(NUMBER_LITERAL) then [:number, t]
|
||||
when t = @ss.scan(IDENTIFIER) then [:id, t]
|
||||
when t = @ss.scan(DOTDOT) then [:dotdot, t]
|
||||
else
|
||||
c = @ss.getch
|
||||
if s = SPECIALS[c]
|
||||
|
||||
@@ -53,8 +53,7 @@ module Liquid
|
||||
elsif token.first == :open_round
|
||||
consume
|
||||
first = expression
|
||||
consume(:dot)
|
||||
consume(:dot)
|
||||
consume(:dotdot)
|
||||
last = expression
|
||||
consume(:close_round)
|
||||
"(#{first}..#{last})"
|
||||
|
||||
@@ -4,6 +4,8 @@ require 'bigdecimal'
|
||||
module Liquid
|
||||
|
||||
module StandardFilters
|
||||
HTML_ESCAPE = { '&' => '&', '>' => '>', '<' => '<', '"' => '"', "'" => ''' }
|
||||
HTML_ESCAPE_ONCE_REGEXP = /["><']|&(?!([a-zA-Z]+|(#\d+));)/
|
||||
|
||||
# Return the size of an array or of an string
|
||||
def size(input)
|
||||
@@ -31,9 +33,7 @@ module Liquid
|
||||
end
|
||||
|
||||
def escape_once(input)
|
||||
ActionView::Helpers::TagHelper.escape_once(input)
|
||||
rescue NameError
|
||||
input
|
||||
input.to_s.gsub(HTML_ESCAPE_ONCE_REGEXP, HTML_ESCAPE)
|
||||
end
|
||||
|
||||
alias_method :h, :escape
|
||||
@@ -43,8 +43,7 @@ module Liquid
|
||||
if input.nil? then return end
|
||||
l = length.to_i - truncate_string.length
|
||||
l = 0 if l < 0
|
||||
truncated = RUBY_VERSION[0,3] == "1.8" ? input.scan(/./mu)[0...l].to_s : input[0...l]
|
||||
input.length > length.to_i ? truncated + truncate_string : input
|
||||
input.length > length.to_i ? input[0...l] + truncate_string : input
|
||||
end
|
||||
|
||||
def truncatewords(input, words = 15, truncate_string = "...")
|
||||
@@ -245,12 +244,17 @@ module Liquid
|
||||
apply_operation(input, operand, :%)
|
||||
end
|
||||
|
||||
def default(input, default_value = "")
|
||||
is_blank = input.respond_to?(:empty?) ? input.empty? : !input
|
||||
is_blank ? default_value : input
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def flatten_if_necessary(input)
|
||||
ary = if input.is_a?(Array)
|
||||
input.flatten
|
||||
elsif input.kind_of?(Enumerable)
|
||||
elsif input.is_a?(Enumerable) && !input.is_a?(Hash)
|
||||
input
|
||||
else
|
||||
[input].flatten
|
||||
|
||||
+12
-4
@@ -11,6 +11,11 @@ module Liquid
|
||||
@@filters = []
|
||||
@@known_filters = Set.new
|
||||
@@known_methods = Set.new
|
||||
@@strainer_class_cache = Hash.new do |hash, filters|
|
||||
hash[filters] = Class.new(Strainer) do
|
||||
filters.each { |f| include f }
|
||||
end
|
||||
end
|
||||
|
||||
def initialize(context)
|
||||
@context = context
|
||||
@@ -32,10 +37,13 @@ module Liquid
|
||||
end
|
||||
end
|
||||
|
||||
def self.create(context)
|
||||
strainer = Strainer.new(context)
|
||||
@@filters.each { |m| strainer.extend(m) }
|
||||
strainer
|
||||
def self.strainer_class_cache
|
||||
@@strainer_class_cache
|
||||
end
|
||||
|
||||
def self.create(context, filters = [])
|
||||
filters = @@filters + filters
|
||||
strainer_class_cache[filters].new(context)
|
||||
end
|
||||
|
||||
def invoke(method, *args)
|
||||
|
||||
+1
-1
@@ -31,7 +31,7 @@ module Liquid
|
||||
end
|
||||
|
||||
def blank?
|
||||
@blank || true
|
||||
@blank || false
|
||||
end
|
||||
|
||||
def parse_with_selected_parser(markup)
|
||||
|
||||
@@ -25,10 +25,13 @@ module Liquid
|
||||
def render(context)
|
||||
val = @from.render(context)
|
||||
context.scopes.last[@to] = val
|
||||
context.resource_limits[:assign_score_current] += (val.respond_to?(:length) ? val.length : 1)
|
||||
context.increment_used_resources(:assign_score_current, val)
|
||||
''
|
||||
end
|
||||
|
||||
def blank?
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
Template.register_tag('assign', Assign)
|
||||
|
||||
@@ -27,7 +27,7 @@ module Liquid
|
||||
def render(context)
|
||||
output = super
|
||||
context.scopes.last[@to] = output
|
||||
context.resource_limits[:assign_score_current] += (output.respond_to?(:length) ? output.length : 1)
|
||||
context.increment_used_resources(:assign_score_current, output)
|
||||
''
|
||||
end
|
||||
|
||||
|
||||
@@ -4,6 +4,9 @@ module Liquid
|
||||
''
|
||||
end
|
||||
|
||||
def unknown_tag(tag, markup, tokens)
|
||||
end
|
||||
|
||||
def blank?
|
||||
true
|
||||
end
|
||||
|
||||
@@ -83,8 +83,7 @@ module Liquid
|
||||
limit = context[@attributes['limit']]
|
||||
to = limit ? limit.to_i + from : nil
|
||||
|
||||
|
||||
segment = Utils.slice_collection_using_each(collection, from, to)
|
||||
segment = Utils.slice_collection(collection, from, to)
|
||||
|
||||
return render_else(context) if segment.empty?
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ module Liquid
|
||||
class If < Block
|
||||
Syntax = /(#{QuotedFragment})\s*([=!<>a-z_]+)?\s*(#{QuotedFragment})?/o
|
||||
ExpressionsAndOperators = /(?:\b(?:\s?and\s?|\s?or\s?)\b|(?:\s*(?!\b(?:\s?and\s?|\s?or\s?)\b)(?:#{QuotedFragment}|\S+)\s*)+)/o
|
||||
BOOLEAN_OPERATORS = %w(and or)
|
||||
|
||||
def initialize(tag_name, markup, tokens)
|
||||
@blocks = []
|
||||
@@ -67,7 +68,8 @@ module Liquid
|
||||
raise(SyntaxError.new(options[:locale].t("errors.syntax.if"))) unless expressions.shift.to_s =~ Syntax
|
||||
|
||||
new_condition = Condition.new($1, $2, $3)
|
||||
new_condition.send(operator.to_sym, condition)
|
||||
raise(SyntaxError.new(options[:locale].t("errors.syntax.if"))) unless BOOLEAN_OPERATORS.include?(operator)
|
||||
new_condition.send(operator, condition)
|
||||
condition = new_condition
|
||||
end
|
||||
|
||||
|
||||
@@ -51,13 +51,14 @@ module Liquid
|
||||
context[key] = context[value]
|
||||
end
|
||||
|
||||
context_variable_name = @template_name[1..-2].split('/').last
|
||||
if variable.is_a?(Array)
|
||||
variable.collect do |var|
|
||||
context[@template_name[1..-2]] = var
|
||||
context[context_variable_name] = var
|
||||
partial.render(context)
|
||||
end
|
||||
else
|
||||
context[@template_name[1..-2]] = variable
|
||||
context[context_variable_name] = variable
|
||||
partial.render(context)
|
||||
end
|
||||
end
|
||||
|
||||
+13
-4
@@ -1,5 +1,18 @@
|
||||
module Liquid
|
||||
module Utils
|
||||
|
||||
def self.slice_collection(collection, from, to)
|
||||
if (from != 0 || to != nil) && collection.respond_to?(:load_slice)
|
||||
collection.load_slice(from, to)
|
||||
else
|
||||
slice_collection_using_each(collection, from, to)
|
||||
end
|
||||
end
|
||||
|
||||
def self.non_blank_string?(collection)
|
||||
collection.is_a?(String) && collection != ''
|
||||
end
|
||||
|
||||
def self.slice_collection_using_each(collection, from, to)
|
||||
segments = []
|
||||
index = 0
|
||||
@@ -22,9 +35,5 @@ module Liquid
|
||||
|
||||
segments
|
||||
end
|
||||
|
||||
def self.non_blank_string?(collection)
|
||||
collection.is_a?(String) && collection != ''
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# encoding: utf-8
|
||||
module Liquid
|
||||
VERSION = "2.6.0"
|
||||
VERSION = "3.0.0"
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user