mirror of
https://github.com/Shopify/liquid.git
synced 2026-09-15 08:50:45 -07:00
Support ... inline snippet syntax
This commit is contained in:
committed by
Guilherme Carreiro
parent
c7ad1c90ca
commit
9bcfd32e65
@@ -8,7 +8,8 @@
|
||||
|
||||
<body>
|
||||
<div class="liquid" style="font-size: 56px;">
|
||||
|
||||
{% assign foo = true %}
|
||||
{% assign link = "variable" %}
|
||||
|
||||
{% snippet main %}
|
||||
{% assign foo = false %}
|
||||
@@ -17,15 +18,16 @@
|
||||
<p>This is an inline snippet</p>
|
||||
|
||||
<ul>
|
||||
<li><a href="/wow-a-link">wow a link</a></li>
|
||||
<li><a href="/wow-a-link">wow a {{ link }}</a></li>
|
||||
<li>1 + 1 = {{ 1 | plus: 1 }}</li>
|
||||
<li>{% if true %}Yes!{% endif %}</li>
|
||||
<li>{% if foo %}NO{% endif %}</li>
|
||||
<li>foo = {% if foo %}true{%else%}false{% endif %}</li>
|
||||
<li>{{ missing_var | default: 'fallback' }}</li>
|
||||
</ul>
|
||||
{% endsnippet %}
|
||||
|
||||
{% render main, arg: 'lsf' %}
|
||||
{% render main, arg: 'lsf', ... %}
|
||||
{{ foo }}
|
||||
|
||||
</div>
|
||||
</body>
|
||||
|
||||
+8
-2
@@ -17,6 +17,7 @@ module Liquid
|
||||
DASH = [:dash, "-"].freeze
|
||||
DOT = [:dot, "."].freeze
|
||||
DOTDOT = [:dotdot, ".."].freeze
|
||||
DOTDOTDOT = [:dotdotdot, "..."].freeze
|
||||
DOT_ORD = ".".ord
|
||||
DOUBLE_STRING_LITERAL = /"[^\"]*"/
|
||||
EOS = [:end_of_string].freeze
|
||||
@@ -113,10 +114,15 @@ module Liquid
|
||||
|
||||
if (special = SPECIAL_TABLE[peeked])
|
||||
ss.scan_byte
|
||||
# Special case for ".."
|
||||
# Special case for ".." and "..."
|
||||
if special == DOT && ss.peek_byte == DOT_ORD
|
||||
ss.scan_byte
|
||||
output << DOTDOT
|
||||
if ss.peek_byte == DOT_ORD
|
||||
ss.scan_byte
|
||||
output << DOTDOTDOT
|
||||
else
|
||||
output << DOTDOT
|
||||
end
|
||||
elsif special == DASH
|
||||
# Special case for negative numbers
|
||||
if (peeked_byte = ss.peek_byte) && NUMBER_TABLE[peeked_byte]
|
||||
|
||||
@@ -62,7 +62,13 @@ module Liquid
|
||||
|
||||
inner_context = context.new_isolated_subcontext
|
||||
|
||||
if inherit_context?
|
||||
if is_file
|
||||
inner_context.template_name = partial.name
|
||||
inner_context.partial = true
|
||||
end
|
||||
|
||||
if is_inline && inherit_context?
|
||||
|
||||
context.scopes.each do |scope|
|
||||
scope.each do |key, value|
|
||||
inner_context[key] = value
|
||||
@@ -125,6 +131,14 @@ module Liquid
|
||||
|
||||
p.consume?(:comma)
|
||||
|
||||
@inherit_context = false
|
||||
# ... inline snippets syntax
|
||||
if p.consume?(:dotdotdot)
|
||||
p.consume?(:comma)
|
||||
|
||||
@inherit_context = true
|
||||
end
|
||||
|
||||
@attributes = {}
|
||||
while p.look(:id)
|
||||
key = p.consume
|
||||
@@ -137,7 +151,12 @@ module Liquid
|
||||
end
|
||||
|
||||
def rigid_template_name(p)
|
||||
p.consume(:string)
|
||||
if p.look(:string)
|
||||
p.consume(:string)
|
||||
# inline snippets use variable identifiers
|
||||
elsif p.look(:id)
|
||||
p.consume(:id)
|
||||
end
|
||||
end
|
||||
|
||||
def strict_parse(markup)
|
||||
@@ -155,6 +174,7 @@ module Liquid
|
||||
@variable_name_expr = variable_name ? parse_expression(variable_name) : nil
|
||||
@template_name_expr = parse_expression(template_name)
|
||||
@is_for_loop = (with_or_for == FOR)
|
||||
@inherit_context = markup.include?('...')
|
||||
|
||||
@attributes = {}
|
||||
markup.scan(TagAttributes) do |key, value|
|
||||
|
||||
@@ -115,6 +115,23 @@ class SnippetTest < Minitest::Test
|
||||
assert_template_result(expected, template)
|
||||
end
|
||||
|
||||
def test_render_inline_snippet_with_evaluated_assign
|
||||
template = <<~LIQUID.strip
|
||||
{% snippet input %}
|
||||
<h1>{{ greeting }}</h1>
|
||||
{% endsnippet %}
|
||||
|
||||
{%- assign greeting = "hello" | upcase -%}
|
||||
{%- render input, greeting: greeting -%}
|
||||
LIQUID
|
||||
expected = <<~OUTPUT
|
||||
|
||||
<h1>HELLO</h1>
|
||||
OUTPUT
|
||||
|
||||
assert_template_result(expected, template)
|
||||
end
|
||||
|
||||
def test_render_inline_snippet_with_multiple_arguments
|
||||
template = <<~LIQUID.strip
|
||||
{% snippet input %}
|
||||
@@ -301,8 +318,36 @@ class SnippetTest < Minitest::Test
|
||||
assert_template_result(expected, template)
|
||||
end
|
||||
|
||||
def test_render_inline_snippet_with_outside_context_rigid
|
||||
template = <<~LIQUID.strip
|
||||
{% assign color_scheme = 'dark' %}
|
||||
|
||||
{% snippet header %}
|
||||
<div class="header header--{{ color_scheme }}">
|
||||
{{ message }}
|
||||
</div>
|
||||
{% endsnippet %}
|
||||
|
||||
|
||||
{% render header, ..., message: 'Welcome!' %}
|
||||
LIQUID
|
||||
expected = <<~OUTPUT
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="header header--dark">
|
||||
Welcome!
|
||||
</div>
|
||||
OUTPUT
|
||||
|
||||
assert_template_result(expected, template, error_mode: :rigid)
|
||||
end
|
||||
|
||||
def test_inline_snippet_local_scope_takes_precedence
|
||||
template = <<~LIQUID.strip
|
||||
template = <<~LIQUID
|
||||
{% assign color_scheme = 'dark' %}
|
||||
|
||||
{% snippet header %}
|
||||
@@ -339,17 +384,17 @@ class SnippetTest < Minitest::Test
|
||||
end
|
||||
|
||||
def test_render_captured_snippet
|
||||
template = <<~LIQUID.strip
|
||||
template = <<~LIQUID
|
||||
{% assign color_scheme = 'dark' %}
|
||||
|
||||
{% snippet header %}
|
||||
<div class="header header--{{ color_scheme }}">
|
||||
{{ message }}
|
||||
</div>
|
||||
<div class="header header--{{ color_scheme }}">
|
||||
{{ message }}
|
||||
</div>
|
||||
{% endsnippet %}
|
||||
|
||||
{% capture up_header %}
|
||||
{% render header, ..., message: 'Welcome!' %}
|
||||
{%- render header, ..., message: 'Welcome!' -%}
|
||||
{% endcapture %}
|
||||
|
||||
{{ up_header | upcase }}
|
||||
@@ -366,11 +411,9 @@ class SnippetTest < Minitest::Test
|
||||
|
||||
|
||||
|
||||
|
||||
<DIV CLASS="HEADER HEADER--DARK">
|
||||
WELCOME!
|
||||
</DIV>
|
||||
|
||||
<DIV CLASS="HEADER HEADER--DARK">
|
||||
WELCOME!
|
||||
</DIV>
|
||||
|
||||
|
||||
SNIPPETDROP
|
||||
@@ -395,7 +438,7 @@ class SnippetTest < Minitest::Test
|
||||
{% assign color_scheme = 'auto' %}
|
||||
|
||||
<div class="main main--{{ color_scheme }}">
|
||||
{% render header, ..., message: 'Welcome!' %}
|
||||
{% render header, ..., message: 'Welcome!' %}
|
||||
</div>
|
||||
{% endsnippet %}
|
||||
|
||||
@@ -448,4 +491,59 @@ class SnippetTest < Minitest::Test
|
||||
|
||||
# assert_template_result(expected, template)
|
||||
# end
|
||||
|
||||
# def test_render_inline_snippet_forloop
|
||||
# template = <<~LIQUID.strip
|
||||
# {% snippet item %}
|
||||
# <li>{{ forloop.index }}: {{ item }}</li>
|
||||
# {% endsnippet %}
|
||||
|
||||
# {% assign items = "A,B,C" | split: "," %}
|
||||
# {%- render item for items -%}
|
||||
# LIQUID
|
||||
# expected = <<~OUTPUT
|
||||
|
||||
# <li>1: A</li>
|
||||
|
||||
# <li>2: B</li>
|
||||
|
||||
# <li>3: C</li>
|
||||
# OUTPUT
|
||||
|
||||
# assert_template_result(expected, template)
|
||||
# end
|
||||
|
||||
# def test_render_inline_snippet_with
|
||||
# template = <<~LIQUID.strip
|
||||
# {% snippet header %}
|
||||
# <div>{{ header }}</div>
|
||||
# {% endsnippet %}
|
||||
|
||||
# {% assign product = "Apple" %}
|
||||
# {%- render header with product -%}
|
||||
# LIQUID
|
||||
# expected = <<~OUTPUT
|
||||
|
||||
# <div>Apple</div>
|
||||
# OUTPUT
|
||||
|
||||
# assert_template_result(expected, template)
|
||||
# end
|
||||
|
||||
# def test_render_inline_snippet_alias
|
||||
# template = <<~LIQUID.strip
|
||||
# {% snippet product_card %}
|
||||
# <div class="product">{{ item }}</div>
|
||||
# {% endsnippet %}
|
||||
|
||||
# {% assign featured = "Apple" %}
|
||||
# {%- render product_card with featured as item -%}
|
||||
# LIQUID
|
||||
# expected = <<~OUTPUT
|
||||
|
||||
# <div class="product">Apple</div>
|
||||
# OUTPUT
|
||||
|
||||
# assert_template_result(expected, template)
|
||||
# end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user