diff --git a/lib/liquid/context.rb b/lib/liquid/context.rb index 66d7129e..3b32584e 100644 --- a/lib/liquid/context.rb +++ b/lib/liquid/context.rb @@ -115,6 +115,11 @@ module Liquid strainer.invoke_single(method, input).to_liquid end + # Fast path for two-argument filter invocation (e.g. {{ value | default: 'x' }}) + def invoke_two(method, input, arg1) + strainer.invoke_two(method, input, arg1).to_liquid + end + # Push new local scope on the stack. use Context#stack instead def push(new_scope = {}) @scopes.unshift(new_scope) diff --git a/lib/liquid/strainer_template.rb b/lib/liquid/strainer_template.rb index b3db4dbd..d01c1381 100644 --- a/lib/liquid/strainer_template.rb +++ b/lib/liquid/strainer_template.rb @@ -72,5 +72,18 @@ module Liquid rescue ::ArgumentError => e raise Liquid::ArgumentError, e.message, e.backtrace end + + # Fast path for two-argument filter invocation (input + one arg). + def invoke_two(method, input, arg1) + if self.class.invokable?(method) + send(method, input, arg1) + elsif @context.strict_filters + raise Liquid::UndefinedFilter, "undefined filter #{method}" + else + input + end + rescue ::ArgumentError => e + raise Liquid::ArgumentError, e.message, e.backtrace + end end end diff --git a/lib/liquid/variable.rb b/lib/liquid/variable.rb index 7762ae66..40755b15 100644 --- a/lib/liquid/variable.rb +++ b/lib/liquid/variable.rb @@ -307,6 +307,9 @@ module Liquid @filters.each do |filter_name, filter_args, filter_kwargs| if filter_args.empty? && !filter_kwargs obj = context.invoke_single(filter_name, obj) + elsif !filter_kwargs && filter_args.length == 1 + # Single positional arg — most common after no-arg + obj = context.invoke_two(filter_name, obj, context.evaluate(filter_args[0])) else filter_args = evaluate_filter_expressions(context, filter_args, filter_kwargs) obj = context.invoke(filter_name, obj, *filter_args)