add invoke_two fast path for single-arg filter invocation, avoids splat chain

This commit is contained in:
Tobi Lutke
2026-03-11 08:49:37 -04:00
parent 76ae8f13e9
commit d574f193dc
3 changed files with 21 additions and 0 deletions
+5
View File
@@ -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 <tt>Context#stack</tt> instead
def push(new_scope = {})
@scopes.unshift(new_scope)
+13
View File
@@ -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
+3
View File
@@ -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)