liquid 5.4.0 → 5.6.4
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.
- checksums.yaml +4 -4
- data/History.md +11 -0
- data/README.md +48 -6
- data/lib/liquid/block.rb +8 -4
- data/lib/liquid/block_body.rb +28 -10
- data/lib/liquid/condition.rb +9 -4
- data/lib/liquid/const.rb +8 -0
- data/lib/liquid/context.rb +24 -14
- data/lib/liquid/deprecations.rb +22 -0
- data/lib/liquid/drop.rb +4 -0
- data/lib/liquid/environment.rb +159 -0
- data/lib/liquid/errors.rb +16 -15
- data/lib/liquid/expression.rb +101 -22
- data/lib/liquid/forloop_drop.rb +2 -5
- data/lib/liquid/lexer.rb +155 -44
- data/lib/liquid/locales/en.yml +1 -0
- data/lib/liquid/parse_context.rb +29 -6
- data/lib/liquid/parse_tree_visitor.rb +1 -1
- data/lib/liquid/parser.rb +3 -3
- data/lib/liquid/partial_cache.rb +12 -3
- data/lib/liquid/range_lookup.rb +14 -4
- data/lib/liquid/standardfilters.rb +82 -21
- data/lib/liquid/tablerowloop_drop.rb +1 -1
- data/lib/liquid/tag/disabler.rb +0 -8
- data/lib/liquid/tag.rb +13 -3
- data/lib/liquid/tags/assign.rb +1 -3
- data/lib/liquid/tags/break.rb +1 -3
- data/lib/liquid/tags/capture.rb +0 -2
- data/lib/liquid/tags/case.rb +1 -3
- data/lib/liquid/tags/comment.rb +60 -3
- data/lib/liquid/tags/continue.rb +1 -3
- data/lib/liquid/tags/cycle.rb +14 -4
- data/lib/liquid/tags/decrement.rb +8 -7
- data/lib/liquid/tags/echo.rb +2 -4
- data/lib/liquid/tags/for.rb +6 -8
- data/lib/liquid/tags/if.rb +3 -5
- data/lib/liquid/tags/ifchanged.rb +0 -2
- data/lib/liquid/tags/include.rb +8 -8
- data/lib/liquid/tags/increment.rb +8 -7
- data/lib/liquid/tags/inline_comment.rb +0 -15
- data/lib/liquid/tags/raw.rb +2 -4
- data/lib/liquid/tags/render.rb +14 -12
- data/lib/liquid/tags/table_row.rb +18 -6
- data/lib/liquid/tags/unless.rb +3 -5
- data/lib/liquid/tags.rb +47 -0
- data/lib/liquid/template.rb +60 -57
- data/lib/liquid/tokenizer.rb +127 -11
- data/lib/liquid/variable.rb +14 -8
- data/lib/liquid/variable_lookup.rb +13 -5
- data/lib/liquid/version.rb +1 -1
- data/lib/liquid.rb +15 -16
- metadata +37 -10
- data/lib/liquid/strainer_factory.rb +0 -41
@@ -6,7 +6,14 @@ require 'bigdecimal'
|
|
6
6
|
|
7
7
|
module Liquid
|
8
8
|
module StandardFilters
|
9
|
-
|
9
|
+
MAX_I32 = (1 << 31) - 1
|
10
|
+
private_constant :MAX_I32
|
11
|
+
|
12
|
+
MIN_I64 = -(1 << 63)
|
13
|
+
MAX_I64 = (1 << 63) - 1
|
14
|
+
I64_RANGE = MIN_I64..MAX_I64
|
15
|
+
private_constant :MIN_I64, :MAX_I64, :I64_RANGE
|
16
|
+
|
10
17
|
HTML_ESCAPE = {
|
11
18
|
'&' => '&',
|
12
19
|
'>' => '>',
|
@@ -18,10 +25,23 @@ module Liquid
|
|
18
25
|
STRIP_HTML_BLOCKS = Regexp.union(
|
19
26
|
%r{<script.*?</script>}m,
|
20
27
|
/<!--.*?-->/m,
|
21
|
-
%r{<style.*?</style>}m
|
28
|
+
%r{<style.*?</style>}m,
|
22
29
|
)
|
23
30
|
STRIP_HTML_TAGS = /<.*?>/m
|
24
31
|
|
32
|
+
class << self
|
33
|
+
def try_coerce_encoding(input, encoding:)
|
34
|
+
original_encoding = input.encoding
|
35
|
+
if input.encoding != encoding
|
36
|
+
input.force_encoding(encoding)
|
37
|
+
unless input.valid_encoding?
|
38
|
+
input.force_encoding(original_encoding)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
input
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
25
45
|
# @liquid_public_docs
|
26
46
|
# @liquid_type filter
|
27
47
|
# @liquid_category array
|
@@ -62,7 +82,7 @@ module Liquid
|
|
62
82
|
# @liquid_type filter
|
63
83
|
# @liquid_category string
|
64
84
|
# @liquid_summary
|
65
|
-
# Capitalizes the first word in a string.
|
85
|
+
# Capitalizes the first word in a string and downcases the remaining characters.
|
66
86
|
# @liquid_syntax string | capitalize
|
67
87
|
# @liquid_return [string]
|
68
88
|
def capitalize(input)
|
@@ -73,7 +93,7 @@ module Liquid
|
|
73
93
|
# @liquid_type filter
|
74
94
|
# @liquid_category string
|
75
95
|
# @liquid_summary
|
76
|
-
# Escapes a
|
96
|
+
# Escapes special characters in HTML, such as `<>`, `'`, and `&`, and converts characters into escape sequences. The filter doesn't effect characters within the string that don’t have a corresponding escape sequence.".
|
77
97
|
# @liquid_syntax string | escape
|
78
98
|
# @liquid_return [string]
|
79
99
|
def escape(input)
|
@@ -143,7 +163,8 @@ module Liquid
|
|
143
163
|
# @liquid_syntax string | base64_decode
|
144
164
|
# @liquid_return [string]
|
145
165
|
def base64_decode(input)
|
146
|
-
|
166
|
+
input = input.to_s
|
167
|
+
StandardFilters.try_coerce_encoding(Base64.strict_decode64(input), encoding: input.encoding)
|
147
168
|
rescue ::ArgumentError
|
148
169
|
raise Liquid::ArgumentError, "invalid base64 provided to base64_decode"
|
149
170
|
end
|
@@ -167,7 +188,8 @@ module Liquid
|
|
167
188
|
# @liquid_syntax string | base64_url_safe_decode
|
168
189
|
# @liquid_return [string]
|
169
190
|
def base64_url_safe_decode(input)
|
170
|
-
|
191
|
+
input = input.to_s
|
192
|
+
StandardFilters.try_coerce_encoding(Base64.urlsafe_decode64(input), encoding: input.encoding)
|
171
193
|
rescue ::ArgumentError
|
172
194
|
raise Liquid::ArgumentError, "invalid base64 provided to base64_url_safe_decode"
|
173
195
|
end
|
@@ -186,10 +208,19 @@ module Liquid
|
|
186
208
|
offset = Utils.to_integer(offset)
|
187
209
|
length = length ? Utils.to_integer(length) : 1
|
188
210
|
|
189
|
-
|
190
|
-
input.
|
191
|
-
|
192
|
-
|
211
|
+
begin
|
212
|
+
if input.is_a?(Array)
|
213
|
+
input.slice(offset, length) || []
|
214
|
+
else
|
215
|
+
input.to_s.slice(offset, length) || ''
|
216
|
+
end
|
217
|
+
rescue RangeError
|
218
|
+
if I64_RANGE.cover?(length) && I64_RANGE.cover?(offset)
|
219
|
+
raise # unexpected error
|
220
|
+
end
|
221
|
+
offset = offset.clamp(I64_RANGE)
|
222
|
+
length = length.clamp(I64_RANGE)
|
223
|
+
retry
|
193
224
|
end
|
194
225
|
end
|
195
226
|
|
@@ -239,9 +270,9 @@ module Liquid
|
|
239
270
|
wordlist = begin
|
240
271
|
input.split(" ", words + 1)
|
241
272
|
rescue RangeError
|
242
|
-
|
243
|
-
|
244
|
-
raise
|
273
|
+
# integer too big for String#split, but we can semantically assume no truncation is needed
|
274
|
+
return input if words + 1 > MAX_I32
|
275
|
+
raise # unexpected error
|
245
276
|
end
|
246
277
|
return input if wordlist.length <= words
|
247
278
|
|
@@ -599,7 +630,7 @@ module Liquid
|
|
599
630
|
# @liquid_description
|
600
631
|
# > Note:
|
601
632
|
# > The `concat` filter won't filter out duplicates. If you want to remove duplicates, then you need to use the
|
602
|
-
# > [`uniq` filter](/api/liquid/filters
|
633
|
+
# > [`uniq` filter](/docs/api/liquid/filters/uniq).
|
603
634
|
# @liquid_syntax array | concat: array
|
604
635
|
# @liquid_return [array[untyped]]
|
605
636
|
def concat(input, array)
|
@@ -741,7 +772,7 @@ module Liquid
|
|
741
772
|
# @liquid_type filter
|
742
773
|
# @liquid_category math
|
743
774
|
# @liquid_summary
|
744
|
-
# Divides a number by a given number.
|
775
|
+
# Divides a number by a given number. The `divided_by` filter produces a result of the same type as the divisor. This means if you divide by an integer, the result will be an integer, and if you divide by a float, the result will be a float.
|
745
776
|
# @liquid_syntax number | divided_by: number
|
746
777
|
# @liquid_return [number]
|
747
778
|
def divided_by(input, operand)
|
@@ -841,18 +872,48 @@ module Liquid
|
|
841
872
|
# @liquid_summary
|
842
873
|
# Sets a default value for any variable whose value is one of the following:
|
843
874
|
#
|
844
|
-
# - [`empty`](/api/liquid/basics#empty)
|
845
|
-
# - [`false`](/api/liquid/basics#truthy-and-falsy)
|
846
|
-
# - [`nil`](/api/liquid/basics#nil)
|
875
|
+
# - [`empty`](/docs/api/liquid/basics#empty)
|
876
|
+
# - [`false`](/docs/api/liquid/basics#truthy-and-falsy)
|
877
|
+
# - [`nil`](/docs/api/liquid/basics#nil)
|
847
878
|
# @liquid_syntax variable | default: variable
|
848
879
|
# @liquid_return [untyped]
|
849
|
-
# @liquid_optional_param allow_false [boolean] Whether to use false values instead of the default.
|
880
|
+
# @liquid_optional_param allow_false: [boolean] Whether to use false values instead of the default.
|
850
881
|
def default(input, default_value = '', options = {})
|
851
882
|
options = {} unless options.is_a?(Hash)
|
852
883
|
false_check = options['allow_false'] ? input.nil? : !Liquid::Utils.to_liquid_value(input)
|
853
884
|
false_check || (input.respond_to?(:empty?) && input.empty?) ? default_value : input
|
854
885
|
end
|
855
886
|
|
887
|
+
# @liquid_public_docs
|
888
|
+
# @liquid_type filter
|
889
|
+
# @liquid_category array
|
890
|
+
# @liquid_summary
|
891
|
+
# Returns the sum of all elements in an array.
|
892
|
+
# @liquid_syntax array | sum
|
893
|
+
# @liquid_return [number]
|
894
|
+
def sum(input, property = nil)
|
895
|
+
ary = InputIterator.new(input, context)
|
896
|
+
return 0 if ary.empty?
|
897
|
+
|
898
|
+
values_for_sum = ary.map do |item|
|
899
|
+
if property.nil?
|
900
|
+
item
|
901
|
+
elsif item.respond_to?(:[])
|
902
|
+
item[property]
|
903
|
+
else
|
904
|
+
0
|
905
|
+
end
|
906
|
+
rescue TypeError
|
907
|
+
raise_property_error(property)
|
908
|
+
end
|
909
|
+
|
910
|
+
result = InputIterator.new(values_for_sum, context).sum do |item|
|
911
|
+
Utils.to_number(item)
|
912
|
+
end
|
913
|
+
|
914
|
+
result.is_a?(BigDecimal) ? result.to_f : result
|
915
|
+
end
|
916
|
+
|
856
917
|
private
|
857
918
|
|
858
919
|
attr_reader :context
|
@@ -883,6 +944,8 @@ module Liquid
|
|
883
944
|
def nil_safe_casecmp(a, b)
|
884
945
|
if !a.nil? && !b.nil?
|
885
946
|
a.to_s.casecmp(b.to_s)
|
947
|
+
elsif a.nil? && b.nil?
|
948
|
+
0
|
886
949
|
else
|
887
950
|
a.nil? ? 1 : -1
|
888
951
|
end
|
@@ -938,6 +1001,4 @@ module Liquid
|
|
938
1001
|
end
|
939
1002
|
end
|
940
1003
|
end
|
941
|
-
|
942
|
-
Template.register_filter(StandardFilters)
|
943
1004
|
end
|
@@ -5,7 +5,7 @@ module Liquid
|
|
5
5
|
# @liquid_type object
|
6
6
|
# @liquid_name tablerowloop
|
7
7
|
# @liquid_summary
|
8
|
-
# Information about a parent [`tablerow` loop](/api/liquid/tags
|
8
|
+
# Information about a parent [`tablerow` loop](/docs/api/liquid/tags/tablerow).
|
9
9
|
class TablerowloopDrop < Drop
|
10
10
|
def initialize(length, cols)
|
11
11
|
@length = length
|
data/lib/liquid/tag/disabler.rb
CHANGED
@@ -3,14 +3,6 @@
|
|
3
3
|
module Liquid
|
4
4
|
class Tag
|
5
5
|
module Disabler
|
6
|
-
module ClassMethods
|
7
|
-
attr_reader :disabled_tags
|
8
|
-
end
|
9
|
-
|
10
|
-
def self.prepended(base)
|
11
|
-
base.extend(ClassMethods)
|
12
|
-
end
|
13
|
-
|
14
6
|
def render_to_output_buffer(context, output)
|
15
7
|
context.with_disabled_tags(self.class.disabled_tags) do
|
16
8
|
super
|
data/lib/liquid/tag.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'liquid/tag/disabler'
|
4
|
+
require 'liquid/tag/disableable'
|
5
|
+
|
3
6
|
module Liquid
|
4
7
|
class Tag
|
5
8
|
attr_reader :nodelist, :tag_name, :line_number, :parse_context
|
@@ -14,12 +17,18 @@ module Liquid
|
|
14
17
|
end
|
15
18
|
|
16
19
|
def disable_tags(*tag_names)
|
17
|
-
|
18
|
-
|
20
|
+
tag_names += disabled_tags
|
21
|
+
define_singleton_method(:disabled_tags) { tag_names }
|
19
22
|
prepend(Disabler)
|
20
23
|
end
|
21
24
|
|
22
25
|
private :new
|
26
|
+
|
27
|
+
protected
|
28
|
+
|
29
|
+
def disabled_tags
|
30
|
+
[]
|
31
|
+
end
|
23
32
|
end
|
24
33
|
|
25
34
|
def initialize(tag_name, markup, parse_context)
|
@@ -48,7 +57,8 @@ module Liquid
|
|
48
57
|
# of the `render_to_output_buffer` method will become the default and the `render`
|
49
58
|
# method will be removed.
|
50
59
|
def render_to_output_buffer(context, output)
|
51
|
-
|
60
|
+
render_result = render(context)
|
61
|
+
output << render_result if render_result
|
52
62
|
output
|
53
63
|
end
|
54
64
|
|
data/lib/liquid/tags/assign.rb
CHANGED
@@ -8,7 +8,7 @@ module Liquid
|
|
8
8
|
# @liquid_summary
|
9
9
|
# Creates a new variable.
|
10
10
|
# @liquid_description
|
11
|
-
# You can create variables of any [basic type](/api/liquid/basics#types), [object](/api/liquid/objects), or object property.
|
11
|
+
# You can create variables of any [basic type](/docs/api/liquid/basics#types), [object](/docs/api/liquid/objects), or object property.
|
12
12
|
# @liquid_syntax
|
13
13
|
# {% assign variable_name = value %}
|
14
14
|
# @liquid_syntax_keyword variable_name The name of the variable being created.
|
@@ -72,6 +72,4 @@ module Liquid
|
|
72
72
|
end
|
73
73
|
end
|
74
74
|
end
|
75
|
-
|
76
|
-
Template.register_tag('assign', Assign)
|
77
75
|
end
|
data/lib/liquid/tags/break.rb
CHANGED
@@ -15,7 +15,7 @@ module Liquid
|
|
15
15
|
# @liquid_category iteration
|
16
16
|
# @liquid_name break
|
17
17
|
# @liquid_summary
|
18
|
-
# Stops a [`for` loop](/api/liquid/tags
|
18
|
+
# Stops a [`for` loop](/docs/api/liquid/tags/for) from iterating.
|
19
19
|
# @liquid_syntax
|
20
20
|
# {% break %}
|
21
21
|
class Break < Tag
|
@@ -26,6 +26,4 @@ module Liquid
|
|
26
26
|
output
|
27
27
|
end
|
28
28
|
end
|
29
|
-
|
30
|
-
Template.register_tag('break', Break)
|
31
29
|
end
|
data/lib/liquid/tags/capture.rb
CHANGED
data/lib/liquid/tags/case.rb
CHANGED
@@ -77,7 +77,7 @@ module Liquid
|
|
77
77
|
end
|
78
78
|
|
79
79
|
result = Liquid::Utils.to_liquid_value(
|
80
|
-
block.evaluate(context)
|
80
|
+
block.evaluate(context),
|
81
81
|
)
|
82
82
|
|
83
83
|
if result
|
@@ -123,6 +123,4 @@ module Liquid
|
|
123
123
|
end
|
124
124
|
end
|
125
125
|
end
|
126
|
-
|
127
|
-
Template.register_tag('case', Case)
|
128
126
|
end
|
data/lib/liquid/tags/comment.rb
CHANGED
@@ -8,7 +8,7 @@ module Liquid
|
|
8
8
|
# @liquid_summary
|
9
9
|
# Prevents an expression from being rendered or output.
|
10
10
|
# @liquid_description
|
11
|
-
# Any text inside `comment` tags won't be output, and any Liquid code
|
11
|
+
# Any text inside `comment` tags won't be output, and any Liquid code will be parsed, but not executed.
|
12
12
|
# @liquid_syntax
|
13
13
|
# {% comment %}
|
14
14
|
# content
|
@@ -25,7 +25,64 @@ module Liquid
|
|
25
25
|
def blank?
|
26
26
|
true
|
27
27
|
end
|
28
|
-
end
|
29
28
|
|
30
|
-
|
29
|
+
private
|
30
|
+
|
31
|
+
def parse_body(body, tokenizer)
|
32
|
+
if parse_context.depth >= MAX_DEPTH
|
33
|
+
raise StackLevelError, "Nesting too deep"
|
34
|
+
end
|
35
|
+
|
36
|
+
parse_context.depth += 1
|
37
|
+
comment_tag_depth = 1
|
38
|
+
|
39
|
+
begin
|
40
|
+
# Consume tokens without creating child nodes.
|
41
|
+
# The children tag doesn't require to be a valid Liquid except the comment and raw tag.
|
42
|
+
# The child comment and raw tag must be closed.
|
43
|
+
while (token = tokenizer.send(:shift))
|
44
|
+
tag_name = if tokenizer.for_liquid_tag
|
45
|
+
next if token.empty? || token.match?(BlockBody::WhitespaceOrNothing)
|
46
|
+
|
47
|
+
tag_name_match = BlockBody::LiquidTagToken.match(token)
|
48
|
+
|
49
|
+
next if tag_name_match.nil?
|
50
|
+
|
51
|
+
tag_name_match[1]
|
52
|
+
else
|
53
|
+
token =~ BlockBody::FullToken
|
54
|
+
Regexp.last_match(2)
|
55
|
+
end
|
56
|
+
|
57
|
+
case tag_name
|
58
|
+
when "raw"
|
59
|
+
parse_raw_tag_body(tokenizer)
|
60
|
+
when "comment"
|
61
|
+
comment_tag_depth += 1
|
62
|
+
when "endcomment"
|
63
|
+
comment_tag_depth -= 1
|
64
|
+
end
|
65
|
+
|
66
|
+
if comment_tag_depth.zero?
|
67
|
+
parse_context.trim_whitespace = (token[-3] == WhitespaceControl) unless tokenizer.for_liquid_tag
|
68
|
+
return false
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
raise_tag_never_closed(block_name)
|
73
|
+
ensure
|
74
|
+
parse_context.depth -= 1
|
75
|
+
end
|
76
|
+
|
77
|
+
false
|
78
|
+
end
|
79
|
+
|
80
|
+
def parse_raw_tag_body(tokenizer)
|
81
|
+
while (token = tokenizer.send(:shift))
|
82
|
+
return if token =~ BlockBody::FullTokenPossiblyInvalid && "endraw" == Regexp.last_match(2)
|
83
|
+
end
|
84
|
+
|
85
|
+
raise_tag_never_closed("raw")
|
86
|
+
end
|
87
|
+
end
|
31
88
|
end
|
data/lib/liquid/tags/continue.rb
CHANGED
@@ -6,7 +6,7 @@ module Liquid
|
|
6
6
|
# @liquid_category iteration
|
7
7
|
# @liquid_name continue
|
8
8
|
# @liquid_summary
|
9
|
-
# Causes a [`for` loop](/api/liquid/tags
|
9
|
+
# Causes a [`for` loop](/docs/api/liquid/tags/for) to skip to the next iteration.
|
10
10
|
# @liquid_syntax
|
11
11
|
# {% continue %}
|
12
12
|
class Continue < Tag
|
@@ -17,6 +17,4 @@ module Liquid
|
|
17
17
|
output
|
18
18
|
end
|
19
19
|
end
|
20
|
-
|
21
|
-
Template.register_tag('continue', Continue)
|
22
20
|
end
|
data/lib/liquid/tags/cycle.rb
CHANGED
@@ -6,7 +6,7 @@ module Liquid
|
|
6
6
|
# @liquid_category iteration
|
7
7
|
# @liquid_name cycle
|
8
8
|
# @liquid_summary
|
9
|
-
# Loops through a group of strings and outputs them one at a time for each iteration of a [`for` loop](/api/liquid/tags
|
9
|
+
# Loops through a group of strings and outputs them one at a time for each iteration of a [`for` loop](/docs/api/liquid/tags/for).
|
10
10
|
# @liquid_description
|
11
11
|
# The `cycle` tag must be used inside a `for` loop.
|
12
12
|
#
|
@@ -26,14 +26,20 @@ module Liquid
|
|
26
26
|
when NamedSyntax
|
27
27
|
@variables = variables_from_string(Regexp.last_match(2))
|
28
28
|
@name = parse_expression(Regexp.last_match(1))
|
29
|
+
@is_named = true
|
29
30
|
when SimpleSyntax
|
30
31
|
@variables = variables_from_string(markup)
|
31
32
|
@name = @variables.to_s
|
33
|
+
@is_named = !@name.match?(/\w+:0x\h{8}/)
|
32
34
|
else
|
33
35
|
raise SyntaxError, options[:locale].t("errors.syntax.cycle")
|
34
36
|
end
|
35
37
|
end
|
36
38
|
|
39
|
+
def named?
|
40
|
+
@is_named
|
41
|
+
end
|
42
|
+
|
37
43
|
def render_to_output_buffer(context, output)
|
38
44
|
context.registers[:cycle] ||= {}
|
39
45
|
|
@@ -62,7 +68,13 @@ module Liquid
|
|
62
68
|
def variables_from_string(markup)
|
63
69
|
markup.split(',').collect do |var|
|
64
70
|
var =~ /\s*(#{QuotedFragment})\s*/o
|
65
|
-
|
71
|
+
next unless Regexp.last_match(1)
|
72
|
+
|
73
|
+
# Expression Parser returns cached objects, and we need to dup them to
|
74
|
+
# start the cycle over for each new cycle call.
|
75
|
+
# Liquid-C does not have a cache, so we don't need to dup the object.
|
76
|
+
var = parse_expression(Regexp.last_match(1))
|
77
|
+
var.is_a?(VariableLookup) ? var.dup : var
|
66
78
|
end.compact
|
67
79
|
end
|
68
80
|
|
@@ -72,6 +84,4 @@ module Liquid
|
|
72
84
|
end
|
73
85
|
end
|
74
86
|
end
|
75
|
-
|
76
|
-
Template.register_tag('cycle', Cycle)
|
77
87
|
end
|
@@ -12,26 +12,27 @@ module Liquid
|
|
12
12
|
# or [section](/themes/architecture/sections) file that they're created in. However, the variable is shared across
|
13
13
|
# [snippets](/themes/architecture#snippets) included in the file.
|
14
14
|
#
|
15
|
-
# Similarly, variables that are created with `decrement` are independent from those created with [`assign`](/api/liquid/tags
|
16
|
-
# and [`capture`](/api/liquid/tags
|
15
|
+
# Similarly, variables that are created with `decrement` are independent from those created with [`assign`](/docs/api/liquid/tags/assign)
|
16
|
+
# and [`capture`](/docs/api/liquid/tags/capture). However, `decrement` and [`increment`](/docs/api/liquid/tags/increment) share
|
17
17
|
# variables.
|
18
18
|
# @liquid_syntax
|
19
19
|
# {% decrement variable_name %}
|
20
20
|
# @liquid_syntax_keyword variable_name The name of the variable being decremented.
|
21
21
|
class Decrement < Tag
|
22
|
+
attr_reader :variable_name
|
23
|
+
|
22
24
|
def initialize(tag_name, markup, options)
|
23
25
|
super
|
24
|
-
@
|
26
|
+
@variable_name = markup.strip
|
25
27
|
end
|
26
28
|
|
27
29
|
def render_to_output_buffer(context, output)
|
28
|
-
|
30
|
+
counter_environment = context.environments.first
|
31
|
+
value = counter_environment[@variable_name] || 0
|
29
32
|
value -= 1
|
30
|
-
|
33
|
+
counter_environment[@variable_name] = value
|
31
34
|
output << value.to_s
|
32
35
|
output
|
33
36
|
end
|
34
37
|
end
|
35
|
-
|
36
|
-
Template.register_tag('decrement', Decrement)
|
37
38
|
end
|
data/lib/liquid/tags/echo.rb
CHANGED
@@ -9,10 +9,10 @@ module Liquid
|
|
9
9
|
# Outputs an expression.
|
10
10
|
# @liquid_description
|
11
11
|
# Using the `echo` tag is the same as wrapping an expression in curly brackets (`{{` and `}}`). However, unlike the curly
|
12
|
-
# bracket method, you can use the `echo` tag inside [`liquid` tags](/api/liquid/tags
|
12
|
+
# bracket method, you can use the `echo` tag inside [`liquid` tags](/docs/api/liquid/tags/liquid).
|
13
13
|
#
|
14
14
|
# > Tip:
|
15
|
-
# > You can use [filters](/api/liquid/filters) on expressions inside `echo` tags.
|
15
|
+
# > You can use [filters](/docs/api/liquid/filters) on expressions inside `echo` tags.
|
16
16
|
# @liquid_syntax
|
17
17
|
# {% liquid
|
18
18
|
# echo expression
|
@@ -36,6 +36,4 @@ module Liquid
|
|
36
36
|
end
|
37
37
|
end
|
38
38
|
end
|
39
|
-
|
40
|
-
Template.register_tag('echo', Echo)
|
41
39
|
end
|
data/lib/liquid/tags/for.rb
CHANGED
@@ -9,10 +9,10 @@ module Liquid
|
|
9
9
|
# Renders an expression for every item in an array.
|
10
10
|
# @liquid_description
|
11
11
|
# You can do a maximum of 50 iterations with a `for` loop. If you need to iterate over more than 50 items, then use the
|
12
|
-
# [`paginate` tag](/api/liquid/tags
|
12
|
+
# [`paginate` tag](/docs/api/liquid/tags/paginate) to split the items over multiple pages.
|
13
13
|
#
|
14
14
|
# > Tip:
|
15
|
-
# > Every `for` loop has an associated [`forloop` object](/api/liquid/objects
|
15
|
+
# > Every `for` loop has an associated [`forloop` object](/docs/api/liquid/objects/forloop) with information about the loop.
|
16
16
|
# @liquid_syntax
|
17
17
|
# {% for variable in array %}
|
18
18
|
# expression
|
@@ -88,7 +88,7 @@ module Liquid
|
|
88
88
|
end
|
89
89
|
|
90
90
|
def strict_parse(markup)
|
91
|
-
p =
|
91
|
+
p = @parse_context.new_parser(markup)
|
92
92
|
@variable_name = p.consume(:id)
|
93
93
|
raise SyntaxError, options[:locale].t("errors.syntax.for_invalid_in") unless p.id?('in')
|
94
94
|
|
@@ -98,11 +98,12 @@ module Liquid
|
|
98
98
|
@name = "#{@variable_name}-#{collection_name}"
|
99
99
|
@reversed = p.id?('reversed')
|
100
100
|
|
101
|
-
while p.look(:
|
101
|
+
while p.look(:comma) || p.look(:id)
|
102
|
+
p.consume?(:comma)
|
102
103
|
unless (attribute = p.id?('limit') || p.id?('offset'))
|
103
104
|
raise SyntaxError, options[:locale].t("errors.syntax.for_invalid_attribute")
|
104
105
|
end
|
105
|
-
p.consume
|
106
|
+
p.consume(:colon)
|
106
107
|
set_attribute(attribute, p.expression)
|
107
108
|
end
|
108
109
|
p.consume(:end_of_string)
|
@@ -177,7 +178,6 @@ module Liquid
|
|
177
178
|
case key
|
178
179
|
when 'offset'
|
179
180
|
@from = if expr == 'continue'
|
180
|
-
Usage.increment('for_offset_continue')
|
181
181
|
:continue
|
182
182
|
else
|
183
183
|
parse_expression(expr)
|
@@ -201,6 +201,4 @@ module Liquid
|
|
201
201
|
end
|
202
202
|
end
|
203
203
|
end
|
204
|
-
|
205
|
-
Template.register_tag('for', For)
|
206
204
|
end
|
data/lib/liquid/tags/if.rb
CHANGED
@@ -53,7 +53,7 @@ module Liquid
|
|
53
53
|
def render_to_output_buffer(context, output)
|
54
54
|
@blocks.each do |block|
|
55
55
|
result = Liquid::Utils.to_liquid_value(
|
56
|
-
block.evaluate(context)
|
56
|
+
block.evaluate(context),
|
57
57
|
)
|
58
58
|
|
59
59
|
if result
|
@@ -102,7 +102,7 @@ module Liquid
|
|
102
102
|
end
|
103
103
|
|
104
104
|
def strict_parse(markup)
|
105
|
-
p =
|
105
|
+
p = @parse_context.new_parser(markup)
|
106
106
|
condition = parse_binary_comparisons(p)
|
107
107
|
p.consume(:end_of_string)
|
108
108
|
condition
|
@@ -111,7 +111,7 @@ module Liquid
|
|
111
111
|
def parse_binary_comparisons(p)
|
112
112
|
condition = parse_comparison(p)
|
113
113
|
first_condition = condition
|
114
|
-
while (op =
|
114
|
+
while (op = p.id?('and') || p.id?('or'))
|
115
115
|
child_condition = parse_comparison(p)
|
116
116
|
condition.send(op, child_condition)
|
117
117
|
condition = child_condition
|
@@ -135,6 +135,4 @@ module Liquid
|
|
135
135
|
end
|
136
136
|
end
|
137
137
|
end
|
138
|
-
|
139
|
-
Template.register_tag('if', If)
|
140
138
|
end
|
data/lib/liquid/tags/include.rb
CHANGED
@@ -8,7 +8,7 @@ module Liquid
|
|
8
8
|
# @liquid_summary
|
9
9
|
# Renders a [snippet](/themes/architecture#snippets).
|
10
10
|
# @liquid_description
|
11
|
-
# Inside the snippet, you can access and alter variables that are [created](/api/liquid/tags
|
11
|
+
# Inside the snippet, you can access and alter variables that are [created](/docs/api/liquid/tags/variable-tags) outside of the
|
12
12
|
# snippet.
|
13
13
|
# @liquid_syntax
|
14
14
|
# {% include 'filename' %}
|
@@ -16,7 +16,7 @@ module Liquid
|
|
16
16
|
# @liquid_deprecated
|
17
17
|
# Deprecated because the way that variables are handled reduces performance and makes code harder to both read and maintain.
|
18
18
|
#
|
19
|
-
# The `include` tag has been replaced by [`render`](/api/liquid/tags
|
19
|
+
# The `include` tag has been replaced by [`render`](/docs/api/liquid/tags/render).
|
20
20
|
class Include < Tag
|
21
21
|
prepend Tag::Disableable
|
22
22
|
|
@@ -52,12 +52,12 @@ module Liquid
|
|
52
52
|
|
53
53
|
def render_to_output_buffer(context, output)
|
54
54
|
template_name = context.evaluate(@template_name_expr)
|
55
|
-
raise ArgumentError, options[:locale].t("errors.argument.include") unless template_name
|
55
|
+
raise ArgumentError, options[:locale].t("errors.argument.include") unless template_name.is_a?(String)
|
56
56
|
|
57
57
|
partial = PartialCache.load(
|
58
58
|
template_name,
|
59
59
|
context: context,
|
60
|
-
parse_context: parse_context
|
60
|
+
parse_context: parse_context,
|
61
61
|
)
|
62
62
|
|
63
63
|
context_variable_name = @alias_name || template_name.split('/').last
|
@@ -70,9 +70,11 @@ module Liquid
|
|
70
70
|
|
71
71
|
old_template_name = context.template_name
|
72
72
|
old_partial = context.partial
|
73
|
+
|
73
74
|
begin
|
74
|
-
context.template_name =
|
75
|
-
context.partial
|
75
|
+
context.template_name = partial.name
|
76
|
+
context.partial = true
|
77
|
+
|
76
78
|
context.stack do
|
77
79
|
@attributes.each do |key, value|
|
78
80
|
context[key] = context.evaluate(value)
|
@@ -108,6 +110,4 @@ module Liquid
|
|
108
110
|
end
|
109
111
|
end
|
110
112
|
end
|
111
|
-
|
112
|
-
Template.register_tag('include', Include)
|
113
113
|
end
|