Skip to content

Commit

Permalink
WIP - Support {% render obj %}
Browse files Browse the repository at this point in the history
  • Loading branch information
catlee committed Feb 3, 2022
1 parent 3de1db3 commit 47fbff0
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 9 deletions.
1 change: 1 addition & 0 deletions lib/liquid.rb
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ module Liquid
require 'liquid/expression'
require 'liquid/context'
require 'liquid/parser_switching'
require 'liquid/renderabledrop'
require 'liquid/tag'
require 'liquid/tag/disabler'
require 'liquid/tag/disableable'
Expand Down
1 change: 1 addition & 0 deletions lib/liquid/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,6 @@
render: "Syntax error in tag 'render' - Template name must be a quoted string"
argument:
include: "Argument error in tag 'include' - Illegal template name"
render: "Argument error in tag 'render' - Illegal template name"
disabled:
tag: "usage is not allowed in this context"
9 changes: 9 additions & 0 deletions lib/liquid/renderabledrop.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# frozen_string_literal: true

module Liquid
class RenderableDrop < Drop
def render(_context, _output)
raise NotImplementedError, "render must be implemented for #{self.class.name}"
end
end
end
37 changes: 31 additions & 6 deletions lib/liquid/tags/render.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,20 @@
module Liquid
class Render < Tag
FOR = 'for'
SYNTAX = /(#{QuotedString}+)(\s+(with|#{FOR})\s+(#{QuotedFragment}+))?(\s+(?:as)\s+(#{VariableSegment}+))?/o
SYNTAX = %r{
(
## for {% render "snippet" %}
#{Liquid::QuotedString}+ |
## for {% render block %}
\A#{Liquid::VariableSegment}+
)
## for {% render "snippet" with product as p %}
## or {% render "snippet" for products p %}
(\s+(with|#{Liquid::Render::FOR})\s+(#{Liquid::QuotedFragment}+))?
(\s+(?:as)\s+(#{Liquid::VariableSegment}+))?
## variables passed into the tag (e.g. {% render "snippet", var1: value1, var2: value2 %}
## are not matched by this regex and are handled by .initialize
}xo

disable_tags "include"

Expand All @@ -14,13 +27,13 @@ def initialize(tag_name, markup, options)

raise SyntaxError, options[:locale].t("errors.syntax.render") unless markup =~ SYNTAX

template_name = Regexp.last_match(1)
@template_name = Regexp.last_match(1)
with_or_for = Regexp.last_match(3)
variable_name = Regexp.last_match(4)

@alias_name = Regexp.last_match(6)
@variable_name_expr = variable_name ? parse_expression(variable_name) : nil
@template_name_expr = parse_expression(template_name)
@template_name_expr = parse_expression(@template_name)
@for = (with_or_for == FOR)

@attributes = {}
Expand All @@ -34,9 +47,21 @@ def render_to_output_buffer(context, output)
end

def render_tag(context, output)
# Though we evaluate this here we will only ever parse it as a string literal.
template_name = context.evaluate(@template_name_expr)
raise ArgumentError, options[:locale].t("errors.argument.include") unless template_name
render_target = context.evaluate(@template_name_expr)
raise ArgumentError, options[:locale].t("errors.argument.render") unless render_target

# Check to see if this is a renderable drop
if render_target.is_a?(Liquid::RenderableDrop)
return render_target.render(context, output)
end

# Otherwise it must be a quoted string
unless /#{Liquid::QuotedString}+/.match?(@template_name)
output << "<!-- #{options[:locale].t('errors.syntax.render')} -->"
return
end

template_name = render_target

partial = PartialCache.load(
template_name,
Expand Down
5 changes: 2 additions & 3 deletions test/integration/tags/render_tag_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,8 @@ def test_sub_contexts_count_towards_the_same_recursion_limit
def test_dynamically_choosen_templates_are_not_allowed
Liquid::Template.file_system = StubFileSystem.new('snippet' => 'should not be rendered')

assert_raises(Liquid::SyntaxError) do
Liquid::Template.parse("{% assign name = 'snippet' %}{% render name %}")
end
assert_equal("<!-- Syntax error in tag 'render' - Template name must be a quoted string -->",
Liquid::Template.parse("{% assign name = 'snippet' %}{% render name %}").render!)
end

def test_include_tag_caches_second_read_of_same_partial
Expand Down

0 comments on commit 47fbff0

Please sign in to comment.