Class: Liquid::Strainer

Inherits:
Object
  • Object
show all
Defined in:
lib/liquid/strainer.rb

Overview

Strainer is the parent class for the filters system. New filters are mixed into the strainer class which is then instantiated for each liquid template render run.

The Strainer only allows method calls defined in filters given to it via Strainer.global_filter, Context#add_filters or Template.register_filter

Constant Summary collapse

@@global_strainer =
Class.new(Strainer) do
  @filter_methods = Set.new
end
@@strainer_class_cache =
Hash.new do |hash, filters|
  hash[filters] = Class.new(@@global_strainer) do
    @filter_methods = @@global_strainer.filter_methods.dup
    filters.each { |f| add_filter(f) }
  end
end

Class Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(context) ⇒ Strainer

Returns a new instance of Strainer.


20
21
22
# File 'lib/liquid/strainer.rb', line 20

def initialize(context)
  @context = context
end

Class Attribute Details

.filter_methodsObject (readonly)

Returns the value of attribute filter_methods


25
26
27
# File 'lib/liquid/strainer.rb', line 25

def filter_methods
  @filter_methods
end

Class Method Details

.add_filter(filter) ⇒ Object

Raises:


28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/liquid/strainer.rb', line 28

def self.add_filter(filter)
  raise ArgumentError, "Expected module but got: #{filter.class}" unless filter.is_a?(Module)
  unless self.include?(filter)
    invokable_non_public_methods = (filter.private_instance_methods + filter.protected_instance_methods).select { |m| invokable?(m) }
    if invokable_non_public_methods.any?
      raise MethodOverrideError, "Filter overrides registered public methods as non public: #{invokable_non_public_methods.join(', ')}"
    else
      send(:include, filter)
      @filter_methods.merge(filter.public_instance_methods.map(&:to_s))
    end
  end
end

.create(context, filters = []) ⇒ Object


50
51
52
# File 'lib/liquid/strainer.rb', line 50

def self.create(context, filters = [])
  @@strainer_class_cache[filters].new(context)
end

.global_filter(filter) ⇒ Object


41
42
43
44
# File 'lib/liquid/strainer.rb', line 41

def self.global_filter(filter)
  @@strainer_class_cache.clear
  @@global_strainer.add_filter(filter)
end

.invokable?(method) ⇒ Boolean

Returns:

  • (Boolean)

46
47
48
# File 'lib/liquid/strainer.rb', line 46

def self.invokable?(method)
  @filter_methods.include?(method.to_s)
end

Instance Method Details

#invoke(method, *args) ⇒ Object


54
55
56
57
58
59
60
61
62
63
64
# File 'lib/liquid/strainer.rb', line 54

def invoke(method, *args)
  if self.class.invokable?(method)
    send(method, *args)
  elsif @context && @context.strict_filters
    raise Liquid::UndefinedFilter, "undefined filter #{method}"
  else
    args.first
  end
rescue ::ArgumentError => e
  raise Liquid::ArgumentError, e.message, e.backtrace
end