mirror of
https://github.com/kemko/liquid.git
synced 2026-01-04 09:15:41 +03:00
Compare commits
48 Commits
benchmark-
...
allow-whit
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5153ad1a78 | ||
|
|
a206c8301d | ||
|
|
ee0de01480 | ||
|
|
887b05e6ed | ||
|
|
5d68e8803f | ||
|
|
dedd1d3dc0 | ||
|
|
d9ae36ec40 | ||
|
|
b9ac3fef8f | ||
|
|
f5faa4858c | ||
|
|
bc5e444d04 | ||
|
|
3a4b63f37e | ||
|
|
a1a128db19 | ||
|
|
d502b9282a | ||
|
|
fee8e41466 | ||
|
|
37260f17ff | ||
|
|
2da9d49478 | ||
|
|
7196a2d58e | ||
|
|
a056f6521c | ||
|
|
de16db9b72 | ||
|
|
b4ea483c4e | ||
|
|
7843bcca8d | ||
|
|
76ea5596ff | ||
|
|
f9318e8c93 | ||
|
|
71253ec6f9 | ||
|
|
0fa075b879 | ||
|
|
6d080afd22 | ||
|
|
a67e2a0a00 | ||
|
|
f387508666 | ||
|
|
632b1fb702 | ||
|
|
d84870d7a5 | ||
|
|
584b492e70 | ||
|
|
b79c9cb9bf | ||
|
|
cf5ccede50 | ||
|
|
23622a9739 | ||
|
|
7ba5a6ab75 | ||
|
|
be3d261e11 | ||
|
|
eeb061ef44 | ||
|
|
67b2c320a1 | ||
|
|
1d151885be | ||
|
|
e836024dd9 | ||
|
|
638455ed92 | ||
|
|
b2a74883e9 | ||
|
|
6875e5e16f | ||
|
|
a5717a3f8d | ||
|
|
804fcfebd1 | ||
|
|
b37ee5684a | ||
|
|
0573b63b4c | ||
|
|
29c21d7867 |
@@ -3,6 +3,7 @@
|
|||||||
## 3.0.0 / not yet released / branch "master"
|
## 3.0.0 / not yet released / branch "master"
|
||||||
|
|
||||||
* ...
|
* ...
|
||||||
|
* Removed Block#end_tag. Instead, override parse with `super` followed by your code. See #446 [Dylan Thacker-Smith, dylanahsmith]
|
||||||
* Fixed condition with wrong data types, see #423 [Bogdan Gusiev]
|
* Fixed condition with wrong data types, see #423 [Bogdan Gusiev]
|
||||||
* Add url_encode to standard filters, see #421 [Derrick Reimer, djreimer]
|
* Add url_encode to standard filters, see #421 [Derrick Reimer, djreimer]
|
||||||
* Add uniq to standard filters [Florian Weingarten, fw42]
|
* Add uniq to standard filters [Florian Weingarten, fw42]
|
||||||
|
|||||||
@@ -11,7 +11,8 @@ class LiquidServlet < WEBrick::HTTPServlet::AbstractServlet
|
|||||||
private
|
private
|
||||||
|
|
||||||
def handle(type, req, res)
|
def handle(type, req, res)
|
||||||
@request, @response = req, res
|
@request = req
|
||||||
|
@response = res
|
||||||
|
|
||||||
@request.path_info =~ /(\w+)\z/
|
@request.path_info =~ /(\w+)\z/
|
||||||
@action = $1 || 'index'
|
@action = $1 || 'index'
|
||||||
|
|||||||
@@ -14,48 +14,45 @@ module Liquid
|
|||||||
@nodelist ||= []
|
@nodelist ||= []
|
||||||
@nodelist.clear
|
@nodelist.clear
|
||||||
|
|
||||||
# All child tags of the current block.
|
|
||||||
@children = []
|
|
||||||
|
|
||||||
while token = tokens.shift
|
while token = tokens.shift
|
||||||
unless token.empty?
|
begin
|
||||||
case
|
unless token.empty?
|
||||||
when token.start_with?(TAGSTART)
|
case
|
||||||
if token =~ FullToken
|
when token.start_with?(TAGSTART)
|
||||||
|
if token =~ FullToken
|
||||||
|
|
||||||
# if we found the proper block delimiter just end parsing here and let the outer block
|
# if we found the proper block delimiter just end parsing here and let the outer block
|
||||||
# proceed
|
# proceed
|
||||||
if block_delimiter == $1
|
return if block_delimiter == $1
|
||||||
end_tag
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
# fetch the tag from registered blocks
|
# fetch the tag from registered blocks
|
||||||
if tag = Template.tags[$1]
|
if tag = Template.tags[$1]
|
||||||
markup = token.is_a?(Token) ? token.child($2) : $2
|
markup = token.is_a?(Token) ? token.child($2) : $2
|
||||||
new_tag = tag.parse($1, markup, tokens, @options)
|
new_tag = tag.parse($1, markup, tokens, @options)
|
||||||
new_tag.line_number = token.line_number if token.is_a?(Token)
|
new_tag.line_number = token.line_number if token.is_a?(Token)
|
||||||
@blank &&= new_tag.blank?
|
@blank &&= new_tag.blank?
|
||||||
@nodelist << new_tag
|
@nodelist << new_tag
|
||||||
@children << new_tag
|
else
|
||||||
|
# this tag is not registered with the system
|
||||||
|
# pass it to the current block for special handling or error reporting
|
||||||
|
unknown_tag($1, $2, tokens)
|
||||||
|
end
|
||||||
else
|
else
|
||||||
# this tag is not registered with the system
|
raise SyntaxError.new(options[:locale].t("errors.syntax.tag_termination".freeze, :token => token, :tag_end => TagEnd.inspect))
|
||||||
# pass it to the current block for special handling or error reporting
|
|
||||||
unknown_tag($1, $2, tokens)
|
|
||||||
end
|
end
|
||||||
|
when token.start_with?(VARSTART)
|
||||||
|
new_var = create_variable(token)
|
||||||
|
new_var.line_number = token.line_number if token.is_a?(Token)
|
||||||
|
@nodelist << new_var
|
||||||
|
@blank = false
|
||||||
else
|
else
|
||||||
raise SyntaxError.new(options[:locale].t("errors.syntax.tag_termination".freeze, :token => token, :tag_end => TagEnd.inspect))
|
@nodelist << token
|
||||||
|
@blank &&= (token =~ /\A\s*\z/)
|
||||||
end
|
end
|
||||||
when token.start_with?(VARSTART)
|
|
||||||
new_var = create_variable(token)
|
|
||||||
new_var.line_number = token.line_number if token.is_a?(Token)
|
|
||||||
@nodelist << new_var
|
|
||||||
@children << new_var
|
|
||||||
@blank = false
|
|
||||||
else
|
|
||||||
@nodelist << token
|
|
||||||
@blank &&= (token =~ /\A\s*\z/)
|
|
||||||
end
|
end
|
||||||
|
rescue SyntaxError => e
|
||||||
|
e.set_line_number_from_token(token)
|
||||||
|
raise
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -70,16 +67,13 @@ module Liquid
|
|||||||
all_warnings = []
|
all_warnings = []
|
||||||
all_warnings.concat(@warnings) if @warnings
|
all_warnings.concat(@warnings) if @warnings
|
||||||
|
|
||||||
(@children || []).each do |node|
|
(nodelist || []).each do |node|
|
||||||
all_warnings.concat(node.warnings || [])
|
all_warnings.concat(node.warnings || []) if node.respond_to?(:warnings)
|
||||||
end
|
end
|
||||||
|
|
||||||
all_warnings
|
all_warnings
|
||||||
end
|
end
|
||||||
|
|
||||||
def end_tag
|
|
||||||
end
|
|
||||||
|
|
||||||
def unknown_tag(tag, params, tokens)
|
def unknown_tag(tag, params, tokens)
|
||||||
case tag
|
case tag
|
||||||
when 'else'.freeze
|
when 'else'.freeze
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ module Liquid
|
|||||||
#
|
#
|
||||||
# Example:
|
# Example:
|
||||||
#
|
#
|
||||||
# c = Condition.new('1', '==', '1')
|
# c = Condition.new(1, '==', 1)
|
||||||
# c.evaluate #=> true
|
# c.evaluate #=> true
|
||||||
#
|
#
|
||||||
class Condition #:nodoc:
|
class Condition #:nodoc:
|
||||||
@@ -28,7 +28,9 @@ module Liquid
|
|||||||
attr_accessor :left, :operator, :right
|
attr_accessor :left, :operator, :right
|
||||||
|
|
||||||
def initialize(left = nil, operator = nil, right = nil)
|
def initialize(left = nil, operator = nil, right = nil)
|
||||||
@left, @operator, @right = left, operator, right
|
@left = left
|
||||||
|
@operator = operator
|
||||||
|
@right = right
|
||||||
@child_relation = nil
|
@child_relation = nil
|
||||||
@child_condition = nil
|
@child_condition = nil
|
||||||
end
|
end
|
||||||
@@ -47,11 +49,13 @@ module Liquid
|
|||||||
end
|
end
|
||||||
|
|
||||||
def or(condition)
|
def or(condition)
|
||||||
@child_relation, @child_condition = :or, condition
|
@child_relation = :or
|
||||||
|
@child_condition = condition
|
||||||
end
|
end
|
||||||
|
|
||||||
def and(condition)
|
def and(condition)
|
||||||
@child_relation, @child_condition = :and, condition
|
@child_relation = :and
|
||||||
|
@child_condition = condition
|
||||||
end
|
end
|
||||||
|
|
||||||
def attach(attachment)
|
def attach(attachment)
|
||||||
@@ -92,9 +96,10 @@ module Liquid
|
|||||||
# If the operator is empty this means that the decision statement is just
|
# If the operator is empty this means that the decision statement is just
|
||||||
# a single variable. We can just poll this variable from the context and
|
# a single variable. We can just poll this variable from the context and
|
||||||
# return this as the result.
|
# return this as the result.
|
||||||
return context[left] if op == nil
|
return context.evaluate(left) if op == nil
|
||||||
|
|
||||||
left, right = context[left], context[right]
|
left = context.evaluate(left)
|
||||||
|
right = context.evaluate(right)
|
||||||
|
|
||||||
operation = self.class.operators[op] || raise(Liquid::ArgumentError.new("Unknown operator #{op}"))
|
operation = self.class.operators[op] || raise(Liquid::ArgumentError.new("Unknown operator #{op}"))
|
||||||
|
|
||||||
|
|||||||
@@ -21,10 +21,9 @@ module Liquid
|
|||||||
@scopes = [(outer_scope || {})]
|
@scopes = [(outer_scope || {})]
|
||||||
@registers = registers
|
@registers = registers
|
||||||
@errors = []
|
@errors = []
|
||||||
@resource_limits = resource_limits || Template.default_resource_limits
|
@resource_limits = resource_limits || Template.default_resource_limits.dup
|
||||||
@resource_limits[:render_score_current] = 0
|
@resource_limits[:render_score_current] = 0
|
||||||
@resource_limits[:assign_score_current] = 0
|
@resource_limits[:assign_score_current] = 0
|
||||||
@parsed_expression = Hash.new{ |cache, markup| cache[markup] = Expression.parse(markup) }
|
|
||||||
squash_instance_assigns_with_environments
|
squash_instance_assigns_with_environments
|
||||||
|
|
||||||
@this_stack_used = false
|
@this_stack_used = false
|
||||||
@@ -170,7 +169,7 @@ module Liquid
|
|||||||
# Example:
|
# Example:
|
||||||
# products == empty #=> products.empty?
|
# products == empty #=> products.empty?
|
||||||
def [](expression)
|
def [](expression)
|
||||||
evaluate(@parsed_expression[expression])
|
evaluate(Expression.parse(expression))
|
||||||
end
|
end
|
||||||
|
|
||||||
def has_key?(key)
|
def has_key?(key)
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ module Liquid
|
|||||||
|
|
||||||
def set_line_number_from_token(token)
|
def set_line_number_from_token(token)
|
||||||
return unless token.respond_to?(:line_number)
|
return unless token.respond_to?(:line_number)
|
||||||
|
return if self.line_number
|
||||||
self.line_number = token.line_number
|
self.line_number = token.line_number
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -50,10 +51,10 @@ module Liquid
|
|||||||
|
|
||||||
class ArgumentError < Error; end
|
class ArgumentError < Error; end
|
||||||
class ContextError < Error; end
|
class ContextError < Error; end
|
||||||
class FilterNotFound < Error; end
|
|
||||||
class FileSystemError < Error; end
|
class FileSystemError < Error; end
|
||||||
class StandardError < Error; end
|
class StandardError < Error; end
|
||||||
class SyntaxError < Error; end
|
class SyntaxError < Error; end
|
||||||
class StackLevelError < Error; end
|
class StackLevelError < Error; end
|
||||||
|
class TaintedError < Error; end
|
||||||
class MemoryError < Error; end
|
class MemoryError < Error; end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -9,9 +9,11 @@ module Liquid
|
|||||||
'['.freeze => :open_square,
|
'['.freeze => :open_square,
|
||||||
']'.freeze => :close_square,
|
']'.freeze => :close_square,
|
||||||
'('.freeze => :open_round,
|
'('.freeze => :open_round,
|
||||||
')'.freeze => :close_round
|
')'.freeze => :close_round,
|
||||||
|
'?'.freeze => :question,
|
||||||
|
'-'.freeze => :dash
|
||||||
}
|
}
|
||||||
IDENTIFIER = /[\w\-?!]+/
|
IDENTIFIER = /\w+/
|
||||||
SINGLE_STRING_LITERAL = /'[^\']*'/
|
SINGLE_STRING_LITERAL = /'[^\']*'/
|
||||||
DOUBLE_STRING_LITERAL = /"[^\"]*"/
|
DOUBLE_STRING_LITERAL = /"[^\"]*"/
|
||||||
NUMBER_LITERAL = /-?\d+(\.\d+)?/
|
NUMBER_LITERAL = /-?\d+(\.\d+)?/
|
||||||
|
|||||||
@@ -75,6 +75,13 @@ module Liquid
|
|||||||
|
|
||||||
def variable_signature
|
def variable_signature
|
||||||
str = consume(:id)
|
str = consume(:id)
|
||||||
|
while consume?(:dash)
|
||||||
|
str << "-".freeze
|
||||||
|
str << consume(:id)
|
||||||
|
end
|
||||||
|
if consume?(:question)
|
||||||
|
str << "?".freeze
|
||||||
|
end
|
||||||
if look(:open_square)
|
if look(:open_square)
|
||||||
str << consume
|
str << consume
|
||||||
str << expression
|
str << expression
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ module Liquid
|
|||||||
|
|
||||||
class Include < Tag
|
class Include < Tag
|
||||||
def render_with_profiling(context)
|
def render_with_profiling(context)
|
||||||
Profiler.profile_children(@template_name) do
|
Profiler.profile_children(context.evaluate(@template_name).to_s) do
|
||||||
render_without_profiling(context)
|
render_without_profiling(context)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ module Liquid
|
|||||||
end
|
end
|
||||||
|
|
||||||
def escape(input)
|
def escape(input)
|
||||||
CGI.escapeHTML(input) rescue input
|
CGI.escapeHTML(input).untaint rescue input
|
||||||
end
|
end
|
||||||
alias_method :h, :escape
|
alias_method :h, :escape
|
||||||
|
|
||||||
|
|||||||
@@ -8,14 +8,14 @@ module Liquid
|
|||||||
@blocks = []
|
@blocks = []
|
||||||
|
|
||||||
if markup =~ Syntax
|
if markup =~ Syntax
|
||||||
@left = $1
|
@left = Expression.parse($1)
|
||||||
else
|
else
|
||||||
raise SyntaxError.new(options[:locale].t("errors.syntax.case".freeze))
|
raise SyntaxError.new(options[:locale].t("errors.syntax.case".freeze))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def nodelist
|
def nodelist
|
||||||
@blocks.map(&:attachment).flatten
|
@blocks.flat_map(&:attachment)
|
||||||
end
|
end
|
||||||
|
|
||||||
def unknown_tag(tag, markup, tokens)
|
def unknown_tag(tag, markup, tokens)
|
||||||
@@ -58,7 +58,7 @@ module Liquid
|
|||||||
|
|
||||||
markup = $2
|
markup = $2
|
||||||
|
|
||||||
block = Condition.new(@left, '=='.freeze, $1)
|
block = Condition.new(@left, '=='.freeze, Expression.parse($1))
|
||||||
block.attach(@nodelist)
|
block.attach(@nodelist)
|
||||||
@blocks.push(block)
|
@blocks.push(block)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -20,10 +20,10 @@ module Liquid
|
|||||||
case markup
|
case markup
|
||||||
when NamedSyntax
|
when NamedSyntax
|
||||||
@variables = variables_from_string($2)
|
@variables = variables_from_string($2)
|
||||||
@name = $1
|
@name = Expression.parse($1)
|
||||||
when SimpleSyntax
|
when SimpleSyntax
|
||||||
@variables = variables_from_string(markup)
|
@variables = variables_from_string(markup)
|
||||||
@name = "'#{@variables.to_s}'"
|
@name = @variables.to_s
|
||||||
else
|
else
|
||||||
raise SyntaxError.new(options[:locale].t("errors.syntax.cycle".freeze))
|
raise SyntaxError.new(options[:locale].t("errors.syntax.cycle".freeze))
|
||||||
end
|
end
|
||||||
@@ -33,9 +33,9 @@ module Liquid
|
|||||||
context.registers[:cycle] ||= Hash.new(0)
|
context.registers[:cycle] ||= Hash.new(0)
|
||||||
|
|
||||||
context.stack do
|
context.stack do
|
||||||
key = context[@name]
|
key = context.evaluate(@name)
|
||||||
iteration = context.registers[:cycle][key]
|
iteration = context.registers[:cycle][key]
|
||||||
result = context[@variables[iteration]]
|
result = context.evaluate(@variables[iteration])
|
||||||
iteration += 1
|
iteration += 1
|
||||||
iteration = 0 if iteration >= @variables.size
|
iteration = 0 if iteration >= @variables.size
|
||||||
context.registers[:cycle][key] = iteration
|
context.registers[:cycle][key] = iteration
|
||||||
@@ -48,7 +48,7 @@ module Liquid
|
|||||||
def variables_from_string(markup)
|
def variables_from_string(markup)
|
||||||
markup.split(',').collect do |var|
|
markup.split(',').collect do |var|
|
||||||
var =~ /\s*(#{QuotedFragment})\s*/o
|
var =~ /\s*(#{QuotedFragment})\s*/o
|
||||||
$1 ? $1 : nil
|
$1 ? Expression.parse($1) : nil
|
||||||
end.compact
|
end.compact
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -68,19 +68,19 @@ module Liquid
|
|||||||
def render(context)
|
def render(context)
|
||||||
context.registers[:for] ||= Hash.new(0)
|
context.registers[:for] ||= Hash.new(0)
|
||||||
|
|
||||||
collection = context[@collection_name]
|
collection = context.evaluate(@collection_name)
|
||||||
collection = collection.to_a if collection.is_a?(Range)
|
collection = collection.to_a if collection.is_a?(Range)
|
||||||
|
|
||||||
# Maintains Ruby 1.8.7 String#each behaviour on 1.9
|
# Maintains Ruby 1.8.7 String#each behaviour on 1.9
|
||||||
return render_else(context) unless iterable?(collection)
|
return render_else(context) unless iterable?(collection)
|
||||||
|
|
||||||
from = if @attributes['offset'.freeze] == 'continue'.freeze
|
from = if @from == :continue
|
||||||
context.registers[:for][@name].to_i
|
context.registers[:for][@name].to_i
|
||||||
else
|
else
|
||||||
context[@attributes['offset'.freeze]].to_i
|
context.evaluate(@from).to_i
|
||||||
end
|
end
|
||||||
|
|
||||||
limit = context[@attributes['limit'.freeze]]
|
limit = context.evaluate(@limit)
|
||||||
to = limit ? limit.to_i + from : nil
|
to = limit ? limit.to_i + from : nil
|
||||||
|
|
||||||
segment = Utils.slice_collection(collection, from, to)
|
segment = Utils.slice_collection(collection, from, to)
|
||||||
@@ -128,12 +128,12 @@ module Liquid
|
|||||||
def lax_parse(markup)
|
def lax_parse(markup)
|
||||||
if markup =~ Syntax
|
if markup =~ Syntax
|
||||||
@variable_name = $1
|
@variable_name = $1
|
||||||
@collection_name = $2
|
collection_name = $2
|
||||||
@name = "#{$1}-#{$2}"
|
|
||||||
@reversed = $3
|
@reversed = $3
|
||||||
@attributes = {}
|
@name = "#{@variable_name}-#{collection_name}"
|
||||||
|
@collection_name = Expression.parse(collection_name)
|
||||||
markup.scan(TagAttributes) do |key, value|
|
markup.scan(TagAttributes) do |key, value|
|
||||||
@attributes[key] = value
|
set_attribute(key, value)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
raise SyntaxError.new(options[:locale].t("errors.syntax.for".freeze))
|
raise SyntaxError.new(options[:locale].t("errors.syntax.for".freeze))
|
||||||
@@ -144,24 +144,36 @@ module Liquid
|
|||||||
p = Parser.new(markup)
|
p = Parser.new(markup)
|
||||||
@variable_name = p.consume(:id)
|
@variable_name = p.consume(:id)
|
||||||
raise SyntaxError.new(options[:locale].t("errors.syntax.for_invalid_in".freeze)) unless p.id?('in'.freeze)
|
raise SyntaxError.new(options[:locale].t("errors.syntax.for_invalid_in".freeze)) unless p.id?('in'.freeze)
|
||||||
@collection_name = p.expression
|
collection_name = p.expression
|
||||||
@name = "#{@variable_name}-#{@collection_name}"
|
@name = "#{@variable_name}-#{collection_name}"
|
||||||
|
@collection_name = Expression.parse(collection_name)
|
||||||
@reversed = p.id?('reversed'.freeze)
|
@reversed = p.id?('reversed'.freeze)
|
||||||
|
|
||||||
@attributes = {}
|
|
||||||
while p.look(:id) && p.look(:colon, 1)
|
while p.look(:id) && p.look(:colon, 1)
|
||||||
unless attribute = p.id?('limit'.freeze) || p.id?('offset'.freeze)
|
unless attribute = p.id?('limit'.freeze) || p.id?('offset'.freeze)
|
||||||
raise SyntaxError.new(options[:locale].t("errors.syntax.for_invalid_attribute".freeze))
|
raise SyntaxError.new(options[:locale].t("errors.syntax.for_invalid_attribute".freeze))
|
||||||
end
|
end
|
||||||
p.consume
|
p.consume
|
||||||
val = p.expression
|
set_attribute(attribute, p.expression)
|
||||||
@attributes[attribute] = val
|
|
||||||
end
|
end
|
||||||
p.consume(:end_of_string)
|
p.consume(:end_of_string)
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def set_attribute(key, expr)
|
||||||
|
case key
|
||||||
|
when 'offset'.freeze
|
||||||
|
@from = if expr == 'continue'.freeze
|
||||||
|
:continue
|
||||||
|
else
|
||||||
|
Expression.parse(expr)
|
||||||
|
end
|
||||||
|
when 'limit'.freeze
|
||||||
|
@limit = Expression.parse(expr)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def render_else(context)
|
def render_else(context)
|
||||||
return @else_block ? [render_all(@else_block, context)] : ''.freeze
|
return @else_block ? [render_all(@else_block, context)] : ''.freeze
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ module Liquid
|
|||||||
end
|
end
|
||||||
|
|
||||||
def nodelist
|
def nodelist
|
||||||
@blocks.map(&:attachment).flatten
|
@blocks.flat_map(&:attachment)
|
||||||
end
|
end
|
||||||
|
|
||||||
def unknown_tag(tag, markup, tokens)
|
def unknown_tag(tag, markup, tokens)
|
||||||
@@ -57,17 +57,17 @@ module Liquid
|
|||||||
end
|
end
|
||||||
|
|
||||||
def lax_parse(markup)
|
def lax_parse(markup)
|
||||||
expressions = markup.scan(ExpressionsAndOperators).reverse
|
expressions = markup.scan(ExpressionsAndOperators)
|
||||||
raise(SyntaxError.new(options[:locale].t("errors.syntax.if".freeze))) unless expressions.shift =~ Syntax
|
raise(SyntaxError.new(options[:locale].t("errors.syntax.if".freeze))) unless expressions.pop =~ Syntax
|
||||||
|
|
||||||
condition = Condition.new($1, $2, $3)
|
condition = Condition.new(Expression.parse($1), $2, Expression.parse($3))
|
||||||
|
|
||||||
while not expressions.empty?
|
while not expressions.empty?
|
||||||
operator = (expressions.shift).to_s.strip
|
operator = expressions.pop.to_s.strip
|
||||||
|
|
||||||
raise(SyntaxError.new(options[:locale].t("errors.syntax.if".freeze))) unless expressions.shift.to_s =~ Syntax
|
raise(SyntaxError.new(options[:locale].t("errors.syntax.if".freeze))) unless expressions.pop.to_s =~ Syntax
|
||||||
|
|
||||||
new_condition = Condition.new($1, $2, $3)
|
new_condition = Condition.new(Expression.parse($1), $2, Expression.parse($3))
|
||||||
raise(SyntaxError.new(options[:locale].t("errors.syntax.if".freeze))) unless BOOLEAN_OPERATORS.include?(operator)
|
raise(SyntaxError.new(options[:locale].t("errors.syntax.if".freeze))) unless BOOLEAN_OPERATORS.include?(operator)
|
||||||
new_condition.send(operator, condition)
|
new_condition.send(operator, condition)
|
||||||
condition = new_condition
|
condition = new_condition
|
||||||
@@ -92,9 +92,9 @@ module Liquid
|
|||||||
end
|
end
|
||||||
|
|
||||||
def parse_comparison(p)
|
def parse_comparison(p)
|
||||||
a = p.expression
|
a = Expression.parse(p.expression)
|
||||||
if op = p.consume?(:comparison)
|
if op = p.consume?(:comparison)
|
||||||
b = p.expression
|
b = Expression.parse(p.expression)
|
||||||
Condition.new(a, op, b)
|
Condition.new(a, op, b)
|
||||||
else
|
else
|
||||||
Condition.new(a)
|
Condition.new(a)
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ module Liquid
|
|||||||
def render(context)
|
def render(context)
|
||||||
context.stack do
|
context.stack do
|
||||||
|
|
||||||
output = render_all(@nodelist, context)
|
output = super
|
||||||
|
|
||||||
if output != context.registers[:ifchanged]
|
if output != context.registers[:ifchanged]
|
||||||
context.registers[:ifchanged] = output
|
context.registers[:ifchanged] = output
|
||||||
|
|||||||
@@ -22,12 +22,16 @@ module Liquid
|
|||||||
|
|
||||||
if markup =~ Syntax
|
if markup =~ Syntax
|
||||||
|
|
||||||
@template_name = $1
|
template_name = $1
|
||||||
@variable_name = $3
|
variable_name = $3
|
||||||
|
|
||||||
|
@variable_name = Expression.parse(variable_name || template_name[1..-2])
|
||||||
|
@context_variable_name = template_name[1..-2].split('/'.freeze).last
|
||||||
|
@template_name = Expression.parse(template_name)
|
||||||
@attributes = {}
|
@attributes = {}
|
||||||
|
|
||||||
markup.scan(TagAttributes) do |key, value|
|
markup.scan(TagAttributes) do |key, value|
|
||||||
@attributes[key] = value
|
@attributes[key] = Expression.parse(value)
|
||||||
end
|
end
|
||||||
|
|
||||||
else
|
else
|
||||||
@@ -40,21 +44,20 @@ module Liquid
|
|||||||
|
|
||||||
def render(context)
|
def render(context)
|
||||||
partial = load_cached_partial(context)
|
partial = load_cached_partial(context)
|
||||||
variable = context[@variable_name || @template_name[1..-2]]
|
variable = context.evaluate(@variable_name)
|
||||||
|
|
||||||
context.stack do
|
context.stack do
|
||||||
@attributes.each do |key, value|
|
@attributes.each do |key, value|
|
||||||
context[key] = context[value]
|
context[key] = context.evaluate(value)
|
||||||
end
|
end
|
||||||
|
|
||||||
context_variable_name = @template_name[1..-2].split('/'.freeze).last
|
|
||||||
if variable.is_a?(Array)
|
if variable.is_a?(Array)
|
||||||
variable.collect do |var|
|
variable.collect do |var|
|
||||||
context[context_variable_name] = var
|
context[@context_variable_name] = var
|
||||||
partial.render(context)
|
partial.render(context)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
context[context_variable_name] = variable
|
context[@context_variable_name] = variable
|
||||||
partial.render(context)
|
partial.render(context)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -63,7 +66,7 @@ module Liquid
|
|||||||
private
|
private
|
||||||
def load_cached_partial(context)
|
def load_cached_partial(context)
|
||||||
cached_partials = context.registers[:cached_partials] || {}
|
cached_partials = context.registers[:cached_partials] || {}
|
||||||
template_name = context[@template_name]
|
template_name = context.evaluate(@template_name)
|
||||||
|
|
||||||
if cached = cached_partials[template_name]
|
if cached = cached_partials[template_name]
|
||||||
return cached
|
return cached
|
||||||
@@ -81,9 +84,9 @@ module Liquid
|
|||||||
# make read_template_file call backwards-compatible.
|
# make read_template_file call backwards-compatible.
|
||||||
case file_system.method(:read_template_file).arity
|
case file_system.method(:read_template_file).arity
|
||||||
when 1
|
when 1
|
||||||
file_system.read_template_file(context[@template_name])
|
file_system.read_template_file(context.evaluate(@template_name))
|
||||||
when 2
|
when 2
|
||||||
file_system.read_template_file(context[@template_name], context)
|
file_system.read_template_file(context.evaluate(@template_name), context)
|
||||||
else
|
else
|
||||||
raise ArgumentError, "file_system.read_template_file expects two parameters: (template_name, context)"
|
raise ArgumentError, "file_system.read_template_file expects two parameters: (template_name, context)"
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -8,10 +8,7 @@ module Liquid
|
|||||||
while token = tokens.shift
|
while token = tokens.shift
|
||||||
if token =~ FullTokenPossiblyInvalid
|
if token =~ FullTokenPossiblyInvalid
|
||||||
@nodelist << $1 if $1 != "".freeze
|
@nodelist << $1 if $1 != "".freeze
|
||||||
if block_delimiter == $2
|
return if block_delimiter == $2
|
||||||
end_tag
|
|
||||||
return
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
@nodelist << token if not token.empty?
|
@nodelist << token if not token.empty?
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -6,10 +6,10 @@ module Liquid
|
|||||||
super
|
super
|
||||||
if markup =~ Syntax
|
if markup =~ Syntax
|
||||||
@variable_name = $1
|
@variable_name = $1
|
||||||
@collection_name = $2
|
@collection_name = Expression.parse($2)
|
||||||
@attributes = {}
|
@attributes = {}
|
||||||
markup.scan(TagAttributes) do |key, value|
|
markup.scan(TagAttributes) do |key, value|
|
||||||
@attributes[key] = value
|
@attributes[key] = Expression.parse(value)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
raise SyntaxError.new(options[:locale].t("errors.syntax.table_row".freeze))
|
raise SyntaxError.new(options[:locale].t("errors.syntax.table_row".freeze))
|
||||||
@@ -17,16 +17,16 @@ module Liquid
|
|||||||
end
|
end
|
||||||
|
|
||||||
def render(context)
|
def render(context)
|
||||||
collection = context[@collection_name] or return ''.freeze
|
collection = context.evaluate(@collection_name) or return ''.freeze
|
||||||
|
|
||||||
from = @attributes['offset'.freeze] ? context[@attributes['offset'.freeze]].to_i : 0
|
from = @attributes.key?('offset'.freeze) ? context.evaluate(@attributes['offset'.freeze]).to_i : 0
|
||||||
to = @attributes['limit'.freeze] ? from + context[@attributes['limit'.freeze]].to_i : nil
|
to = @attributes.key?('limit'.freeze) ? from + context.evaluate(@attributes['limit'.freeze]).to_i : nil
|
||||||
|
|
||||||
collection = Utils.slice_collection(collection, from, to)
|
collection = Utils.slice_collection(collection, from, to)
|
||||||
|
|
||||||
length = collection.length
|
length = collection.length
|
||||||
|
|
||||||
cols = context[@attributes['cols'.freeze]].to_i
|
cols = context.evaluate(@attributes['cols'.freeze]).to_i
|
||||||
|
|
||||||
row = 1
|
row = 1
|
||||||
col = 0
|
col = 0
|
||||||
@@ -54,7 +54,7 @@ module Liquid
|
|||||||
|
|
||||||
col += 1
|
col += 1
|
||||||
|
|
||||||
result << "<td class=\"col#{col}\">" << render_all(@nodelist, context) << '</td>'
|
result << "<td class=\"col#{col}\">" << super << '</td>'
|
||||||
|
|
||||||
if col == cols and (index != length - 1)
|
if col == cols and (index != length - 1)
|
||||||
col = 0
|
col = 0
|
||||||
|
|||||||
@@ -60,6 +60,12 @@ module Liquid
|
|||||||
# :strict will enforce correct syntax.
|
# :strict will enforce correct syntax.
|
||||||
attr_writer :error_mode
|
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
|
def file_system
|
||||||
@@file_system
|
@@file_system
|
||||||
end
|
end
|
||||||
@@ -80,6 +86,10 @@ module Liquid
|
|||||||
@error_mode || :lax
|
@error_mode || :lax
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def taint_mode
|
||||||
|
@taint_mode || :lax
|
||||||
|
end
|
||||||
|
|
||||||
# Pass a module with filter methods which should be available
|
# Pass a module with filter methods which should be available
|
||||||
# to all liquid views. Good for registering the standard library
|
# to all liquid views. Good for registering the standard library
|
||||||
def register_filter(mod)
|
def register_filter(mod)
|
||||||
|
|||||||
@@ -35,15 +35,17 @@ module Liquid
|
|||||||
|
|
||||||
def lax_parse(markup)
|
def lax_parse(markup)
|
||||||
@filters = []
|
@filters = []
|
||||||
if markup =~ /\s*(#{QuotedFragment})(.*)/om
|
if markup =~ /(#{QuotedFragment})(.*)/om
|
||||||
@name = Regexp.last_match(1)
|
name_markup = $1
|
||||||
if Regexp.last_match(2) =~ /#{FilterSeparator}\s*(.*)/om
|
filter_markup = $2
|
||||||
filters = Regexp.last_match(1).scan(FilterParser)
|
@name = Expression.parse(name_markup)
|
||||||
|
if filter_markup =~ /#{FilterSeparator}\s*(.*)/om
|
||||||
|
filters = $1.scan(FilterParser)
|
||||||
filters.each do |f|
|
filters.each do |f|
|
||||||
if f =~ /\w+/
|
if f =~ /\w+/
|
||||||
filtername = Regexp.last_match(0)
|
filtername = Regexp.last_match(0)
|
||||||
filterargs = f.scan(/(?:#{FilterArgumentSeparator}|#{ArgumentSeparator})\s*((?:\w+\s*\:\s*)?#{QuotedFragment})/o).flatten
|
filterargs = f.scan(/(?:#{FilterArgumentSeparator}|#{ArgumentSeparator})\s*((?:\w+\s*\:\s*)?#{QuotedFragment})/o).flatten
|
||||||
@filters << [filtername, filterargs]
|
@filters << parse_filter_expressions(filtername, filterargs)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -53,7 +55,7 @@ module Liquid
|
|||||||
def strict_parse(markup)
|
def strict_parse(markup)
|
||||||
# Very simple valid cases
|
# Very simple valid cases
|
||||||
if markup =~ EasyParse
|
if markup =~ EasyParse
|
||||||
@name = $1
|
@name = Expression.parse($1)
|
||||||
@filters = []
|
@filters = []
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
@@ -61,11 +63,11 @@ module Liquid
|
|||||||
@filters = []
|
@filters = []
|
||||||
p = Parser.new(markup)
|
p = Parser.new(markup)
|
||||||
# Could be just filters with no input
|
# Could be just filters with no input
|
||||||
@name = p.look(:pipe) ? ''.freeze : p.expression
|
@name = p.look(:pipe) ? nil : Expression.parse(p.expression)
|
||||||
while p.consume?(:pipe)
|
while p.consume?(:pipe)
|
||||||
filtername = p.consume(:id)
|
filtername = p.consume(:id)
|
||||||
filterargs = p.consume?(:colon) ? parse_filterargs(p) : []
|
filterargs = p.consume?(:colon) ? parse_filterargs(p) : []
|
||||||
@filters << [filtername, filterargs]
|
@filters << parse_filter_expressions(filtername, filterargs)
|
||||||
end
|
end
|
||||||
p.consume(:end_of_string)
|
p.consume(:end_of_string)
|
||||||
end
|
end
|
||||||
@@ -81,22 +83,51 @@ module Liquid
|
|||||||
end
|
end
|
||||||
|
|
||||||
def render(context)
|
def render(context)
|
||||||
return ''.freeze if @name.nil?
|
@filters.inject(context.evaluate(@name)) do |output, (filter_name, filter_args, filter_kwargs)|
|
||||||
@filters.inject(context[@name]) do |output, filter|
|
filter_args = evaluate_filter_expressions(context, filter_args, filter_kwargs)
|
||||||
filterargs = []
|
output = context.invoke(filter_name, output, *filter_args)
|
||||||
keyword_args = {}
|
end.tap{ |obj| taint_check(obj) }
|
||||||
filter[1].to_a.each do |a|
|
end
|
||||||
if matches = a.match(/\A#{TagAttributes}\z/o)
|
|
||||||
keyword_args[matches[1]] = context[matches[2]]
|
private
|
||||||
else
|
|
||||||
filterargs << context[a]
|
def parse_filter_expressions(filter_name, unparsed_args)
|
||||||
end
|
filter_args = []
|
||||||
|
keyword_args = {}
|
||||||
|
unparsed_args.each do |a|
|
||||||
|
if matches = a.match(/\A#{TagAttributes}\z/o)
|
||||||
|
keyword_args[matches[1]] = Expression.parse(matches[2])
|
||||||
|
else
|
||||||
|
filter_args << Expression.parse(a)
|
||||||
end
|
end
|
||||||
filterargs << keyword_args unless keyword_args.empty?
|
end
|
||||||
begin
|
result = [filter_name, filter_args]
|
||||||
output = context.invoke(filter[0], output, *filterargs)
|
result << keyword_args unless keyword_args.empty?
|
||||||
rescue FilterNotFound
|
result
|
||||||
raise FilterNotFound, "Error - filter '#{filter[0]}' in '#{@markup.strip}' could not be found."
|
end
|
||||||
|
|
||||||
|
def evaluate_filter_expressions(context, filter_args, filter_kwargs)
|
||||||
|
parsed_args = filter_args.map{ |expr| context.evaluate(expr) }
|
||||||
|
if filter_kwargs
|
||||||
|
parsed_kwargs = {}
|
||||||
|
filter_kwargs.each do |key, expr|
|
||||||
|
parsed_kwargs[key] = context.evaluate(expr)
|
||||||
|
end
|
||||||
|
parsed_args << parsed_kwargs
|
||||||
|
end
|
||||||
|
parsed_args
|
||||||
|
end
|
||||||
|
|
||||||
|
def taint_check(obj)
|
||||||
|
if obj.tainted?
|
||||||
|
@markup =~ QuotedFragment
|
||||||
|
name = Regexp.last_match(0)
|
||||||
|
case Template.taint_mode
|
||||||
|
when :warn
|
||||||
|
@warnings ||= []
|
||||||
|
@warnings << "variable '#{name}' is tainted and was not escaped"
|
||||||
|
when :error
|
||||||
|
raise TaintedError, "Error - variable '#{name}' is tainted and was not escaped"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -64,5 +64,15 @@ module Liquid
|
|||||||
|
|
||||||
object
|
object
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def ==(other)
|
||||||
|
self.class == other.class && self.state == other.state
|
||||||
|
end
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
def state
|
||||||
|
[@name, @lookups, @command_flags]
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -4,8 +4,6 @@ class Paginate < Liquid::Block
|
|||||||
def initialize(tag_name, markup, options)
|
def initialize(tag_name, markup, options)
|
||||||
super
|
super
|
||||||
|
|
||||||
@nodelist = []
|
|
||||||
|
|
||||||
if markup =~ Syntax
|
if markup =~ Syntax
|
||||||
@collection_name = $1
|
@collection_name = $1
|
||||||
@page_size = if $2
|
@page_size = if $2
|
||||||
@@ -73,7 +71,7 @@ class Paginate < Liquid::Block
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
render_all(@nodelist, context)
|
super
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -23,12 +23,10 @@ class ContextTest < Minitest::Test
|
|||||||
end
|
end
|
||||||
|
|
||||||
def test_has_key_will_not_add_an_error_for_missing_keys
|
def test_has_key_will_not_add_an_error_for_missing_keys
|
||||||
Template.error_mode = :strict
|
with_error_mode :strict do
|
||||||
|
context = Context.new
|
||||||
context = Context.new
|
context.has_key?('unknown')
|
||||||
|
assert_empty context.errors
|
||||||
context.has_key?('unknown')
|
end
|
||||||
|
|
||||||
assert_empty context.errors
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -48,6 +48,10 @@ class ProductDrop < Liquid::Drop
|
|||||||
ContextDrop.new
|
ContextDrop.new
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def user_input
|
||||||
|
"foo".taint
|
||||||
|
end
|
||||||
|
|
||||||
protected
|
protected
|
||||||
def callmenot
|
def callmenot
|
||||||
"protected"
|
"protected"
|
||||||
@@ -108,6 +112,30 @@ class DropsTest < Minitest::Test
|
|||||||
assert_equal ' ', tpl.render!('product' => ProductDrop.new)
|
assert_equal ' ', tpl.render!('product' => ProductDrop.new)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_rendering_raises_on_tainted_attr
|
||||||
|
with_taint_mode(:error) do
|
||||||
|
tpl = Liquid::Template.parse('{{ product.user_input }}')
|
||||||
|
assert_raises TaintedError do
|
||||||
|
tpl.render!('product' => ProductDrop.new)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_rendering_warns_on_tainted_attr
|
||||||
|
with_taint_mode(:warn) do
|
||||||
|
tpl = Liquid::Template.parse('{{ product.user_input }}')
|
||||||
|
tpl.render!('product' => ProductDrop.new)
|
||||||
|
assert_match /tainted/, tpl.warnings.first
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_rendering_doesnt_raise_on_escaped_tainted_attr
|
||||||
|
with_taint_mode(:error) do
|
||||||
|
tpl = Liquid::Template.parse('{{ product.user_input | escape }}')
|
||||||
|
tpl.render!('product' => ProductDrop.new)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def test_drop_does_only_respond_to_whitelisted_methods
|
def test_drop_does_only_respond_to_whitelisted_methods
|
||||||
assert_equal "", Liquid::Template.parse("{{ product.inspect }}").render!('product' => ProductDrop.new)
|
assert_equal "", Liquid::Template.parse("{{ product.inspect }}").render!('product' => ProductDrop.new)
|
||||||
assert_equal "", Liquid::Template.parse("{{ product.pretty_inspect }}").render!('product' => ProductDrop.new)
|
assert_equal "", Liquid::Template.parse("{{ product.pretty_inspect }}").render!('product' => ProductDrop.new)
|
||||||
|
|||||||
@@ -100,6 +100,73 @@ class ErrorHandlingTest < Minitest::Test
|
|||||||
assert_equal Liquid::ArgumentError, template.errors.first.class
|
assert_equal Liquid::ArgumentError, template.errors.first.class
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_with_line_numbers_adds_numbers_to_parser_errors
|
||||||
|
err = assert_raises(SyntaxError) do
|
||||||
|
template = Liquid::Template.parse(%q{
|
||||||
|
foobar
|
||||||
|
|
||||||
|
{% "cat" | foobar %}
|
||||||
|
|
||||||
|
bla
|
||||||
|
},
|
||||||
|
:line_numbers => true
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_match /Liquid syntax error \(line 4\)/, err.message
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_parsing_warn_with_line_numbers_adds_numbers_to_lexer_errors
|
||||||
|
template = Liquid::Template.parse(%q{
|
||||||
|
foobar
|
||||||
|
|
||||||
|
{% if 1 =! 2 %}ok{% endif %}
|
||||||
|
|
||||||
|
bla
|
||||||
|
},
|
||||||
|
:error_mode => :warn,
|
||||||
|
:line_numbers => true
|
||||||
|
)
|
||||||
|
|
||||||
|
assert_equal ['Liquid syntax error (line 4): Unexpected character = in "1 =! 2"'],
|
||||||
|
template.warnings.map(&:message)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_parsing_strict_with_line_numbers_adds_numbers_to_lexer_errors
|
||||||
|
err = assert_raises(SyntaxError) do
|
||||||
|
Liquid::Template.parse(%q{
|
||||||
|
foobar
|
||||||
|
|
||||||
|
{% if 1 =! 2 %}ok{% endif %}
|
||||||
|
|
||||||
|
bla
|
||||||
|
},
|
||||||
|
:error_mode => :strict,
|
||||||
|
:line_numbers => true
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_equal 'Liquid syntax error (line 4): Unexpected character = in "1 =! 2"', err.message
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_syntax_errors_in_nested_blocks_have_correct_line_number
|
||||||
|
err = assert_raises(SyntaxError) do
|
||||||
|
Liquid::Template.parse(%q{
|
||||||
|
foobar
|
||||||
|
|
||||||
|
{% if 1 != 2 %}
|
||||||
|
{% foo %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
bla
|
||||||
|
},
|
||||||
|
:line_numbers => true
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_equal "Liquid syntax error (line 5): Unknown tag 'foo'", err.message
|
||||||
|
end
|
||||||
|
|
||||||
def test_strict_error_messages
|
def test_strict_error_messages
|
||||||
err = assert_raises(SyntaxError) do
|
err = assert_raises(SyntaxError) do
|
||||||
Liquid::Template.parse(' {% if 1 =! 2 %}ok{% endif %} ', :error_mode => :strict)
|
Liquid::Template.parse(' {% if 1 =! 2 %}ok{% endif %} ', :error_mode => :strict)
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ class RenderProfilingTest < Minitest::Test
|
|||||||
t = Template.parse("{% include 'a_template' %}", :profile => true)
|
t = Template.parse("{% include 'a_template' %}", :profile => true)
|
||||||
t.render!
|
t.render!
|
||||||
|
|
||||||
assert t.profiler.total_render_time > 0, "Total render time was not calculated"
|
assert t.profiler.total_render_time >= 0, "Total render time was not calculated"
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_profiling_uses_include_to_mark_children
|
def test_profiling_uses_include_to_mark_children
|
||||||
@@ -89,7 +89,7 @@ class RenderProfilingTest < Minitest::Test
|
|||||||
|
|
||||||
include_node = t.profiler[1]
|
include_node = t.profiler[1]
|
||||||
include_node.children.each do |child|
|
include_node.children.each do |child|
|
||||||
assert_equal "'a_template'", child.partial
|
assert_equal "a_template", child.partial
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -99,12 +99,12 @@ class RenderProfilingTest < Minitest::Test
|
|||||||
|
|
||||||
a_template = t.profiler[1]
|
a_template = t.profiler[1]
|
||||||
a_template.children.each do |child|
|
a_template.children.each do |child|
|
||||||
assert_equal "'a_template'", child.partial
|
assert_equal "a_template", child.partial
|
||||||
end
|
end
|
||||||
|
|
||||||
b_template = t.profiler[2]
|
b_template = t.profiler[2]
|
||||||
b_template.children.each do |child|
|
b_template.children.each do |child|
|
||||||
assert_equal "'b_template'", child.partial
|
assert_equal "b_template", child.partial
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -114,12 +114,12 @@ class RenderProfilingTest < Minitest::Test
|
|||||||
|
|
||||||
a_template1 = t.profiler[1]
|
a_template1 = t.profiler[1]
|
||||||
a_template1.children.each do |child|
|
a_template1.children.each do |child|
|
||||||
assert_equal "'a_template'", child.partial
|
assert_equal "a_template", child.partial
|
||||||
end
|
end
|
||||||
|
|
||||||
a_template2 = t.profiler[2]
|
a_template2 = t.profiler[2]
|
||||||
a_template2.children.each do |child|
|
a_template2.children.each do |child|
|
||||||
assert_equal "'a_template'", child.partial
|
assert_equal "a_template", child.partial
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,11 @@ class IfElseTagTest < Minitest::Test
|
|||||||
assert_template_result(' you rock ?','{% if false %} you suck {% endif %} {% if true %} you rock {% endif %}?')
|
assert_template_result(' you rock ?','{% if false %} you suck {% endif %} {% if true %} you rock {% endif %}?')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_literal_comparisons
|
||||||
|
assert_template_result(' NO ','{% assign v = false %}{% if v %} YES {% else %} NO {% endif %}')
|
||||||
|
assert_template_result(' YES ','{% assign v = nil %}{% if v == nil %} YES {% else %} NO {% endif %}')
|
||||||
|
end
|
||||||
|
|
||||||
def test_if_else
|
def test_if_else
|
||||||
assert_template_result(' YES ','{% if false %} NO {% else %} YES {% endif %}')
|
assert_template_result(' YES ','{% if false %} NO {% else %} YES {% endif %}')
|
||||||
assert_template_result(' YES ','{% if true %} YES {% else %} NO {% endif %}')
|
assert_template_result(' YES ','{% if true %} YES {% else %} NO {% endif %}')
|
||||||
|
|||||||
@@ -27,6 +27,9 @@ class TestFileSystem
|
|||||||
when "pick_a_source"
|
when "pick_a_source"
|
||||||
"from TestFileSystem"
|
"from TestFileSystem"
|
||||||
|
|
||||||
|
when 'assignments'
|
||||||
|
"{% assign foo = 'bar' %}"
|
||||||
|
|
||||||
else
|
else
|
||||||
template_path
|
template_path
|
||||||
end
|
end
|
||||||
@@ -108,6 +111,10 @@ class IncludeTagTest < Minitest::Test
|
|||||||
'echo1' => 'test123', 'more_echos' => { "echo2" => 'test321'}
|
'echo1' => 'test123', 'more_echos' => { "echo2" => 'test321'}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_included_templates_assigns_variables
|
||||||
|
assert_template_result "bar", "{% include 'assignments' %}{{ foo }}"
|
||||||
|
end
|
||||||
|
|
||||||
def test_nested_include_tag
|
def test_nested_include_tag
|
||||||
assert_template_result "body body_detail", "{% include 'body' %}"
|
assert_template_result "body body_detail", "{% include 'body' %}"
|
||||||
|
|
||||||
|
|||||||
@@ -135,6 +135,18 @@ class TemplateTest < Minitest::Test
|
|||||||
assert t.resource_limits[:render_length_current] > 0
|
assert t.resource_limits[:render_length_current] > 0
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_default_resource_limits_unaffected_by_render_with_context
|
||||||
|
context = Context.new
|
||||||
|
t = Template.parse("{% for a in (1..100) %} {% assign foo = 1 %} {% endfor %}")
|
||||||
|
t.render!(context)
|
||||||
|
assert context.resource_limits[:assign_score_current] > 0
|
||||||
|
assert context.resource_limits[:render_score_current] > 0
|
||||||
|
assert context.resource_limits[:render_length_current] > 0
|
||||||
|
refute Template.default_resource_limits.key?(:assign_score_current)
|
||||||
|
refute Template.default_resource_limits.key?(:render_score_current)
|
||||||
|
refute Template.default_resource_limits.key?(:render_length_current)
|
||||||
|
end
|
||||||
|
|
||||||
def test_can_use_drop_as_context
|
def test_can_use_drop_as_context
|
||||||
t = Template.new
|
t = Template.new
|
||||||
t.registers['lulz'] = 'haha'
|
t.registers['lulz'] = 'haha'
|
||||||
|
|||||||
@@ -31,6 +31,12 @@ class VariableTest < Minitest::Test
|
|||||||
|
|
||||||
def test_false_renders_as_false
|
def test_false_renders_as_false
|
||||||
assert_equal 'false', Template.parse("{{ foo }}").render!('foo' => false)
|
assert_equal 'false', Template.parse("{{ foo }}").render!('foo' => false)
|
||||||
|
assert_equal 'false', Template.parse("{{ false }}").render!
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_nil_renders_as_empty_string
|
||||||
|
assert_equal '', Template.parse("{{ nil }}").render!
|
||||||
|
assert_equal 'cat', Template.parse("{{ nil | append: 'cat' }}").render!
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_preset_assigns
|
def test_preset_assigns
|
||||||
|
|||||||
@@ -57,6 +57,14 @@ module Minitest
|
|||||||
Liquid::Strainer.class_variable_set(:@@filters, original_filters)
|
Liquid::Strainer.class_variable_set(:@@filters, original_filters)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def with_taint_mode(mode)
|
||||||
|
old_mode = Liquid::Template.taint_mode
|
||||||
|
Liquid::Template.taint_mode = mode
|
||||||
|
yield
|
||||||
|
ensure
|
||||||
|
Liquid::Template.taint_mode = old_mode
|
||||||
|
end
|
||||||
|
|
||||||
def with_error_mode(mode)
|
def with_error_mode(mode)
|
||||||
old_mode = Liquid::Template.error_mode
|
old_mode = Liquid::Template.error_mode
|
||||||
Liquid::Template.error_mode = mode
|
Liquid::Template.error_mode = mode
|
||||||
|
|||||||
@@ -4,110 +4,111 @@ class ConditionUnitTest < Minitest::Test
|
|||||||
include Liquid
|
include Liquid
|
||||||
|
|
||||||
def test_basic_condition
|
def test_basic_condition
|
||||||
assert_equal false, Condition.new('1', '==', '2').evaluate
|
assert_equal false, Condition.new(1, '==', 2).evaluate
|
||||||
assert_equal true, Condition.new('1', '==', '1').evaluate
|
assert_equal true, Condition.new(1, '==', 1).evaluate
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_default_operators_evalute_true
|
def test_default_operators_evalute_true
|
||||||
assert_evalutes_true '1', '==', '1'
|
assert_evalutes_true 1, '==', 1
|
||||||
assert_evalutes_true '1', '!=', '2'
|
assert_evalutes_true 1, '!=', 2
|
||||||
assert_evalutes_true '1', '<>', '2'
|
assert_evalutes_true 1, '<>', 2
|
||||||
assert_evalutes_true '1', '<', '2'
|
assert_evalutes_true 1, '<', 2
|
||||||
assert_evalutes_true '2', '>', '1'
|
assert_evalutes_true 2, '>', 1
|
||||||
assert_evalutes_true '1', '>=', '1'
|
assert_evalutes_true 1, '>=', 1
|
||||||
assert_evalutes_true '2', '>=', '1'
|
assert_evalutes_true 2, '>=', 1
|
||||||
assert_evalutes_true '1', '<=', '2'
|
assert_evalutes_true 1, '<=', 2
|
||||||
assert_evalutes_true '1', '<=', '1'
|
assert_evalutes_true 1, '<=', 1
|
||||||
# negative numbers
|
# negative numbers
|
||||||
assert_evalutes_true '1', '>', '-1'
|
assert_evalutes_true 1, '>', -1
|
||||||
assert_evalutes_true '-1', '<', '1'
|
assert_evalutes_true -1, '<', 1
|
||||||
assert_evalutes_true '1.0', '>', '-1.0'
|
assert_evalutes_true 1.0, '>', -1.0
|
||||||
assert_evalutes_true '-1.0', '<', '1.0'
|
assert_evalutes_true -1.0, '<', 1.0
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_default_operators_evalute_false
|
def test_default_operators_evalute_false
|
||||||
assert_evalutes_false '1', '==', '2'
|
assert_evalutes_false 1, '==', 2
|
||||||
assert_evalutes_false '1', '!=', '1'
|
assert_evalutes_false 1, '!=', 1
|
||||||
assert_evalutes_false '1', '<>', '1'
|
assert_evalutes_false 1, '<>', 1
|
||||||
assert_evalutes_false '1', '<', '0'
|
assert_evalutes_false 1, '<', 0
|
||||||
assert_evalutes_false '2', '>', '4'
|
assert_evalutes_false 2, '>', 4
|
||||||
assert_evalutes_false '1', '>=', '3'
|
assert_evalutes_false 1, '>=', 3
|
||||||
assert_evalutes_false '2', '>=', '4'
|
assert_evalutes_false 2, '>=', 4
|
||||||
assert_evalutes_false '1', '<=', '0'
|
assert_evalutes_false 1, '<=', 0
|
||||||
assert_evalutes_false '1', '<=', '0'
|
assert_evalutes_false 1, '<=', 0
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_contains_works_on_strings
|
def test_contains_works_on_strings
|
||||||
assert_evalutes_true "'bob'", 'contains', "'o'"
|
assert_evalutes_true 'bob', 'contains', 'o'
|
||||||
assert_evalutes_true "'bob'", 'contains', "'b'"
|
assert_evalutes_true 'bob', 'contains', 'b'
|
||||||
assert_evalutes_true "'bob'", 'contains', "'bo'"
|
assert_evalutes_true 'bob', 'contains', 'bo'
|
||||||
assert_evalutes_true "'bob'", 'contains', "'ob'"
|
assert_evalutes_true 'bob', 'contains', 'ob'
|
||||||
assert_evalutes_true "'bob'", 'contains', "'bob'"
|
assert_evalutes_true 'bob', 'contains', 'bob'
|
||||||
|
|
||||||
assert_evalutes_false "'bob'", 'contains', "'bob2'"
|
assert_evalutes_false 'bob', 'contains', 'bob2'
|
||||||
assert_evalutes_false "'bob'", 'contains', "'a'"
|
assert_evalutes_false 'bob', 'contains', 'a'
|
||||||
assert_evalutes_false "'bob'", 'contains', "'---'"
|
assert_evalutes_false 'bob', 'contains', '---'
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_invalid_comparation_operator
|
def test_invalid_comparation_operator
|
||||||
assert_evaluates_argument_error "1", '~~', '0'
|
assert_evaluates_argument_error 1, '~~', 0
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_comparation_of_int_and_str
|
def test_comparation_of_int_and_str
|
||||||
assert_evaluates_argument_error "'1'", '>', '0'
|
assert_evaluates_argument_error '1', '>', 0
|
||||||
assert_evaluates_argument_error "'1'", '<', '0'
|
assert_evaluates_argument_error '1', '<', 0
|
||||||
assert_evaluates_argument_error "'1'", '>=', '0'
|
assert_evaluates_argument_error '1', '>=', 0
|
||||||
assert_evaluates_argument_error "'1'", '<=', '0'
|
assert_evaluates_argument_error '1', '<=', 0
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_contains_works_on_arrays
|
def test_contains_works_on_arrays
|
||||||
@context = Liquid::Context.new
|
@context = Liquid::Context.new
|
||||||
@context['array'] = [1,2,3,4,5]
|
@context['array'] = [1,2,3,4,5]
|
||||||
|
array_expr = VariableLookup.new("array")
|
||||||
|
|
||||||
assert_evalutes_false "array", 'contains', '0'
|
assert_evalutes_false array_expr, 'contains', 0
|
||||||
assert_evalutes_true "array", 'contains', '1'
|
assert_evalutes_true array_expr, 'contains', 1
|
||||||
assert_evalutes_true "array", 'contains', '2'
|
assert_evalutes_true array_expr, 'contains', 2
|
||||||
assert_evalutes_true "array", 'contains', '3'
|
assert_evalutes_true array_expr, 'contains', 3
|
||||||
assert_evalutes_true "array", 'contains', '4'
|
assert_evalutes_true array_expr, 'contains', 4
|
||||||
assert_evalutes_true "array", 'contains', '5'
|
assert_evalutes_true array_expr, 'contains', 5
|
||||||
assert_evalutes_false "array", 'contains', '6'
|
assert_evalutes_false array_expr, 'contains', 6
|
||||||
assert_evalutes_false "array", 'contains', '"1"'
|
assert_evalutes_false array_expr, 'contains', "1"
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_contains_returns_false_for_nil_operands
|
def test_contains_returns_false_for_nil_operands
|
||||||
@context = Liquid::Context.new
|
@context = Liquid::Context.new
|
||||||
assert_evalutes_false "not_assigned", 'contains', '0'
|
assert_evalutes_false VariableLookup.new('not_assigned'), 'contains', '0'
|
||||||
assert_evalutes_false "0", 'contains', 'not_assigned'
|
assert_evalutes_false 0, 'contains', VariableLookup.new('not_assigned')
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_contains_return_false_on_wrong_data_type
|
def test_contains_return_false_on_wrong_data_type
|
||||||
assert_evalutes_false "1", 'contains', '0'
|
assert_evalutes_false 1, 'contains', 0
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_or_condition
|
def test_or_condition
|
||||||
condition = Condition.new('1', '==', '2')
|
condition = Condition.new(1, '==', 2)
|
||||||
|
|
||||||
assert_equal false, condition.evaluate
|
assert_equal false, condition.evaluate
|
||||||
|
|
||||||
condition.or Condition.new('2', '==', '1')
|
condition.or Condition.new(2, '==', 1)
|
||||||
|
|
||||||
assert_equal false, condition.evaluate
|
assert_equal false, condition.evaluate
|
||||||
|
|
||||||
condition.or Condition.new('1', '==', '1')
|
condition.or Condition.new(1, '==', 1)
|
||||||
|
|
||||||
assert_equal true, condition.evaluate
|
assert_equal true, condition.evaluate
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_and_condition
|
def test_and_condition
|
||||||
condition = Condition.new('1', '==', '1')
|
condition = Condition.new(1, '==', 1)
|
||||||
|
|
||||||
assert_equal true, condition.evaluate
|
assert_equal true, condition.evaluate
|
||||||
|
|
||||||
condition.and Condition.new('2', '==', '2')
|
condition.and Condition.new(2, '==', 2)
|
||||||
|
|
||||||
assert_equal true, condition.evaluate
|
assert_equal true, condition.evaluate
|
||||||
|
|
||||||
condition.and Condition.new('2', '==', '1')
|
condition.and Condition.new(2, '==', 1)
|
||||||
|
|
||||||
assert_equal false, condition.evaluate
|
assert_equal false, condition.evaluate
|
||||||
end
|
end
|
||||||
@@ -115,18 +116,17 @@ class ConditionUnitTest < Minitest::Test
|
|||||||
def test_should_allow_custom_proc_operator
|
def test_should_allow_custom_proc_operator
|
||||||
Condition.operators['starts_with'] = Proc.new { |cond, left, right| left =~ %r{^#{right}} }
|
Condition.operators['starts_with'] = Proc.new { |cond, left, right| left =~ %r{^#{right}} }
|
||||||
|
|
||||||
assert_evalutes_true "'bob'", 'starts_with', "'b'"
|
assert_evalutes_true 'bob', 'starts_with', 'b'
|
||||||
assert_evalutes_false "'bob'", 'starts_with', "'o'"
|
assert_evalutes_false 'bob', 'starts_with', 'o'
|
||||||
|
ensure
|
||||||
ensure
|
Condition.operators.delete 'starts_with'
|
||||||
Condition.operators.delete 'starts_with'
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_left_or_right_may_contain_operators
|
def test_left_or_right_may_contain_operators
|
||||||
@context = Liquid::Context.new
|
@context = Liquid::Context.new
|
||||||
@context['one'] = @context['another'] = "gnomeslab-and-or-liquid"
|
@context['one'] = @context['another'] = "gnomeslab-and-or-liquid"
|
||||||
|
|
||||||
assert_evalutes_true "one", '==', "another"
|
assert_evalutes_true VariableLookup.new("one"), '==', VariableLookup.new("another")
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|||||||
@@ -469,16 +469,6 @@ class ContextUnitTest < Minitest::Test
|
|||||||
|
|
||||||
refute mock_any.has_been_called?
|
refute mock_any.has_been_called?
|
||||||
assert mock_empty.has_been_called?
|
assert mock_empty.has_been_called?
|
||||||
end
|
|
||||||
|
|
||||||
def test_variable_lookup_caches_markup
|
|
||||||
mock_scan = Spy.on_instance_method(String, :scan).and_return(["string"])
|
|
||||||
|
|
||||||
@context['string'] = 'string'
|
|
||||||
@context['string']
|
|
||||||
@context['string']
|
|
||||||
|
|
||||||
assert_equal 1, mock_scan.calls.size
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_context_initialization_with_a_proc_in_environment
|
def test_context_initialization_with_a_proc_in_environment
|
||||||
|
|||||||
@@ -31,8 +31,8 @@ class LexerUnitTest < Minitest::Test
|
|||||||
end
|
end
|
||||||
|
|
||||||
def test_fancy_identifiers
|
def test_fancy_identifiers
|
||||||
tokens = Lexer.new('hi! five?').tokenize
|
tokens = Lexer.new('hi five?').tokenize
|
||||||
assert_equal [[:id,'hi!'], [:id, 'five?'], [:end_of_string]], tokens
|
assert_equal [[:id,'hi'], [:id, 'five'], [:question, '?'], [:end_of_string]], tokens
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_whitespace
|
def test_whitespace
|
||||||
|
|||||||
@@ -44,9 +44,9 @@ class ParserUnitTest < Minitest::Test
|
|||||||
end
|
end
|
||||||
|
|
||||||
def test_expressions
|
def test_expressions
|
||||||
p = Parser.new("hi.there hi[5].! hi.there.bob")
|
p = Parser.new("hi.there hi?[5].there? hi.there.bob")
|
||||||
assert_equal 'hi.there', p.expression
|
assert_equal 'hi.there', p.expression
|
||||||
assert_equal 'hi[5].!', p.expression
|
assert_equal 'hi?[5].there?', p.expression
|
||||||
assert_equal 'hi.there.bob', p.expression
|
assert_equal 'hi.there.bob', p.expression
|
||||||
|
|
||||||
p = Parser.new("567 6.0 'lol' \"wut\"")
|
p = Parser.new("567 6.0 'lol' \"wut\"")
|
||||||
|
|||||||
@@ -57,7 +57,8 @@ class StrainerUnitTest < Minitest::Test
|
|||||||
end
|
end
|
||||||
|
|
||||||
def test_strainer_uses_a_class_cache_to_avoid_method_cache_invalidation
|
def test_strainer_uses_a_class_cache_to_avoid_method_cache_invalidation
|
||||||
a, b = Module.new, Module.new
|
a = Module.new
|
||||||
|
b = Module.new
|
||||||
strainer = Strainer.create(nil, [a,b])
|
strainer = Strainer.create(nil, [a,b])
|
||||||
assert_kind_of Strainer, strainer
|
assert_kind_of Strainer, strainer
|
||||||
assert_kind_of a, strainer
|
assert_kind_of a, strainer
|
||||||
|
|||||||
@@ -5,125 +5,126 @@ class VariableUnitTest < Minitest::Test
|
|||||||
|
|
||||||
def test_variable
|
def test_variable
|
||||||
var = Variable.new('hello')
|
var = Variable.new('hello')
|
||||||
assert_equal 'hello', var.name
|
assert_equal VariableLookup.new('hello'), var.name
|
||||||
|
|
||||||
|
var = Variable.new('hello[goodbye ]')
|
||||||
|
assert_equal VariableLookup.new('hello[goodbye]'), var.name
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_filters
|
def test_filters
|
||||||
var = Variable.new('hello | textileze')
|
var = Variable.new('hello | textileze')
|
||||||
assert_equal 'hello', var.name
|
assert_equal VariableLookup.new('hello'), var.name
|
||||||
assert_equal [["textileze",[]]], var.filters
|
assert_equal [['textileze',[]]], var.filters
|
||||||
|
|
||||||
var = Variable.new('hello | textileze | paragraph')
|
var = Variable.new('hello | textileze | paragraph')
|
||||||
assert_equal 'hello', var.name
|
assert_equal VariableLookup.new('hello'), var.name
|
||||||
assert_equal [["textileze",[]], ["paragraph",[]]], var.filters
|
assert_equal [['textileze',[]], ['paragraph',[]]], var.filters
|
||||||
|
|
||||||
var = Variable.new(%! hello | strftime: '%Y'!)
|
var = Variable.new(%! hello | strftime: '%Y'!)
|
||||||
assert_equal 'hello', var.name
|
assert_equal VariableLookup.new('hello'), var.name
|
||||||
assert_equal [["strftime",["'%Y'"]]], var.filters
|
assert_equal [['strftime',['%Y']]], var.filters
|
||||||
|
|
||||||
var = Variable.new(%! 'typo' | link_to: 'Typo', true !)
|
var = Variable.new(%! 'typo' | link_to: 'Typo', true !)
|
||||||
assert_equal %!'typo'!, var.name
|
assert_equal 'typo', var.name
|
||||||
assert_equal [["link_to",["'Typo'", "true"]]], var.filters
|
assert_equal [['link_to',['Typo', true]]], var.filters
|
||||||
|
|
||||||
var = Variable.new(%! 'typo' | link_to: 'Typo', false !)
|
var = Variable.new(%! 'typo' | link_to: 'Typo', false !)
|
||||||
assert_equal %!'typo'!, var.name
|
assert_equal 'typo', var.name
|
||||||
assert_equal [["link_to",["'Typo'", "false"]]], var.filters
|
assert_equal [['link_to',['Typo', false]]], var.filters
|
||||||
|
|
||||||
var = Variable.new(%! 'foo' | repeat: 3 !)
|
var = Variable.new(%! 'foo' | repeat: 3 !)
|
||||||
assert_equal %!'foo'!, var.name
|
assert_equal 'foo', var.name
|
||||||
assert_equal [["repeat",["3"]]], var.filters
|
assert_equal [['repeat',[3]]], var.filters
|
||||||
|
|
||||||
var = Variable.new(%! 'foo' | repeat: 3, 3 !)
|
var = Variable.new(%! 'foo' | repeat: 3, 3 !)
|
||||||
assert_equal %!'foo'!, var.name
|
assert_equal 'foo', var.name
|
||||||
assert_equal [["repeat",["3","3"]]], var.filters
|
assert_equal [['repeat',[3,3]]], var.filters
|
||||||
|
|
||||||
var = Variable.new(%! 'foo' | repeat: 3, 3, 3 !)
|
var = Variable.new(%! 'foo' | repeat: 3, 3, 3 !)
|
||||||
assert_equal %!'foo'!, var.name
|
assert_equal 'foo', var.name
|
||||||
assert_equal [["repeat",["3","3","3"]]], var.filters
|
assert_equal [['repeat',[3,3,3]]], var.filters
|
||||||
|
|
||||||
var = Variable.new(%! hello | strftime: '%Y, okay?'!)
|
var = Variable.new(%! hello | strftime: '%Y, okay?'!)
|
||||||
assert_equal 'hello', var.name
|
assert_equal VariableLookup.new('hello'), var.name
|
||||||
assert_equal [["strftime",["'%Y, okay?'"]]], var.filters
|
assert_equal [['strftime',['%Y, okay?']]], var.filters
|
||||||
|
|
||||||
var = Variable.new(%! hello | things: "%Y, okay?", 'the other one'!)
|
var = Variable.new(%! hello | things: "%Y, okay?", 'the other one'!)
|
||||||
assert_equal 'hello', var.name
|
assert_equal VariableLookup.new('hello'), var.name
|
||||||
assert_equal [["things",["\"%Y, okay?\"","'the other one'"]]], var.filters
|
assert_equal [['things',['%Y, okay?','the other one']]], var.filters
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_filter_with_date_parameter
|
def test_filter_with_date_parameter
|
||||||
|
|
||||||
var = Variable.new(%! '2006-06-06' | date: "%m/%d/%Y"!)
|
var = Variable.new(%! '2006-06-06' | date: "%m/%d/%Y"!)
|
||||||
assert_equal "'2006-06-06'", var.name
|
assert_equal '2006-06-06', var.name
|
||||||
assert_equal [["date",["\"%m/%d/%Y\""]]], var.filters
|
assert_equal [['date',['%m/%d/%Y']]], var.filters
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_filters_without_whitespace
|
def test_filters_without_whitespace
|
||||||
var = Variable.new('hello | textileze | paragraph')
|
var = Variable.new('hello | textileze | paragraph')
|
||||||
assert_equal 'hello', var.name
|
assert_equal VariableLookup.new('hello'), var.name
|
||||||
assert_equal [["textileze",[]], ["paragraph",[]]], var.filters
|
assert_equal [['textileze',[]], ['paragraph',[]]], var.filters
|
||||||
|
|
||||||
var = Variable.new('hello|textileze|paragraph')
|
var = Variable.new('hello|textileze|paragraph')
|
||||||
assert_equal 'hello', var.name
|
assert_equal VariableLookup.new('hello'), var.name
|
||||||
assert_equal [["textileze",[]], ["paragraph",[]]], var.filters
|
assert_equal [['textileze',[]], ['paragraph',[]]], var.filters
|
||||||
|
|
||||||
var = Variable.new("hello|replace:'foo','bar'|textileze")
|
var = Variable.new("hello|replace:'foo','bar'|textileze")
|
||||||
assert_equal 'hello', var.name
|
assert_equal VariableLookup.new('hello'), var.name
|
||||||
assert_equal [["replace", ["'foo'", "'bar'"]], ["textileze", []]], var.filters
|
assert_equal [['replace', ['foo', 'bar']], ['textileze', []]], var.filters
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_symbol
|
def test_symbol
|
||||||
var = Variable.new("http://disney.com/logo.gif | image: 'med' ", :error_mode => :lax)
|
var = Variable.new("http://disney.com/logo.gif | image: 'med' ", :error_mode => :lax)
|
||||||
assert_equal "http://disney.com/logo.gif", var.name
|
assert_equal VariableLookup.new('http://disney.com/logo.gif'), var.name
|
||||||
assert_equal [["image",["'med'"]]], var.filters
|
assert_equal [['image',['med']]], var.filters
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_string_to_filter
|
def test_string_to_filter
|
||||||
var = Variable.new("'http://disney.com/logo.gif' | image: 'med' ")
|
var = Variable.new("'http://disney.com/logo.gif' | image: 'med' ")
|
||||||
assert_equal "'http://disney.com/logo.gif'", var.name
|
assert_equal 'http://disney.com/logo.gif', var.name
|
||||||
assert_equal [["image",["'med'"]]], var.filters
|
assert_equal [['image',['med']]], var.filters
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_string_single_quoted
|
def test_string_single_quoted
|
||||||
var = Variable.new(%| "hello" |)
|
var = Variable.new(%| "hello" |)
|
||||||
assert_equal '"hello"', var.name
|
assert_equal 'hello', var.name
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_string_double_quoted
|
def test_string_double_quoted
|
||||||
var = Variable.new(%| 'hello' |)
|
var = Variable.new(%| 'hello' |)
|
||||||
assert_equal "'hello'", var.name
|
assert_equal 'hello', var.name
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_integer
|
def test_integer
|
||||||
var = Variable.new(%| 1000 |)
|
var = Variable.new(%| 1000 |)
|
||||||
assert_equal "1000", var.name
|
assert_equal 1000, var.name
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_float
|
def test_float
|
||||||
var = Variable.new(%| 1000.01 |)
|
var = Variable.new(%| 1000.01 |)
|
||||||
assert_equal "1000.01", var.name
|
assert_equal 1000.01, var.name
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_string_with_special_chars
|
def test_string_with_special_chars
|
||||||
var = Variable.new(%| 'hello! $!@.;"ddasd" ' |)
|
var = Variable.new(%| 'hello! $!@.;"ddasd" ' |)
|
||||||
assert_equal %|'hello! $!@.;"ddasd" '|, var.name
|
assert_equal 'hello! $!@.;"ddasd" ', var.name
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_string_dot
|
def test_string_dot
|
||||||
var = Variable.new(%| test.test |)
|
var = Variable.new(%| test.test |)
|
||||||
assert_equal 'test.test', var.name
|
assert_equal VariableLookup.new('test.test'), var.name
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_filter_with_keyword_arguments
|
def test_filter_with_keyword_arguments
|
||||||
var = Variable.new(%! hello | things: greeting: "world", farewell: 'goodbye'!)
|
var = Variable.new(%! hello | things: greeting: "world", farewell: 'goodbye'!)
|
||||||
assert_equal 'hello', var.name
|
assert_equal VariableLookup.new('hello'), var.name
|
||||||
assert_equal [['things',["greeting: \"world\"","farewell: 'goodbye'"]]], var.filters
|
assert_equal [['things', [], { 'greeting' => 'world', 'farewell' => 'goodbye' }]], var.filters
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_lax_filter_argument_parsing
|
def test_lax_filter_argument_parsing
|
||||||
var = Variable.new(%! number_of_comments | pluralize: 'comment': 'comments' !, :error_mode => :lax)
|
var = Variable.new(%! number_of_comments | pluralize: 'comment': 'comments' !, :error_mode => :lax)
|
||||||
assert_equal 'number_of_comments', var.name
|
assert_equal VariableLookup.new('number_of_comments'), var.name
|
||||||
assert_equal [['pluralize',["'comment'","'comments'"]]], var.filters
|
assert_equal [['pluralize',['comment','comments']]], var.filters
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_strict_filter_argument_parsing
|
def test_strict_filter_argument_parsing
|
||||||
|
|||||||
Reference in New Issue
Block a user