From 03ce70e2d893b156727d2efc9b170325ba0eef33 Mon Sep 17 00:00:00 2001 From: Stan Lo Date: Tue, 14 Mar 2023 14:27:38 +0800 Subject: [PATCH] Support BasicObject --- lib/pp.rb | 25 ++++++++++++++++++++----- test/test_pp.rb | 11 +++++++++++ 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/lib/pp.rb b/lib/pp.rb index b81f84c..887f233 100644 --- a/lib/pp.rb +++ b/lib/pp.rb @@ -137,6 +137,9 @@ class << self end end + M_RESPOND_TO = Object.instance_method(:respond_to?) + private_constant :M_RESPOND_TO + module PPMethods # Yields to a block @@ -188,7 +191,7 @@ 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 obj.is_a?(::Delegator) + obj = obj.__getobj__ if defined?(::Delegator) and ::Delegator === obj if check_inspect_key(obj) group {obj.pretty_print_cycle self} @@ -197,7 +200,12 @@ def pp(obj) begin push_inspect_key(obj) - group {obj.pretty_print self} + + if M_RESPOND_TO.bind_call(obj, :pretty_print) + group { obj.pretty_print self } + else + group { Object.instance_method(:pretty_print).bind_call(obj, self) } + end ensure pop_inspect_key(obj) unless PP.sharing_detection end @@ -266,8 +274,15 @@ def seplist(list, sep=nil, iter_method=:each) # :yield: element # A present standard failsafe for pretty printing any given Object def pp_object(obj) + instance_variables = + if M_RESPOND_TO.bind_call(obj, :pretty_print_instance_variables) + obj.pretty_print_instance_variables + else + Object.instance_method(:pretty_print_instance_variables).bind_call(obj) + end + object_address_group(obj) { - seplist(obj.pretty_print_instance_variables, lambda { text ',' }) {|v| + seplist(instance_variables, lambda { text ',' }) {|v| breakable v = v.to_s if Symbol === v text v @@ -325,7 +340,7 @@ def pretty_print(q) end if inspect_method && inspect_method.owner != Kernel q.text self.inspect - elsif !inspect_method && self.respond_to?(:inspect) + elsif !inspect_method && M_RESPOND_TO.bind_call(self, :inspect) q.text self.inspect else q.pp_object(self) @@ -346,7 +361,7 @@ def pretty_print_cycle(q) # This method should return an array of names of instance variables as symbols or strings as: # +[:@a, :@b]+. def pretty_print_instance_variables - instance_variables.sort + Object.instance_method(:instance_variables).bind_call(self).sort end # Is #inspect implementation using #pretty_print. diff --git a/test/test_pp.rb b/test/test_pp.rb index bb2299a..49af4ad 100644 --- a/test/test_pp.rb +++ b/test/test_pp.rb @@ -16,6 +16,17 @@ def test_list0123_11 assert_equal("[0,\n 1,\n 2,\n 3]\n", PP.pp([0,1,2,3], ''.dup, 11)) end + def test_basic_object + foo_class = Class.new(Object) do + def initialize + @obj = BasicObject.new + end + end + assert_match(/#/, PP.pp(BasicObject.new, ''.dup, 12)) + assert_match(/\[0,\n 1,\n 2,\n #\]\n/, PP.pp([0,1,2, BasicObject.new], ''.dup, 12)) + assert_match(/#<#:.*\n @obj=\n #>/, PP.pp(foo_class.new, ''.dup, 12)) + end + OverriddenStruct = Struct.new("OverriddenStruct", :members, :class) def test_struct_override_members # [ruby-core:7865] a = OverriddenStruct.new(1,2)