Add Liquid::HybridTag

This commit is contained in:
Guilherme Carreiro
2026-03-05 19:17:22 +01:00
parent d897899f66
commit a005b412f7
5 changed files with 328 additions and 0 deletions
+1
View File
@@ -57,6 +57,7 @@ require 'liquid/file_system'
require 'liquid/parser_switching'
require 'liquid/tag'
require 'liquid/block'
require 'liquid/hybrid_tag'
require 'liquid/parse_tree_visitor'
require 'liquid/interrupts'
require 'liquid/tags'
+40
View File
@@ -0,0 +1,40 @@
# frozen_string_literal: true
module Liquid
class HybridTag < Block
def parse(tokens)
if tokens.matching_end_tag?(tag_name)
@block_form = true
super
else
@block_form = false
end
end
def block_form?
@block_form
end
def nodelist
@body ? @body.nodelist : Const::EMPTY_ARRAY
end
def render_to_output_buffer(context, output)
if @block_form
render_block_form_to_output_buffer(context, output)
else
render_self_closing_to_output_buffer(context, output)
end
end
private
def render_block_form_to_output_buffer(_context, _output)
raise NotImplementedError, "#{self.class} must implement render_block_form_to_output_buffer"
end
def render_self_closing_to_output_buffer(_context, _output)
raise NotImplementedError, "#{self.class} must implement render_self_closing_to_output_buffer"
end
end
end
+44
View File
@@ -9,6 +9,7 @@ module Liquid
TAG_END = /%\}/
TAG_OR_VARIABLE_START = /\{[\{\%]/
NEWLINE = /\n/
TAG_NAME_PATTERN = /\A\{%-?\s*(\w+)/
OPEN_CURLEY = "{".ord
CLOSE_CURLEY = "}".ord
@@ -48,6 +49,49 @@ module Liquid
token
end
def peek
@tokens[@offset]
end
def position
[@offset, @line_number]
end
def position=(pos)
@offset, @line_number = pos
end
# Depth-aware forward scan of pre-tokenized tokens starting from the
# current position.
def matching_end_tag?(tag_name)
end_tag_name = "end#{tag_name}"
depth = 0
i = @offset
while i < @tokens.length
token = @tokens[i]
i += 1
next unless token.start_with?("{%")
# TODO: use tag_name
match = TAG_NAME_PATTERN.match(token)
next unless match
name = match[1]
if name == tag_name
depth += 1
elsif name == end_tag_name
return true if depth == 0
depth -= 1
end
end
false
end
private
def tokenize