Skip to content

Commit 0f2c21e

Browse files
committed
Add support for recursive liquid tags
Matches to liquid_c and liquid v5.5.0. Also, fix rounding with invalid precision parameters to better match ruby's version of liquid. Liquex currently converts {{ 0 | round 'invalid' }} to '0.0'. Ruby rounds this to '0'. Ref: Shopify/liquid#1731
1 parent 2041b97 commit 0f2c21e

File tree

6 files changed

+109
-15
lines changed

6 files changed

+109
-15
lines changed

.devcontainer/Dockerfile

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
FROM elixir:1.14
22

3-
ENV LIQUID_VERSION 5.4.0
3+
ENV LIQUID_VERSION 5.5.0
44

55
# Install ruby. Since we are only using this to install Liquid,
66
# we don't really care which version

lib/liquex/cache.ex

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,5 @@ defmodule Liquex.Cache do
1111
Fetch a value from cache. If the value doesn't exist, run the given function
1212
and store the results within the cache.
1313
"""
14-
@callback fetch(key, (-> value())) :: value()
14+
@callback fetch(key, (() -> value())) :: value()
1515
end

lib/liquex/filter.ex

+6-10
Original file line numberDiff line numberDiff line change
@@ -561,12 +561,10 @@ defmodule Liquex.Filter do
561561
"""
562562
@spec round(binary | number | nil, binary | number | nil, any) :: number
563563
def round(value, precision \\ 0, context),
564-
do: do_round(to_number(value), to_number(precision, false), context)
564+
do: do_round(to_number(value), to_number(precision), context)
565565

566566
defp do_round(value, _, _) when is_integer(value), do: value
567-
defp do_round(value, precision, _) when precision == 0, do: Float.round(value) |> trunc()
568-
defp do_round(value, precision, _) when precision < 0, do: Float.round(value)
569-
defp do_round(value, nil, _), do: Float.round(value)
567+
defp do_round(value, precision, _) when precision <= 0, do: Float.round(value) |> trunc()
570568

571569
defp do_round(value, precision, _) do
572570
# Special case negative and invalid precisions
@@ -844,12 +842,10 @@ defmodule Liquex.Filter do
844842
"""
845843
def where(list, key, _), do: Liquex.Collection.where(list, key)
846844

847-
defp to_number(value, allow_conversion_to_zero \\ true)
848-
defp to_number(value, _) when is_number(value), do: value
849-
defp to_number(nil, true), do: 0
850-
defp to_number(nil, false), do: nil
845+
defp to_number(nil), do: 0
846+
defp to_number(value) when is_number(value), do: value
851847

852-
defp to_number(value, allow_conversion_to_zero) when is_binary(value) do
848+
defp to_number(value) when is_binary(value) do
853849
case Integer.parse(value) do
854850
# Integer value
855851
{int_val, ""} ->
@@ -864,7 +860,7 @@ defmodule Liquex.Filter do
864860

865861
# Unknown, so use Ruby's style of "Convert to 0 instead"
866862
_ ->
867-
if allow_conversion_to_zero == true, do: 0, else: nil
863+
0
868864
end
869865
end
870866
end

lib/liquex/tag/inline_comment_tag.ex

+14-1
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,24 @@
11
defmodule Liquex.Tag.InlineCommentTag do
22
@moduledoc """
3+
A tag that allows for inline comments using the # character.
4+
5+
## liquid
6+
Nothing in the comments will be rendered.
7+
{% # This is a comment and won't be rendered %}
8+
9+
{% liquid # This is also a comment and won't be rendered %}
10+
11+
12+
### Output
13+
Nothing in the comments will be rendered.
14+
15+
316
"""
417

518
@behaviour Liquex.Tag
619

7-
alias Liquex.Parser.Tag
820
alias Liquex.Parser.Literal
21+
alias Liquex.Parser.Tag
922

1023
import NimbleParsec
1124

lib/liquex/tag/liquid_tag.ex

+20-2
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,30 @@ defmodule Liquex.Tag.LiquidTag do
3636
@spec parse :: NimbleParsec.t()
3737
def parse do
3838
Tag.open_tag()
39+
|> liquid_contents()
40+
|> ignore(Literal.whitespace())
41+
|> ignore(Tag.close_tag())
42+
end
43+
44+
@impl true
45+
@spec parse_liquid_tag :: NimbleParsec.t()
46+
def parse_liquid_tag do
47+
# Yo dawg! I heard you like liquid tags, so I put a liquid tag in your
48+
# liquid tag so you can tag while you tag.
49+
50+
# This was added in reference to pull request 1731
51+
# https://github.com/Shopify/liquid/pull/1731
52+
53+
liquid_contents()
54+
|> ignore(Tag.end_liquid_line())
55+
end
56+
57+
defp liquid_contents(combinator \\ empty()) do
58+
combinator
3959
|> string("liquid")
4060
|> Literal.whitespace(1)
4161
|> ignore()
4262
|> tag(parsec(:liquid_tag_contents), :contents)
43-
|> ignore(Literal.whitespace())
44-
|> ignore(Tag.close_tag())
4563
end
4664

4765
@impl true

test/liquex/tag/liquid_tag_test.exs

+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
defmodule Liquex.Tag.LiquidTagTest do
2+
use ExUnit.Case, async: true
3+
import Liquex.TestHelpers
4+
5+
describe "parse" do
6+
test "handles recursive liquid tags" do
7+
assert_parse(
8+
"{% liquid liquid echo 'hello' %}",
9+
[
10+
{
11+
{:tag, Liquex.Tag.LiquidTag},
12+
[
13+
contents: [
14+
{{:tag, Liquex.Tag.LiquidTag},
15+
[contents: [{{:tag, Liquex.Tag.EchoTag}, [literal: "hello", filters: []]}]]}
16+
]
17+
]
18+
}
19+
]
20+
)
21+
end
22+
23+
test "handles recursive liquid tags at depth higher than 2" do
24+
assert_parse(
25+
"{% liquid liquid liquid liquid liquid echo 'hello' %}",
26+
[
27+
{{:tag, Liquex.Tag.LiquidTag},
28+
[
29+
contents: [
30+
{{:tag, Liquex.Tag.LiquidTag},
31+
[
32+
contents: [
33+
{{:tag, Liquex.Tag.LiquidTag},
34+
[
35+
contents: [
36+
{{:tag, Liquex.Tag.LiquidTag},
37+
[
38+
contents: [
39+
{{:tag, Liquex.Tag.LiquidTag},
40+
[
41+
contents: [
42+
{{:tag, Liquex.Tag.EchoTag}, [literal: "hello", filters: []]}
43+
]
44+
]}
45+
]
46+
]}
47+
]
48+
]}
49+
]
50+
]}
51+
]
52+
]}
53+
]
54+
)
55+
end
56+
end
57+
58+
describe "render" do
59+
# Most of these tests are done in the individual tag tests. This is only
60+
# focusing on recursive liquid tags.
61+
test "renders tag" do
62+
assert render("""
63+
{% liquid liquid liquid liquid echo 'hello world' %}
64+
""") == "hello world"
65+
end
66+
end
67+
end

0 commit comments

Comments
 (0)