diff --git a/lib/liquid.rb b/lib/liquid.rb index 7772bb5f..f6aabb0d 100644 --- a/lib/liquid.rb +++ b/lib/liquid.rb @@ -59,8 +59,8 @@ require 'liquid/forloop_drop' require 'liquid/extensions' require 'liquid/errors' require 'liquid/interrupts' -require 'liquid/strainer_factory' require 'liquid/strainer_template' +require 'liquid/strainer_factory' require 'liquid/expression' require 'liquid/context' require 'liquid/parser_switching' diff --git a/lib/liquid/strainer_factory.rb b/lib/liquid/strainer_factory.rb index 7a7bcb8a..739227ff 100644 --- a/lib/liquid/strainer_factory.rb +++ b/lib/liquid/strainer_factory.rb @@ -7,25 +7,26 @@ module Liquid def add_global_filter(filter) strainer_class_cache.clear - global_filters << filter + GlobalCache.add_filter(filter) end def create(context, filters = []) strainer_from_cache(filters).new(context) end + GlobalCache = Class.new(StrainerTemplate) + private - def global_filters - @global_filters ||= [] - end - def strainer_from_cache(filters) - strainer_class_cache[filters] ||= begin - klass = Class.new(StrainerTemplate) - global_filters.each { |f| klass.add_filter(f) } - filters.each { |f| klass.add_filter(f) } - klass + if filters.empty? + GlobalCache + else + strainer_class_cache[filters] ||= begin + klass = Class.new(GlobalCache) + filters.each { |f| klass.add_filter(f) } + klass + end end end diff --git a/lib/liquid/strainer_template.rb b/lib/liquid/strainer_template.rb index a3ad06a7..c16be3b0 100644 --- a/lib/liquid/strainer_template.rb +++ b/lib/liquid/strainer_template.rb @@ -31,6 +31,11 @@ module Liquid filter_methods.include?(method.to_s) end + def inherited(subclass) + super + subclass.instance_variable_set(:@filter_methods, @filter_methods.dup) + end + private def filter_methods diff --git a/test/test_helper.rb b/test/test_helper.rb index f5c1c6a6..874dd8f4 100755 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -72,21 +72,21 @@ module Minitest end def with_global_filter(*globals) - original_global_filters = Liquid::StrainerFactory.instance_variable_get(:@global_filters) - Liquid::StrainerFactory.instance_variable_set(:@global_filters, []) - globals.each do |global| - Liquid::StrainerFactory.add_global_filter(global) - end - - Liquid::StrainerFactory.send(:strainer_class_cache).clear + original_global_cache = Liquid::StrainerFactory::GlobalCache + Liquid::StrainerFactory.send(:remove_const, :GlobalCache) + Liquid::StrainerFactory.const_set(:GlobalCache, Class.new(Liquid::StrainerTemplate)) globals.each do |global| Liquid::Template.register_filter(global) end - yield - ensure Liquid::StrainerFactory.send(:strainer_class_cache).clear - Liquid::StrainerFactory.instance_variable_set(:@global_filters, original_global_filters) + begin + yield + ensure + Liquid::StrainerFactory.send(:remove_const, :GlobalCache) + Liquid::StrainerFactory.const_set(:GlobalCache, original_global_cache) + Liquid::StrainerFactory.send(:strainer_class_cache).clear + end end def with_error_mode(mode) diff --git a/test/unit/strainer_factory_unit_test.rb b/test/unit/strainer_factory_unit_test.rb index 05a9c834..43eafc1d 100644 --- a/test/unit/strainer_factory_unit_test.rb +++ b/test/unit/strainer_factory_unit_test.rb @@ -52,7 +52,8 @@ class StrainerFactoryUnitTest < Minitest::Test /\ALiquid error: wrong number of arguments \((1 for 0|given 1, expected 0)\)\z/, exception.message ) - assert_equal(exception.backtrace[0].split(':')[0], __FILE__) + source = AccessScopeFilters.instance_method(:public_filter).source_location + assert_equal(source.map(&:to_s), exception.backtrace[0].split(':')[0..1]) end def test_strainer_only_invokes_public_filter_methods diff --git a/test/unit/strainer_template_unit_test.rb b/test/unit/strainer_template_unit_test.rb index e72ed44d..fd6a5a3c 100644 --- a/test/unit/strainer_template_unit_test.rb +++ b/test/unit/strainer_template_unit_test.rb @@ -57,8 +57,8 @@ class StrainerTemplateUnitTest < Minitest::Test end def test_add_filter_does_not_raise_when_module_overrides_previously_registered_method - strainer = Context.new.strainer with_global_filter do + strainer = Context.new.strainer strainer.class.add_filter(PublicMethodOverrideFilter) assert(strainer.class.send(:filter_methods).include?('public_filter')) end