Skip to content

Commit

Permalink
Allow for custom Hash classes to override #to_s
Browse files Browse the repository at this point in the history
  • Loading branch information
ianks committed Jan 16, 2025
1 parent a617b91 commit d209d14
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 18 deletions.
46 changes: 28 additions & 18 deletions lib/liquid/utils.rb
Original file line number Diff line number Diff line change
Expand Up @@ -90,34 +90,38 @@ def self.to_liquid_value(obj)
obj
end

if RUBY_VERSION >= '3.4'
def self.to_s(obj, seen = {})
case obj
when Hash
def self.to_s(obj, seen = {})
case obj
when Hash
# If the custom hash implementation overrides `#to_s`, use their
# custom implementation. Otherwise we use Liquid's default
# implementation.
if obj.class.instance_method(:to_s) == HASH_TO_S_METHOD
hash_inspect(obj, seen)
when Array
array_inspect(obj, seen)
else
obj.to_s
end
when Array
array_inspect(obj, seen)
else
obj.to_s
end
end

def self.inspect(obj, seen = {})
case obj
when Hash
def self.inspect(obj, seen = {})
case obj
when Hash
# If the custom hash implementation overrides `#inspect`, use their
# custom implementation. Otherwise we use Liquid's default
# implementation.
if obj.class.instance_method(:inspect) == HASH_INSPECT_METHOD
hash_inspect(obj, seen)
when Array
array_inspect(obj, seen)
else
obj.inspect
end
end
else
def self.to_s(obj, seen = nil)
obj.to_s
end

def self.inspect(obj, seen = nil)
when Array
array_inspect(obj, seen)
else
obj.inspect
end
end
Expand Down Expand Up @@ -175,5 +179,11 @@ def self.hash_inspect(hash, seen = {})
ensure
seen.delete(hash.object_id)
end

HASH_TO_S_METHOD = Hash.instance_method(:to_s)
private_constant :HASH_TO_S_METHOD

HASH_INSPECT_METHOD = Hash.instance_method(:inspect)
private_constant :HASH_INSPECT_METHOD
end
end
23 changes: 23 additions & 0 deletions test/integration/hash_rendering_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -80,4 +80,27 @@ def test_render_hash_with_array_values_hash
def test_render_hash_with_hash_key
assert_template_result("{{\"foo\"=>\"bar\"}=>42}", "{{ my_hash }}", { "my_hash" => { Hash["foo" => "bar"] => 42 } })
end

def test_join_filter_with_hash
array = [{ "key1" => "value1" }, { "key2" => "value2" }]
glue = { "lol" => "wut" }
assert_template_result("{\"key1\"=>\"value1\"}{\"lol\"=>\"wut\"}{\"key2\"=>\"value2\"}", "{{ my_array | join: glue }}", { "my_array" => array, "glue" => glue })
end

def test_rendering_hash_with_custom_to_s_method_uses_custom_to_s
my_hash = Class.new(Hash) do
def to_s
"kewl"
end
end.new

assert_template_result("kewl", "{{ my_hash }}", { "my_hash" => my_hash })
end

def test_rendering_hash_without_custom_to_s_uses_default_inspect
my_hash = Class.new(Hash).new
my_hash[:foo] = :bar

assert_template_result("{:foo=>:bar}", "{{ my_hash }}", { "my_hash" => my_hash })
end
end

0 comments on commit d209d14

Please sign in to comment.