mirror of
https://github.com/kemko/liquid.git
synced 2026-01-02 00:05:42 +03:00
Compare commits
13 Commits
simplify_f
...
v2.6.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dcd21d3db3 | ||
|
|
deeb813d53 | ||
|
|
eb409ff237 | ||
|
|
442041206f | ||
|
|
dc6c6fbb9a | ||
|
|
4293be3154 | ||
|
|
736c11c876 | ||
|
|
a41a60d294 | ||
|
|
307cab2eaa | ||
|
|
a64360d148 | ||
|
|
6cb5a9b7cc | ||
|
|
4207d1f086 | ||
|
|
988a1694fd |
24
History.md
24
History.md
@@ -3,7 +3,13 @@
|
|||||||
IMPORTANT: Liquid 2.6 is going to be the last version of Liquid which maintains explicit Ruby 1.8 compatability.
|
IMPORTANT: Liquid 2.6 is going to be the last version of Liquid which maintains explicit Ruby 1.8 compatability.
|
||||||
The following releases will only be tested against Ruby 1.9 and Ruby 2.0 and are likely to break on Ruby 1.8.
|
The following releases will only be tested against Ruby 1.9 and Ruby 2.0 and are likely to break on Ruby 1.8.
|
||||||
|
|
||||||
## 2.6.0 / Master branch (not yet released)
|
## 2.6.1 / 2014-01-10 / branch "2-6-stable"
|
||||||
|
|
||||||
|
Security fix, cherry-picked from master (4e14a65):
|
||||||
|
* Don't call to_sym when creating conditions for security reasons, see #273 [Bouke van der Bijl, bouk]
|
||||||
|
* Prevent arbitrary method invocation on condition objects, see #274 [Dylan Thacker-Smith, dylanahsmith]
|
||||||
|
|
||||||
|
## 2.6.0 / 2013-11-25
|
||||||
|
|
||||||
* ...
|
* ...
|
||||||
* Bugfix for #106: fix example servlet [gnowoel]
|
* Bugfix for #106: fix example servlet [gnowoel]
|
||||||
@@ -14,6 +20,7 @@ The following releases will only be tested against Ruby 1.9 and Ruby 2.0 and are
|
|||||||
* Bugfix for #204: 'raw' parsing bug [Florian Weingarten, fw42]
|
* Bugfix for #204: 'raw' parsing bug [Florian Weingarten, fw42]
|
||||||
* Bugfix for #150: 'for' parsing bug [Peter Schröder, phoet]
|
* Bugfix for #150: 'for' parsing bug [Peter Schröder, phoet]
|
||||||
* Bugfix for #126: Strip CRLF in strip_newline [Peter Schröder, phoet]
|
* Bugfix for #126: Strip CRLF in strip_newline [Peter Schröder, phoet]
|
||||||
|
* Bugfix for #174, "can't convert Fixnum into String" for "replace" [wǒ_is神仙, jsw0528]
|
||||||
* Allow a Liquid::Drop to be passed into Template#render [Daniel Huckstep, darkhelmet]
|
* Allow a Liquid::Drop to be passed into Template#render [Daniel Huckstep, darkhelmet]
|
||||||
* Resource limits [Florian Weingarten, fw42]
|
* Resource limits [Florian Weingarten, fw42]
|
||||||
* Add reverse filter [Jay Strybis, unreal]
|
* Add reverse filter [Jay Strybis, unreal]
|
||||||
@@ -24,6 +31,21 @@ The following releases will only be tested against Ruby 1.9 and Ruby 2.0 and are
|
|||||||
* Better documentation for 'include' tag (closes #163) [Peter Schröder, phoet]
|
* Better documentation for 'include' tag (closes #163) [Peter Schröder, phoet]
|
||||||
* Use of BigDecimal on filters to have better precision (closes #155) [Arthur Nogueira Neves, arthurnn]
|
* Use of BigDecimal on filters to have better precision (closes #155) [Arthur Nogueira Neves, arthurnn]
|
||||||
|
|
||||||
|
## 2.5.4 / 2013-11-11 / branch "2.5-stable"
|
||||||
|
|
||||||
|
* Fix "can't convert Fixnum into String" for "replace", see #173, [wǒ_is神仙, jsw0528]
|
||||||
|
|
||||||
|
## 2.5.3 / 2013-10-09
|
||||||
|
|
||||||
|
* #232, #234, #237: Fix map filter bugs [Florian Weingarten, fw42]
|
||||||
|
|
||||||
|
## 2.5.2 / 2013-09-03 / deleted
|
||||||
|
|
||||||
|
Yanked from rubygems, as it contained too many changes that broke compatibility. Those changes will be on following major releases.
|
||||||
|
|
||||||
|
## 2.5.1 / 2013-07-24
|
||||||
|
|
||||||
|
* #230: Fix security issue with map filter, Use invoke_drop in map filter [Florian Weingarten, fw42]
|
||||||
|
|
||||||
## 2.5.0 / 2013-03-06
|
## 2.5.0 / 2013-03-06
|
||||||
|
|
||||||
|
|||||||
24
Rakefile
24
Rakefile
@@ -1,9 +1,7 @@
|
|||||||
#!/usr/bin/env ruby
|
|
||||||
|
|
||||||
require 'rubygems'
|
|
||||||
require 'rake'
|
require 'rake'
|
||||||
require 'rake/testtask'
|
require 'rake/testtask'
|
||||||
require 'rubygems/package_task'
|
$LOAD_PATH.unshift File.expand_path("../lib", __FILE__)
|
||||||
|
require "liquid/version"
|
||||||
|
|
||||||
task :default => 'test'
|
task :default => 'test'
|
||||||
|
|
||||||
@@ -13,14 +11,20 @@ Rake::TestTask.new(:test) do |t|
|
|||||||
t.verbose = false
|
t.verbose = false
|
||||||
end
|
end
|
||||||
|
|
||||||
gemspec = eval(File.read('liquid.gemspec'))
|
task :gem => :build
|
||||||
Gem::PackageTask.new(gemspec) do |pkg|
|
task :build do
|
||||||
pkg.gem_spec = gemspec
|
system "gem build liquid.gemspec"
|
||||||
end
|
end
|
||||||
|
|
||||||
desc "Build the gem and release it to rubygems.org"
|
task :install => :build do
|
||||||
task :release => :gem do
|
system "gem install liquid-#{Liquid::VERSION}.gem"
|
||||||
sh "gem push pkg/liquid-#{gemspec.version}.gem"
|
end
|
||||||
|
|
||||||
|
task :release => :build do
|
||||||
|
system "git tag -a v#{Liquid::VERSION} -m 'Tagging #{Liquid::VERSION}'"
|
||||||
|
system "git push --tags"
|
||||||
|
system "gem push liquid-#{Liquid::VERSION}.gem"
|
||||||
|
system "rm liquid-#{Liquid::VERSION}.gem"
|
||||||
end
|
end
|
||||||
|
|
||||||
namespace :benchmark do
|
namespace :benchmark do
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ module Liquid
|
|||||||
|
|
||||||
# Check for method existence without invoking respond_to?, which creates symbols
|
# Check for method existence without invoking respond_to?, which creates symbols
|
||||||
def self.invokable?(method_name)
|
def self.invokable?(method_name)
|
||||||
@invokable_methods ||= Set.new((public_instance_methods - Liquid::Drop.public_instance_methods).map(&:to_s))
|
@invokable_methods ||= Set.new(["to_liquid"] + (public_instance_methods - Liquid::Drop.public_instance_methods).map(&:to_s))
|
||||||
@invokable_methods.include?(method_name.to_s)
|
@invokable_methods.include?(method_name.to_s)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -100,10 +100,15 @@ module Liquid
|
|||||||
# map/collect on a given property
|
# map/collect on a given property
|
||||||
def map(input, property)
|
def map(input, property)
|
||||||
ary = [input].flatten
|
ary = [input].flatten
|
||||||
if ary.first.respond_to?('[]') and !ary.first[property].nil?
|
ary.map do |e|
|
||||||
ary.map {|e| e[property] }
|
e = e.call if e.is_a?(Proc)
|
||||||
elsif ary.first.respond_to?(property)
|
e = e.to_liquid if e.respond_to?(:to_liquid)
|
||||||
ary.map {|e| e.send(property) }
|
|
||||||
|
if property == "to_liquid"
|
||||||
|
e
|
||||||
|
elsif e.respond_to?(:[])
|
||||||
|
e[property]
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ module Liquid
|
|||||||
SyntaxHelp = "Syntax Error in tag 'if' - Valid syntax: if [expression]"
|
SyntaxHelp = "Syntax Error in tag 'if' - Valid syntax: if [expression]"
|
||||||
Syntax = /(#{QuotedFragment})\s*([=!<>a-z_]+)?\s*(#{QuotedFragment})?/o
|
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
|
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)
|
def initialize(tag_name, markup, tokens)
|
||||||
@blocks = []
|
@blocks = []
|
||||||
@@ -61,7 +62,8 @@ module Liquid
|
|||||||
raise(SyntaxError, SyntaxHelp) unless expressions.shift.to_s =~ Syntax
|
raise(SyntaxError, SyntaxHelp) unless expressions.shift.to_s =~ Syntax
|
||||||
|
|
||||||
new_condition = Condition.new($1, $2, $3)
|
new_condition = Condition.new($1, $2, $3)
|
||||||
new_condition.send(operator.to_sym, condition)
|
raise SyntaxError, "invalid boolean operator" unless BOOLEAN_OPERATORS.include?(operator)
|
||||||
|
new_condition.send(operator, condition)
|
||||||
condition = new_condition
|
condition = new_condition
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -71,8 +73,6 @@ module Liquid
|
|||||||
@blocks.push(block)
|
@blocks.push(block)
|
||||||
@nodelist = block.attach(Array.new)
|
@nodelist = block.attach(Array.new)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
Template.register_tag('if', If)
|
Template.register_tag('if', If)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# encoding: utf-8
|
# encoding: utf-8
|
||||||
module Liquid
|
module Liquid
|
||||||
VERSION = "2.6.0"
|
VERSION = "2.6.1"
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -71,23 +71,34 @@ class DropsTest < Test::Unit::TestCase
|
|||||||
include Liquid
|
include Liquid
|
||||||
|
|
||||||
def test_product_drop
|
def test_product_drop
|
||||||
|
|
||||||
assert_nothing_raised do
|
assert_nothing_raised do
|
||||||
tpl = Liquid::Template.parse( ' ' )
|
tpl = Liquid::Template.parse( ' ' )
|
||||||
tpl.render('product' => ProductDrop.new)
|
tpl.render('product' => ProductDrop.new)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
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.pretty_inspect }}").render('product' => ProductDrop.new)
|
||||||
|
assert_equal "", Liquid::Template.parse("{{ product.whatever }}").render('product' => ProductDrop.new)
|
||||||
|
assert_equal "", Liquid::Template.parse('{{ product | map: "inspect" }}').render('product' => ProductDrop.new)
|
||||||
|
assert_equal "", Liquid::Template.parse('{{ product | map: "pretty_inspect" }}').render('product' => ProductDrop.new)
|
||||||
|
assert_equal "", Liquid::Template.parse('{{ product | map: "whatever" }}').render('product' => ProductDrop.new)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_drops_respond_to_to_liquid
|
||||||
|
assert_equal "text1", Liquid::Template.parse("{{ product.to_liquid.texts.text }}").render('product' => ProductDrop.new)
|
||||||
|
assert_equal "text1", Liquid::Template.parse('{{ product | map: "to_liquid" | map: "texts" | map: "text" }}').render('product' => ProductDrop.new)
|
||||||
|
end
|
||||||
|
|
||||||
def test_text_drop
|
def test_text_drop
|
||||||
output = Liquid::Template.parse( ' {{ product.texts.text }} ' ).render('product' => ProductDrop.new)
|
output = Liquid::Template.parse( ' {{ product.texts.text }} ' ).render('product' => ProductDrop.new)
|
||||||
assert_equal ' text1 ', output
|
assert_equal ' text1 ', output
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_unknown_method
|
def test_unknown_method
|
||||||
output = Liquid::Template.parse( ' {{ product.catchall.unknown }} ' ).render('product' => ProductDrop.new)
|
output = Liquid::Template.parse( ' {{ product.catchall.unknown }} ' ).render('product' => ProductDrop.new)
|
||||||
assert_equal ' method: unknown ', output
|
assert_equal ' method: unknown ', output
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_integer_argument_drop
|
def test_integer_argument_drop
|
||||||
|
|||||||
@@ -6,6 +6,27 @@ class Filters
|
|||||||
include Liquid::StandardFilters
|
include Liquid::StandardFilters
|
||||||
end
|
end
|
||||||
|
|
||||||
|
class TestThing
|
||||||
|
def initialize
|
||||||
|
@foo = 0
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_s
|
||||||
|
"woot: #{@foo}"
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_liquid
|
||||||
|
@foo += 1
|
||||||
|
self
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class TestDrop < Liquid::Drop
|
||||||
|
def test
|
||||||
|
"testfoo"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
class StandardFiltersTest < Test::Unit::TestCase
|
class StandardFiltersTest < Test::Unit::TestCase
|
||||||
include Liquid
|
include Liquid
|
||||||
|
|
||||||
@@ -97,6 +118,23 @@ class StandardFiltersTest < Test::Unit::TestCase
|
|||||||
'ary' => [{'foo' => {'bar' => 'a'}}, {'foo' => {'bar' => 'b'}}, {'foo' => {'bar' => 'c'}}]
|
'ary' => [{'foo' => {'bar' => 'a'}}, {'foo' => {'bar' => 'b'}}, {'foo' => {'bar' => 'c'}}]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_map_doesnt_call_arbitrary_stuff
|
||||||
|
assert_equal "", Liquid::Template.parse('{{ "foo" | map: "__id__" }}').render
|
||||||
|
assert_equal "", Liquid::Template.parse('{{ "foo" | map: "inspect" }}').render
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_map_calls_to_liquid
|
||||||
|
t = TestThing.new
|
||||||
|
assert_equal "woot: 1", Liquid::Template.parse('{{ foo }}').render("foo" => t)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_map_over_proc
|
||||||
|
drop = TestDrop.new
|
||||||
|
p = Proc.new{ drop }
|
||||||
|
templ = '{{ procs | map: "test" }}'
|
||||||
|
assert_equal "testfoo", Liquid::Template.parse(templ).render("procs" => [p])
|
||||||
|
end
|
||||||
|
|
||||||
def test_date
|
def test_date
|
||||||
assert_equal 'May', @filters.date(Time.parse("2006-05-05 10:00:00"), "%B")
|
assert_equal 'May', @filters.date(Time.parse("2006-05-05 10:00:00"), "%B")
|
||||||
assert_equal 'June', @filters.date(Time.parse("2006-06-05 10:00:00"), "%B")
|
assert_equal 'June', @filters.date(Time.parse("2006-06-05 10:00:00"), "%B")
|
||||||
|
|||||||
@@ -157,4 +157,10 @@ class IfElseTagTest < Test::Unit::TestCase
|
|||||||
assert_template_result('yes',
|
assert_template_result('yes',
|
||||||
%({% if 'gnomeslab-and-or-liquid' contains 'gnomeslab-and-or-liquid' %}yes{% endif %}))
|
%({% if 'gnomeslab-and-or-liquid' contains 'gnomeslab-and-or-liquid' %}yes{% endif %}))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_operators_are_whitelisted
|
||||||
|
assert_raise(SyntaxError) do
|
||||||
|
assert_template_result('', %({% if 1 or throw or or 1 %}yes{% endif %}))
|
||||||
|
end
|
||||||
|
end
|
||||||
end # IfElseTest
|
end # IfElseTest
|
||||||
|
|||||||
Reference in New Issue
Block a user