liquid 1.7.0 → 1.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. data/CHANGELOG +17 -15
  2. data/History.txt +44 -0
  3. data/MIT-LICENSE +2 -2
  4. data/Manifest.txt +6 -1
  5. data/{README → README.txt} +0 -0
  6. data/Rakefile +3 -3
  7. data/init.rb +5 -3
  8. data/lib/liquid.rb +8 -6
  9. data/lib/liquid/block.rb +6 -9
  10. data/lib/liquid/condition.rb +49 -17
  11. data/lib/liquid/context.rb +67 -41
  12. data/lib/liquid/errors.rb +8 -5
  13. data/lib/liquid/htmltags.rb +17 -7
  14. data/lib/liquid/module_ex.rb +62 -0
  15. data/lib/liquid/standardfilters.rb +39 -0
  16. data/lib/liquid/strainer.rb +20 -11
  17. data/lib/liquid/tag.rb +4 -3
  18. data/lib/liquid/tags/assign.rb +15 -4
  19. data/lib/liquid/tags/capture.rb +15 -2
  20. data/lib/liquid/tags/case.rb +51 -36
  21. data/lib/liquid/tags/cycle.rb +16 -2
  22. data/lib/liquid/tags/for.rb +45 -8
  23. data/lib/liquid/tags/if.rb +35 -7
  24. data/lib/liquid/tags/include.rb +2 -3
  25. data/lib/liquid/tags/unless.rb +6 -2
  26. data/lib/liquid/template.rb +13 -18
  27. data/lib/liquid/variable.rb +25 -12
  28. data/test/block_test.rb +8 -0
  29. data/test/condition_test.rb +109 -0
  30. data/test/context_test.rb +88 -10
  31. data/test/drop_test.rb +3 -1
  32. data/test/error_handling_test.rb +16 -3
  33. data/test/extra/breakpoint.rb +0 -0
  34. data/test/extra/caller.rb +0 -0
  35. data/test/filter_test.rb +3 -3
  36. data/test/html_tag_test.rb +7 -0
  37. data/test/if_else_test.rb +32 -0
  38. data/test/include_tag_test.rb +24 -1
  39. data/test/module_ex_test.rb +89 -0
  40. data/test/parsing_quirks_test.rb +15 -0
  41. data/test/regexp_test.rb +4 -3
  42. data/test/standard_filter_test.rb +27 -2
  43. data/test/standard_tag_test.rb +67 -20
  44. data/test/test_helper.rb +20 -0
  45. data/test/unless_else_test.rb +8 -0
  46. metadata +60 -46
data/CHANGELOG CHANGED
@@ -1,30 +1,32 @@
1
- Changelog
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
- Implemented .to_liquid for all objects which can be passed to liquid like Strings Arrays Hashes Numerics and Booleans.
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
- Added more tags to standard library
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 include tag ( like partials in rails )
8
+ * Added more tags to standard library
9
9
 
10
- [...] Gazillion of detail improvements
10
+ * Added include tag ( like partials in rails )
11
11
 
12
- Added strainers as filter hosts for better security [Tobias Luetke]
12
+ * [...] Gazillion of detail improvements
13
13
 
14
- Fixed that rails integration would call filter with the wrong "self" [Michael Geary]
14
+ * Added strainers as filter hosts for better security [Tobias Luetke]
15
15
 
16
- Fixed bad error reporting when a filter called a method which doesn't exist. Liquid told you that it couldn't find the
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
- Removed count helper from standard lib. use size [Tobias Luetke]
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
- Fixed bug with string filter parameters failing to tolerate commas in strings. [Paul Hammond]
20
+ * Removed count helper from standard lib. use size [Tobias Luetke]
22
21
 
23
- 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]
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 PURPOa AND
17
- NONINFRINGEMENT. IN NO EVENT SaALL THE AUTHORS OR COPYRIGHT HOLDERS BE
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
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.7.0"
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 = nil
20
+ p.description = PKG_DESC
21
21
  p.author = "Tobias Luetke"
22
22
  p.email = "tobi@leetsoft.com"
23
- p.url = "http://home.leetsoft.com/liquid"
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::Base::register_template_handler :liquid, LiquidView
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 PURPOa AND
17
- # NONINFRINGEMENT. IN NO EVENT SaALL THE AUTHORS OR COPYRIGHT HOLDERS BE
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 = /[\w\-\.\[\]]/
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}.*?#{VariableEnd})/
38
- VariableParser = /(?=\[)#{VariableSegment}+(?=\])|#{VariableSegment}+/
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
- self.class.name.scan(/\w+$/).first.downcase
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
- if token.respond_to?(:render)
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.template.handle_error(e)
92
+ context.handle_error(e)
96
93
  end
97
94
 
98
95
  end
@@ -1,21 +1,55 @@
1
1
  module Liquid
2
- # Container for liquid nodes which conveniently wrapps decision making logic
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 = case op
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 left.respond_to?(operation) and right.respond_to?(operation)
73
- left.send(operation, right)
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
 
@@ -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 :template
17
+ attr_reader :errors, :registers
21
18
 
22
- def initialize(template)
23
- @template = template
24
- @scopes = [template.assigns]
25
- end
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.context = self if variable.respond_to?(:context=)
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 = markup.scan(VariableParser)
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(parts.shift).to_liquid
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
- # Hash
177
- if object.respond_to?(:has_key?) and object.has_key?(part)
200
+ # Hash
201
+ if object.respond_to?(:has_key?) and object.has_key?(part)
178
202
 
179
- # if its a proc we will replace the entry in the hash table with the proc
180
- object[part] = object[part].call(self) if object[part].is_a?(Proc) and object.respond_to?(:[]=)
181
- object = object[part].to_liquid
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
- # Array
184
- elsif object.respond_to?(:fetch) and part =~ /^\d+$/
185
- pos = part.to_i
208
+ # Array
209
+ elsif object.respond_to?(:fetch) and part =~ /^\d+$/
210
+ pos = part.to_i
186
211
 
187
- object[pos] = object[pos].call(self) if object[pos].is_a?(Proc) and object.respond_to?(:[]=)
188
- object = object[pos].to_liquid
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
- # Some special cases. If no key with the same name was found we interpret following calls
191
- # as commands and call them on the current object
192
- elsif object.respond_to?(part) and ['size', 'first', 'last'].include?(part)
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
- object = object.send(part.intern).to_liquid
219
+ object = object.send(part.intern).to_liquid
195
220
 
196
- # No key was present with the desired value and it wasn't one of the directly supported
197
- # keywords either. The only thing we got left is to return nil
198
- else
199
- return nil
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