mirror of
https://github.com/Shopify/liquid.git
synced 2026-09-13 07:50:43 -07:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
de603f07af |
@@ -112,6 +112,8 @@ module Liquid
|
||||
if left.is_a?(MethodLiteral)
|
||||
if right.respond_to?(left.method_name)
|
||||
return right.send(left.method_name)
|
||||
elsif (res = fallback_simulation_of_active_support(left.method_name, right))
|
||||
return res
|
||||
else
|
||||
return nil
|
||||
end
|
||||
@@ -120,6 +122,8 @@ module Liquid
|
||||
if right.is_a?(MethodLiteral)
|
||||
if left.respond_to?(right.method_name)
|
||||
return left.send(right.method_name)
|
||||
elsif (res = fallback_simulation_of_active_support(right.method_name, left))
|
||||
return res
|
||||
else
|
||||
return nil
|
||||
end
|
||||
@@ -128,6 +132,17 @@ module Liquid
|
||||
left == right
|
||||
end
|
||||
|
||||
# ActiveSupport creates #blank? as an alias for #empty? on Hash and Array.
|
||||
# Without this simulation, [] == blank behaves differently when AS is loaded vs. not.
|
||||
def fallback_simulation_of_active_support(method_name, obj)
|
||||
return nil unless method_name == :blank?
|
||||
|
||||
case obj
|
||||
when Array, Hash
|
||||
obj.empty?
|
||||
end # else nil
|
||||
end
|
||||
|
||||
def interpret_condition(left, right, op, context)
|
||||
# If the operator is empty this means that the decision statement is just
|
||||
# a single variable. We can just poll this variable from the context and
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'test_helper'
|
||||
|
||||
class ArrayTest < Minitest::Test
|
||||
include Liquid
|
||||
|
||||
def test_array_size
|
||||
assert_template_result("0", "{{a.size}}", { 'a' => [] })
|
||||
assert_template_result("2", "{{a.size}}", { 'a' => [1, 2] })
|
||||
end
|
||||
|
||||
def test_array_first
|
||||
assert_template_result("", "{{a.first}}", { 'a' => [] })
|
||||
assert_template_result("1", "{{a.first}}", { 'a' => [1, 2] })
|
||||
end
|
||||
|
||||
def test_array_last
|
||||
assert_template_result("", "{{a.last}}", { 'a' => [] })
|
||||
assert_template_result("2", "{{a.last}}", { 'a' => [1, 2] })
|
||||
end
|
||||
|
||||
def test_array_index
|
||||
assert_template_result("", "{{a[1]}}", { 'a' => [] })
|
||||
assert_template_result("2", "{{a[1]}}", { 'a' => [1, 2] })
|
||||
end
|
||||
|
||||
def test_negative_array_index
|
||||
assert_template_result("3", "{{a[-1]}}", { 'a' => [1, 2, 3] })
|
||||
assert_template_result("1", "{{a[-3]}}", { 'a' => [1, 2, 3] })
|
||||
assert_template_result("", "{{a[-4]}}", { 'a' => [1, 2, 3] })
|
||||
end
|
||||
|
||||
def test_array_to_s
|
||||
arr = ["a", ["b", 1], "c"]
|
||||
assert_template_result("ab1c", "{{a}}", { 'a' => arr })
|
||||
end
|
||||
|
||||
def test_auto_methods
|
||||
a1 = []
|
||||
a2 = [1, 2, 3, "abc"]
|
||||
assert_template_result("0,nonblank", "{{a.size}},{%if a['size'] == blank%}blank{%else%}nonblank{%endif%}", { 'a' => a1 })
|
||||
assert_template_result("4,nonblank", "{{a.size}},{%if a['size'] == blank%}blank{%else%}nonblank{%endif%}", { 'a' => a2 })
|
||||
assert_template_result(",", "{{a.first}},{{a['first']}}", { 'a' => a1 })
|
||||
assert_template_result("1,", "{{a.first}},{{a['first']}}", { 'a' => a2 })
|
||||
assert_template_result(",", "{{a.last}},{{a['last']}}", { 'a' => a1 })
|
||||
assert_template_result("abc,", "{{a.last}},{{a['last']}}", { 'a' => a2 })
|
||||
end
|
||||
|
||||
def test_array_equality
|
||||
a0 = []
|
||||
a1 = [1]
|
||||
a2 = [1, 2]
|
||||
a3 = [1]
|
||||
|
||||
arrays = [a0, a1, a2, a3]
|
||||
arrays.each_with_index do |a, i|
|
||||
arrays.each_with_index do |b, j|
|
||||
prefix = "(#{i},#{j})"
|
||||
assert_template_result(
|
||||
prefix + (a == b ? "y" : "n"),
|
||||
"#{prefix}{% if a == b %}y{%else%}n{%endif%}",
|
||||
{ "a" => a, "b" => b },
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def test_contains
|
||||
a0 = [1, "a", ["b", "c"], true]
|
||||
a1 = ["b", "c"]
|
||||
a2 = ["B", "C"]
|
||||
|
||||
tpl = "{%if a contains b%}y{%else%}n{%endif%}"
|
||||
|
||||
assert_template_result("y", tpl, { "a" => a0, "b" => 1 })
|
||||
assert_template_result("n", tpl, { "a" => a0, "b" => 2 })
|
||||
assert_template_result("y", tpl, { "a" => a0, "b" => a1 })
|
||||
assert_template_result("n", tpl, { "a" => a0, "b" => a2 })
|
||||
end
|
||||
|
||||
def test_empty
|
||||
assert_template_result("y", "{%if a == empty%}y{%else%}n{%endif%}", { 'a' => [] })
|
||||
assert_template_result("n", "{%if a == empty%}y{%else%}n{%endif%}", { 'a' => [1, 2] })
|
||||
end
|
||||
|
||||
def test_blank
|
||||
assert_template_result("y", "{%if a == blank%}y{%else%}n{%endif%}", { 'a' => [] })
|
||||
assert_template_result("n", "{%if a == blank%}y{%else%}n{%endif%}", { 'a' => [1, 2] })
|
||||
end
|
||||
|
||||
def test_iter
|
||||
a0 = [1, "a"]
|
||||
assert_template_result("1a", "{%for i in a%}{{i}}{%endfor%}", { 'a' => a0 })
|
||||
end
|
||||
|
||||
def test_output
|
||||
a0 = []
|
||||
a1 = [1, "a", ["b", "c"], true]
|
||||
assert_template_result("", "{{a}}", { 'a' => a0 })
|
||||
assert_template_result("1abctrue", "{{a}}", { 'a' => a1 })
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,223 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "test_helper"
|
||||
require "json"
|
||||
|
||||
class HashTest < Minitest::Test
|
||||
include Liquid
|
||||
|
||||
class HashSubclass < Hash
|
||||
def []=(key, value)
|
||||
super(fmt_key(key), value)
|
||||
end
|
||||
|
||||
def [](key)
|
||||
super(fmt_key(key))
|
||||
end
|
||||
|
||||
def key?(key)
|
||||
super(fmt_key(key))
|
||||
end
|
||||
|
||||
def include?(key)
|
||||
super(fmt_key(key))
|
||||
end
|
||||
|
||||
def to_s
|
||||
super.upcase
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def fmt_key(key)
|
||||
return key unless key.is_a?(String)
|
||||
|
||||
key.upcase
|
||||
end
|
||||
end
|
||||
|
||||
def test_size
|
||||
assert_template_result("0", "{{h.size}}", { "h" => {} })
|
||||
assert_template_result("1", "{{h.size}}", { "h" => { "a" => 1 } })
|
||||
end
|
||||
|
||||
def test_first
|
||||
assert_template_result("", "{{h.first}}", { "h" => {} })
|
||||
assert_template_result("a1", "{{h.first}}", { "h" => { "a" => 1 } })
|
||||
end
|
||||
|
||||
def test_last
|
||||
assert_template_result("", "{{h.last}}", { "h" => { "a" => 1 } })
|
||||
end
|
||||
|
||||
def test_index
|
||||
assert_template_result("", "{{h['a']}}", { "h" => {} })
|
||||
assert_template_result("1", "{{h['a']}}", { "h" => { "a" => 1 } })
|
||||
end
|
||||
|
||||
def test_to_s
|
||||
h = { "a" => 1, "b" => [1, { "c" => 2 }] }
|
||||
assert_template_result("{\"a\"=>1, \"b\"=>[1, {\"c\"=>2}]}", "{{h}}", { "h" => h })
|
||||
end
|
||||
|
||||
def test_auto_methods
|
||||
h1 = { "a" => 1 }
|
||||
h2 = { "last" => 10, "first" => 11, "size" => 12 }
|
||||
assert_template_result("1,nonblank", "{{h.size}},{%if h['size'] == blank%}blank{%else%}nonblank{%endif%}", { "h" => h1 })
|
||||
assert_template_result("12,nonblank", "{{h.size}},{%if h['size'] == blank%}blank{%else%}nonblank{%endif%}", { "h" => h2 })
|
||||
assert_template_result("a1,", "{{h.first}},{{h['first']}}", { "h" => h1 })
|
||||
assert_template_result("11,11", "{{h.first}},{{h['first']}}", { "h" => h2 })
|
||||
assert_template_result(",", "{{h.last}},{{h['last']}}", { "h" => h1 })
|
||||
assert_template_result("10,10", "{{h.last}},{{h['last']}}", { "h" => h2 })
|
||||
end
|
||||
|
||||
def test_equality
|
||||
h0 = {}
|
||||
h1 = { "a" => 1 }
|
||||
h2 = { "a" => 1, "b" => 2 }
|
||||
h3 = { "a" => 1 }
|
||||
|
||||
hashes = [h0, h1, h2, h3]
|
||||
hashes.each_with_index do |a, i|
|
||||
hashes.each_with_index do |b, j|
|
||||
prefix = "(#{i},#{j})"
|
||||
assert_template_result(
|
||||
prefix + (a == b ? "y" : "n"),
|
||||
"#{prefix}{% if a == b %}y{%else%}n{%endif%}",
|
||||
{ "a" => a, "b" => b },
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def test_contains
|
||||
h = { "a" => 1, "b" => { "c" => "d" }, "3" => ["f", 2] }
|
||||
|
||||
tpl = "{%if h contains b%}y{%else%}n{%endif%}"
|
||||
|
||||
assert_template_result("y", tpl, { "h" => h, "b" => "a" })
|
||||
# assert_template_result("y", tpl, h, { "h" => { "b" => "a".html_safe } })
|
||||
assert_template_result("y", tpl, { "h" => h, "b" => "a".b })
|
||||
assert_template_result("n", tpl, { "h" => h, "b" => "A" })
|
||||
# assert_template_result("n", tpl, h, { "h" => { "b" => "A".html_safe } })
|
||||
assert_template_result("n", tpl, { "h" => h, "b" => "A".b })
|
||||
|
||||
assert_template_result("n", tpl, { "h" => h, "b" => 1 })
|
||||
assert_template_result("n", tpl, { "h" => h, "b" => "1" })
|
||||
|
||||
assert_template_result("n", tpl, { "h" => h, "b" => 3 })
|
||||
assert_template_result("y", tpl, { "h" => h, "b" => "3" })
|
||||
end
|
||||
|
||||
def test_empty
|
||||
assert_template_result("y", "{%if h == empty%}y{%else%}n{%endif%}", { "h" => {} })
|
||||
assert_template_result("n", "{%if h == empty%}y{%else%}n{%endif%}", { "h" => { "a" => 1 } })
|
||||
end
|
||||
|
||||
def test_blank
|
||||
assert_template_result("y", "{%if h == blank%}y{%else%}n{%endif%}", { "h" => {} })
|
||||
assert_template_result("n", "{%if h == blank%}y{%else%}n{%endif%}", { "h" => { "a" => 1 } })
|
||||
end
|
||||
|
||||
def test_iter
|
||||
h0 = { "a" => 1, "b" => { "c" => "d" }, "3" => ["f", 2] }
|
||||
assert_template_result("a1b{\"c\"=>\"d\"}3f2", "{%for i in h%}{{i}}{%endfor%}", { "h" => h0 })
|
||||
end
|
||||
|
||||
def test_output
|
||||
h0 = {}
|
||||
h1 = { "a" => 1, "b" => { "c" => "d" }, "3" => ["f", 2] }
|
||||
assert_template_result("{}", "{{h}}", { "h" => h0 })
|
||||
assert_template_result("{\"a\"=>1, \"b\"=>{\"c\"=>\"d\"}, \"3\"=>[\"f\", 2]}", "{{h}}", { "h" => h1 })
|
||||
end
|
||||
|
||||
def test_integer_key
|
||||
h = { 2 => "huh" }
|
||||
assert_template_result("huh", "{{h[2]}}", { "h" => h })
|
||||
assert_template_result("huh", "{{h[b]}}", { "h" => h, "b" => 2 })
|
||||
assert_template_result("", "{{h[b]}}", { "h" => h, "b" => "2" })
|
||||
end
|
||||
|
||||
def test_nil_key
|
||||
assert_hash_roundtrip(nil, nil)
|
||||
refute_hash_roundtrip(nil, "nil")
|
||||
refute_hash_roundtrip(nil, "null")
|
||||
end
|
||||
|
||||
def test_bool_key
|
||||
assert_hash_roundtrip(true, true)
|
||||
refute_hash_roundtrip(true, false)
|
||||
refute_hash_roundtrip(true, "true")
|
||||
refute_hash_roundtrip(true, nil)
|
||||
end
|
||||
|
||||
def test_int_key
|
||||
assert_hash_roundtrip(1, 1)
|
||||
refute_hash_roundtrip(1, 2)
|
||||
refute_hash_roundtrip(1, "1")
|
||||
refute_hash_roundtrip(1, 1.0000000000001)
|
||||
end
|
||||
|
||||
def test_string_key
|
||||
assert_hash_roundtrip("word", "word")
|
||||
# assert_hash_roundtrip("word", "word".html_safe)
|
||||
assert_hash_roundtrip("word", "word".b)
|
||||
refute_hash_roundtrip("word", "word ")
|
||||
refute_hash_roundtrip("word", nil)
|
||||
refute_hash_roundtrip("word", true)
|
||||
end
|
||||
|
||||
def test_weird_keys
|
||||
assert_hash_roundtrip([1, 2], [1, 2])
|
||||
refute_hash_roundtrip([1, 2], [1, 3])
|
||||
assert_hash_roundtrip({ "a" => 1 }, { "a" => 1 })
|
||||
refute_hash_roundtrip({ "a" => 1 }, { "a" => 2 })
|
||||
o = Struct.new(:to_liquid).new(Object.new)
|
||||
# failed_hash_roundtrip(o, o)
|
||||
refute_hash_roundtrip(o, 1)
|
||||
refute_hash_roundtrip(o, nil)
|
||||
assert_hash_roundtrip("\xff".b, "\xff".b)
|
||||
assert_hash_roundtrip(1..2, 1..2)
|
||||
refute_hash_roundtrip(1..2, 1...2)
|
||||
assert_hash_roundtrip(
|
||||
111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111,
|
||||
111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111,
|
||||
)
|
||||
# f64 hashing isn't perfect but we can make some basic assertions.
|
||||
assert_hash_roundtrip(1.1234, 1.1234)
|
||||
refute_hash_roundtrip(1.1234, 1.1)
|
||||
end
|
||||
|
||||
def test_hash_html_key
|
||||
# I mean this is probably not ideal but this is the way liquid works.
|
||||
assert_template_result("{\"a<script>b\"=>\"y\"}", "{{h}}", { "h" => { "a<script>b" => "y" } })
|
||||
end
|
||||
|
||||
def test_hash_subclass
|
||||
hs = HashSubclass.new
|
||||
hs["A"] = "b"
|
||||
assert_template_result("b", "{{h['a']}}", { "h" => hs })
|
||||
assert_template_result("b", "{{h['A']}}", { "h" => hs })
|
||||
assert_template_result("", "{{h['b']}}", { "h" => hs })
|
||||
assert_template_result("yes", "{% if h contains 'a' %}yes{%else%}no{%endif%}", { "h" => hs })
|
||||
assert_template_result('{"A"=>"B"}', "{{h}}", { "h" => hs })
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def failed_hash_roundtrip(key, test)
|
||||
assert_template_result(
|
||||
"Liquid error (templates/index line 1): internal",
|
||||
"{{h[b]}}",
|
||||
{ "h" => { key => "y" }, "b" => test },
|
||||
)
|
||||
end
|
||||
|
||||
def assert_hash_roundtrip(key, test)
|
||||
assert_template_result("y", "{{h[b]}}", { "h" => { key => "y" }, "b" => test })
|
||||
end
|
||||
|
||||
def refute_hash_roundtrip(key, test)
|
||||
assert_template_result("", "{{h[b]}}", { "h" => { key => "y" }, "b" => test })
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user