liquid 4.0.4 → 5.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.
- checksums.yaml +4 -4
- data/History.md +32 -4
- data/README.md +6 -0
- data/lib/liquid/block.rb +31 -14
- data/lib/liquid/block_body.rb +164 -54
- data/lib/liquid/condition.rb +39 -18
- data/lib/liquid/context.rb +106 -51
- data/lib/liquid/document.rb +47 -9
- data/lib/liquid/drop.rb +4 -2
- data/lib/liquid/errors.rb +20 -18
- data/lib/liquid/expression.rb +29 -34
- data/lib/liquid/extensions.rb +2 -0
- data/lib/liquid/file_system.rb +6 -4
- data/lib/liquid/forloop_drop.rb +11 -4
- data/lib/liquid/i18n.rb +5 -3
- data/lib/liquid/interrupts.rb +3 -1
- data/lib/liquid/lexer.rb +30 -23
- data/lib/liquid/locales/en.yml +3 -1
- data/lib/liquid/parse_context.rb +16 -4
- data/lib/liquid/parse_tree_visitor.rb +2 -2
- data/lib/liquid/parser.rb +30 -18
- data/lib/liquid/parser_switching.rb +17 -3
- data/lib/liquid/partial_cache.rb +24 -0
- data/lib/liquid/profiler/hooks.rb +26 -14
- data/lib/liquid/profiler.rb +67 -86
- data/lib/liquid/range_lookup.rb +5 -3
- data/lib/liquid/register.rb +6 -0
- data/lib/liquid/resource_limits.rb +47 -8
- data/lib/liquid/standardfilters.rb +62 -43
- data/lib/liquid/static_registers.rb +44 -0
- data/lib/liquid/strainer_factory.rb +36 -0
- data/lib/liquid/strainer_template.rb +53 -0
- data/lib/liquid/tablerowloop_drop.rb +6 -4
- data/lib/liquid/tag/disableable.rb +22 -0
- data/lib/liquid/tag/disabler.rb +21 -0
- data/lib/liquid/tag.rb +28 -6
- data/lib/liquid/tags/assign.rb +24 -10
- data/lib/liquid/tags/break.rb +8 -3
- data/lib/liquid/tags/capture.rb +11 -8
- data/lib/liquid/tags/case.rb +33 -27
- data/lib/liquid/tags/comment.rb +5 -3
- data/lib/liquid/tags/continue.rb +8 -3
- data/lib/liquid/tags/cycle.rb +25 -14
- data/lib/liquid/tags/decrement.rb +6 -3
- data/lib/liquid/tags/echo.rb +26 -0
- data/lib/liquid/tags/for.rb +68 -44
- data/lib/liquid/tags/if.rb +35 -23
- data/lib/liquid/tags/ifchanged.rb +11 -10
- data/lib/liquid/tags/include.rb +34 -47
- data/lib/liquid/tags/increment.rb +7 -3
- data/lib/liquid/tags/raw.rb +14 -11
- data/lib/liquid/tags/render.rb +84 -0
- data/lib/liquid/tags/table_row.rb +23 -19
- data/lib/liquid/tags/unless.rb +15 -15
- data/lib/liquid/template.rb +55 -69
- data/lib/liquid/template_factory.rb +9 -0
- data/lib/liquid/tokenizer.rb +17 -9
- data/lib/liquid/usage.rb +8 -0
- data/lib/liquid/utils.rb +5 -3
- data/lib/liquid/variable.rb +47 -19
- data/lib/liquid/variable_lookup.rb +8 -6
- data/lib/liquid/version.rb +2 -1
- data/lib/liquid.rb +17 -5
- data/test/integration/assign_test.rb +74 -5
- data/test/integration/blank_test.rb +11 -8
- data/test/integration/block_test.rb +47 -1
- data/test/integration/capture_test.rb +18 -10
- data/test/integration/context_test.rb +608 -5
- data/test/integration/document_test.rb +4 -2
- data/test/integration/drop_test.rb +67 -57
- data/test/integration/error_handling_test.rb +73 -61
- data/test/integration/expression_test.rb +46 -0
- data/test/integration/filter_test.rb +53 -42
- data/test/integration/hash_ordering_test.rb +5 -3
- data/test/integration/output_test.rb +26 -24
- data/test/integration/parsing_quirks_test.rb +19 -7
- data/test/integration/{render_profiling_test.rb → profiler_test.rb} +84 -25
- data/test/integration/security_test.rb +30 -21
- data/test/integration/standard_filter_test.rb +339 -281
- data/test/integration/tag/disableable_test.rb +59 -0
- data/test/integration/tag_test.rb +45 -0
- data/test/integration/tags/break_tag_test.rb +4 -2
- data/test/integration/tags/continue_tag_test.rb +4 -2
- data/test/integration/tags/echo_test.rb +13 -0
- data/test/integration/tags/for_tag_test.rb +107 -51
- data/test/integration/tags/if_else_tag_test.rb +5 -3
- data/test/integration/tags/include_tag_test.rb +70 -54
- data/test/integration/tags/increment_tag_test.rb +4 -2
- data/test/integration/tags/liquid_tag_test.rb +116 -0
- data/test/integration/tags/raw_tag_test.rb +14 -11
- data/test/integration/tags/render_tag_test.rb +213 -0
- data/test/integration/tags/standard_tag_test.rb +38 -31
- data/test/integration/tags/statements_test.rb +23 -21
- data/test/integration/tags/table_row_test.rb +2 -0
- data/test/integration/tags/unless_else_tag_test.rb +4 -2
- data/test/integration/template_test.rb +118 -124
- data/test/integration/trim_mode_test.rb +78 -44
- data/test/integration/variable_test.rb +43 -32
- data/test/test_helper.rb +75 -14
- data/test/unit/block_unit_test.rb +19 -24
- data/test/unit/condition_unit_test.rb +79 -77
- data/test/unit/file_system_unit_test.rb +6 -4
- data/test/unit/i18n_unit_test.rb +7 -5
- data/test/unit/lexer_unit_test.rb +11 -9
- data/test/{integration → unit}/parse_tree_visitor_test.rb +1 -1
- data/test/unit/parser_unit_test.rb +37 -35
- data/test/unit/partial_cache_unit_test.rb +128 -0
- data/test/unit/regexp_unit_test.rb +17 -15
- data/test/unit/static_registers_unit_test.rb +156 -0
- data/test/unit/strainer_factory_unit_test.rb +100 -0
- data/test/unit/strainer_template_unit_test.rb +82 -0
- data/test/unit/tag_unit_test.rb +5 -3
- data/test/unit/tags/case_tag_unit_test.rb +3 -1
- data/test/unit/tags/for_tag_unit_test.rb +4 -2
- data/test/unit/tags/if_tag_unit_test.rb +3 -1
- data/test/unit/template_factory_unit_test.rb +12 -0
- data/test/unit/template_unit_test.rb +19 -10
- data/test/unit/tokenizer_unit_test.rb +19 -17
- data/test/unit/variable_unit_test.rb +51 -49
- metadata +75 -47
- data/lib/liquid/strainer.rb +0 -66
- data/test/unit/context_unit_test.rb +0 -490
- data/test/unit/strainer_unit_test.rb +0 -164
data/lib/liquid/tokenizer.rb
CHANGED
@@ -1,29 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Liquid
|
2
4
|
class Tokenizer
|
3
|
-
attr_reader :line_number
|
5
|
+
attr_reader :line_number, :for_liquid_tag
|
4
6
|
|
5
|
-
def initialize(source, line_numbers = false)
|
6
|
-
@source
|
7
|
-
@line_number
|
8
|
-
@
|
7
|
+
def initialize(source, line_numbers = false, line_number: nil, for_liquid_tag: false)
|
8
|
+
@source = source
|
9
|
+
@line_number = line_number || (line_numbers ? 1 : nil)
|
10
|
+
@for_liquid_tag = for_liquid_tag
|
11
|
+
@tokens = tokenize
|
9
12
|
end
|
10
13
|
|
11
14
|
def shift
|
12
|
-
token = @tokens.shift
|
13
|
-
|
15
|
+
(token = @tokens.shift) || return
|
16
|
+
|
17
|
+
if @line_number
|
18
|
+
@line_number += @for_liquid_tag ? 1 : token.count("\n")
|
19
|
+
end
|
20
|
+
|
14
21
|
token
|
15
22
|
end
|
16
23
|
|
17
24
|
private
|
18
25
|
|
19
26
|
def tokenize
|
20
|
-
@source = @source.source if @source.respond_to?(:source)
|
21
27
|
return [] if @source.to_s.empty?
|
22
28
|
|
29
|
+
return @source.split("\n") if @for_liquid_tag
|
30
|
+
|
23
31
|
tokens = @source.split(TemplateParser)
|
24
32
|
|
25
33
|
# removes the rogue empty element at the beginning of the array
|
26
|
-
tokens.shift if tokens[0]
|
34
|
+
tokens.shift if tokens[0]&.empty?
|
27
35
|
|
28
36
|
tokens
|
29
37
|
end
|
data/lib/liquid/usage.rb
ADDED
data/lib/liquid/utils.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Liquid
|
2
4
|
module Utils
|
3
5
|
def self.slice_collection(collection, from, to)
|
@@ -10,7 +12,7 @@ module Liquid
|
|
10
12
|
|
11
13
|
def self.slice_collection_using_each(collection, from, to)
|
12
14
|
segments = []
|
13
|
-
index
|
15
|
+
index = 0
|
14
16
|
|
15
17
|
# Maintains Ruby 1.8.7 String#each behaviour on 1.9
|
16
18
|
if collection.is_a?(String)
|
@@ -50,7 +52,7 @@ module Liquid
|
|
50
52
|
when Numeric
|
51
53
|
obj
|
52
54
|
when String
|
53
|
-
|
55
|
+
/\A-?\d+\.\d+\z/.match?(obj.strip) ? BigDecimal(obj) : obj.to_i
|
54
56
|
else
|
55
57
|
if obj.respond_to?(:to_number)
|
56
58
|
obj.to_number
|
@@ -69,7 +71,7 @@ module Liquid
|
|
69
71
|
end
|
70
72
|
|
71
73
|
case obj
|
72
|
-
when 'now'
|
74
|
+
when 'now', 'today'
|
73
75
|
Time.now
|
74
76
|
when /\A\d+\z/, Integer
|
75
77
|
Time.at(obj.to_i)
|
data/lib/liquid/variable.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Liquid
|
2
4
|
# Holds variables. Variables are only loaded "just in time"
|
3
5
|
# and are not evaluated as part of the render stage
|
@@ -10,10 +12,10 @@ module Liquid
|
|
10
12
|
# {{ user | link }}
|
11
13
|
#
|
12
14
|
class Variable
|
13
|
-
FilterMarkupRegex
|
14
|
-
FilterParser
|
15
|
-
FilterArgsRegex
|
16
|
-
JustTagAttributes
|
15
|
+
FilterMarkupRegex = /#{FilterSeparator}\s*(.*)/om
|
16
|
+
FilterParser = /(?:\s+|#{QuotedFragment}|#{ArgumentSeparator})+/o
|
17
|
+
FilterArgsRegex = /(?:#{FilterArgumentSeparator}|#{ArgumentSeparator})\s*((?:\w+\s*\:\s*)?#{QuotedFragment})/o
|
18
|
+
JustTagAttributes = /\A#{TagAttributes}\z/o
|
17
19
|
MarkupWithQuotedFragment = /(#{QuotedFragment})(.*)/om
|
18
20
|
|
19
21
|
attr_accessor :filters, :name, :line_number
|
@@ -23,12 +25,12 @@ module Liquid
|
|
23
25
|
include ParserSwitching
|
24
26
|
|
25
27
|
def initialize(markup, parse_context)
|
26
|
-
@markup
|
27
|
-
@name
|
28
|
+
@markup = markup
|
29
|
+
@name = nil
|
28
30
|
@parse_context = parse_context
|
29
|
-
@line_number
|
31
|
+
@line_number = parse_context.line_number
|
30
32
|
|
31
|
-
|
33
|
+
strict_parse_with_error_mode_fallback(markup)
|
32
34
|
end
|
33
35
|
|
34
36
|
def raw
|
@@ -43,11 +45,11 @@ module Liquid
|
|
43
45
|
@filters = []
|
44
46
|
return unless markup =~ MarkupWithQuotedFragment
|
45
47
|
|
46
|
-
name_markup
|
47
|
-
filter_markup =
|
48
|
-
@name
|
48
|
+
name_markup = Regexp.last_match(1)
|
49
|
+
filter_markup = Regexp.last_match(2)
|
50
|
+
@name = Expression.parse(name_markup)
|
49
51
|
if filter_markup =~ FilterMarkupRegex
|
50
|
-
filters =
|
52
|
+
filters = Regexp.last_match(1).scan(FilterParser)
|
51
53
|
filters.each do |f|
|
52
54
|
next unless f =~ /\w+/
|
53
55
|
filtername = Regexp.last_match(0)
|
@@ -61,6 +63,8 @@ module Liquid
|
|
61
63
|
@filters = []
|
62
64
|
p = Parser.new(markup)
|
63
65
|
|
66
|
+
return if p.look(:end_of_string)
|
67
|
+
|
64
68
|
@name = Expression.parse(p.expression)
|
65
69
|
while p.consume?(:pipe)
|
66
70
|
filtername = p.consume(:id)
|
@@ -79,33 +83,57 @@ module Liquid
|
|
79
83
|
end
|
80
84
|
|
81
85
|
def render(context)
|
82
|
-
obj =
|
86
|
+
obj = context.evaluate(@name)
|
87
|
+
|
88
|
+
@filters.each do |filter_name, filter_args, filter_kwargs|
|
83
89
|
filter_args = evaluate_filter_expressions(context, filter_args, filter_kwargs)
|
84
|
-
context.invoke(filter_name,
|
90
|
+
obj = context.invoke(filter_name, obj, *filter_args)
|
85
91
|
end
|
86
92
|
|
87
93
|
context.apply_global_filter(obj)
|
88
94
|
end
|
89
95
|
|
96
|
+
def render_to_output_buffer(context, output)
|
97
|
+
obj = render(context)
|
98
|
+
|
99
|
+
if obj.is_a?(Array)
|
100
|
+
output << obj.join
|
101
|
+
elsif obj.nil?
|
102
|
+
else
|
103
|
+
output << obj.to_s
|
104
|
+
end
|
105
|
+
|
106
|
+
output
|
107
|
+
end
|
108
|
+
|
109
|
+
def disabled?(_context)
|
110
|
+
false
|
111
|
+
end
|
112
|
+
|
113
|
+
def disabled_tags
|
114
|
+
[]
|
115
|
+
end
|
116
|
+
|
90
117
|
private
|
91
118
|
|
92
119
|
def parse_filter_expressions(filter_name, unparsed_args)
|
93
|
-
filter_args
|
94
|
-
keyword_args =
|
120
|
+
filter_args = []
|
121
|
+
keyword_args = nil
|
95
122
|
unparsed_args.each do |a|
|
96
|
-
if matches = a.match(JustTagAttributes)
|
123
|
+
if (matches = a.match(JustTagAttributes))
|
124
|
+
keyword_args ||= {}
|
97
125
|
keyword_args[matches[1]] = Expression.parse(matches[2])
|
98
126
|
else
|
99
127
|
filter_args << Expression.parse(a)
|
100
128
|
end
|
101
129
|
end
|
102
130
|
result = [filter_name, filter_args]
|
103
|
-
result << keyword_args
|
131
|
+
result << keyword_args if keyword_args
|
104
132
|
result
|
105
133
|
end
|
106
134
|
|
107
135
|
def evaluate_filter_expressions(context, filter_args, filter_kwargs)
|
108
|
-
parsed_args = filter_args.map{ |expr| context.evaluate(expr) }
|
136
|
+
parsed_args = filter_args.map { |expr| context.evaluate(expr) }
|
109
137
|
if filter_kwargs
|
110
138
|
parsed_kwargs = {}
|
111
139
|
filter_kwargs.each do |key, expr|
|
@@ -1,7 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Liquid
|
2
4
|
class VariableLookup
|
3
5
|
SQUARE_BRACKETED = /\A\[(.*)\]\z/m
|
4
|
-
COMMAND_METHODS
|
6
|
+
COMMAND_METHODS = ['size', 'first', 'last'].freeze
|
5
7
|
|
6
8
|
attr_reader :name, :lookups
|
7
9
|
|
@@ -14,17 +16,17 @@ module Liquid
|
|
14
16
|
|
15
17
|
name = lookups.shift
|
16
18
|
if name =~ SQUARE_BRACKETED
|
17
|
-
name = Expression.parse(
|
19
|
+
name = Expression.parse(Regexp.last_match(1))
|
18
20
|
end
|
19
21
|
@name = name
|
20
22
|
|
21
|
-
@lookups
|
23
|
+
@lookups = lookups
|
22
24
|
@command_flags = 0
|
23
25
|
|
24
26
|
@lookups.each_index do |i|
|
25
27
|
lookup = lookups[i]
|
26
28
|
if lookup =~ SQUARE_BRACKETED
|
27
|
-
lookups[i] = Expression.parse(
|
29
|
+
lookups[i] = Expression.parse(Regexp.last_match(1))
|
28
30
|
elsif COMMAND_METHODS.include?(lookup)
|
29
31
|
@command_flags |= 1 << i
|
30
32
|
end
|
@@ -32,7 +34,7 @@ module Liquid
|
|
32
34
|
end
|
33
35
|
|
34
36
|
def evaluate(context)
|
35
|
-
name
|
37
|
+
name = context.evaluate(@name)
|
36
38
|
object = context.find_variable(name)
|
37
39
|
|
38
40
|
@lookups.each_index do |i|
|
@@ -45,7 +47,7 @@ module Liquid
|
|
45
47
|
(object.respond_to?(:fetch) && key.is_a?(Integer)))
|
46
48
|
|
47
49
|
# if its a proc we will replace the entry with the proc
|
48
|
-
res
|
50
|
+
res = context.lookup_and_evaluate(object, key)
|
49
51
|
object = res.to_liquid
|
50
52
|
|
51
53
|
# Some special cases. If the part wasn't in square brackets and
|
data/lib/liquid/version.rb
CHANGED
data/lib/liquid.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# Copyright (c) 2005 Tobias Luetke
|
2
4
|
#
|
3
5
|
# Permission is hereby granted, free of charge, to any person obtaining
|
@@ -21,10 +23,10 @@
|
|
21
23
|
|
22
24
|
module Liquid
|
23
25
|
FilterSeparator = /\|/
|
24
|
-
ArgumentSeparator = ','
|
25
|
-
FilterArgumentSeparator = ':'
|
26
|
-
VariableAttributeSeparator = '.'
|
27
|
-
WhitespaceControl = '-'
|
26
|
+
ArgumentSeparator = ','
|
27
|
+
FilterArgumentSeparator = ':'
|
28
|
+
VariableAttributeSeparator = '.'
|
29
|
+
WhitespaceControl = '-'
|
28
30
|
TagStart = /\{\%/
|
29
31
|
TagEnd = /\%\}/
|
30
32
|
VariableSignature = /\(?[\w\-\.\[\]]\)?/
|
@@ -40,6 +42,8 @@ module Liquid
|
|
40
42
|
TemplateParser = /(#{PartialTemplateParser}|#{AnyStartingTag})/om
|
41
43
|
VariableParser = /\[[^\]]+\]|#{VariableSegment}+\??/o
|
42
44
|
|
45
|
+
RAISE_EXCEPTION_LAMBDA = ->(_e) { raise }
|
46
|
+
|
43
47
|
singleton_class.send(:attr_accessor, :cache_classes)
|
44
48
|
self.cache_classes = true
|
45
49
|
end
|
@@ -55,11 +59,14 @@ require 'liquid/forloop_drop'
|
|
55
59
|
require 'liquid/extensions'
|
56
60
|
require 'liquid/errors'
|
57
61
|
require 'liquid/interrupts'
|
58
|
-
require 'liquid/
|
62
|
+
require 'liquid/strainer_factory'
|
63
|
+
require 'liquid/strainer_template'
|
59
64
|
require 'liquid/expression'
|
60
65
|
require 'liquid/context'
|
61
66
|
require 'liquid/parser_switching'
|
62
67
|
require 'liquid/tag'
|
68
|
+
require 'liquid/tag/disabler'
|
69
|
+
require 'liquid/tag/disableable'
|
63
70
|
require 'liquid/block'
|
64
71
|
require 'liquid/block_body'
|
65
72
|
require 'liquid/document'
|
@@ -74,6 +81,11 @@ require 'liquid/condition'
|
|
74
81
|
require 'liquid/utils'
|
75
82
|
require 'liquid/tokenizer'
|
76
83
|
require 'liquid/parse_context'
|
84
|
+
require 'liquid/partial_cache'
|
85
|
+
require 'liquid/usage'
|
86
|
+
require 'liquid/register'
|
87
|
+
require 'liquid/static_registers'
|
88
|
+
require 'liquid/template_factory'
|
77
89
|
|
78
90
|
# Load all the tags of the standard library
|
79
91
|
#
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'test_helper'
|
2
4
|
|
3
5
|
class AssignTest < Minitest::Test
|
@@ -8,9 +10,9 @@ class AssignTest < Minitest::Test
|
|
8
10
|
{% assign this-thing = 'Print this-thing' %}
|
9
11
|
{{ this-thing }}
|
10
12
|
END_TEMPLATE
|
11
|
-
template
|
12
|
-
rendered
|
13
|
-
assert_equal
|
13
|
+
template = Template.parse(template_source)
|
14
|
+
rendered = template.render!
|
15
|
+
assert_equal("Print this-thing", rendered.strip)
|
14
16
|
end
|
15
17
|
|
16
18
|
def test_assigned_variable
|
@@ -42,7 +44,74 @@ class AssignTest < Minitest::Test
|
|
42
44
|
end
|
43
45
|
end
|
44
46
|
with_error_mode(:lax) do
|
45
|
-
assert
|
47
|
+
assert(Template.parse("{% assign foo = ('X' | downcase) %}"))
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_expression_with_whitespace_in_square_brackets
|
52
|
+
source = "{% assign r = a[ 'b' ] %}{{ r }}"
|
53
|
+
assert_template_result('result', source, 'a' => { 'b' => 'result' })
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_assign_score_exceeding_resource_limit
|
57
|
+
t = Template.parse("{% assign foo = 42 %}{% assign bar = 23 %}")
|
58
|
+
t.resource_limits.assign_score_limit = 1
|
59
|
+
assert_equal("Liquid error: Memory limits exceeded", t.render)
|
60
|
+
assert(t.resource_limits.reached?)
|
61
|
+
|
62
|
+
t.resource_limits.assign_score_limit = 2
|
63
|
+
assert_equal("", t.render!)
|
64
|
+
refute_nil(t.resource_limits.assign_score)
|
65
|
+
end
|
66
|
+
|
67
|
+
def test_assign_score_exceeding_limit_from_composite_object
|
68
|
+
t = Template.parse("{% assign foo = 'aaaa' | reverse %}")
|
69
|
+
|
70
|
+
t.resource_limits.assign_score_limit = 3
|
71
|
+
assert_equal("Liquid error: Memory limits exceeded", t.render)
|
72
|
+
assert(t.resource_limits.reached?)
|
73
|
+
|
74
|
+
t.resource_limits.assign_score_limit = 5
|
75
|
+
assert_equal("", t.render!)
|
76
|
+
end
|
77
|
+
|
78
|
+
def test_assign_score_of_int
|
79
|
+
assert_equal(1, assign_score_of(123))
|
80
|
+
end
|
81
|
+
|
82
|
+
def test_assign_score_of_string_counts_bytes
|
83
|
+
assert_equal(3, assign_score_of('123'))
|
84
|
+
assert_equal(5, assign_score_of('12345'))
|
85
|
+
assert_equal(9, assign_score_of('すごい'))
|
86
|
+
end
|
87
|
+
|
88
|
+
def test_assign_score_of_array
|
89
|
+
assert_equal(1, assign_score_of([]))
|
90
|
+
assert_equal(2, assign_score_of([123]))
|
91
|
+
assert_equal(6, assign_score_of([123, 'abcd']))
|
92
|
+
end
|
93
|
+
|
94
|
+
def test_assign_score_of_hash
|
95
|
+
assert_equal(1, assign_score_of({}))
|
96
|
+
assert_equal(5, assign_score_of('int' => 123))
|
97
|
+
assert_equal(12, assign_score_of('int' => 123, 'str' => 'abcd'))
|
98
|
+
end
|
99
|
+
|
100
|
+
private
|
101
|
+
|
102
|
+
class ObjectWrapperDrop < Liquid::Drop
|
103
|
+
def initialize(obj)
|
104
|
+
@obj = obj
|
105
|
+
end
|
106
|
+
|
107
|
+
def value
|
108
|
+
@obj
|
46
109
|
end
|
47
110
|
end
|
48
|
-
|
111
|
+
|
112
|
+
def assign_score_of(obj)
|
113
|
+
context = Liquid::Context.new('drop' => ObjectWrapperDrop.new(obj))
|
114
|
+
Liquid::Template.parse('{% assign obj = drop.value %}').render!(context)
|
115
|
+
context.resource_limits.assign_score
|
116
|
+
end
|
117
|
+
end
|
@@ -1,11 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'test_helper'
|
2
4
|
|
3
5
|
class FoobarTag < Liquid::Tag
|
4
|
-
def
|
5
|
-
|
6
|
+
def render_to_output_buffer(_context, output)
|
7
|
+
output << ' '
|
8
|
+
output
|
6
9
|
end
|
7
|
-
|
8
|
-
Liquid::Template.register_tag('foobar', FoobarTag)
|
9
10
|
end
|
10
11
|
|
11
12
|
class BlankTestFileSystem
|
@@ -31,7 +32,9 @@ class BlankTest < Minitest::Test
|
|
31
32
|
end
|
32
33
|
|
33
34
|
def test_new_tags_are_not_blank_by_default
|
34
|
-
|
35
|
+
with_custom_tag('foobar', FoobarTag) do
|
36
|
+
assert_template_result(" " * N, wrap_in_for("{% foobar %}"))
|
37
|
+
end
|
35
38
|
end
|
36
39
|
|
37
40
|
def test_loops_are_blank
|
@@ -93,9 +96,9 @@ class BlankTest < Minitest::Test
|
|
93
96
|
|
94
97
|
def test_include_is_blank
|
95
98
|
Liquid::Template.file_system = BlankTestFileSystem.new
|
96
|
-
assert_template_result
|
97
|
-
assert_template_result
|
98
|
-
assert_template_result
|
99
|
+
assert_template_result("foobar" * (N + 1), wrap("{% include 'foobar' %}"))
|
100
|
+
assert_template_result(" foobar " * (N + 1), wrap("{% include ' foobar ' %}"))
|
101
|
+
assert_template_result(" " * (N + 1), wrap(" {% include ' ' %} "))
|
99
102
|
end
|
100
103
|
|
101
104
|
def test_case_is_blank
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'test_helper'
|
2
4
|
|
3
5
|
class BlockTest < Minitest::Test
|
@@ -7,6 +9,50 @@ class BlockTest < Minitest::Test
|
|
7
9
|
exc = assert_raises(SyntaxError) do
|
8
10
|
Template.parse("{% if true %}{% endunless %}")
|
9
11
|
end
|
10
|
-
assert_equal
|
12
|
+
assert_equal(exc.message, "Liquid syntax error: 'endunless' is not a valid delimiter for if tags. use endif")
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_with_custom_tag
|
16
|
+
with_custom_tag('testtag', Block) do
|
17
|
+
assert(Liquid::Template.parse("{% testtag %} {% endtesttag %}"))
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_custom_block_tags_have_a_default_render_to_output_buffer_method_for_backwards_compatibility
|
22
|
+
klass1 = Class.new(Block) do
|
23
|
+
def render(*)
|
24
|
+
'hello'
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
with_custom_tag('blabla', klass1) do
|
29
|
+
template = Liquid::Template.parse("{% blabla %} bla {% endblabla %}")
|
30
|
+
|
31
|
+
assert_equal('hello', template.render)
|
32
|
+
|
33
|
+
buf = +''
|
34
|
+
output = template.render({}, output: buf)
|
35
|
+
assert_equal('hello', output)
|
36
|
+
assert_equal('hello', buf)
|
37
|
+
assert_equal(buf.object_id, output.object_id)
|
38
|
+
end
|
39
|
+
|
40
|
+
klass2 = Class.new(klass1) do
|
41
|
+
def render(*)
|
42
|
+
'foo' + super + 'bar'
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
with_custom_tag('blabla', klass2) do
|
47
|
+
template = Liquid::Template.parse("{% blabla %} foo {% endblabla %}")
|
48
|
+
|
49
|
+
assert_equal('foohellobar', template.render)
|
50
|
+
|
51
|
+
buf = +''
|
52
|
+
output = template.render({}, output: buf)
|
53
|
+
assert_equal('foohellobar', output)
|
54
|
+
assert_equal('foohellobar', buf)
|
55
|
+
assert_equal(buf.object_id, output.object_id)
|
56
|
+
end
|
11
57
|
end
|
12
58
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'test_helper'
|
2
4
|
|
3
5
|
class CaptureTest < Minitest::Test
|
@@ -12,9 +14,9 @@ class CaptureTest < Minitest::Test
|
|
12
14
|
{% capture this-thing %}Print this-thing{% endcapture %}
|
13
15
|
{{ this-thing }}
|
14
16
|
END_TEMPLATE
|
15
|
-
template
|
16
|
-
rendered
|
17
|
-
assert_equal
|
17
|
+
template = Template.parse(template_source)
|
18
|
+
rendered = template.render!
|
19
|
+
assert_equal("Print this-thing", rendered.strip)
|
18
20
|
end
|
19
21
|
|
20
22
|
def test_capture_to_variable_from_outer_scope_if_existing
|
@@ -28,9 +30,9 @@ class CaptureTest < Minitest::Test
|
|
28
30
|
{% endif %}
|
29
31
|
{{var}}
|
30
32
|
END_TEMPLATE
|
31
|
-
template
|
32
|
-
rendered
|
33
|
-
assert_equal
|
33
|
+
template = Template.parse(template_source)
|
34
|
+
rendered = template.render!
|
35
|
+
assert_equal("test-string", rendered.gsub(/\s/, ''))
|
34
36
|
end
|
35
37
|
|
36
38
|
def test_assigning_from_capture
|
@@ -43,8 +45,14 @@ class CaptureTest < Minitest::Test
|
|
43
45
|
{% endfor %}
|
44
46
|
{{ first }}-{{ second }}
|
45
47
|
END_TEMPLATE
|
46
|
-
template
|
47
|
-
rendered
|
48
|
-
assert_equal
|
48
|
+
template = Template.parse(template_source)
|
49
|
+
rendered = template.render!
|
50
|
+
assert_equal("3-3", rendered.gsub(/\s/, ''))
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_increment_assign_score_by_bytes_not_characters
|
54
|
+
t = Template.parse("{% capture foo %}すごい{% endcapture %}")
|
55
|
+
t.render!
|
56
|
+
assert_equal(9, t.resource_limits.assign_score)
|
49
57
|
end
|
50
|
-
end
|
58
|
+
end
|