mirror of
https://github.com/Shopify/liquid.git
synced 2026-09-19 19:00:39 -07:00
Liquid::Traversal
This enables traversal over whole document tree.
This commit is contained in:
@@ -29,7 +29,7 @@ module Liquid
|
||||
@@operators
|
||||
end
|
||||
|
||||
attr_reader :attachment
|
||||
attr_reader :attachment, :child_condition
|
||||
attr_accessor :left, :operator, :right
|
||||
|
||||
def initialize(left = nil, operator = nil, right = nil)
|
||||
@@ -83,7 +83,7 @@ module Liquid
|
||||
|
||||
protected
|
||||
|
||||
attr_reader :child_relation, :child_condition
|
||||
attr_reader :child_relation
|
||||
|
||||
private
|
||||
|
||||
|
||||
@@ -10,6 +10,8 @@ module Liquid
|
||||
class Assign < Tag
|
||||
Syntax = /(#{VariableSignature}+)\s*=\s*(.*)\s*/om
|
||||
|
||||
attr_reader :to, :from
|
||||
|
||||
def initialize(tag_name, markup, options)
|
||||
super
|
||||
if markup =~ Syntax
|
||||
|
||||
@@ -3,6 +3,8 @@ module Liquid
|
||||
Syntax = /(#{QuotedFragment})/o
|
||||
WhenSyntax = /(#{QuotedFragment})(?:(?:\s+or\s+|\s*\,\s*)(#{QuotedFragment}.*))?/om
|
||||
|
||||
attr_reader :blocks, :left
|
||||
|
||||
def initialize(tag_name, markup, options)
|
||||
super
|
||||
@blocks = []
|
||||
|
||||
@@ -15,6 +15,8 @@ module Liquid
|
||||
SimpleSyntax = /\A#{QuotedFragment}+/o
|
||||
NamedSyntax = /\A(#{QuotedFragment})\s*\:\s*(.*)/om
|
||||
|
||||
attr_reader :variables
|
||||
|
||||
def initialize(tag_name, markup, options)
|
||||
super
|
||||
case markup
|
||||
|
||||
@@ -46,8 +46,7 @@ module Liquid
|
||||
class For < Block
|
||||
Syntax = /\A(#{VariableSegment}+)\s+in\s+(#{QuotedFragment}+)\s*(reversed)?/o
|
||||
|
||||
attr_reader :collection_name
|
||||
attr_reader :variable_name
|
||||
attr_reader :collection_name, :variable_name, :limit, :from
|
||||
|
||||
def initialize(tag_name, markup, options)
|
||||
super
|
||||
|
||||
@@ -14,21 +14,23 @@ module Liquid
|
||||
ExpressionsAndOperators = /(?:\b(?:\s?and\s?|\s?or\s?)\b|(?:\s*(?!\b(?:\s?and\s?|\s?or\s?)\b)(?:#{QuotedFragment}|\S+)\s*)+)/o
|
||||
BOOLEAN_OPERATORS = %w(and or)
|
||||
|
||||
attr_reader :blocks
|
||||
|
||||
def initialize(tag_name, markup, options)
|
||||
super
|
||||
@blocks = []
|
||||
push_block('if'.freeze, markup)
|
||||
end
|
||||
|
||||
def nodelist
|
||||
@blocks.map(&:attachment)
|
||||
end
|
||||
|
||||
def parse(tokens)
|
||||
while parse_body(@blocks.last.attachment, tokens)
|
||||
end
|
||||
end
|
||||
|
||||
def nodelist
|
||||
@blocks.map(&:attachment)
|
||||
end
|
||||
|
||||
def unknown_tag(tag, markup, tokens)
|
||||
if ['elsif'.freeze, 'else'.freeze].include?(tag)
|
||||
push_block(tag, markup)
|
||||
|
||||
@@ -16,6 +16,8 @@ module Liquid
|
||||
class Include < Tag
|
||||
Syntax = /(#{QuotedFragment}+)(\s+(?:with|for)\s+(#{QuotedFragment}+))?/o
|
||||
|
||||
attr_reader :template_name_expr, :variable_name_expr, :attributes
|
||||
|
||||
def initialize(tag_name, markup, options)
|
||||
super
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@ module Liquid
|
||||
class TableRow < Block
|
||||
Syntax = /(\w+)\s+in\s+(#{QuotedFragment}+)/o
|
||||
|
||||
attr_reader :variable_name, :collection_name, :attributes
|
||||
|
||||
def initialize(tag_name, markup, options)
|
||||
super
|
||||
if markup =~ Syntax
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Liquid
|
||||
class Traversal
|
||||
def self.for(node, callbacks = Hash.new(proc {}))
|
||||
kase = CASES.find { |(klass, _)| node.is_a?(klass) }&.last
|
||||
(kase || self).new(node, callbacks)
|
||||
end
|
||||
|
||||
def initialize(node, callbacks)
|
||||
@node = node
|
||||
@callbacks = callbacks
|
||||
end
|
||||
|
||||
def callback_for(*classes, &block)
|
||||
callback = block
|
||||
callback = ->(node, _) { block.call(node) } if block.arity.abs == 1
|
||||
callback = ->(_, _) { block.call } if block.arity.zero?
|
||||
classes.each { |klass| @callbacks[klass] = callback }
|
||||
self
|
||||
end
|
||||
|
||||
def traverse(context = nil)
|
||||
children.map do |node|
|
||||
item, new_context = @callbacks[node.class].call(node, context)
|
||||
[
|
||||
item,
|
||||
Traversal.for(node, @callbacks).traverse(new_context || context)
|
||||
]
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def children
|
||||
@node.respond_to?(:nodelist) ? Array(@node.nodelist) : []
|
||||
end
|
||||
|
||||
class Assign < Traversal
|
||||
def children
|
||||
[@node.from]
|
||||
end
|
||||
end
|
||||
|
||||
class Case < Traversal
|
||||
def children
|
||||
[@node.left] + @node.blocks
|
||||
end
|
||||
end
|
||||
|
||||
class Condition < Traversal
|
||||
def children
|
||||
[
|
||||
@node.left, @node.right,
|
||||
@node.child_condition, @node.attachment
|
||||
].compact
|
||||
end
|
||||
end
|
||||
|
||||
class Cycle < Traversal
|
||||
def children
|
||||
Array(@node.variables)
|
||||
end
|
||||
end
|
||||
|
||||
class For < Traversal
|
||||
def children
|
||||
(super + [@node.limit, @node.from, @node.collection_name]).compact
|
||||
end
|
||||
end
|
||||
|
||||
class If < Traversal
|
||||
def children
|
||||
@node.blocks
|
||||
end
|
||||
end
|
||||
|
||||
class Include < Traversal
|
||||
def children
|
||||
[
|
||||
@node.template_name_expr,
|
||||
@node.variable_name_expr
|
||||
] + @node.attributes.values
|
||||
end
|
||||
end
|
||||
|
||||
class TableRow < Traversal
|
||||
def children
|
||||
super + @node.attributes.values + [@node.collection_name]
|
||||
end
|
||||
end
|
||||
|
||||
class Variable < Traversal
|
||||
def children
|
||||
[@node.name] + @node.filters.flatten
|
||||
end
|
||||
end
|
||||
|
||||
class VariableLookup < Traversal
|
||||
def children
|
||||
@node.lookups
|
||||
end
|
||||
end
|
||||
|
||||
CASES = {
|
||||
Liquid::Assign => Assign,
|
||||
Liquid::Case => Case,
|
||||
Liquid::Condition => Condition,
|
||||
Liquid::Cycle => Cycle,
|
||||
Liquid::For => For,
|
||||
Liquid::If => If,
|
||||
Liquid::Include => Include,
|
||||
Liquid::TableRow => TableRow,
|
||||
Liquid::Variable => Variable,
|
||||
Liquid::VariableLookup => VariableLookup
|
||||
}.freeze
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user