mirror of
https://github.com/Shopify/liquid.git
synced 2026-09-13 07:50:43 -07:00
Compare commits
25
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8b1b9f649a | ||
|
|
474315c6bb | ||
|
|
667664bb22 | ||
|
|
1cdd1f0834 | ||
|
|
1cd5ec54f0 | ||
|
|
29732f4305 | ||
|
|
abed47547c | ||
|
|
ace3fe15ac | ||
|
|
db8e85ab31 | ||
|
|
f484b868d0 | ||
|
|
3e8994c258 | ||
|
|
7ccac29688 | ||
|
|
96b5325f87 | ||
|
|
b8f05267a9 | ||
|
|
6ce4ec1011 | ||
|
|
a39422feac | ||
|
|
2c2f5826d5 | ||
|
|
c99c93255d | ||
|
|
c0c191cabd | ||
|
|
6765d93938 | ||
|
|
4f17abfb4a | ||
|
|
eff2a63204 | ||
|
|
fbab19ac8c | ||
|
|
b14bf94c98 | ||
|
|
951be6c1f5 |
@@ -109,14 +109,22 @@ module Liquid
|
||||
end
|
||||
end
|
||||
|
||||
private def parse_for_document(tokenizer, parse_context)
|
||||
private def handle_invalid_tag_token(token, parse_context)
|
||||
if token.end_with?('%}')
|
||||
yield token, token
|
||||
else
|
||||
BlockBody.raise_missing_tag_terminator(token, parse_context)
|
||||
end
|
||||
end
|
||||
|
||||
private def parse_for_document(tokenizer, parse_context, &block)
|
||||
while (token = tokenizer.shift)
|
||||
next if token.empty?
|
||||
case
|
||||
when token.start_with?(TAGSTART)
|
||||
whitespace_handler(token, parse_context)
|
||||
unless token =~ FullToken
|
||||
BlockBody.raise_missing_tag_terminator(token, parse_context)
|
||||
return handle_invalid_tag_token(token, parse_context, &block)
|
||||
end
|
||||
tag_name = Regexp.last_match(2)
|
||||
markup = Regexp.last_match(4)
|
||||
|
||||
@@ -5,7 +5,7 @@ module Liquid
|
||||
# @liquid_type object
|
||||
# @liquid_name forloop
|
||||
# @liquid_summary
|
||||
# Information about a parent [`for` loop](/api/liquid/tags#for).
|
||||
# Information about a parent [`for` loop](/api/liquid/tags/for).
|
||||
class ForloopDrop < Drop
|
||||
def initialize(name, length, parentloop)
|
||||
@name = name
|
||||
@@ -30,10 +30,7 @@ module Liquid
|
||||
# @liquid_return [forloop]
|
||||
attr_reader :parentloop
|
||||
|
||||
def name
|
||||
Usage.increment('forloop_drop_name')
|
||||
@name
|
||||
end
|
||||
attr_reader :name
|
||||
|
||||
# @liquid_public_docs
|
||||
# @liquid_summary
|
||||
|
||||
@@ -6,7 +6,14 @@ require 'bigdecimal'
|
||||
|
||||
module Liquid
|
||||
module StandardFilters
|
||||
MAX_INT = (1 << 31) - 1
|
||||
MAX_I32 = (1 << 31) - 1
|
||||
private_constant :MAX_I32
|
||||
|
||||
MIN_I64 = -(1 << 63)
|
||||
MAX_I64 = (1 << 63) - 1
|
||||
I64_RANGE = MIN_I64..MAX_I64
|
||||
private_constant :MIN_I64, :MAX_I64, :I64_RANGE
|
||||
|
||||
HTML_ESCAPE = {
|
||||
'&' => '&',
|
||||
'>' => '>',
|
||||
@@ -186,10 +193,19 @@ module Liquid
|
||||
offset = Utils.to_integer(offset)
|
||||
length = length ? Utils.to_integer(length) : 1
|
||||
|
||||
if input.is_a?(Array)
|
||||
input.slice(offset, length) || []
|
||||
else
|
||||
input.to_s.slice(offset, length) || ''
|
||||
begin
|
||||
if input.is_a?(Array)
|
||||
input.slice(offset, length) || []
|
||||
else
|
||||
input.to_s.slice(offset, length) || ''
|
||||
end
|
||||
rescue RangeError
|
||||
if I64_RANGE.cover?(length) && I64_RANGE.cover?(offset)
|
||||
raise # unexpected error
|
||||
end
|
||||
offset = offset.clamp(I64_RANGE)
|
||||
length = length.clamp(I64_RANGE)
|
||||
retry
|
||||
end
|
||||
end
|
||||
|
||||
@@ -239,9 +255,9 @@ module Liquid
|
||||
wordlist = begin
|
||||
input.split(" ", words + 1)
|
||||
rescue RangeError
|
||||
raise if words + 1 < MAX_INT
|
||||
# e.g. integer #{words} too big to convert to `int'
|
||||
raise Liquid::ArgumentError, "integer #{words} too big for truncatewords"
|
||||
# integer too big for String#split, but we can semantically assume no truncation is needed
|
||||
return input if words + 1 > MAX_I32
|
||||
raise # unexpected error
|
||||
end
|
||||
return input if wordlist.length <= words
|
||||
|
||||
@@ -599,7 +615,7 @@ module Liquid
|
||||
# @liquid_description
|
||||
# > Note:
|
||||
# > The `concat` filter won't filter out duplicates. If you want to remove duplicates, then you need to use the
|
||||
# > [`uniq` filter](/api/liquid/filters#uniq).
|
||||
# > [`uniq` filter](/api/liquid/filters/uniq).
|
||||
# @liquid_syntax array | concat: array
|
||||
# @liquid_return [array[untyped]]
|
||||
def concat(input, array)
|
||||
|
||||
@@ -5,7 +5,7 @@ module Liquid
|
||||
# @liquid_type object
|
||||
# @liquid_name tablerowloop
|
||||
# @liquid_summary
|
||||
# Information about a parent [`tablerow` loop](/api/liquid/tags#tablerow).
|
||||
# Information about a parent [`tablerow` loop](/api/liquid/tags/tablerow).
|
||||
class TablerowloopDrop < Drop
|
||||
def initialize(length, cols)
|
||||
@length = length
|
||||
|
||||
+8
-2
@@ -14,12 +14,18 @@ module Liquid
|
||||
end
|
||||
|
||||
def disable_tags(*tag_names)
|
||||
@disabled_tags ||= []
|
||||
@disabled_tags.concat(tag_names)
|
||||
tag_names += disabled_tags
|
||||
define_singleton_method(:disabled_tags) { tag_names }
|
||||
prepend(Disabler)
|
||||
end
|
||||
|
||||
private :new
|
||||
|
||||
protected
|
||||
|
||||
def disabled_tags
|
||||
[]
|
||||
end
|
||||
end
|
||||
|
||||
def initialize(tag_name, markup, parse_context)
|
||||
|
||||
@@ -3,14 +3,6 @@
|
||||
module Liquid
|
||||
class Tag
|
||||
module Disabler
|
||||
module ClassMethods
|
||||
attr_reader :disabled_tags
|
||||
end
|
||||
|
||||
def self.prepended(base)
|
||||
base.extend(ClassMethods)
|
||||
end
|
||||
|
||||
def render_to_output_buffer(context, output)
|
||||
context.with_disabled_tags(self.class.disabled_tags) do
|
||||
super
|
||||
|
||||
@@ -15,7 +15,7 @@ module Liquid
|
||||
# @liquid_category iteration
|
||||
# @liquid_name break
|
||||
# @liquid_summary
|
||||
# Stops a [`for` loop](/api/liquid/tags#for) from iterating.
|
||||
# Stops a [`for` loop](/api/liquid/tags/for) from iterating.
|
||||
# @liquid_syntax
|
||||
# {% break %}
|
||||
class Break < Tag
|
||||
|
||||
@@ -8,7 +8,7 @@ module Liquid
|
||||
# @liquid_summary
|
||||
# Prevents an expression from being rendered or output.
|
||||
# @liquid_description
|
||||
# Any text inside `comment` tags won't be output, and any Liquid code won't be rendered.
|
||||
# Any text inside `comment` tags won't be output, and any Liquid code will be parsed, but not executed.
|
||||
# @liquid_syntax
|
||||
# {% comment %}
|
||||
# content
|
||||
|
||||
@@ -6,7 +6,7 @@ module Liquid
|
||||
# @liquid_category iteration
|
||||
# @liquid_name continue
|
||||
# @liquid_summary
|
||||
# TESTING TESTING Causes a [`for` loop](/api/liquid/tags#for) to skip to the next iteration.
|
||||
# Causes a [`for` loop](/api/liquid/tags/for) to skip to the next iteration.
|
||||
# @liquid_syntax
|
||||
# {% continue %}
|
||||
class Continue < Tag
|
||||
|
||||
@@ -6,7 +6,7 @@ module Liquid
|
||||
# @liquid_category iteration
|
||||
# @liquid_name cycle
|
||||
# @liquid_summary
|
||||
# Loops through a group of strings and outputs them one at a time for each iteration of a [`for` loop](/api/liquid/tags#for).
|
||||
# Loops through a group of strings and outputs them one at a time for each iteration of a [`for` loop](/api/liquid/tags/for).
|
||||
# @liquid_description
|
||||
# The `cycle` tag must be used inside a `for` loop.
|
||||
#
|
||||
|
||||
@@ -12,8 +12,8 @@ module Liquid
|
||||
# or [section](/themes/architecture/sections) file that they're created in. However, the variable is shared across
|
||||
# [snippets](/themes/architecture#snippets) included in the file.
|
||||
#
|
||||
# Similarly, variables that are created with `decrement` are independent from those created with [`assign`](/api/liquid/tags#assign)
|
||||
# and [`capture`](/api/liquid/tags#capture). However, `decrement` and [`increment`](/api/liquid/tags#increment) share
|
||||
# Similarly, variables that are created with `decrement` are independent from those created with [`assign`](/api/liquid/tags/assign)
|
||||
# and [`capture`](/api/liquid/tags/capture). However, `decrement` and [`increment`](/api/liquid/tags/increment) share
|
||||
# variables.
|
||||
# @liquid_syntax
|
||||
# {% decrement variable_name %}
|
||||
|
||||
@@ -9,7 +9,7 @@ module Liquid
|
||||
# Outputs an expression.
|
||||
# @liquid_description
|
||||
# Using the `echo` tag is the same as wrapping an expression in curly brackets (`{{` and `}}`). However, unlike the curly
|
||||
# bracket method, you can use the `echo` tag inside [`liquid` tags](/api/liquid/tags#liquid).
|
||||
# bracket method, you can use the `echo` tag inside [`liquid` tags](/api/liquid/tags/liquid).
|
||||
#
|
||||
# > Tip:
|
||||
# > You can use [filters](/api/liquid/filters) on expressions inside `echo` tags.
|
||||
|
||||
@@ -9,10 +9,10 @@ module Liquid
|
||||
# Renders an expression for every item in an array.
|
||||
# @liquid_description
|
||||
# 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
|
||||
# [`paginate` tag](/api/liquid/tags#paginate) to split the items over multiple pages.
|
||||
# [`paginate` tag](/api/liquid/tags/paginate) to split the items over multiple pages.
|
||||
#
|
||||
# > Tip:
|
||||
# > Every `for` loop has an associated [`forloop` object](/api/liquid/objects#forloop) with information about the loop.
|
||||
# > Every `for` loop has an associated [`forloop` object](/api/liquid/objects/forloop) with information about the loop.
|
||||
# @liquid_syntax
|
||||
# {% for variable in array %}
|
||||
# expression
|
||||
@@ -177,7 +177,6 @@ module Liquid
|
||||
case key
|
||||
when 'offset'
|
||||
@from = if expr == 'continue'
|
||||
Usage.increment('for_offset_continue')
|
||||
:continue
|
||||
else
|
||||
parse_expression(expr)
|
||||
|
||||
@@ -8,7 +8,7 @@ module Liquid
|
||||
# @liquid_summary
|
||||
# Renders a [snippet](/themes/architecture#snippets).
|
||||
# @liquid_description
|
||||
# Inside the snippet, you can access and alter variables that are [created](/api/liquid/tags#variable-tags) outside of the
|
||||
# Inside the snippet, you can access and alter variables that are [created](/api/liquid/tags/variable-tags) outside of the
|
||||
# snippet.
|
||||
# @liquid_syntax
|
||||
# {% include 'filename' %}
|
||||
@@ -16,7 +16,7 @@ module Liquid
|
||||
# @liquid_deprecated
|
||||
# Deprecated because the way that variables are handled reduces performance and makes code harder to both read and maintain.
|
||||
#
|
||||
# The `include` tag has been replaced by [`render`](/api/liquid/tags#render).
|
||||
# The `include` tag has been replaced by [`render`](/api/liquid/tags/render).
|
||||
class Include < Tag
|
||||
prepend Tag::Disableable
|
||||
|
||||
@@ -52,7 +52,7 @@ module Liquid
|
||||
|
||||
def render_to_output_buffer(context, output)
|
||||
template_name = context.evaluate(@template_name_expr)
|
||||
raise ArgumentError, options[:locale].t("errors.argument.include") unless template_name
|
||||
raise ArgumentError, options[:locale].t("errors.argument.include") unless template_name.is_a?(String)
|
||||
|
||||
partial = PartialCache.load(
|
||||
template_name,
|
||||
|
||||
@@ -12,8 +12,8 @@ module Liquid
|
||||
# or [section](/themes/architecture/sections) file that they're created in. However, the variable is shared across
|
||||
# [snippets](/themes/architecture#snippets) included in the file.
|
||||
#
|
||||
# Similarly, variables that are created with `increment` are independent from those created with [`assign`](/api/liquid/tags#assign)
|
||||
# and [`capture`](/api/liquid/tags#capture). However, `increment` and [`decrement`](/api/liquid/tags#decrement) share
|
||||
# Similarly, variables that are created with `increment` are independent from those created with [`assign`](/api/liquid/tags/assign)
|
||||
# and [`capture`](/api/liquid/tags/capture). However, `increment` and [`decrement`](/api/liquid/tags/decrement) share
|
||||
# variables.
|
||||
# @liquid_syntax
|
||||
# {% increment variable_name %}
|
||||
|
||||
@@ -1,19 +1,6 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Liquid
|
||||
# @liquid_public_docs
|
||||
# @liquid_type tag
|
||||
# @liquid_category syntax
|
||||
# @liquid_name inline_comment
|
||||
# @liquid_summary
|
||||
# Prevents an expression from being rendered or output.
|
||||
# @liquid_description
|
||||
# Any text inside an `inline_comment` tag won't be rendered or output.
|
||||
#
|
||||
# You can create multi-line inline comments. However, each line must begin with a `#`.
|
||||
# @liquid_syntax
|
||||
# {% # content %}
|
||||
# @liquid_syntax_keyword content The content of the comment.
|
||||
class InlineComment < Tag
|
||||
def initialize(tag_name, markup, options)
|
||||
super
|
||||
|
||||
@@ -8,19 +8,19 @@ module Liquid
|
||||
# @liquid_summary
|
||||
# Renders a [snippet](/themes/architecture#snippets) or [app block](/themes/architecture/sections/section-schema#render-app-blocks).
|
||||
# @liquid_description
|
||||
# Inside snippets and app blocks, you can't directly access variables that are [created](/api/liquid/tags#variable-tags) outside
|
||||
# of the snippet or app block. However, you can [specify variables as parameters](/api/liquid/tags#render-passing-variables-to-snippets)
|
||||
# Inside snippets and app blocks, you can't directly access variables that are [created](/api/liquid/tags/variable-tags) outside
|
||||
# of the snippet or app block. However, you can [specify variables as parameters](/api/liquid/tags/render#render-passing-variables-to-a-snippet)
|
||||
# to pass outside variables to snippets.
|
||||
#
|
||||
# While you can't directly access created variables, you can access global objects, as well as any objects that are
|
||||
# directly accessible outside the snippet or app block. For example, a snippet or app block inside the [product template](/themes/architecture/templates/product)
|
||||
# can access the [`product` object](/api/liquid/objects#product), and a snippet or app block inside a [section](/themes/architecture/sections)
|
||||
# can access the [`section` object](/api/liquid/objects#section).
|
||||
# can access the [`product` object](/api/liquid/objects/product), and a snippet or app block inside a [section](/themes/architecture/sections)
|
||||
# can access the [`section` object](/api/liquid/objects/section).
|
||||
#
|
||||
# Outside a snippet or app block, you can't access variables created inside the snippet or app block.
|
||||
#
|
||||
# > Note:
|
||||
# > When you render a snippet using the `render` tag, you can't use the [`include` tag](/api/liquid/tags#include)
|
||||
# > When you render a snippet using the `render` tag, you can't use the [`include` tag](/api/liquid/tags/include)
|
||||
# > inside the snippet.
|
||||
# @liquid_syntax
|
||||
# {% render 'filename' %}
|
||||
|
||||
@@ -11,7 +11,7 @@ module Liquid
|
||||
# The `tablerow` tag must be wrapped in HTML `<table>` and `</table>` tags.
|
||||
#
|
||||
# > Tip:
|
||||
# > Every `tablerow` loop has an associated [`tablerowloop` object](/api/liquid/objects#tablerowloop) with information about the loop.
|
||||
# > Every `tablerow` loop has an associated [`tablerowloop` object](/api/liquid/objects/tablerowloop) with information about the loop.
|
||||
# @liquid_syntax
|
||||
# {% tablerow variable in array %}
|
||||
# expression
|
||||
@@ -51,7 +51,7 @@ module Liquid
|
||||
collection = Utils.slice_collection(collection, from, to)
|
||||
length = collection.length
|
||||
|
||||
cols = context.evaluate(@attributes['cols']).to_i
|
||||
cols = @attributes.key?('cols') ? context.evaluate(@attributes['cols']).to_i : length
|
||||
|
||||
output << "<tr class=\"row1\">\n"
|
||||
context.stack do
|
||||
|
||||
@@ -11,7 +11,7 @@ module Liquid
|
||||
# Renders an expression unless a specific condition is `true`.
|
||||
# @liquid_description
|
||||
# > Tip:
|
||||
# > Similar to the [`if` tag](/api/liquid/tags#if), you can use `elsif` to add more conditions to an `unless` tag.
|
||||
# > Similar to the [`if` tag](/api/liquid/tags/if), you can use `elsif` to add more conditions to an `unless` tag.
|
||||
# @liquid_syntax
|
||||
# {% unless condition %}
|
||||
# expression
|
||||
|
||||
@@ -8,11 +8,15 @@ module Liquid
|
||||
@source = source.to_s.to_str
|
||||
@line_number = line_number || (line_numbers ? 1 : nil)
|
||||
@for_liquid_tag = for_liquid_tag
|
||||
@offset = 0
|
||||
@tokens = tokenize
|
||||
end
|
||||
|
||||
def shift
|
||||
(token = @tokens.shift) || return
|
||||
token = @tokens[@offset]
|
||||
return nil unless token
|
||||
|
||||
@offset += 1
|
||||
|
||||
if @line_number
|
||||
@line_number += @for_liquid_tag ? 1 : token.count("\n")
|
||||
@@ -31,7 +35,9 @@ module Liquid
|
||||
tokens = @source.split(TemplateParser)
|
||||
|
||||
# removes the rogue empty element at the beginning of the array
|
||||
tokens.shift if tokens[0]&.empty?
|
||||
if tokens[0]&.empty?
|
||||
@offset += 1
|
||||
end
|
||||
|
||||
tokens
|
||||
end
|
||||
|
||||
@@ -109,6 +109,10 @@ class StandardFiltersTest < Minitest::Test
|
||||
assert_raises(Liquid::ArgumentError) do
|
||||
@filters.slice('foobar', 0, "")
|
||||
end
|
||||
assert_equal("", @filters.slice("foobar", 0, -(1 << 64)))
|
||||
assert_equal("foobar", @filters.slice("foobar", 0, 1 << 63))
|
||||
assert_equal("", @filters.slice("foobar", 1 << 63, 6))
|
||||
assert_equal("", @filters.slice("foobar", -(1 << 63), 6))
|
||||
end
|
||||
|
||||
def test_slice_on_arrays
|
||||
@@ -123,6 +127,10 @@ class StandardFiltersTest < Minitest::Test
|
||||
assert_equal(%w(r), @filters.slice(input, -1))
|
||||
assert_equal(%w(), @filters.slice(input, 100, 10))
|
||||
assert_equal(%w(), @filters.slice(input, -100, 10))
|
||||
assert_equal([], @filters.slice(input, 0, -(1 << 64)))
|
||||
assert_equal(input, @filters.slice(input, 0, 1 << 63))
|
||||
assert_equal([], @filters.slice(input, 1 << 63, 6))
|
||||
assert_equal([], @filters.slice(input, -(1 << 63), 6))
|
||||
end
|
||||
|
||||
def test_truncate
|
||||
@@ -132,6 +140,8 @@ class StandardFiltersTest < Minitest::Test
|
||||
assert_equal('1234567890', @filters.truncate('1234567890'))
|
||||
assert_equal("测试...", @filters.truncate("测试测试测试测试", 5))
|
||||
assert_equal('12341', @filters.truncate("1234567890", 5, 1))
|
||||
assert_equal("foobar", @filters.truncate("foobar", 1 << 63))
|
||||
assert_equal("...", @filters.truncate("foobar", -(1 << 63)))
|
||||
end
|
||||
|
||||
def test_split
|
||||
@@ -227,10 +237,8 @@ class StandardFiltersTest < Minitest::Test
|
||||
assert_equal('one two three...', @filters.truncatewords("one two\tthree\nfour", 3))
|
||||
assert_equal('one two...', @filters.truncatewords("one two three four", 2))
|
||||
assert_equal('one...', @filters.truncatewords("one two three four", 0))
|
||||
exception = assert_raises(Liquid::ArgumentError) do
|
||||
@filters.truncatewords("one two three four", 1 << 31)
|
||||
end
|
||||
assert_equal("Liquid error: integer #{1 << 31} too big for truncatewords", exception.message)
|
||||
assert_equal('one two three four', @filters.truncatewords("one two three four", 1 << 31))
|
||||
assert_equal('one...', @filters.truncatewords("one two three four", -(1 << 32)))
|
||||
end
|
||||
|
||||
def test_strip_html
|
||||
|
||||
@@ -450,30 +450,4 @@ HERE
|
||||
|
||||
assert(context.registers[:for_stack].empty?)
|
||||
end
|
||||
|
||||
def test_instrument_for_offset_continue
|
||||
assert_usage_increment('for_offset_continue') do
|
||||
Template.parse('{% for item in items offset:continue %}{{item}}{% endfor %}')
|
||||
end
|
||||
|
||||
assert_usage_increment('for_offset_continue', times: 0) do
|
||||
Template.parse('{% for item in items offset:2 %}{{item}}{% endfor %}')
|
||||
end
|
||||
end
|
||||
|
||||
def test_instrument_forloop_drop_name
|
||||
assigns = { 'items' => [1, 2, 3, 4, 5] }
|
||||
|
||||
assert_usage_increment('forloop_drop_name', times: 5) do
|
||||
Template.parse('{% for item in items %}{{forloop.name}}{% endfor %}').render!(assigns)
|
||||
end
|
||||
|
||||
assert_usage_increment('forloop_drop_name', times: 0) do
|
||||
Template.parse('{% for item in items %}{{forloop.index}}{% endfor %}').render!(assigns)
|
||||
end
|
||||
|
||||
assert_usage_increment('forloop_drop_name', times: 0) do
|
||||
Template.parse('{% for item in items %}{{item}}{% endfor %}').render!(assigns)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -249,6 +249,11 @@ class IncludeTagTest < Minitest::Test
|
||||
"{% include nil %}", render_errors: true)
|
||||
end
|
||||
|
||||
def test_render_raise_argument_error_when_template_is_not_a_string
|
||||
assert_template_result("Liquid error (line 1): Argument error in tag 'include' - Illegal template name",
|
||||
"{% include 123 %}", render_errors: true)
|
||||
end
|
||||
|
||||
def test_including_via_variable_value
|
||||
assert_template_result("from TestFileSystem", "{% assign page = 'pick_a_source' %}{% include page %}",
|
||||
partials: { "pick_a_source" => "from TestFileSystem" })
|
||||
|
||||
@@ -6,20 +6,21 @@ class IncrementTagTest < Minitest::Test
|
||||
include Liquid
|
||||
|
||||
def test_inc
|
||||
assert_template_result('0', '{%increment port %}', {})
|
||||
assert_template_result('0 1', '{%increment port %} {%increment port%}', {})
|
||||
assert_template_result('0 1', '{%increment port %} {{ port }}')
|
||||
assert_template_result(' 0 1 2', '{{port}} {%increment port %} {%increment port%} {{port}}')
|
||||
assert_template_result('0 0 1 2 1',
|
||||
'{%increment port %} {%increment starboard%} ' \
|
||||
'{%increment port %} {%increment port%} ' \
|
||||
'{%increment starboard %}', {})
|
||||
'{%increment starboard %}')
|
||||
end
|
||||
|
||||
def test_dec
|
||||
assert_template_result('9', '{%decrement port %}', { 'port' => 10 })
|
||||
assert_template_result('-1 -2', '{%decrement port %} {%decrement port%}', {})
|
||||
assert_template_result('1 5 2 2 5',
|
||||
assert_template_result('-1 -1', '{%decrement port %} {{ port }}', { 'port' => 10 })
|
||||
assert_template_result(' -1 -2 -2', '{{port}} {%decrement port %} {%decrement port%} {{port}}')
|
||||
assert_template_result('0 1 2 0 3 1 1 3',
|
||||
'{%increment starboard %} {%increment starboard%} {%increment starboard%} ' \
|
||||
'{%increment port %} {%increment starboard%} ' \
|
||||
'{%increment port %} {%decrement port%} ' \
|
||||
'{%decrement starboard %}', { 'port' => 1, 'starboard' => 5 })
|
||||
'{%decrement starboard %}')
|
||||
end
|
||||
end
|
||||
|
||||
@@ -36,6 +36,8 @@ class StandardTagTest < Minitest::Test
|
||||
assert_template_result('', '{%comment%}{% endif %}{%endcomment%}')
|
||||
assert_template_result('', '{% comment %}{% endwhatever %}{% endcomment %}')
|
||||
assert_template_result('', '{% comment %}{% raw %} {{%%%%}} }} { {% endcomment %} {% comment {% endraw %} {% endcomment %}')
|
||||
assert_template_result('', '{% comment %}{% " %}{% endcomment %}')
|
||||
assert_template_result('', '{% comment %}{%%}{% endcomment %}')
|
||||
|
||||
assert_template_result('foobar', 'foo{%comment%}comment{%endcomment%}bar')
|
||||
assert_template_result('foobar', 'foo{% comment %}comment{% endcomment %}bar')
|
||||
|
||||
@@ -65,4 +65,70 @@ class TableRowTest < Minitest::Test
|
||||
"{% tablerow char in characters cols:3 %}I WILL NOT BE OUTPUT{% endtablerow %}",
|
||||
{ 'characters' => '' })
|
||||
end
|
||||
|
||||
def test_cols_nil_constant_same_as_evaluated_nil_expression
|
||||
expect = "<tr class=\"row1\">\n" \
|
||||
"<td class=\"col1\">false</td>" \
|
||||
"<td class=\"col2\">false</td>" \
|
||||
"</tr>\n"
|
||||
|
||||
assert_template_result(expect,
|
||||
"{% tablerow i in (1..2) cols:nil %}{{ tablerowloop.col_last }}{% endtablerow %}")
|
||||
|
||||
assert_template_result(expect,
|
||||
"{% tablerow i in (1..2) cols:var %}{{ tablerowloop.col_last }}{% endtablerow %}",
|
||||
{ "var" => nil })
|
||||
end
|
||||
|
||||
def test_tablerow_loop_drop_attributes
|
||||
template = <<~LIQUID.chomp
|
||||
{% tablerow i in (1...2) %}
|
||||
col: {{ tablerowloop.col }}
|
||||
col0: {{ tablerowloop.col0 }}
|
||||
col_first: {{ tablerowloop.col_first }}
|
||||
col_last: {{ tablerowloop.col_last }}
|
||||
first: {{ tablerowloop.first }}
|
||||
index: {{ tablerowloop.index }}
|
||||
index0: {{ tablerowloop.index0 }}
|
||||
last: {{ tablerowloop.last }}
|
||||
length: {{ tablerowloop.length }}
|
||||
rindex: {{ tablerowloop.rindex }}
|
||||
rindex0: {{ tablerowloop.rindex0 }}
|
||||
row: {{ tablerowloop.row }}
|
||||
{% endtablerow %}
|
||||
LIQUID
|
||||
|
||||
expected_output = <<~OUTPUT
|
||||
<tr class="row1">
|
||||
<td class="col1">
|
||||
col: 1
|
||||
col0: 0
|
||||
col_first: true
|
||||
col_last: false
|
||||
first: true
|
||||
index: 1
|
||||
index0: 0
|
||||
last: false
|
||||
length: 2
|
||||
rindex: 2
|
||||
rindex0: 1
|
||||
row: 1
|
||||
</td><td class="col2">
|
||||
col: 2
|
||||
col0: 1
|
||||
col_first: false
|
||||
col_last: true
|
||||
first: false
|
||||
index: 2
|
||||
index0: 1
|
||||
last: true
|
||||
length: 2
|
||||
rindex: 1
|
||||
rindex0: 0
|
||||
row: 1
|
||||
</td></tr>
|
||||
OUTPUT
|
||||
|
||||
assert_template_result(expected_output, template)
|
||||
end
|
||||
end
|
||||
|
||||
+2
-2
@@ -42,9 +42,9 @@ module Minitest
|
||||
message: nil, partials: nil, error_mode: nil, render_errors: false
|
||||
)
|
||||
template = Liquid::Template.parse(template, line_numbers: true, error_mode: error_mode&.to_sym)
|
||||
file_system = StubFileSystem.new(partials) if partials
|
||||
file_system = StubFileSystem.new(partials || {})
|
||||
registers = Liquid::Registers.new(file_system: file_system)
|
||||
context = Liquid::Context.build(environments: assigns, rethrow_errors: !render_errors, registers: registers)
|
||||
context = Liquid::Context.build(static_environments: assigns, rethrow_errors: !render_errors, registers: registers)
|
||||
output = template.render(context)
|
||||
assert_equal(expected, output, message)
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user