mirror of
https://github.com/Shopify/liquid.git
synced 2026-10-01 08:05:15 -07:00
Compare commits
34
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4f35b0bc66 | ||
|
|
a5e5fab82a | ||
|
|
02ecaab9d1 | ||
|
|
1b2b62964e | ||
|
|
9b38a15282 | ||
|
|
7b25b770af | ||
|
|
cf76c0bbec | ||
|
|
6a0fe3f7e3 | ||
|
|
730ad3684a | ||
|
|
3ac7e470e6 | ||
|
|
369a6c55e3 | ||
|
|
f5ed5404b5 | ||
|
|
a3c837687e | ||
|
|
96a036372d | ||
|
|
fc9c338682 | ||
|
|
3c5ad7db61 | ||
|
|
c658bf970a | ||
|
|
c618ac1c9f | ||
|
|
0f0d5d889f | ||
|
|
11a1f8e673 | ||
|
|
24d461a9e3 | ||
|
|
cbb422e5d3 | ||
|
|
bf0f79f36c | ||
|
|
cf2787791e | ||
|
|
407a8e5b0f | ||
|
|
e3dcc75ab5 | ||
|
|
ceb7a4237f | ||
|
|
7b60b7fef5 | ||
|
|
33e1a8ffbc | ||
|
|
cc47fa8f03 | ||
|
|
b1b9b9f691 | ||
|
|
75e7725f57 | ||
|
|
de6d15a73e | ||
|
|
2c5d2be193 |
@@ -23,6 +23,6 @@ group :test do
|
||||
gem 'rubocop-performance', require: false
|
||||
|
||||
platform :mri, :truffleruby do
|
||||
gem 'liquid-c', github: 'Shopify/liquid-c', ref: 'master'
|
||||
gem 'liquid-c', github: 'Shopify/liquid-c', ref: 'main'
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[](http://travis-ci.org/Shopify/liquid)
|
||||
[](https://github.com/Shopify/liquid/actions/workflows/liquid.yml)
|
||||
[](http://inch-ci.org/github/Shopify/liquid)
|
||||
|
||||
# Liquid template engine
|
||||
|
||||
@@ -24,6 +24,9 @@ module Liquid
|
||||
else
|
||||
false
|
||||
end
|
||||
rescue Encoding::CompatibilityError
|
||||
# "✅".b.include?("✅") raises Encoding::CompatibilityError despite being materially equal
|
||||
left.b.include?(right.b)
|
||||
end,
|
||||
}
|
||||
|
||||
|
||||
@@ -197,10 +197,14 @@ module Liquid
|
||||
try_variable_find_in_environments(key, raise_on_not_found: raise_on_not_found)
|
||||
end
|
||||
|
||||
variable = variable.to_liquid
|
||||
# update variable's context before invoking #to_liquid
|
||||
variable.context = self if variable.respond_to?(:context=)
|
||||
|
||||
variable
|
||||
liquid_variable = variable.to_liquid
|
||||
|
||||
liquid_variable.context = self if variable != liquid_variable && liquid_variable.respond_to?(:context=)
|
||||
|
||||
liquid_variable
|
||||
end
|
||||
|
||||
def lookup_and_evaluate(obj, key, raise_on_not_found: true)
|
||||
|
||||
+16
-15
@@ -40,19 +40,20 @@ module Liquid
|
||||
end
|
||||
end
|
||||
|
||||
ArgumentError = Class.new(Error)
|
||||
ContextError = Class.new(Error)
|
||||
FileSystemError = Class.new(Error)
|
||||
StandardError = Class.new(Error)
|
||||
SyntaxError = Class.new(Error)
|
||||
StackLevelError = Class.new(Error)
|
||||
MemoryError = Class.new(Error)
|
||||
ZeroDivisionError = Class.new(Error)
|
||||
FloatDomainError = Class.new(Error)
|
||||
UndefinedVariable = Class.new(Error)
|
||||
UndefinedDropMethod = Class.new(Error)
|
||||
UndefinedFilter = Class.new(Error)
|
||||
MethodOverrideError = Class.new(Error)
|
||||
DisabledError = Class.new(Error)
|
||||
InternalError = Class.new(Error)
|
||||
ArgumentError = Class.new(Error)
|
||||
ContextError = Class.new(Error)
|
||||
FileSystemError = Class.new(Error)
|
||||
StandardError = Class.new(Error)
|
||||
SyntaxError = Class.new(Error)
|
||||
StackLevelError = Class.new(Error)
|
||||
MemoryError = Class.new(Error)
|
||||
ZeroDivisionError = Class.new(Error)
|
||||
FloatDomainError = Class.new(Error)
|
||||
UndefinedVariable = Class.new(Error)
|
||||
UndefinedDropMethod = Class.new(Error)
|
||||
UndefinedFilter = Class.new(Error)
|
||||
MethodOverrideError = Class.new(Error)
|
||||
DisabledError = Class.new(Error)
|
||||
InternalError = Class.new(Error)
|
||||
TemplateEncodingError = Class.new(Error)
|
||||
end
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
include: "Error in tag 'include' - Valid syntax: include '[template]' (with|for) [object|collection]"
|
||||
inline_comment_invalid: "Syntax error in tag '#' - Each line of comments must be prefixed by the '#' character"
|
||||
invalid_delimiter: "'%{tag}' is not a valid delimiter for %{block_name} tags. use %{block_delimiter}"
|
||||
invalid_template_encoding: "Invalid template encoding"
|
||||
render: "Syntax error in tag 'render' - Template name must be a quoted string"
|
||||
table_row: "Syntax Error in 'table_row loop' - Valid syntax: table_row [item] in [collection] cols=3"
|
||||
tag_never_closed: "'%{block_name}' tag was never closed"
|
||||
|
||||
@@ -29,6 +29,19 @@ module Liquid
|
||||
)
|
||||
STRIP_HTML_TAGS = /<.*?>/m
|
||||
|
||||
class << self
|
||||
def try_coerce_encoding(input, encoding:)
|
||||
original_encoding = input.encoding
|
||||
if input.encoding != encoding
|
||||
input.force_encoding(encoding)
|
||||
unless input.valid_encoding?
|
||||
input.force_encoding(original_encoding)
|
||||
end
|
||||
end
|
||||
input
|
||||
end
|
||||
end
|
||||
|
||||
# @liquid_public_docs
|
||||
# @liquid_type filter
|
||||
# @liquid_category array
|
||||
@@ -150,7 +163,8 @@ module Liquid
|
||||
# @liquid_syntax string | base64_decode
|
||||
# @liquid_return [string]
|
||||
def base64_decode(input)
|
||||
Base64.strict_decode64(input.to_s)
|
||||
input = input.to_s
|
||||
StandardFilters.try_coerce_encoding(Base64.strict_decode64(input), encoding: input.encoding)
|
||||
rescue ::ArgumentError
|
||||
raise Liquid::ArgumentError, "invalid base64 provided to base64_decode"
|
||||
end
|
||||
@@ -174,7 +188,8 @@ module Liquid
|
||||
# @liquid_syntax string | base64_url_safe_decode
|
||||
# @liquid_return [string]
|
||||
def base64_url_safe_decode(input)
|
||||
Base64.urlsafe_decode64(input.to_s)
|
||||
input = input.to_s
|
||||
StandardFilters.try_coerce_encoding(Base64.urlsafe_decode64(input), encoding: input.encoding)
|
||||
rescue ::ArgumentError
|
||||
raise Liquid::ArgumentError, "invalid base64 provided to base64_url_safe_decode"
|
||||
end
|
||||
@@ -892,9 +907,11 @@ module Liquid
|
||||
raise_property_error(property)
|
||||
end
|
||||
|
||||
InputIterator.new(values_for_sum, context).sum do |item|
|
||||
result = InputIterator.new(values_for_sum, context).sum do |item|
|
||||
Utils.to_number(item)
|
||||
end
|
||||
|
||||
result.is_a?(BigDecimal) ? result.to_f : result
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
+2
-1
@@ -54,7 +54,8 @@ module Liquid
|
||||
# of the `render_to_output_buffer` method will become the default and the `render`
|
||||
# method will be removed.
|
||||
def render_to_output_buffer(context, output)
|
||||
output << render(context)
|
||||
render_result = render(context)
|
||||
output << render_result if render_result
|
||||
output
|
||||
end
|
||||
|
||||
|
||||
@@ -15,8 +15,6 @@ module Liquid
|
||||
# {% endcomment %}
|
||||
# @liquid_syntax_keyword content The content of the comment.
|
||||
class Comment < Block
|
||||
TAG_DELIMITER = /\A(.*)#{TagStart}#{WhitespaceControl}?\s*(endcomment)\s*(.*)?#{WhitespaceControl}?#{TagEnd}\z/om
|
||||
|
||||
def render_to_output_buffer(_context, output)
|
||||
output
|
||||
end
|
||||
@@ -51,18 +49,9 @@ module Liquid
|
||||
next if tag_name_match.nil?
|
||||
|
||||
tag_name_match[1]
|
||||
elsif TAG_DELIMITER.match?(token)
|
||||
# aggressively match comment delimiter
|
||||
"endcomment"
|
||||
elsif token =~ BlockBody::FullToken && Regexp.last_match(2) == "comment"
|
||||
# aggressively match comment tag
|
||||
"comment"
|
||||
else
|
||||
tag_name_match = BlockBody::FullTokenPossiblyInvalid.match(token)
|
||||
|
||||
next if tag_name_match.nil?
|
||||
|
||||
tag_name_match[2]
|
||||
token =~ BlockBody::FullToken
|
||||
Regexp.last_match(2)
|
||||
end
|
||||
|
||||
case tag_name
|
||||
@@ -72,8 +61,11 @@ module Liquid
|
||||
comment_tag_depth += 1
|
||||
when "endcomment"
|
||||
comment_tag_depth -= 1
|
||||
end
|
||||
|
||||
return false if comment_tag_depth.zero?
|
||||
if comment_tag_depth.zero?
|
||||
parse_context.trim_whitespace = (token[-3] == WhitespaceControl) unless tokenizer.for_liquid_tag
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -107,6 +107,12 @@ module Liquid
|
||||
# Returns self for easy chaining
|
||||
def parse(source, options = {})
|
||||
parse_context = configure_options(options)
|
||||
source = source.to_s.to_str
|
||||
|
||||
unless source.valid_encoding?
|
||||
raise TemplateEncodingError, parse_context.locale.t("errors.syntax.invalid_template_encoding")
|
||||
end
|
||||
|
||||
tokenizer = parse_context.new_tokenizer(source, start_line_number: @line_numbers && 1)
|
||||
@root = Document.parse(tokenizer, parse_context)
|
||||
self
|
||||
|
||||
@@ -5,7 +5,7 @@ module Liquid
|
||||
attr_reader :line_number, :for_liquid_tag
|
||||
|
||||
def initialize(source, line_numbers = false, line_number: nil, for_liquid_tag: false)
|
||||
@source = source.to_s.to_str
|
||||
@source = source
|
||||
@line_number = line_number || (line_numbers ? 1 : nil)
|
||||
@for_liquid_tag = for_liquid_tag
|
||||
@offset = 0
|
||||
|
||||
@@ -36,6 +36,24 @@ class Category
|
||||
end
|
||||
end
|
||||
|
||||
class ProductsDrop < Liquid::Drop
|
||||
def initialize(products)
|
||||
@products = products
|
||||
end
|
||||
|
||||
def size
|
||||
@products.size
|
||||
end
|
||||
|
||||
def to_liquid
|
||||
if @context["forloop"]
|
||||
@products.first(@context["forloop"].length)
|
||||
else
|
||||
@products
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class CategoryDrop < Liquid::Drop
|
||||
attr_accessor :category, :context
|
||||
|
||||
@@ -635,6 +653,25 @@ class ContextTest < Minitest::Test
|
||||
assert_equal(:my_value, c.registers[:my_register])
|
||||
end
|
||||
|
||||
def test_variable_to_liquid_returns_contextual_drop
|
||||
context = {
|
||||
"products" => ProductsDrop.new(["A", "B", "C", "D", "E"]),
|
||||
}
|
||||
|
||||
template = Liquid::Template.parse(<<~LIQUID)
|
||||
{%- for i in (1..3) -%}
|
||||
for_loop_products_count: {{ products | size }}
|
||||
{% endfor %}
|
||||
|
||||
unscoped_products_count: {{ products | size }}
|
||||
LIQUID
|
||||
|
||||
result = template.render(context)
|
||||
|
||||
assert_includes(result, "for_loop_products_count: 3")
|
||||
assert_includes(result, "unscoped_products_count: 5")
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def assert_no_object_allocations
|
||||
|
||||
@@ -176,7 +176,17 @@ class StandardFiltersTest < Minitest::Test
|
||||
end
|
||||
|
||||
def test_base64_decode
|
||||
assert_equal('one two three', @filters.base64_decode('b25lIHR3byB0aHJlZQ=='))
|
||||
decoded = @filters.base64_decode('b25lIHR3byB0aHJlZQ==')
|
||||
assert_equal('one two three', decoded)
|
||||
assert_equal(Encoding::UTF_8, decoded.encoding)
|
||||
|
||||
decoded = @filters.base64_decode('4pyF')
|
||||
assert_equal('✅', decoded)
|
||||
assert_equal(Encoding::UTF_8, decoded.encoding)
|
||||
|
||||
decoded = @filters.base64_decode("/w==")
|
||||
assert_equal(Encoding::ASCII_8BIT, decoded.encoding)
|
||||
assert_equal((+"\xFF").force_encoding(Encoding::ASCII_8BIT), decoded)
|
||||
|
||||
exception = assert_raises(Liquid::ArgumentError) do
|
||||
@filters.base64_decode("invalidbase64")
|
||||
@@ -194,10 +204,21 @@ class StandardFiltersTest < Minitest::Test
|
||||
end
|
||||
|
||||
def test_base64_url_safe_decode
|
||||
decoded = @filters.base64_url_safe_decode('YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXogQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVogMTIzNDU2Nzg5MCAhQCMkJV4mKigpLT1fKy8_Ljo7W117fVx8')
|
||||
assert_equal(
|
||||
'abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ 1234567890 !@#$%^&*()-=_+/?.:;[]{}\|',
|
||||
@filters.base64_url_safe_decode('YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXogQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVogMTIzNDU2Nzg5MCAhQCMkJV4mKigpLT1fKy8_Ljo7W117fVx8'),
|
||||
decoded,
|
||||
)
|
||||
assert_equal(Encoding::UTF_8, decoded.encoding)
|
||||
|
||||
decoded = @filters.base64_url_safe_decode('4pyF')
|
||||
assert_equal('✅', decoded)
|
||||
assert_equal(Encoding::UTF_8, decoded.encoding)
|
||||
|
||||
decoded = @filters.base64_url_safe_decode("_w==")
|
||||
assert_equal(Encoding::ASCII_8BIT, decoded.encoding)
|
||||
assert_equal((+"\xFF").force_encoding(Encoding::ASCII_8BIT), decoded)
|
||||
|
||||
exception = assert_raises(Liquid::ArgumentError) do
|
||||
@filters.base64_url_safe_decode("invalidbase64")
|
||||
end
|
||||
@@ -994,6 +1015,42 @@ class StandardFiltersTest < Minitest::Test
|
||||
assert(t.foo > 0)
|
||||
end
|
||||
|
||||
def test_sum_of_floats
|
||||
input = [0.1, 0.2, 0.3]
|
||||
assert_equal(0.6, @filters.sum(input))
|
||||
assert_template_result("0.6", "{{ input | sum }}", { "input" => input })
|
||||
end
|
||||
|
||||
def test_sum_of_negative_floats
|
||||
input = [0.1, 0.2, -0.3]
|
||||
assert_equal(0.0, @filters.sum(input))
|
||||
assert_template_result("0.0", "{{ input | sum }}", { "input" => input })
|
||||
end
|
||||
|
||||
def test_sum_with_float_strings
|
||||
input = [0.1, "0.2", "0.3"]
|
||||
assert_equal(0.6, @filters.sum(input))
|
||||
assert_template_result("0.6", "{{ input | sum }}", { "input" => input })
|
||||
end
|
||||
|
||||
def test_sum_resulting_in_negative_float
|
||||
input = [0.1, -0.2, -0.3]
|
||||
assert_equal(-0.4, @filters.sum(input))
|
||||
assert_template_result("-0.4", "{{ input | sum }}", { "input" => input })
|
||||
end
|
||||
|
||||
def test_sum_with_floats_and_indexable_map_values
|
||||
input = [{ "quantity" => 1 }, { "quantity" => 0.2, "weight" => -0.3 }, { "weight" => 0.4 }]
|
||||
assert_equal(0.0, @filters.sum(input))
|
||||
assert_equal(1.2, @filters.sum(input, "quantity"))
|
||||
assert_equal(0.1, @filters.sum(input, "weight"))
|
||||
assert_equal(0.0, @filters.sum(input, "subtotal"))
|
||||
assert_template_result("0", "{{ input | sum }}", { "input" => input })
|
||||
assert_template_result("1.2", "{{ input | sum: 'quantity' }}", { "input" => input })
|
||||
assert_template_result("0.1", "{{ input | sum: 'weight' }}", { "input" => input })
|
||||
assert_template_result("0", "{{ input | sum: 'subtotal' }}", { "input" => input })
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def with_timezone(tz)
|
||||
|
||||
@@ -337,4 +337,22 @@ class TemplateTest < Minitest::Test
|
||||
assert_equal("x=2", output)
|
||||
assert_instance_of(String, output)
|
||||
end
|
||||
|
||||
def test_raises_error_with_invalid_utf8
|
||||
e = assert_raises(TemplateEncodingError) do
|
||||
Template.parse(<<~LIQUID)
|
||||
{% comment %}
|
||||
\xC0
|
||||
{% endcomment %}
|
||||
LIQUID
|
||||
end
|
||||
|
||||
assert_equal('Liquid error: Invalid template encoding', e.message)
|
||||
end
|
||||
|
||||
def test_allows_non_string_values_as_source
|
||||
assert_equal('', Template.parse(nil).render)
|
||||
assert_equal('1', Template.parse(1).render)
|
||||
assert_equal('true', Template.parse(true).render)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -55,6 +55,11 @@ class ConditionUnitTest < Minitest::Test
|
||||
assert_evaluates_false('bob', 'contains', '---')
|
||||
end
|
||||
|
||||
def test_contains_binary_encoding_compatibility_with_utf8
|
||||
assert_evaluates_true('🙈'.b, 'contains', '🙈')
|
||||
assert_evaluates_true('🙈', 'contains', '🙈'.b)
|
||||
end
|
||||
|
||||
def test_invalid_comparation_operator
|
||||
assert_evaluates_argument_error(1, '~~', 0)
|
||||
end
|
||||
@@ -166,14 +171,14 @@ class ConditionUnitTest < Minitest::Test
|
||||
def assert_evaluates_true(left, op, right)
|
||||
assert(
|
||||
Condition.new(left, op, right).evaluate(@context),
|
||||
"Evaluated false: #{left} #{op} #{right}",
|
||||
"Evaluated false: #{left.inspect} #{op} #{right.inspect}",
|
||||
)
|
||||
end
|
||||
|
||||
def assert_evaluates_false(left, op, right)
|
||||
assert(
|
||||
!Condition.new(left, op, right).evaluate(@context),
|
||||
"Evaluated true: #{left} #{op} #{right}",
|
||||
"Evaluated true: #{left.inspect} #{op} #{right.inspect}",
|
||||
)
|
||||
end
|
||||
|
||||
|
||||
@@ -20,4 +20,13 @@ class TagUnitTest < Minitest::Test
|
||||
tag = Tag.parse("some_tag", "", Tokenizer.new(""), ParseContext.new)
|
||||
assert_equal('some_tag', tag.tag_name)
|
||||
end
|
||||
|
||||
class CustomTag < Liquid::Tag
|
||||
def render(_context); end
|
||||
end
|
||||
|
||||
def test_tag_render_to_output_buffer_nil_value
|
||||
custom_tag = CustomTag.parse("some_tag", "", Tokenizer.new(""), ParseContext.new)
|
||||
assert_equal('some string', custom_tag.render_to_output_buffer(Context.new, "some string"))
|
||||
end
|
||||
end
|
||||
|
||||
@@ -31,25 +31,45 @@ class CommentTagUnitTest < Minitest::Test
|
||||
LIQUID
|
||||
end
|
||||
|
||||
def test_allows_incomplete_tags_inside_a_comment
|
||||
assert_template_result("", <<~LIQUID.chomp)
|
||||
def test_allows_unclosed_tags
|
||||
assert_template_result('', <<~LIQUID.chomp)
|
||||
{% comment %}
|
||||
{% assign foo = "1"
|
||||
{% if true %}
|
||||
{% endcomment %}
|
||||
LIQUID
|
||||
end
|
||||
|
||||
def test_open_tags_in_comment
|
||||
assert_template_result('', <<~LIQUID.chomp)
|
||||
{% comment %}
|
||||
{% assign a = 123 {% comment %}
|
||||
{% endcomment %}
|
||||
LIQUID
|
||||
|
||||
assert_template_result("", <<~LIQUID.chomp)
|
||||
{% comment %}
|
||||
assert_raises(Liquid::SyntaxError) do
|
||||
assert_template_result("", <<~LIQUID.chomp)
|
||||
{% comment %}
|
||||
{% invalid
|
||||
{% assign foo = "1"
|
||||
{% endcomment %}
|
||||
{% endcomment %}
|
||||
LIQUID
|
||||
LIQUID
|
||||
end
|
||||
|
||||
assert_template_result("", <<~LIQUID.chomp)
|
||||
{% comment %}
|
||||
{% {{ {%- endcomment %}
|
||||
LIQUID
|
||||
assert_raises(Liquid::SyntaxError) do
|
||||
assert_template_result("", <<~LIQUID.chomp)
|
||||
{% comment %}
|
||||
{% comment %}
|
||||
{% invalid
|
||||
{% endcomment %}
|
||||
{% endcomment %}
|
||||
LIQUID
|
||||
end
|
||||
|
||||
assert_raises(Liquid::SyntaxError) do
|
||||
assert_template_result("", <<~LIQUID.chomp)
|
||||
{% comment %}
|
||||
{% {{ {%- endcomment %}
|
||||
LIQUID
|
||||
end
|
||||
end
|
||||
|
||||
def test_child_comment_tags_need_to_be_closed
|
||||
@@ -135,4 +155,48 @@ class CommentTagUnitTest < Minitest::Test
|
||||
LIQUID
|
||||
)
|
||||
end
|
||||
|
||||
def test_ignores_delimiter_with_extra_strings
|
||||
assert_template_result(
|
||||
'',
|
||||
<<~LIQUID.chomp,
|
||||
{% if true %}
|
||||
{% comment %}
|
||||
{% commentXXXXX %}wut{% endcommentXXXXX %}
|
||||
{% endcomment %}
|
||||
{% endif %}
|
||||
LIQUID
|
||||
)
|
||||
end
|
||||
|
||||
def test_delimiter_can_have_extra_strings
|
||||
assert_template_result('', "{% comment %}123{% endcomment xyz %}")
|
||||
assert_template_result('', "{% comment %}123{% endcomment\txyz %}")
|
||||
assert_template_result('', "{% comment %}123{% endcomment\nxyz %}")
|
||||
assert_template_result('', "{% comment %}123{% endcomment\n xyz endcomment %}")
|
||||
assert_template_result('', "{%comment}{% assign a = 1 %}{%endcomment}{% endif %}")
|
||||
end
|
||||
|
||||
def test_with_whitespace_control
|
||||
assert_template_result("Hello!", " {%- comment -%}123{%- endcomment -%}Hello!")
|
||||
assert_template_result("Hello!", "{%- comment -%}123{%- endcomment -%} Hello!")
|
||||
assert_template_result("Hello!", " {%- comment -%}123{%- endcomment -%} Hello!")
|
||||
|
||||
assert_template_result("Hello!", <<~LIQUID.chomp)
|
||||
{%- comment %}Whitespace control!{% endcomment -%}
|
||||
Hello!
|
||||
LIQUID
|
||||
end
|
||||
|
||||
def test_dont_override_liquid_tag_whitespace_control
|
||||
assert_template_result("Hello!World!", <<~LIQUID.chomp)
|
||||
Hello!
|
||||
{%- liquid
|
||||
comment
|
||||
this is inside a liquid tag
|
||||
endcomment
|
||||
-%}
|
||||
World!
|
||||
LIQUID
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user