From 76dc82808dc6daab7247aaacb5faec0f76c397b9 Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Fri, 28 Aug 2026 02:43:24 +0300 Subject: [PATCH 1/2] Respect custom Delegator printers from upstream PR 60 Source-only backport of 30113562abd53b4689ef20288a13bdc3fef5577d; tests excluded under consumer task policy. --- lib/pp.rb | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/pp.rb b/lib/pp.rb index 798a4f4..2768ca0 100644 --- a/lib/pp.rb +++ b/lib/pp.rb @@ -200,14 +200,17 @@ def pop_inspect_key(id) def pp(obj) # If obj is a Delegator then use the object being delegated to for cycle # detection - obj = obj.__getobj__ if defined?(::Delegator) and ::Delegator === obj + delegated = defined?(::Delegator) && ::Delegator === obj + key = delegated ? obj.__getobj__ : obj - if check_inspect_key(obj) + if check_inspect_key(key) + obj = key if delegated and !obj.respond_to?(:pretty_print_cycle) group {obj.pretty_print_cycle self} return end - guard_inspect(obj) do + guard_inspect(key) do + obj = key if delegated and !obj.respond_to?(:pretty_print) group do obj.pretty_print self rescue NoMethodError From 5695f43cde17f2cfc27c732879b74ce5cec40753 Mon Sep 17 00:00:00 2001 From: Oskar Eichler Date: Mon, 31 Aug 2026 01:58:39 +0300 Subject: [PATCH 2/2] Preserve custom inspect on Delegator wrappers --- lib/pp.rb | 25 +++++++++++++++++++++---- test/test_pp.rb | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 4 deletions(-) diff --git a/lib/pp.rb b/lib/pp.rb index 2768ca0..32f4c9f 100644 --- a/lib/pp.rb +++ b/lib/pp.rb @@ -210,11 +210,28 @@ def pp(obj) end guard_inspect(key) do - obj = key if delegated and !obj.respond_to?(:pretty_print) + custom_inspect = false + if delegated + delegator_class = obj.class + unless delegator_class.public_method_defined?(:pretty_print) + singleton_methods = obj.singleton_methods(false) + custom_inspect = + !singleton_methods.include?(:pretty_print) && + (delegator_class.public_method_defined?(:inspect) || + singleton_methods.include?(:inspect)) + end + end + obj = key if delegated && !custom_inspect && !obj.respond_to?(:pretty_print) group do - obj.pretty_print self - rescue NoMethodError - text Kernel.instance_method(:inspect).bind_call(obj) + if custom_inspect + text obj.inspect + else + begin + obj.pretty_print self + rescue NoMethodError + text Kernel.instance_method(:inspect).bind_call(obj) + end + end end end end diff --git a/test/test_pp.rb b/test/test_pp.rb index 922ed37..56c32a1 100644 --- a/test/test_pp.rb +++ b/test/test_pp.rb @@ -312,6 +312,24 @@ def test_direct_pp class PPDelegateTest < Test::Unit::TestCase class A < DelegateClass(Array); end + class Delegated < SimpleDelegator + def pretty_print(q) + q.text "" + end + end + + class Inspected < SimpleDelegator + def inspect + "" + end + end + + class RaisingInspect < SimpleDelegator + def inspect + self.missing_from_inspect + end + end + def test_delegate assert_equal("[]\n", A.new([]).pretty_inspect, "[ruby-core:25804]") end @@ -327,6 +345,35 @@ def test_delegate_cycle assert_equal(cycle_pretty_inspect, delegator_cycle_pretty_inspect) end + + def test_delegate_pretty_print + delegated = Delegated.new(HasPrettyPrint.new(nil)) + assert_equal("\n", PP.pp(delegated, ''.dup)) + end + + def test_delegate_inspect + delegated = Inspected.new(HasInspect.new(:target)) + assert_equal("\n", PP.pp(delegated, ''.dup)) + end + + def test_delegate_singleton_inspect + delegated = SimpleDelegator.new(HasInspect.new(:target)) + def delegated.inspect() "" end + + assert_equal("\n", PP.pp(delegated, ''.dup)) + end + + def test_delegate_inspect_error + error = assert_raise(NoMethodError) do + PP.pp(RaisingInspect.new(HasInspect.new(:target)), ''.dup) + end + assert_equal(:missing_from_inspect, error.name) + end + + def test_delegate_basic_object + delegated = SimpleDelegator.new(BasicObject.new) + assert_match(/\A#\n\z/, PP.pp(delegated, ''.dup)) + end end class PPFileStatTest < Test::Unit::TestCase