-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Introduce Inline Snippets tag #2001
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
8c61497
4d13f03
3a13ac7
db474d5
a384e22
ba5aa0a
b5ecd4d
9409dd8
fb6cf17
96a4492
3556c33
c6c342a
1069b94
de23ed8
47288cc
d109bc9
99b0b38
eab457f
c4a6987
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| # frozen_string_literal: true | ||
|
|
||
| module Liquid | ||
| class SnippetDrop < Drop | ||
| attr_reader :body, :name, :filename | ||
|
|
||
| def initialize(body, name, filename) | ||
| super() | ||
| @body = body | ||
| @name = name | ||
| @filename = filename | ||
| end | ||
|
|
||
| def to_partial | ||
| @body | ||
| end | ||
|
|
||
| def to_s | ||
| 'SnippetDrop' | ||
| end | ||
| end | ||
| end |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -27,7 +27,7 @@ module Liquid | |
| # @liquid_syntax_keyword filename The name of the snippet to render, without the `.liquid` extension. | ||
| class Render < Tag | ||
| FOR = 'for' | ||
| SYNTAX = /(#{QuotedString}+)(\s+(with|#{FOR})\s+(#{QuotedFragment}+))?(\s+(?:as)\s+(#{VariableSegment}+))?/o | ||
| SYNTAX = /(#{QuotedString}+|#{VariableSegment}+)(\s+(with|#{FOR})\s+(#{QuotedFragment}+))?(\s+(?:as)\s+(#{VariableSegment}+))?/o | ||
|
|
||
| disable_tags "include" | ||
|
|
||
|
|
@@ -47,21 +47,23 @@ def render_to_output_buffer(context, output) | |
| end | ||
|
|
||
| def render_tag(context, output) | ||
| # The expression should be a String literal, which parses to a String object | ||
| template_name = @template_name_expr | ||
| raise ::ArgumentError unless template_name.is_a?(String) | ||
|
|
||
| partial = PartialCache.load( | ||
| template_name, | ||
| context: context, | ||
| parse_context: parse_context, | ||
| ) | ||
|
|
||
| context_variable_name = @alias_name || template_name.split('/').last | ||
| template = context.evaluate(@template_name_expr) | ||
|
|
||
| if template.respond_to?(:to_partial) | ||
| partial = template.to_partial | ||
| template_name = template.filename | ||
| context_variable_name = @alias_name || template.name | ||
| elsif @template_name_expr.is_a?(String) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: we should first check |
||
| partial = PartialCache.load(template, context: context, parse_context: parse_context) | ||
| template_name = partial.name | ||
| context_variable_name = @alias_name || template_name.split('/').last | ||
| else | ||
| raise ::ArgumentError | ||
| end | ||
|
|
||
| render_partial_func = ->(var, forloop) { | ||
| inner_context = context.new_isolated_subcontext | ||
| inner_context.template_name = partial.name | ||
| inner_context.template_name = template_name | ||
| inner_context.partial = true | ||
| inner_context['forloop'] = forloop if forloop | ||
|
|
||
|
|
@@ -101,14 +103,18 @@ def rigid_parse(markup) | |
| key = p.consume | ||
| p.consume(:colon) | ||
| @attributes[key] = safe_parse_expression(p) | ||
| p.consume?(:comma) | ||
| p.consume?(:comma) # optional comma | ||
| end | ||
|
|
||
| p.consume(:end_of_string) | ||
| end | ||
|
|
||
| def rigid_template_name(p) | ||
| p.consume(:string) | ||
| return p.consume(:string) if p.look(:string) | ||
| return p.consume(:id) if p.look(:id) | ||
|
|
||
| found = p.consume || "nothing" | ||
| raise SyntaxError, options[:locale].t("errors.syntax.render_invalid_template_name", found: found) | ||
| end | ||
|
|
||
| def strict_parse(markup) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| # frozen_string_literal: true | ||
|
|
||
| module Liquid | ||
| # @liquid_public_docs | ||
| # @liquid_type tag | ||
| # @liquid_category variable | ||
| # @liquid_name snippet | ||
| # @liquid_summary | ||
| # Creates a new inline snippet. | ||
| # @liquid_description | ||
| # You can create inline snippets to make your Liquid code more modular. | ||
| # @liquid_syntax | ||
| # {% snippet snippet_name %} | ||
| # value | ||
| # {% endsnippet %} | ||
| class Snippet < Block | ||
| def initialize(tag_name, markup, options) | ||
| super | ||
| p = @parse_context.new_parser(markup) | ||
| if p.look(:id) | ||
| @to = p.consume(:id) | ||
| p.consume(:end_of_string) | ||
| else | ||
| raise SyntaxError, options[:locale].t("errors.syntax.snippet") | ||
| end | ||
karreiro marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| end | ||
|
|
||
| def render_to_output_buffer(context, output) | ||
| snippet_drop = SnippetDrop.new(@body, @to, context.template_name) | ||
| context.scopes.last[@to] = snippet_drop | ||
| context.resource_limits.increment_assign_score(assign_score_of(snippet_drop)) | ||
| output | ||
| end | ||
|
|
||
| def blank? | ||
| true | ||
| end | ||
|
|
||
| private | ||
|
|
||
| def assign_score_of(snippet_drop) | ||
| snippet_drop.body.nodelist.sum { |node| node.to_s.bytesize } | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure if this makes sense. Assigning a snippet drop shouldn't rely on parsed AST for this functionality. |
||
| end | ||
| end | ||
| end | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
would be good to respond to
nameas well for duck typing