liquid 1.7.0 → 1.9.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +17 -15
- data/History.txt +44 -0
- data/MIT-LICENSE +2 -2
- data/Manifest.txt +6 -1
- data/{README → README.txt} +0 -0
- data/Rakefile +3 -3
- data/init.rb +5 -3
- data/lib/liquid.rb +8 -6
- data/lib/liquid/block.rb +6 -9
- data/lib/liquid/condition.rb +49 -17
- data/lib/liquid/context.rb +67 -41
- data/lib/liquid/errors.rb +8 -5
- data/lib/liquid/htmltags.rb +17 -7
- data/lib/liquid/module_ex.rb +62 -0
- data/lib/liquid/standardfilters.rb +39 -0
- data/lib/liquid/strainer.rb +20 -11
- data/lib/liquid/tag.rb +4 -3
- data/lib/liquid/tags/assign.rb +15 -4
- data/lib/liquid/tags/capture.rb +15 -2
- data/lib/liquid/tags/case.rb +51 -36
- data/lib/liquid/tags/cycle.rb +16 -2
- data/lib/liquid/tags/for.rb +45 -8
- data/lib/liquid/tags/if.rb +35 -7
- data/lib/liquid/tags/include.rb +2 -3
- data/lib/liquid/tags/unless.rb +6 -2
- data/lib/liquid/template.rb +13 -18
- data/lib/liquid/variable.rb +25 -12
- data/test/block_test.rb +8 -0
- data/test/condition_test.rb +109 -0
- data/test/context_test.rb +88 -10
- data/test/drop_test.rb +3 -1
- data/test/error_handling_test.rb +16 -3
- data/test/extra/breakpoint.rb +0 -0
- data/test/extra/caller.rb +0 -0
- data/test/filter_test.rb +3 -3
- data/test/html_tag_test.rb +7 -0
- data/test/if_else_test.rb +32 -0
- data/test/include_tag_test.rb +24 -1
- data/test/module_ex_test.rb +89 -0
- data/test/parsing_quirks_test.rb +15 -0
- data/test/regexp_test.rb +4 -3
- data/test/standard_filter_test.rb +27 -2
- data/test/standard_tag_test.rb +67 -20
- data/test/test_helper.rb +20 -0
- data/test/unless_else_test.rb +8 -0
- metadata +60 -46
data/CHANGELOG
CHANGED
@@ -1,30 +1,32 @@
|
|
1
|
-
|
1
|
+
* Fixed gem install rake task
|
2
|
+
* Improve Error encapsulation in liquid by maintaining a own set of exceptions instead of relying on ruby build ins
|
2
3
|
|
3
|
-
|
4
|
-
To export new objects to liquid just implement .to_liquid on them and return objects which themselves have .to_liquid methods.
|
4
|
+
* Added If with or / and expressions
|
5
5
|
|
6
|
-
|
6
|
+
* Implemented .to_liquid for all objects which can be passed to liquid like Strings Arrays Hashes Numerics and Booleans. To export new objects to liquid just implement .to_liquid on them and return objects which themselves have .to_liquid methods.
|
7
7
|
|
8
|
-
Added
|
8
|
+
* Added more tags to standard library
|
9
9
|
|
10
|
-
|
10
|
+
* Added include tag ( like partials in rails )
|
11
11
|
|
12
|
-
|
12
|
+
* [...] Gazillion of detail improvements
|
13
13
|
|
14
|
-
|
14
|
+
* Added strainers as filter hosts for better security [Tobias Luetke]
|
15
15
|
|
16
|
-
Fixed
|
17
|
-
filter which was obviously misleading [Tobias Luetke]
|
16
|
+
* Fixed that rails integration would call filter with the wrong "self" [Michael Geary]
|
18
17
|
|
19
|
-
|
18
|
+
* Fixed bad error reporting when a filter called a method which doesn't exist. Liquid told you that it couldn't find the filter which was obviously misleading [Tobias Luetke]
|
20
19
|
|
21
|
-
|
20
|
+
* Removed count helper from standard lib. use size [Tobias Luetke]
|
22
21
|
|
23
|
-
|
22
|
+
* Fixed bug with string filter parameters failing to tolerate commas in strings. [Paul Hammond]
|
23
|
+
|
24
|
+
* Improved filter parameters. Filter parameters are now context sensitive; Types are resolved according to the rules of the context. Multiple parameters are now separated by the Liquid::ArgumentSeparator: , by default [Paul Hammond]
|
25
|
+
|
24
26
|
{{ 'Typo' | link_to: 'http://typo.leetsoft.com', 'Typo - a modern weblog engine' }}
|
25
27
|
|
26
28
|
|
27
|
-
Added Liquid::Drop. A base class which you can use for exporting proxy objects to liquid which can acquire more data when used in liquid. [Tobias Luetke]
|
29
|
+
* Added Liquid::Drop. A base class which you can use for exporting proxy objects to liquid which can acquire more data when used in liquid. [Tobias Luetke]
|
28
30
|
|
29
31
|
class ProductDrop < Liquid::Drop
|
30
32
|
def top_sales
|
@@ -35,4 +37,4 @@ Added Liquid::Drop. A base class which you can use for exporting proxy objects t
|
|
35
37
|
t.render('product' => ProductDrop.new )
|
36
38
|
|
37
39
|
|
38
|
-
Added filter parameters support. Example: {{ date | format_date: "%Y" }} [Paul Hammond]
|
40
|
+
* Added filter parameters support. Example: {{ date | format_date: "%Y" }} [Paul Hammond]
|
data/History.txt
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
1.9.0 / 2008-03-04
|
2
|
+
|
3
|
+
* Fixed gem install rake task
|
4
|
+
* Improve Error encapsulation in liquid by maintaining a own set of exceptions instead of relying on ruby build ins
|
5
|
+
|
6
|
+
Before 1.9.0
|
7
|
+
|
8
|
+
* Added If with or / and expressions
|
9
|
+
|
10
|
+
* Implemented .to_liquid for all objects which can be passed to liquid like Strings Arrays Hashes Numerics and Booleans. To export new objects to liquid just implement .to_liquid on them and return objects which themselves have .to_liquid methods.
|
11
|
+
|
12
|
+
* Added more tags to standard library
|
13
|
+
|
14
|
+
* Added include tag ( like partials in rails )
|
15
|
+
|
16
|
+
* [...] Gazillion of detail improvements
|
17
|
+
|
18
|
+
* Added strainers as filter hosts for better security [Tobias Luetke]
|
19
|
+
|
20
|
+
* Fixed that rails integration would call filter with the wrong "self" [Michael Geary]
|
21
|
+
|
22
|
+
* Fixed bad error reporting when a filter called a method which doesn't exist. Liquid told you that it couldn't find the filter which was obviously misleading [Tobias Luetke]
|
23
|
+
|
24
|
+
* Removed count helper from standard lib. use size [Tobias Luetke]
|
25
|
+
|
26
|
+
* Fixed bug with string filter parameters failing to tolerate commas in strings. [Paul Hammond]
|
27
|
+
|
28
|
+
* Improved filter parameters. Filter parameters are now context sensitive; Types are resolved according to the rules of the context. Multiple parameters are now separated by the Liquid::ArgumentSeparator: , by default [Paul Hammond]
|
29
|
+
|
30
|
+
{{ 'Typo' | link_to: 'http://typo.leetsoft.com', 'Typo - a modern weblog engine' }}
|
31
|
+
|
32
|
+
|
33
|
+
* Added Liquid::Drop. A base class which you can use for exporting proxy objects to liquid which can acquire more data when used in liquid. [Tobias Luetke]
|
34
|
+
|
35
|
+
class ProductDrop < Liquid::Drop
|
36
|
+
def top_sales
|
37
|
+
Shop.current.products.find(:all, :order => 'sales', :limit => 10 )
|
38
|
+
end
|
39
|
+
end
|
40
|
+
t = Liquid::Template.parse( ' {% for product in product.top_sales %} {{ product.name }} {% endfor %} ' )
|
41
|
+
t.render('product' => ProductDrop.new )
|
42
|
+
|
43
|
+
|
44
|
+
* Added filter parameters support. Example: {{ date | format_date: "%Y" }} [Paul Hammond]
|
data/MIT-LICENSE
CHANGED
@@ -13,8 +13,8 @@ included in all copies or substantial portions of the Software.
|
|
13
13
|
|
14
14
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
15
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
-
MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
17
|
-
NONINFRINGEMENT. IN NO EVENT
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
18
|
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
19
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
20
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Manifest.txt
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
CHANGELOG
|
2
|
+
History.txt
|
2
3
|
MIT-LICENSE
|
3
4
|
Manifest.txt
|
4
|
-
README
|
5
|
+
README.txt
|
5
6
|
Rakefile
|
6
7
|
example/server/example_servlet.rb
|
7
8
|
example/server/liquid_servlet.rb
|
@@ -20,6 +21,7 @@ lib/liquid/errors.rb
|
|
20
21
|
lib/liquid/extensions.rb
|
21
22
|
lib/liquid/file_system.rb
|
22
23
|
lib/liquid/htmltags.rb
|
24
|
+
lib/liquid/module_ex.rb
|
23
25
|
lib/liquid/standardfilters.rb
|
24
26
|
lib/liquid/strainer.rb
|
25
27
|
lib/liquid/tag.rb
|
@@ -36,6 +38,7 @@ lib/liquid/tags/unless.rb
|
|
36
38
|
lib/liquid/template.rb
|
37
39
|
lib/liquid/variable.rb
|
38
40
|
test/block_test.rb
|
41
|
+
test/condition_test.rb
|
39
42
|
test/context_test.rb
|
40
43
|
test/drop_test.rb
|
41
44
|
test/error_handling_test.rb
|
@@ -47,6 +50,7 @@ test/helper.rb
|
|
47
50
|
test/html_tag_test.rb
|
48
51
|
test/if_else_test.rb
|
49
52
|
test/include_tag_test.rb
|
53
|
+
test/module_ex_test.rb
|
50
54
|
test/output_test.rb
|
51
55
|
test/parsing_quirks_test.rb
|
52
56
|
test/regexp_test.rb
|
@@ -56,5 +60,6 @@ test/standard_tag_test.rb
|
|
56
60
|
test/statements_test.rb
|
57
61
|
test/strainer_test.rb
|
58
62
|
test/template_test.rb
|
63
|
+
test/test_helper.rb
|
59
64
|
test/unless_else_test.rb
|
60
65
|
test/variable_test.rb
|
data/{README → README.txt}
RENAMED
File without changes
|
data/Rakefile
CHANGED
@@ -3,7 +3,7 @@ require 'rubygems'
|
|
3
3
|
require 'rake'
|
4
4
|
require 'hoe'
|
5
5
|
|
6
|
-
PKG_VERSION = "1.
|
6
|
+
PKG_VERSION = "1.9.0"
|
7
7
|
PKG_NAME = "liquid"
|
8
8
|
PKG_DESC = "A secure non evaling end user template engine with aesthetic markup."
|
9
9
|
|
@@ -17,8 +17,8 @@ end
|
|
17
17
|
Hoe.new(PKG_NAME, PKG_VERSION) do |p|
|
18
18
|
p.rubyforge_name = PKG_NAME
|
19
19
|
p.summary = PKG_DESC
|
20
|
-
p.description =
|
20
|
+
p.description = PKG_DESC
|
21
21
|
p.author = "Tobias Luetke"
|
22
22
|
p.email = "tobi@leetsoft.com"
|
23
|
-
p.url = "http://
|
23
|
+
p.url = "http://www.liquidmarkup.org"
|
24
24
|
end
|
data/init.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
require 'liquid'
|
2
2
|
require 'extras/liquid_view'
|
3
3
|
|
4
|
-
ActionView::
|
5
|
-
|
6
|
-
|
4
|
+
if defined? ActionView::Template and ActionView::Template.respond_to? :register_template_handler
|
5
|
+
ActionView::Template
|
6
|
+
else
|
7
|
+
ActionView::Base
|
8
|
+
end.register_template_handler(:liquid, LiquidView)
|
data/lib/liquid.rb
CHANGED
@@ -13,8 +13,8 @@
|
|
13
13
|
#
|
14
14
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
15
|
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
-
# MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
17
|
-
# NONINFRINGEMENT. IN NO EVENT
|
16
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
18
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
19
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
20
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
@@ -28,14 +28,15 @@ module Liquid
|
|
28
28
|
VariableAttributeSeparator = '.'
|
29
29
|
TagStart = /\{\%/
|
30
30
|
TagEnd = /\%\}/
|
31
|
-
VariableSignature =
|
32
|
-
VariableSegment = /[\w\-]
|
31
|
+
VariableSignature = /\(?[\w\-\.\[\]]\)?/
|
32
|
+
VariableSegment = /[\w\-]\??/
|
33
33
|
VariableStart = /\{\{/
|
34
34
|
VariableEnd = /\}\}/
|
35
|
+
VariableIncompleteEnd = /\}\}?/
|
35
36
|
QuotedFragment = /"[^"]+"|'[^']+'|[^\s,|]+/
|
36
37
|
TagAttributes = /(\w+)\s*\:\s*(#{QuotedFragment})/
|
37
|
-
TemplateParser = /(#{TagStart}.*?#{TagEnd}|#{VariableStart}.*?#{
|
38
|
-
VariableParser =
|
38
|
+
TemplateParser = /(#{TagStart}.*?#{TagEnd}|#{VariableStart}.*?#{VariableIncompleteEnd})/
|
39
|
+
VariableParser = /\[[^\]]+\]|#{VariableSegment}+/
|
39
40
|
end
|
40
41
|
|
41
42
|
require 'liquid/drop'
|
@@ -52,6 +53,7 @@ require 'liquid/template'
|
|
52
53
|
require 'liquid/htmltags'
|
53
54
|
require 'liquid/standardfilters'
|
54
55
|
require 'liquid/condition'
|
56
|
+
require 'liquid/module_ex'
|
55
57
|
|
56
58
|
# Load all the tags of the standard library
|
57
59
|
#
|
data/lib/liquid/block.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
module Liquid
|
2
2
|
|
3
3
|
class Block < Tag
|
4
|
+
|
4
5
|
def parse(tokens)
|
5
6
|
@nodelist ||= []
|
6
7
|
@nodelist.clear
|
@@ -20,7 +21,7 @@ module Liquid
|
|
20
21
|
|
21
22
|
# fetch the tag from registered blocks
|
22
23
|
if tag = Template.tags[$1]
|
23
|
-
@nodelist << tag.new($2, tokens)
|
24
|
+
@nodelist << tag.new($1, $2, tokens)
|
24
25
|
else
|
25
26
|
# this tag is not registered with the system
|
26
27
|
# pass it to the current block for special handling or error reporting
|
@@ -63,7 +64,7 @@ module Liquid
|
|
63
64
|
end
|
64
65
|
|
65
66
|
def block_name
|
66
|
-
|
67
|
+
@tag_name
|
67
68
|
end
|
68
69
|
|
69
70
|
def create_variable(token)
|
@@ -76,7 +77,7 @@ module Liquid
|
|
76
77
|
def render(context)
|
77
78
|
render_all(@nodelist, context)
|
78
79
|
end
|
79
|
-
|
80
|
+
|
80
81
|
protected
|
81
82
|
|
82
83
|
def assert_missing_delimitation!
|
@@ -86,13 +87,9 @@ module Liquid
|
|
86
87
|
def render_all(list, context)
|
87
88
|
list.collect do |token|
|
88
89
|
begin
|
89
|
-
|
90
|
-
token.render(context)
|
91
|
-
else
|
92
|
-
token.to_s
|
93
|
-
end
|
90
|
+
token.respond_to?(:render) ? token.render(context) : token
|
94
91
|
rescue Exception => e
|
95
|
-
context.
|
92
|
+
context.handle_error(e)
|
96
93
|
end
|
97
94
|
|
98
95
|
end
|
data/lib/liquid/condition.rb
CHANGED
@@ -1,21 +1,55 @@
|
|
1
1
|
module Liquid
|
2
|
-
# Container for liquid nodes which conveniently
|
2
|
+
# Container for liquid nodes which conveniently wraps decision making logic
|
3
3
|
#
|
4
4
|
# Example:
|
5
5
|
#
|
6
6
|
# c = Condition.new('1', '==', '1')
|
7
7
|
# c.evaluate #=> true
|
8
8
|
#
|
9
|
-
class Condition
|
9
|
+
class Condition #:nodoc:
|
10
|
+
@@operators = {
|
11
|
+
'==' => lambda { |cond, left, right| cond.send(:equal_variables, left, right) },
|
12
|
+
'!=' => lambda { |cond, left, right| !cond.send(:equal_variables, left, right) },
|
13
|
+
'<>' => lambda { |cond, left, right| !cond.send(:equal_variables, left, right) },
|
14
|
+
'<' => :<,
|
15
|
+
'>' => :>,
|
16
|
+
'>=' => :>=,
|
17
|
+
'<=' => :<=,
|
18
|
+
'contains' => lambda { |cond, left, right| left.include?(right) },
|
19
|
+
}
|
20
|
+
|
21
|
+
def self.operators
|
22
|
+
@@operators
|
23
|
+
end
|
24
|
+
|
10
25
|
attr_reader :attachment
|
11
26
|
attr_accessor :left, :operator, :right
|
12
27
|
|
13
28
|
def initialize(left = nil, operator = nil, right = nil)
|
14
29
|
@left, @operator, @right = left, operator, right
|
30
|
+
@child_relation = nil
|
31
|
+
@child_condition = nil
|
15
32
|
end
|
16
33
|
|
17
34
|
def evaluate(context = Context.new)
|
18
|
-
interpret_condition(left, right, operator, context)
|
35
|
+
result = interpret_condition(left, right, operator, context)
|
36
|
+
|
37
|
+
case @child_relation
|
38
|
+
when :or
|
39
|
+
result || @child_condition.evaluate(context)
|
40
|
+
when :and
|
41
|
+
result && @child_condition.evaluate(context)
|
42
|
+
else
|
43
|
+
result
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def or(condition)
|
48
|
+
@child_relation, @child_condition = :or, condition
|
49
|
+
end
|
50
|
+
|
51
|
+
def and(condition)
|
52
|
+
@child_relation, @child_condition = :and, condition
|
19
53
|
end
|
20
54
|
|
21
55
|
def attach(attachment)
|
@@ -24,6 +58,10 @@ module Liquid
|
|
24
58
|
|
25
59
|
def else?
|
26
60
|
false
|
61
|
+
end
|
62
|
+
|
63
|
+
def inspect
|
64
|
+
"#<Condition #{[@left, @operator, @right].compact.join(' ')}>"
|
27
65
|
end
|
28
66
|
|
29
67
|
private
|
@@ -56,26 +94,20 @@ module Liquid
|
|
56
94
|
return context[left] if op == nil
|
57
95
|
|
58
96
|
left, right = context[left], context[right]
|
97
|
+
|
59
98
|
|
60
|
-
operation =
|
61
|
-
when '==' then return equal_variables(left, right)
|
62
|
-
when '!=' then return !equal_variables(left, right)
|
63
|
-
when '<>' then return !equal_variables(left, right)
|
64
|
-
when '>' then :>
|
65
|
-
when '<' then :<
|
66
|
-
when '>=' then :>=
|
67
|
-
when '<=' then :<=
|
68
|
-
else
|
69
|
-
raise ArgumentError.new("Error in tag '#{name}' - Unknown operator #{op}")
|
70
|
-
end
|
99
|
+
operation = self.class.operators[op] || raise(ArgumentError.new("Unknown operator #{op}"))
|
71
100
|
|
72
|
-
if
|
73
|
-
|
101
|
+
if operation.respond_to?(:call)
|
102
|
+
operation.call(self, left, right)
|
103
|
+
elsif left.respond_to?(operation) and right.respond_to?(operation)
|
104
|
+
left.send(operation, right)
|
74
105
|
else
|
75
106
|
nil
|
76
107
|
end
|
77
108
|
end
|
78
|
-
end
|
109
|
+
end
|
110
|
+
|
79
111
|
|
80
112
|
class ElseCondition < Condition
|
81
113
|
|
data/lib/liquid/context.rb
CHANGED
@@ -1,8 +1,5 @@
|
|
1
1
|
module Liquid
|
2
2
|
|
3
|
-
class ContextError < StandardError
|
4
|
-
end
|
5
|
-
|
6
3
|
# Context keeps the variable stack and resolves variables, as well as keywords
|
7
4
|
#
|
8
5
|
# context['variable'] = 'testing'
|
@@ -17,20 +14,18 @@ module Liquid
|
|
17
14
|
# context['bob'] #=> nil class Context
|
18
15
|
class Context
|
19
16
|
attr_reader :scopes
|
20
|
-
attr_reader :
|
17
|
+
attr_reader :errors, :registers
|
21
18
|
|
22
|
-
def initialize(
|
23
|
-
@
|
24
|
-
@
|
25
|
-
|
19
|
+
def initialize(assigns = {}, registers = {}, rethrow_errors = false)
|
20
|
+
@scopes = [(assigns || {})]
|
21
|
+
@registers = registers
|
22
|
+
@errors = []
|
23
|
+
@rethrow_errors = rethrow_errors
|
24
|
+
end
|
26
25
|
|
27
26
|
def strainer
|
28
27
|
@strainer ||= Strainer.create(self)
|
29
|
-
end
|
30
|
-
|
31
|
-
def registers
|
32
|
-
@template.registers
|
33
|
-
end
|
28
|
+
end
|
34
29
|
|
35
30
|
# adds filters to this context.
|
36
31
|
# this does not register the filters with the main Template object. see <tt>Template.register_filter</tt>
|
@@ -38,12 +33,22 @@ module Liquid
|
|
38
33
|
def add_filters(filters)
|
39
34
|
filters = [filters].flatten.compact
|
40
35
|
|
41
|
-
raise ArgumentError, "Expected module but got: #{filter_module.class}" unless filters.all? { |f| f.is_a?(Module)}
|
42
|
-
|
43
36
|
filters.each do |f|
|
37
|
+
raise ArgumentError, "Expected module but got: #{f.class}" unless f.is_a?(Module)
|
44
38
|
strainer.extend(f)
|
45
39
|
end
|
46
40
|
end
|
41
|
+
|
42
|
+
def handle_error(e)
|
43
|
+
errors.push(e)
|
44
|
+
raise if @rethrow_errors
|
45
|
+
|
46
|
+
case e
|
47
|
+
when SyntaxError then "Liquid syntax error: #{e.message}"
|
48
|
+
else "Liquid error: #{e.message}"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
47
52
|
|
48
53
|
def invoke(method, *args)
|
49
54
|
if strainer.respond_to?(method)
|
@@ -115,16 +120,16 @@ module Liquid
|
|
115
120
|
#
|
116
121
|
def resolve(key)
|
117
122
|
case key
|
118
|
-
when nil
|
123
|
+
when nil, 'nil', 'null', ''
|
119
124
|
nil
|
120
125
|
when 'true'
|
121
126
|
true
|
122
127
|
when 'false'
|
123
|
-
false
|
128
|
+
false
|
129
|
+
when 'blank'
|
130
|
+
:blank?
|
124
131
|
when 'empty'
|
125
132
|
:empty?
|
126
|
-
when 'nil', 'null'
|
127
|
-
nil
|
128
133
|
# Single quoted strings
|
129
134
|
when /^'(.*)'$/
|
130
135
|
$1.to_s
|
@@ -134,11 +139,15 @@ module Liquid
|
|
134
139
|
# Integer and floats
|
135
140
|
when /^(\d+)$/
|
136
141
|
$1.to_i
|
142
|
+
# Ranges
|
143
|
+
when /^\((\S+)\.\.(\S+)\)$/
|
144
|
+
(resolve($1).to_i..resolve($2).to_i)
|
145
|
+
# Floats
|
137
146
|
when /^(\d[\d\.]+)$/
|
138
147
|
$1.to_f
|
139
148
|
else
|
140
149
|
variable(key)
|
141
|
-
end
|
150
|
+
end
|
142
151
|
end
|
143
152
|
|
144
153
|
# fetches an object starting at the local scope and then moving up
|
@@ -148,7 +157,8 @@ module Liquid
|
|
148
157
|
if scope.has_key?(key)
|
149
158
|
variable = scope[key]
|
150
159
|
variable = scope[key] = variable.call(self) if variable.is_a?(Proc)
|
151
|
-
variable
|
160
|
+
variable = variable.to_liquid
|
161
|
+
variable.context = self if variable.respond_to?(:context=)
|
152
162
|
return variable
|
153
163
|
end
|
154
164
|
end
|
@@ -164,39 +174,55 @@ module Liquid
|
|
164
174
|
# assert_equal 'tobi', @context['hash[name]']
|
165
175
|
#
|
166
176
|
def variable(markup)
|
167
|
-
parts
|
177
|
+
parts = markup.scan(VariableParser)
|
178
|
+
square_bracketed = /^\[(.*)\]$/
|
179
|
+
|
180
|
+
first_part = parts.shift
|
181
|
+
if first_part =~ square_bracketed
|
182
|
+
first_part = resolve($1)
|
183
|
+
end
|
168
184
|
|
169
|
-
if object = find_variable(
|
185
|
+
if object = find_variable(first_part)
|
170
186
|
|
171
187
|
parts.each do |part|
|
172
188
|
|
173
189
|
# If object is a hash we look for the presence of the key and if its available
|
174
190
|
# we return it
|
191
|
+
|
192
|
+
if part =~ square_bracketed
|
193
|
+
part = resolve($1)
|
194
|
+
|
195
|
+
object[pos] = object[part].call(self) if object[part].is_a?(Proc) and object.respond_to?(:[]=)
|
196
|
+
object = object[part].to_liquid
|
197
|
+
|
198
|
+
else
|
175
199
|
|
176
|
-
|
177
|
-
|
200
|
+
# Hash
|
201
|
+
if object.respond_to?(:has_key?) and object.has_key?(part)
|
178
202
|
|
179
|
-
|
180
|
-
|
181
|
-
|
203
|
+
# if its a proc we will replace the entry in the hash table with the proc
|
204
|
+
res = object[part]
|
205
|
+
res = object[part] = res.call(self) if res.is_a?(Proc) and object.respond_to?(:[]=)
|
206
|
+
object = res.to_liquid
|
182
207
|
|
183
|
-
|
184
|
-
|
185
|
-
|
208
|
+
# Array
|
209
|
+
elsif object.respond_to?(:fetch) and part =~ /^\d+$/
|
210
|
+
pos = part.to_i
|
186
211
|
|
187
|
-
|
188
|
-
|
212
|
+
object[pos] = object[pos].call(self) if object[pos].is_a?(Proc) and object.respond_to?(:[]=)
|
213
|
+
object = object[pos].to_liquid
|
189
214
|
|
190
|
-
|
191
|
-
|
192
|
-
|
215
|
+
# Some special cases. If no key with the same name was found we interpret following calls
|
216
|
+
# as commands and call them on the current object
|
217
|
+
elsif object.respond_to?(part) and ['size', 'first', 'last'].include?(part)
|
193
218
|
|
194
|
-
|
219
|
+
object = object.send(part.intern).to_liquid
|
195
220
|
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
221
|
+
# No key was present with the desired value and it wasn't one of the directly supported
|
222
|
+
# keywords either. The only thing we got left is to return nil
|
223
|
+
else
|
224
|
+
return nil
|
225
|
+
end
|
200
226
|
end
|
201
227
|
|
202
228
|
# If we are dealing with a drop here we have to
|