diff --git a/lib/awesome_print/formatter.rb b/lib/awesome_print/formatter.rb index 329b0e6..0e07ecb 100644 --- a/lib/awesome_print/formatter.rb +++ b/lib/awesome_print/formatter.rb @@ -62,9 +62,9 @@ module AwesomePrint #------------------------------------------------------------------------------ def awesome_self(object, type) if @options[:raw] && object.instance_variables.any? - awesome_object(object) - elsif object.respond_to?(:to_hash) - awesome_hash(object.to_hash) + return awesome_object(object) + elsif hash = convert_to_hash(object) + awesome_hash(hash) else colorize(object.inspect.to_s, type) end @@ -318,6 +318,22 @@ module AwesomePrint # Utility methods. #------------------------------------------------------------------------------ + def convert_to_hash(object) + if ! object.respond_to?(:to_hash) + return nil + end + if object.method(:to_hash).arity != 0 + return nil + end + + hash = object.to_hash + if ! hash.respond_to?(:keys) || ! hash.respond_to?('[]') + return nil + end + + return hash + end + def align(value, width) if @options[:multiline] if @options[:indent] > 0 diff --git a/spec/formats_spec.rb b/spec/formats_spec.rb index f769663..4c1c8ac 100644 --- a/spec/formats_spec.rb +++ b/spec/formats_spec.rb @@ -708,5 +708,56 @@ EOS my = My.new expect { my.methods.ai(:plain => true) }.not_to raise_error end + + describe "should handle a class that defines its own #to_hash method" do + it "that takes arguments" do + class My + def to_hash(a, b) + end + end + + my = My.new + expect { my.ai(:plain => true) }.not_to raise_error + end + + it "that returns nil" do + class My + def to_hash() + return nil + end + end + + my = My.new + expect { my.ai(:plain => true) }.not_to raise_error + end + + it "that returns an object that doesn't support #keys" do + class My + def to_hash() + object = Object.new + object.define_singleton_method('[]') { return nil } + + return object + end + end + + my = My.new + expect { my.ai(:plain => true) }.not_to raise_error + end + + it "that returns an object that doesn't support subscripting" do + class My + def to_hash() + object = Object.new + object.define_singleton_method(:keys) { return [:foo] } + + return object + end + end + + my = My.new + expect { my.ai(:plain => true) }.not_to raise_error + end + end end end