From b18930f2ea425ae570ae4bc0d4d41d1fd86bb260 Mon Sep 17 00:00:00 2001 From: Guilherme Carreiro Date: Tue, 2 Jun 2026 16:41:59 +0200 Subject: [PATCH 1/2] Fix `SelfDrop` equality --- lib/liquid/self_drop.rb | 14 ++++++++++++++ test/integration/self_drop_context_test.rb | 18 ++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/lib/liquid/self_drop.rb b/lib/liquid/self_drop.rb index 4bfff0e45..b753f383b 100644 --- a/lib/liquid/self_drop.rb +++ b/lib/liquid/self_drop.rb @@ -35,6 +35,20 @@ def to_liquid self end + def ==(other) + other.is_a?(SelfDrop) && other.self_context.equal?(@self_context) + end + + alias_method :eql?, :== + + def hash + @self_context.object_id.hash + end + + protected + + attr_reader :self_context + undef context= end end diff --git a/test/integration/self_drop_context_test.rb b/test/integration/self_drop_context_test.rb index 338719e81..6fd7ec882 100644 --- a/test/integration/self_drop_context_test.rb +++ b/test/integration/self_drop_context_test.rb @@ -77,6 +77,24 @@ def test_self_drop_context_setter_is_undefined assert_template_result('42', '{{ self.x }}', { 'x' => 42 }) end + def test_self_drop_repeated_lookups_compare_equal_for_same_context + context = Context.new + + assert_equal(context.find_variable("self"), context.find_variable("self")) + end + + def test_assigned_self_drop_compares_equal_to_itself + assert_template_result('T', '{% assign s = self %}{% if s == s %}T{% else %}F{% endif %}') + end + + def test_distinct_self_assignments_compare_equal_for_same_context + assert_template_result('T', '{% assign a = self %}{% assign b = self %}{% if a == b %}T{% else %}F{% endif %}') + end + + def test_bare_self_compares_equal_to_bare_self + assert_template_result('T', '{% if self == self %}T{% else %}F{% endif %}') + end + def test_self_drop_with_strict_variables_does_not_raise_for_defined_var t = Template.parse('{{ self.x }}') result = t.render({ 'x' => 42 }, strict_variables: true) From 771ceccf41822298cd5fce6d2273d0dfe5b38311 Mon Sep 17 00:00:00 2001 From: Guilherme Carreiro Date: Fri, 5 Jun 2026 09:55:31 +0200 Subject: [PATCH 2/2] Cache SelfDrop per context --- lib/liquid/context.rb | 2 +- test/integration/self_drop_context_test.rb | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/liquid/context.rb b/lib/liquid/context.rb index 7902ebcff..26ff72852 100644 --- a/lib/liquid/context.rb +++ b/lib/liquid/context.rb @@ -208,7 +208,7 @@ def find_variable(key, raise_on_not_found: true) # `self` resolves to a SelfDrop (enabling `self['var']` lookups), # but only when it hasn't been explicitly assigned as a local variable. - return SelfDrop.new(self) if key == Expression::SELF && !index + return @self_drop ||= SelfDrop.new(self) if key == Expression::SELF && !index variable = if index lookup_and_evaluate(@scopes[index], key, raise_on_not_found: raise_on_not_found) diff --git a/test/integration/self_drop_context_test.rb b/test/integration/self_drop_context_test.rb index 6fd7ec882..f57fdc393 100644 --- a/test/integration/self_drop_context_test.rb +++ b/test/integration/self_drop_context_test.rb @@ -79,8 +79,12 @@ def test_self_drop_context_setter_is_undefined def test_self_drop_repeated_lookups_compare_equal_for_same_context context = Context.new + drop = context.find_variable("self") + cached_drop = context.find_variable("self") - assert_equal(context.find_variable("self"), context.find_variable("self")) + assert_same(drop, cached_drop) + assert_equal(drop.object_id, cached_drop.object_id) + assert_equal(drop, cached_drop) end def test_assigned_self_drop_compares_equal_to_itself