diff --git a/lib/liquid/context.rb b/lib/liquid/context.rb index 3d6ffc96..270c902d 100644 --- a/lib/liquid/context.rb +++ b/lib/liquid/context.rb @@ -187,16 +187,11 @@ module Liquid # path and find_index() is optimized in MRI to reduce object allocation index = @scopes.find_index { |s| s.key?(key) } - variable = if index + if index lookup_and_evaluate(@scopes[index], key, raise_on_not_found: raise_on_not_found) else try_variable_find_in_environments(key, raise_on_not_found: raise_on_not_found) end - - variable = variable.to_liquid - variable.context = self if variable.respond_to?(:context=) - - variable end def lookup_and_evaluate(obj, key, raise_on_not_found: true) @@ -204,13 +199,17 @@ module Liquid raise Liquid::UndefinedVariable, "undefined variable #{key}" end - value = obj[key] + original = obj[key] - if value.is_a?(Proc) && obj.respond_to?(:[]=) - obj[key] = value.arity == 0 ? value.call : value.call(self) - else - value + value = contextualize(original) + + # TODO: I'd like to fold this under the liquid sanitization + # Original text from VariableLookup: if its a proc we will replace the entry with the proc + if original.is_a?(Proc) && obj.respond_to?(:[]=) + obj[key] = value end + + value end def with_disabled_tags(tag_names) @@ -228,6 +227,25 @@ module Liquid @disabled_tags.fetch(tag_name, 0) > 0 end + # TODO: Let's think as to how name this. + # The strait forward name is to use "to_liquid(object)" but I do not think this fully captures what it do. + # Also, "to_liquid" is already used anywhere and is more of a generic name at this point. + # When we call "to_liquid" we are "sanitizing" the input? + # We also want to "bind" the object to the current rendering "@context". + def contextualize(object) + if object.is_a?(Proc) + object = object.arity == 0 ? object.call : object.call(self) + end + + object = object.to_liquid + + # TODO: ideally all contextualized object would define "context=" even if they end up noop-ing it. + # For now this is not really a pressing issue to deal with. + object.context = self if object.respond_to?(:context=) + + object + end + protected attr_writer :base_scope_depth, :warnings, :errors, :strainer, :filters, :disabled_tags diff --git a/lib/liquid/standardfilters.rb b/lib/liquid/standardfilters.rb index f361c02b..6ff1fcd6 100644 --- a/lib/liquid/standardfilters.rb +++ b/lib/liquid/standardfilters.rb @@ -582,8 +582,11 @@ module Liquid def each @input.each do |e| - e.context = @context if e.respond_to?(:context=) - yield(e.respond_to?(:to_liquid) ? e.to_liquid : e) + # TODO: this conversion should occur outside the filter. + # This is a change I desire to make but might not make the cut for the current change at hand. + e = @context.contextualize(e) + + yield(e) end end end diff --git a/lib/liquid/variable_lookup.rb b/lib/liquid/variable_lookup.rb index 9d5dba68..fa6b5199 100644 --- a/lib/liquid/variable_lookup.rb +++ b/lib/liquid/variable_lookup.rb @@ -49,15 +49,17 @@ module Liquid ((object.respond_to?(:key?) && object.key?(key)) || (object.respond_to?(:fetch) && key.is_a?(Integer))) - # if its a proc we will replace the entry with the proc - res = context.lookup_and_evaluate(object, key) - object = res.to_liquid + object = context.lookup_and_evaluate(object, key) # Some special cases. If the part wasn't in square brackets and # no key with the same name was found we interpret following calls # as commands and call them on the current object elsif @command_flags & (1 << i) != 0 && object.respond_to?(key) - object = object.send(key).to_liquid + + # TODO: These do not go through lookup_and_evaluate. + # Let's see if we can move the conversion back to Context + object = object.send(key) + object = context.contextualize(object) # No key was present with the desired value and it wasn't one of the directly supported # keywords either. The only thing we got left is to return nil or diff --git a/test/integration/standard_filter_test.rb b/test/integration/standard_filter_test.rb index 90ba82bf..52dcb6a8 100644 --- a/test/integration/standard_filter_test.rb +++ b/test/integration/standard_filter_test.rb @@ -861,7 +861,7 @@ class StandardFiltersTest < Minitest::Test { foo: "bar" }, [{ "foo" => "bar" }, { "foo" => 123 }, { "foo" => nil }, { "foo" => true }, { "foo" => ["foo", "bar"] }], { 1 => "bar" }, - ["foo", 123, nil, true, false, Drop, ["foo"], { foo: "bar" }], + ["foo", 123, nil, true, false, test_drop, test_enum, ["foo"], { foo: "bar" }], ] StandardFilters.public_instance_methods(false).each do |method| arg_count = @filters.method(method).arity