Skip to content

Commit

Permalink
chore: extract the code to evaluate the attributes of tag into a module
Browse files Browse the repository at this point in the history
  • Loading branch information
did committed Oct 4, 2024
1 parent 50c068b commit 782e813
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 58 deletions.
63 changes: 63 additions & 0 deletions lib/locomotive/steam/liquid/tags/concerns/attributes_evaluator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
module Locomotive
module Steam
module Liquid
module Tags
module Concerns

# Evaluates the attributes parsed the AttributesParser
module AttributesEvaluator
extend ActiveSupport::Concern

included do
# Regexps are allowed as strings
RegexpFragment = /\/([^\/]+)\/([imx]+)?/o.freeze
StrictRegexpFragment = /\A#{RegexpFragment}\z/o.freeze

REGEX_OPTIONS = {
'i' => Regexp::IGNORECASE,
'm' => Regexp::MULTILINE,
'x' => Regexp::EXTENDED
}.freeze
end

protected

def evaluate_attributes(context)
@attributes = context[attributes_var_name] || {} if attributes_var_name.present?

attributes.inject({}) do |memo, (key, value)|
# _slug instead of _permalink
_key = key.to_s == '_permalink' ? '_slug' : key.to_s

memo.merge({ _key => evaluate_attribute(context, value) })
end
end

def evaluate_attribute(context, value)
case value
when Array
value.map { |v| evaluate_attribute(context, v) }
when Hash
Hash[value.map { |k, v| [k.to_s, evaluate_attribute(context, v)] }]
when StrictRegexpFragment
create_regexp($1, $2)
when ::Liquid::VariableLookup
evaluated_value = context.evaluate(value)
evaluated_value.respond_to?(:_id) ? evaluated_value.send(:_source) : evaluate_attribute(context, evaluated_value)
else
value
end
end

def create_regexp(value, unparsed_options)
options = unparsed_options.blank? ? nil : unparsed_options.split('').uniq.inject(0) do |_options, letter|
_options |= REGEX_OPTIONS[letter]
end
Regexp.new(value, options)
end
end
end
end
end
end
end
16 changes: 15 additions & 1 deletion lib/locomotive/steam/liquid/tags/concerns/attributes_parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,32 @@ module Concerns
# approach (see the SimpleAttributesParser for instance)
module AttributesParser
extend ActiveSupport::Concern

included do
# Mongoid operators available on symbols
OPERATORS = %w(all exists gt gte in lt lte ne nin size near within)

SYMBOL_OPERATORS_REGEXP = /(\w+\.(#{OPERATORS.join('|')})){1}\s*\:/o
end

def parse_markup(markup)
parser = self.class.current_parser

# 'liquid_code.rb' is purely arbitrary
source_buffer = ::Parser::Source::Buffer.new('liquid_code.rb')
source_buffer.source = "{%s}" % markup
source_buffer.source = "{%s}" % clean_markup(markup)

ast = parser.parse(source_buffer)
AstProcessor.new.process(ast)
end

private

def clean_markup(markup)
# convert symbol operators into valid ruby code
markup.gsub(SYMBOL_OPERATORS_REGEXP, ':"\1" =>')
end

class_methods do
def current_parser
(@current_parser ||= build_parser).tap do |parser|
Expand Down
61 changes: 4 additions & 57 deletions lib/locomotive/steam/liquid/tags/with_scope.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,31 +16,15 @@ module Tags
class WithScope < ::Liquid::Block

include Concerns::AttributesParser

# Regexps are allowed as strings
RegexpFragment = /\/([^\/]+)\/([imx]+)?/o.freeze
StrictRegexpFragment = /\A#{RegexpFragment}\z/o.freeze

include Concerns::AttributesEvaluator

SingleVariable = /\A\s*([a-zA-Z_0-9]+)\s*\z/om.freeze

REGEX_OPTIONS = {
'i' => Regexp::IGNORECASE,
'm' => Regexp::MULTILINE,
'x' => Regexp::EXTENDED
}.freeze

OPERATORS = %w(all exists gt gte in lt lte ne nin size near within)

SYMBOL_OPERATORS_REGEXP = /(\w+\.(#{OPERATORS.join('|')})){1}\s*\:/o


attr_reader :attributes, :attributes_var_name

def initialize(tag_name, markup, options)
super

# convert symbol operators into valid ruby code
markup.gsub!(SYMBOL_OPERATORS_REGEXP, ':"\1" =>')

if markup =~ SingleVariable
# alright, maybe we'vot got a single variable built
# with the Action liquid tag instead?
Expand All @@ -57,54 +41,17 @@ def initialize(tag_name, markup, options)

def render(context)
context.stack do
context['with_scope'] = self.evaluate_attributes(context)
context['with_scope'] = evaluate_attributes(context)

# for now, no content type is assigned to this with_scope
context['with_scope_content_type'] = false

super
end
end

protected

def evaluate_attributes(context)
@attributes = context[attributes_var_name] || {} if attributes_var_name.present?

attributes.inject({}) do |memo, (key, value)|
# _slug instead of _permalink
_key = key.to_s == '_permalink' ? '_slug' : key.to_s

memo.merge({ _key => evaluate_attribute(context, value) })
end
end

def evaluate_attribute(context, value)
case value
when Array
value.map { |v| evaluate_attribute(context, v) }
when Hash
Hash[value.map { |k, v| [k.to_s, evaluate_attribute(context, v)] }]
when StrictRegexpFragment
create_regexp($1, $2)
when ::Liquid::VariableLookup
evaluated_value = context.evaluate(value)
evaluated_value.respond_to?(:_id) ? evaluated_value.send(:_source) : evaluate_attribute(context, evaluated_value)
else
value
end
end

def create_regexp(value, unparsed_options)
options = unparsed_options.blank? ? nil : unparsed_options.split('').uniq.inject(0) do |_options, letter|
_options |= REGEX_OPTIONS[letter]
end
Regexp.new(value, options)
end
end

::Liquid::Template.register_tag('with_scope'.freeze, WithScope)

end
end
end
Expand Down

0 comments on commit 782e813

Please sign in to comment.