Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion lib/irb/color_printer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@

module IRB
class ColorPrinter < ::PP
METHOD_IS_A = Object.instance_method(:is_a?)
METHOD_RESPOND_TO = Object.instance_method(:respond_to?)
METHOD_INSPECT = Object.instance_method(:inspect)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know we already have store the method object in other places (e.g. inspector.rb). But I don't want to create dependencies between files just to reuse this as it's easy to find duplications later on.


class << self
def pp(obj, out = $>, width = screen_width)
q = ColorPrinter.new(out, width)
Expand All @@ -22,9 +26,11 @@ def screen_width
end

def pp(obj)
if obj.is_a?(String)
if METHOD_IS_A.bind(obj).call(String)
# Avoid calling Ruby 2.4+ String#pretty_print that splits a string by "\n"
text(obj.inspect)
elsif !METHOD_RESPOND_TO.bind(obj).call(:inspect)
text(METHOD_INSPECT.bind(obj).call)
else
super
end
Expand Down
14 changes: 13 additions & 1 deletion test/irb/test_context.rb
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,6 @@ def test_output_to_pipe
failed: [
[false, "BasicObject.new", /#<NoMethodError: undefined method `to_s' for/],
[:p, "class Foo; undef inspect ;end; Foo.new", /#<NoMethodError: undefined method `inspect' for/],
[true, "BasicObject.new", /#<NoMethodError: undefined method `is_a\?' for/],
[:yaml, "BasicObject.new", /#<NoMethodError: undefined method `inspect' for/],
[:marshal, "[Object.new, Class.new]", /#<TypeError: can't dump anonymous class #<Class:/]
]
Expand All @@ -150,6 +149,19 @@ def test_output_to_pipe
end
end

def test_object_inspection_handles_basic_object
verbose, $VERBOSE = $VERBOSE, nil
irb = IRB::Irb.new(IRB::WorkSpace.new(Object.new), TestInputMethod.new(["BasicObject.new"]))
out, err = capture_output do
irb.eval_input
end
assert_empty err
assert_not_match(/NoMethodError/, out)
assert_match(/#<BasicObject:.*>/, out)
ensure
$VERBOSE = verbose
end

def test_object_inspection_falls_back_to_kernel_inspect_when_errored
verbose, $VERBOSE = $VERBOSE, nil
main = Object.new
Expand Down