liquid 2.6.3 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +46 -13
  3. data/README.md +27 -2
  4. data/lib/liquid/block.rb +85 -51
  5. data/lib/liquid/block_body.rb +123 -0
  6. data/lib/liquid/condition.rb +26 -15
  7. data/lib/liquid/context.rb +106 -140
  8. data/lib/liquid/document.rb +3 -3
  9. data/lib/liquid/drop.rb +17 -1
  10. data/lib/liquid/errors.rb +50 -2
  11. data/lib/liquid/expression.rb +33 -0
  12. data/lib/liquid/file_system.rb +17 -6
  13. data/lib/liquid/i18n.rb +39 -0
  14. data/lib/liquid/interrupts.rb +1 -1
  15. data/lib/liquid/lexer.rb +51 -0
  16. data/lib/liquid/locales/en.yml +22 -0
  17. data/lib/liquid/parser.rb +90 -0
  18. data/lib/liquid/parser_switching.rb +31 -0
  19. data/lib/liquid/profiler/hooks.rb +23 -0
  20. data/lib/liquid/profiler.rb +159 -0
  21. data/lib/liquid/range_lookup.rb +22 -0
  22. data/lib/liquid/standardfilters.rb +143 -55
  23. data/lib/liquid/strainer.rb +14 -4
  24. data/lib/liquid/tag.rb +25 -9
  25. data/lib/liquid/tags/assign.rb +12 -9
  26. data/lib/liquid/tags/break.rb +1 -1
  27. data/lib/liquid/tags/capture.rb +10 -8
  28. data/lib/liquid/tags/case.rb +13 -13
  29. data/lib/liquid/tags/comment.rb +9 -2
  30. data/lib/liquid/tags/continue.rb +1 -4
  31. data/lib/liquid/tags/cycle.rb +5 -7
  32. data/lib/liquid/tags/decrement.rb +3 -4
  33. data/lib/liquid/tags/for.rb +69 -36
  34. data/lib/liquid/tags/if.rb +52 -25
  35. data/lib/liquid/tags/ifchanged.rb +3 -3
  36. data/lib/liquid/tags/include.rb +19 -8
  37. data/lib/liquid/tags/increment.rb +4 -8
  38. data/lib/liquid/tags/raw.rb +4 -7
  39. data/lib/liquid/tags/table_row.rb +73 -0
  40. data/lib/liquid/tags/unless.rb +2 -4
  41. data/lib/liquid/template.rb +124 -14
  42. data/lib/liquid/token.rb +18 -0
  43. data/lib/liquid/utils.rb +13 -4
  44. data/lib/liquid/variable.rb +103 -25
  45. data/lib/liquid/variable_lookup.rb +78 -0
  46. data/lib/liquid/version.rb +1 -1
  47. data/lib/liquid.rb +19 -11
  48. data/test/fixtures/en_locale.yml +9 -0
  49. data/test/{liquid → integration}/assign_test.rb +18 -1
  50. data/test/integration/blank_test.rb +106 -0
  51. data/test/{liquid → integration}/capture_test.rb +3 -3
  52. data/test/integration/context_test.rb +32 -0
  53. data/test/integration/drop_test.rb +271 -0
  54. data/test/integration/error_handling_test.rb +207 -0
  55. data/test/{liquid → integration}/filter_test.rb +11 -11
  56. data/test/integration/hash_ordering_test.rb +23 -0
  57. data/test/{liquid → integration}/output_test.rb +13 -13
  58. data/test/integration/parsing_quirks_test.rb +116 -0
  59. data/test/integration/render_profiling_test.rb +154 -0
  60. data/test/{liquid → integration}/security_test.rb +10 -10
  61. data/test/{liquid → integration}/standard_filter_test.rb +148 -32
  62. data/test/{liquid → integration}/tags/break_tag_test.rb +1 -1
  63. data/test/{liquid → integration}/tags/continue_tag_test.rb +1 -1
  64. data/test/{liquid → integration}/tags/for_tag_test.rb +80 -2
  65. data/test/{liquid → integration}/tags/if_else_tag_test.rb +24 -21
  66. data/test/integration/tags/include_tag_test.rb +234 -0
  67. data/test/{liquid → integration}/tags/increment_tag_test.rb +1 -1
  68. data/test/{liquid → integration}/tags/raw_tag_test.rb +2 -1
  69. data/test/{liquid → integration}/tags/standard_tag_test.rb +28 -26
  70. data/test/integration/tags/statements_test.rb +113 -0
  71. data/test/{liquid/tags/html_tag_test.rb → integration/tags/table_row_test.rb} +5 -5
  72. data/test/{liquid → integration}/tags/unless_else_tag_test.rb +1 -1
  73. data/test/{liquid → integration}/template_test.rb +81 -45
  74. data/test/integration/variable_test.rb +82 -0
  75. data/test/test_helper.rb +73 -20
  76. data/test/{liquid/block_test.rb → unit/block_unit_test.rb} +2 -5
  77. data/test/{liquid/condition_test.rb → unit/condition_unit_test.rb} +23 -1
  78. data/test/{liquid/context_test.rb → unit/context_unit_test.rb} +39 -25
  79. data/test/{liquid/file_system_test.rb → unit/file_system_unit_test.rb} +11 -5
  80. data/test/unit/i18n_unit_test.rb +37 -0
  81. data/test/unit/lexer_unit_test.rb +48 -0
  82. data/test/{liquid/module_ex_test.rb → unit/module_ex_unit_test.rb} +7 -7
  83. data/test/unit/parser_unit_test.rb +82 -0
  84. data/test/{liquid/regexp_test.rb → unit/regexp_unit_test.rb} +3 -3
  85. data/test/{liquid/strainer_test.rb → unit/strainer_unit_test.rb} +20 -1
  86. data/test/unit/tag_unit_test.rb +16 -0
  87. data/test/unit/tags/case_tag_unit_test.rb +10 -0
  88. data/test/unit/tags/for_tag_unit_test.rb +13 -0
  89. data/test/unit/tags/if_tag_unit_test.rb +8 -0
  90. data/test/unit/template_unit_test.rb +69 -0
  91. data/test/unit/tokenizer_unit_test.rb +38 -0
  92. data/test/unit/variable_unit_test.rb +139 -0
  93. metadata +135 -67
  94. data/lib/extras/liquid_view.rb +0 -51
  95. data/lib/liquid/htmltags.rb +0 -73
  96. data/test/liquid/drop_test.rb +0 -180
  97. data/test/liquid/error_handling_test.rb +0 -81
  98. data/test/liquid/hash_ordering_test.rb +0 -25
  99. data/test/liquid/parsing_quirks_test.rb +0 -52
  100. data/test/liquid/tags/include_tag_test.rb +0 -166
  101. data/test/liquid/tags/statements_test.rb +0 -134
  102. data/test/liquid/variable_test.rb +0 -186
data/lib/liquid/tag.rb CHANGED
@@ -1,26 +1,42 @@
1
1
  module Liquid
2
-
3
2
  class Tag
3
+ attr_accessor :options, :line_number
4
+ attr_reader :nodelist, :warnings
5
+ include ParserSwitching
6
+
7
+ class << self
8
+ def parse(tag_name, markup, tokens, options)
9
+ tag = new(tag_name, markup, options)
10
+ tag.parse(tokens)
11
+ tag
12
+ end
13
+
14
+ private :new
15
+ end
4
16
 
5
- attr_accessor :nodelist
6
-
7
- def initialize(tag_name, markup, tokens)
17
+ def initialize(tag_name, markup, options)
8
18
  @tag_name = tag_name
9
19
  @markup = markup
10
- parse(tokens)
20
+ @options = options
11
21
  end
12
22
 
13
23
  def parse(tokens)
14
24
  end
15
25
 
26
+ def raw
27
+ "#{@tag_name} #{@markup}"
28
+ end
29
+
16
30
  def name
17
31
  self.class.name.downcase
18
32
  end
19
33
 
20
34
  def render(context)
21
- ''
35
+ ''.freeze
22
36
  end
23
37
 
24
- end # Tag
25
-
26
- end # Liquid
38
+ def blank?
39
+ false
40
+ end
41
+ end
42
+ end
@@ -9,27 +9,30 @@ module Liquid
9
9
  # {{ foo }}
10
10
  #
11
11
  class Assign < Tag
12
- Syntax = /(#{VariableSignature}+)\s*=\s*(.*)\s*/o
12
+ Syntax = /(#{VariableSignature}+)\s*=\s*(.*)\s*/om
13
13
 
14
- def initialize(tag_name, markup, tokens)
14
+ def initialize(tag_name, markup, options)
15
+ super
15
16
  if markup =~ Syntax
16
17
  @to = $1
17
- @from = Variable.new($2)
18
+ @from = Variable.new($2,options)
19
+ @from.line_number = line_number
18
20
  else
19
- raise SyntaxError.new("Syntax Error in 'assign' - Valid syntax: assign [var] = [source]")
21
+ raise SyntaxError.new options[:locale].t("errors.syntax.assign".freeze)
20
22
  end
21
-
22
- super
23
23
  end
24
24
 
25
25
  def render(context)
26
26
  val = @from.render(context)
27
27
  context.scopes.last[@to] = val
28
- context.resource_limits[:assign_score_current] += (val.respond_to?(:length) ? val.length : 1)
29
- ''
28
+ context.increment_used_resources(:assign_score_current, val)
29
+ ''.freeze
30
30
  end
31
31
 
32
+ def blank?
33
+ true
34
+ end
32
35
  end
33
36
 
34
- Template.register_tag('assign', Assign)
37
+ Template.register_tag('assign'.freeze, Assign)
35
38
  end
@@ -17,5 +17,5 @@ module Liquid
17
17
 
18
18
  end
19
19
 
20
- Template.register_tag('break', Break)
20
+ Template.register_tag('break'.freeze, Break)
21
21
  end
@@ -1,5 +1,4 @@
1
1
  module Liquid
2
-
3
2
  # Capture stores the result of a block into a variable without rendering it inplace.
4
3
  #
5
4
  # {% capture heading %}
@@ -14,23 +13,26 @@ module Liquid
14
13
  class Capture < Block
15
14
  Syntax = /(\w+)/
16
15
 
17
- def initialize(tag_name, markup, tokens)
16
+ def initialize(tag_name, markup, options)
17
+ super
18
18
  if markup =~ Syntax
19
19
  @to = $1
20
20
  else
21
- raise SyntaxError.new("Syntax Error in 'capture' - Valid syntax: capture [var]")
21
+ raise SyntaxError.new(options[:locale].t("errors.syntax.capture"))
22
22
  end
23
-
24
- super
25
23
  end
26
24
 
27
25
  def render(context)
28
26
  output = super
29
27
  context.scopes.last[@to] = output
30
- context.resource_limits[:assign_score_current] += (output.respond_to?(:length) ? output.length : 1)
31
- ''
28
+ context.increment_used_resources(:assign_score_current, output)
29
+ ''.freeze
30
+ end
31
+
32
+ def blank?
33
+ true
32
34
  end
33
35
  end
34
36
 
35
- Template.register_tag('capture', Capture)
37
+ Template.register_tag('capture'.freeze, Capture)
36
38
  end
@@ -1,26 +1,29 @@
1
1
  module Liquid
2
2
  class Case < Block
3
3
  Syntax = /(#{QuotedFragment})/o
4
- WhenSyntax = /(#{QuotedFragment})(?:(?:\s+or\s+|\s*\,\s*)(#{QuotedFragment}.*))?/o
4
+ WhenSyntax = /(#{QuotedFragment})(?:(?:\s+or\s+|\s*\,\s*)(#{QuotedFragment}.*))?/om
5
5
 
6
- def initialize(tag_name, markup, tokens)
6
+ def initialize(tag_name, markup, options)
7
+ super
7
8
  @blocks = []
8
9
 
9
10
  if markup =~ Syntax
10
11
  @left = $1
11
12
  else
12
- raise SyntaxError.new("Syntax Error in tag 'case' - Valid syntax: case [condition]")
13
+ raise SyntaxError.new(options[:locale].t("errors.syntax.case".freeze))
13
14
  end
15
+ end
14
16
 
15
- super
17
+ def nodelist
18
+ @blocks.flat_map(&:attachment)
16
19
  end
17
20
 
18
21
  def unknown_tag(tag, markup, tokens)
19
22
  @nodelist = []
20
23
  case tag
21
- when 'when'
24
+ when 'when'.freeze
22
25
  record_when_condition(markup)
23
- when 'else'
26
+ when 'else'.freeze
24
27
  record_else_condition(markup)
25
28
  else
26
29
  super
@@ -50,30 +53,27 @@ module Liquid
50
53
  while markup
51
54
  # Create a new nodelist and assign it to the new block
52
55
  if not markup =~ WhenSyntax
53
- raise SyntaxError.new("Syntax Error in tag 'case' - Valid when condition: {% when [condition] [or condition2...] %} ")
56
+ raise SyntaxError.new(options[:locale].t("errors.syntax.case_invalid_when".freeze))
54
57
  end
55
58
 
56
59
  markup = $2
57
60
 
58
- block = Condition.new(@left, '==', $1)
61
+ block = Condition.new(@left, '=='.freeze, $1)
59
62
  block.attach(@nodelist)
60
63
  @blocks.push(block)
61
64
  end
62
65
  end
63
66
 
64
67
  def record_else_condition(markup)
65
-
66
68
  if not markup.strip.empty?
67
- raise SyntaxError.new("Syntax Error in tag 'case' - Valid else condition: {% else %} (no parameters) ")
69
+ raise SyntaxError.new(options[:locale].t("errors.syntax.case_invalid_else".freeze))
68
70
  end
69
71
 
70
72
  block = ElseCondition.new
71
73
  block.attach(@nodelist)
72
74
  @blocks << block
73
75
  end
74
-
75
-
76
76
  end
77
77
 
78
- Template.register_tag('case', Case)
78
+ Template.register_tag('case'.freeze, Case)
79
79
  end
@@ -1,9 +1,16 @@
1
1
  module Liquid
2
2
  class Comment < Block
3
3
  def render(context)
4
- ''
4
+ ''.freeze
5
+ end
6
+
7
+ def unknown_tag(tag, markup, tokens)
8
+ end
9
+
10
+ def blank?
11
+ true
5
12
  end
6
13
  end
7
14
 
8
- Template.register_tag('comment', Comment)
15
+ Template.register_tag('comment'.freeze, Comment)
9
16
  end
@@ -1,5 +1,4 @@
1
1
  module Liquid
2
-
3
2
  # Continue tag to be used to break out of a for loop.
4
3
  #
5
4
  # == Basic Usage:
@@ -10,12 +9,10 @@ module Liquid
10
9
  # {% endfor %}
11
10
  #
12
11
  class Continue < Tag
13
-
14
12
  def interrupt
15
13
  ContinueInterrupt.new
16
14
  end
17
-
18
15
  end
19
16
 
20
- Template.register_tag('continue', Continue)
17
+ Template.register_tag('continue'.freeze, Continue)
21
18
  end
@@ -1,5 +1,4 @@
1
1
  module Liquid
2
-
3
2
  # Cycle is usually used within a loop to alternate between values, like colors or DOM classes.
4
3
  #
5
4
  # {% for item in items %}
@@ -13,10 +12,11 @@ module Liquid
13
12
  # <div class="green"> Item five</div>
14
13
  #
15
14
  class Cycle < Tag
16
- SimpleSyntax = /^#{QuotedFragment}+/o
17
- NamedSyntax = /^(#{QuotedFragment})\s*\:\s*(.*)/o
15
+ SimpleSyntax = /\A#{QuotedFragment}+/o
16
+ NamedSyntax = /\A(#{QuotedFragment})\s*\:\s*(.*)/om
18
17
 
19
- def initialize(tag_name, markup, tokens)
18
+ def initialize(tag_name, markup, options)
19
+ super
20
20
  case markup
21
21
  when NamedSyntax
22
22
  @variables = variables_from_string($2)
@@ -25,9 +25,8 @@ module Liquid
25
25
  @variables = variables_from_string(markup)
26
26
  @name = "'#{@variables.to_s}'"
27
27
  else
28
- raise SyntaxError.new("Syntax Error in 'cycle' - Valid syntax: cycle [name :] var [, var2, var3 ...]")
28
+ raise SyntaxError.new(options[:locale].t("errors.syntax.cycle".freeze))
29
29
  end
30
- super
31
30
  end
32
31
 
33
32
  def render(context)
@@ -52,7 +51,6 @@ module Liquid
52
51
  $1 ? $1 : nil
53
52
  end.compact
54
53
  end
55
-
56
54
  end
57
55
 
58
56
  Template.register_tag('cycle', Cycle)
@@ -19,10 +19,9 @@ module Liquid
19
19
  # Hello: -3
20
20
  #
21
21
  class Decrement < Tag
22
- def initialize(tag_name, markup, tokens)
23
- @variable = markup.strip
24
-
22
+ def initialize(tag_name, markup, options)
25
23
  super
24
+ @variable = markup.strip
26
25
  end
27
26
 
28
27
  def render(context)
@@ -35,5 +34,5 @@ module Liquid
35
34
  private
36
35
  end
37
36
 
38
- Template.register_tag('decrement', Decrement)
37
+ Template.register_tag('decrement'.freeze, Decrement)
39
38
  end
@@ -44,28 +44,24 @@ module Liquid
44
44
  # forloop.last:: Returns true if the item is the last item.
45
45
  #
46
46
  class For < Block
47
- Syntax = /\A(\w+)\s+in\s+(#{QuotedFragment}+)\s*(reversed)?/o
47
+ Syntax = /\A(#{VariableSegment}+)\s+in\s+(#{QuotedFragment}+)\s*(reversed)?/o
48
48
 
49
- def initialize(tag_name, markup, tokens)
50
- if markup =~ Syntax
51
- @variable_name = $1
52
- @collection_name = $2
53
- @name = "#{$1}-#{$2}"
54
- @reversed = $3
55
- @attributes = {}
56
- markup.scan(TagAttributes) do |key, value|
57
- @attributes[key] = value
58
- end
49
+ def initialize(tag_name, markup, options)
50
+ super
51
+ parse_with_selected_parser(markup)
52
+ @nodelist = @for_block = []
53
+ end
54
+
55
+ def nodelist
56
+ if @else_block
57
+ @for_block + @else_block
59
58
  else
60
- raise SyntaxError.new("Syntax Error in 'for loop' - Valid syntax: for [item] in [collection]")
59
+ @for_block
61
60
  end
62
-
63
- @nodelist = @for_block = []
64
- super
65
61
  end
66
62
 
67
63
  def unknown_tag(tag, markup, tokens)
68
- return super unless tag == 'else'
64
+ return super unless tag == 'else'.freeze
69
65
  @nodelist = @else_block = []
70
66
  end
71
67
 
@@ -78,17 +74,16 @@ module Liquid
78
74
  # Maintains Ruby 1.8.7 String#each behaviour on 1.9
79
75
  return render_else(context) unless iterable?(collection)
80
76
 
81
- from = if @attributes['offset'] == 'continue'
77
+ from = if @attributes['offset'.freeze] == 'continue'.freeze
82
78
  context.registers[:for][@name].to_i
83
79
  else
84
- context[@attributes['offset']].to_i
80
+ context[@attributes['offset'.freeze]].to_i
85
81
  end
86
82
 
87
- limit = context[@attributes['limit']]
83
+ limit = context[@attributes['limit'.freeze]]
88
84
  to = limit ? limit.to_i + from : nil
89
85
 
90
-
91
- segment = Utils.slice_collection_using_each(collection, from, to)
86
+ segment = Utils.slice_collection(collection, from, to)
92
87
 
93
88
  return render_else(context) if segment.empty?
94
89
 
@@ -104,15 +99,16 @@ module Liquid
104
99
  context.stack do
105
100
  segment.each_with_index do |item, index|
106
101
  context[@variable_name] = item
107
- context['forloop'] = {
108
- 'name' => @name,
109
- 'length' => length,
110
- 'index' => index + 1,
111
- 'index0' => index,
112
- 'rindex' => length - index,
113
- 'rindex0' => length - index - 1,
114
- 'first' => (index == 0),
115
- 'last' => (index == length - 1) }
102
+ context['forloop'.freeze] = {
103
+ 'name'.freeze => @name,
104
+ 'length'.freeze => length,
105
+ 'index'.freeze => index + 1,
106
+ 'index0'.freeze => index,
107
+ 'rindex'.freeze => length - index,
108
+ 'rindex0'.freeze => length - index - 1,
109
+ 'first'.freeze => (index == 0),
110
+ 'last'.freeze => (index == length - 1)
111
+ }
116
112
 
117
113
  result << render_all(@for_block, context)
118
114
 
@@ -127,16 +123,53 @@ module Liquid
127
123
  result
128
124
  end
129
125
 
130
- private
126
+ protected
131
127
 
132
- def render_else(context)
133
- return @else_block ? [render_all(@else_block, context)] : ''
128
+ def lax_parse(markup)
129
+ if markup =~ Syntax
130
+ @variable_name = $1
131
+ @collection_name = $2
132
+ @name = "#{$1}-#{$2}"
133
+ @reversed = $3
134
+ @attributes = {}
135
+ markup.scan(TagAttributes) do |key, value|
136
+ @attributes[key] = value
137
+ end
138
+ else
139
+ raise SyntaxError.new(options[:locale].t("errors.syntax.for".freeze))
134
140
  end
141
+ end
135
142
 
136
- def iterable?(collection)
137
- collection.respond_to?(:each) || Utils.non_blank_string?(collection)
143
+ def strict_parse(markup)
144
+ p = Parser.new(markup)
145
+ @variable_name = p.consume(:id)
146
+ raise SyntaxError.new(options[:locale].t("errors.syntax.for_invalid_in".freeze)) unless p.id?('in'.freeze)
147
+ @collection_name = p.expression
148
+ @name = "#{@variable_name}-#{@collection_name}"
149
+ @reversed = p.id?('reversed'.freeze)
150
+
151
+ @attributes = {}
152
+ while p.look(:id) && p.look(:colon, 1)
153
+ unless attribute = p.id?('limit'.freeze) || p.id?('offset'.freeze)
154
+ raise SyntaxError.new(options[:locale].t("errors.syntax.for_invalid_attribute".freeze))
155
+ end
156
+ p.consume
157
+ val = p.expression
158
+ @attributes[attribute] = val
138
159
  end
160
+ p.consume(:end_of_string)
161
+ end
162
+
163
+ private
164
+
165
+ def render_else(context)
166
+ return @else_block ? [render_all(@else_block, context)] : ''.freeze
167
+ end
168
+
169
+ def iterable?(collection)
170
+ collection.respond_to?(:each) || Utils.non_blank_string?(collection)
171
+ end
139
172
  end
140
173
 
141
- Template.register_tag('for', For)
174
+ Template.register_tag('for'.freeze, For)
142
175
  end
@@ -1,5 +1,4 @@
1
1
  module Liquid
2
-
3
2
  # If is the conditional block
4
3
  #
5
4
  # {% if user.admin %}
@@ -10,23 +9,23 @@ module Liquid
10
9
  #
11
10
  # There are {% if count < 5 %} less {% else %} more {% endif %} items than you need.
12
11
  #
13
- #
14
12
  class If < Block
15
- SyntaxHelp = "Syntax Error in tag 'if' - Valid syntax: if [expression]"
16
13
  Syntax = /(#{QuotedFragment})\s*([=!<>a-z_]+)?\s*(#{QuotedFragment})?/o
17
14
  ExpressionsAndOperators = /(?:\b(?:\s?and\s?|\s?or\s?)\b|(?:\s*(?!\b(?:\s?and\s?|\s?or\s?)\b)(?:#{QuotedFragment}|\S+)\s*)+)/o
18
15
  BOOLEAN_OPERATORS = %w(and or)
19
16
 
20
- def initialize(tag_name, markup, tokens)
17
+ def initialize(tag_name, markup, options)
18
+ super
21
19
  @blocks = []
20
+ push_block('if'.freeze, markup)
21
+ end
22
22
 
23
- push_block('if', markup)
24
-
25
- super
23
+ def nodelist
24
+ @blocks.flat_map(&:attachment)
26
25
  end
27
26
 
28
27
  def unknown_tag(tag, markup, tokens)
29
- if ['elsif', 'else'].include?(tag)
28
+ if ['elsif'.freeze, 'else'.freeze].include?(tag)
30
29
  push_block(tag, markup)
31
30
  else
32
31
  super
@@ -40,40 +39,68 @@ module Liquid
40
39
  return render_all(block.attachment, context)
41
40
  end
42
41
  end
43
- ''
42
+ ''.freeze
44
43
  end
45
44
  end
46
45
 
47
46
  private
48
47
 
49
48
  def push_block(tag, markup)
50
- block = if tag == 'else'
49
+ block = if tag == 'else'.freeze
51
50
  ElseCondition.new
52
51
  else
52
+ parse_with_selected_parser(markup)
53
+ end
53
54
 
54
- expressions = markup.scan(ExpressionsAndOperators).reverse
55
- raise(SyntaxError, SyntaxHelp) unless expressions.shift =~ Syntax
55
+ @blocks.push(block)
56
+ @nodelist = block.attach(Array.new)
57
+ end
56
58
 
57
- condition = Condition.new($1, $2, $3)
59
+ def lax_parse(markup)
60
+ expressions = markup.scan(ExpressionsAndOperators)
61
+ raise(SyntaxError.new(options[:locale].t("errors.syntax.if".freeze))) unless expressions.pop =~ Syntax
58
62
 
59
- while not expressions.empty?
60
- operator = (expressions.shift).to_s.strip
63
+ condition = Condition.new($1, $2, $3)
61
64
 
62
- raise(SyntaxError, SyntaxHelp) unless expressions.shift.to_s =~ Syntax
65
+ while not expressions.empty?
66
+ operator = expressions.pop.to_s.strip
63
67
 
64
- new_condition = Condition.new($1, $2, $3)
65
- raise SyntaxError, "invalid boolean operator" unless BOOLEAN_OPERATORS.include?(operator)
66
- new_condition.send(operator, condition)
67
- condition = new_condition
68
- end
68
+ raise(SyntaxError.new(options[:locale].t("errors.syntax.if".freeze))) unless expressions.pop.to_s =~ Syntax
69
69
 
70
- condition
70
+ new_condition = Condition.new($1, $2, $3)
71
+ raise(SyntaxError.new(options[:locale].t("errors.syntax.if".freeze))) unless BOOLEAN_OPERATORS.include?(operator)
72
+ new_condition.send(operator, condition)
73
+ condition = new_condition
71
74
  end
72
75
 
73
- @blocks.push(block)
74
- @nodelist = block.attach(Array.new)
76
+ condition
77
+ end
78
+
79
+ def strict_parse(markup)
80
+ p = Parser.new(markup)
81
+
82
+ condition = parse_comparison(p)
83
+
84
+ while op = (p.id?('and'.freeze) || p.id?('or'.freeze))
85
+ new_cond = parse_comparison(p)
86
+ new_cond.send(op, condition)
87
+ condition = new_cond
88
+ end
89
+ p.consume(:end_of_string)
90
+
91
+ condition
92
+ end
93
+
94
+ def parse_comparison(p)
95
+ a = p.expression
96
+ if op = p.consume?(:comparison)
97
+ b = p.expression
98
+ Condition.new(a, op, b)
99
+ else
100
+ Condition.new(a)
101
+ end
75
102
  end
76
103
  end
77
104
 
78
- Template.register_tag('if', If)
105
+ Template.register_tag('if'.freeze, If)
79
106
  end
@@ -4,17 +4,17 @@ module Liquid
4
4
  def render(context)
5
5
  context.stack do
6
6
 
7
- output = render_all(@nodelist, context)
7
+ output = super
8
8
 
9
9
  if output != context.registers[:ifchanged]
10
10
  context.registers[:ifchanged] = output
11
11
  output
12
12
  else
13
- ''
13
+ ''.freeze
14
14
  end
15
15
  end
16
16
  end
17
17
  end
18
18
 
19
- Template.register_tag('ifchanged', Ifchanged)
19
+ Template.register_tag('ifchanged'.freeze, Ifchanged)
20
20
  end
@@ -17,7 +17,9 @@ module Liquid
17
17
  class Include < Tag
18
18
  Syntax = /(#{QuotedFragment}+)(\s+(?:with|for)\s+(#{QuotedFragment}+))?/o
19
19
 
20
- def initialize(tag_name, markup, tokens)
20
+ def initialize(tag_name, markup, options)
21
+ super
22
+
21
23
  if markup =~ Syntax
22
24
 
23
25
  @template_name = $1
@@ -29,10 +31,8 @@ module Liquid
29
31
  end
30
32
 
31
33
  else
32
- raise SyntaxError.new("Error in tag 'include' - Valid syntax: include '[template]' (with|for) [object|collection]")
34
+ raise SyntaxError.new(options[:locale].t("errors.syntax.include".freeze))
33
35
  end
34
-
35
- super
36
36
  end
37
37
 
38
38
  def parse(tokens)
@@ -47,13 +47,14 @@ module Liquid
47
47
  context[key] = context[value]
48
48
  end
49
49
 
50
+ context_variable_name = @template_name[1..-2].split('/'.freeze).last
50
51
  if variable.is_a?(Array)
51
52
  variable.collect do |var|
52
- context[@template_name[1..-2]] = var
53
+ context[context_variable_name] = var
53
54
  partial.render(context)
54
55
  end
55
56
  else
56
- context[@template_name[1..-2]] = variable
57
+ context[context_variable_name] = variable
57
58
  partial.render(context)
58
59
  end
59
60
  end
@@ -68,7 +69,7 @@ module Liquid
68
69
  return cached
69
70
  end
70
71
  source = read_template_from_file_system(context)
71
- partial = Liquid::Template.parse(source)
72
+ partial = Liquid::Template.parse(source, pass_options)
72
73
  cached_partials[template_name] = partial
73
74
  context.registers[:cached_partials] = cached_partials
74
75
  partial
@@ -87,7 +88,17 @@ module Liquid
87
88
  raise ArgumentError, "file_system.read_template_file expects two parameters: (template_name, context)"
88
89
  end
89
90
  end
91
+
92
+ def pass_options
93
+ dont_pass = @options[:include_options_blacklist]
94
+ return {locale: @options[:locale]} if dont_pass == true
95
+ opts = @options.merge(included: true, include_options_blacklist: false)
96
+ if dont_pass.is_a?(Array)
97
+ dont_pass.each {|o| opts.delete(o)}
98
+ end
99
+ opts
100
+ end
90
101
  end
91
102
 
92
- Template.register_tag('include', Include)
103
+ Template.register_tag('include'.freeze, Include)
93
104
  end