Navigation Menu

Skip to content

Commit

Permalink
puts: Make it more compatible to MRI
Browse files Browse the repository at this point in the history
- puts calls #to_ary on non-String objects, without checking its existance beforehand.
  This behavior is copied for cases where the receiver has a #method_missing in place that catches this call

- If puts calls #to_s, and #to_s does not return a string (e.g. some bogus override of #to_s), it outputs generic object infos (Class name and address)
  • Loading branch information
andre-richter committed Jan 10, 2016
1 parent 179b77b commit 135145a
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 7 deletions.
14 changes: 9 additions & 5 deletions kernel/common/io.rb
Expand Up @@ -1793,16 +1793,20 @@ def puts(*args)
args.each do |arg|
if arg.equal? nil
str = ""
elsif arg.kind_of? String
str = arg
elsif Thread.guarding? arg
str = "[...]"
elsif arg.respond_to?(:to_ary)
else
Thread.recursion_guard arg do
arg.to_ary.each do |a|
puts a
begin
arg.to_ary.each { |a| puts a }
rescue NoMethodError
unless (str = arg.to_s).kind_of? String
str = "#<#{arg.class}:0x#{arg.object_id.to_s(16)}>"
end
end
end
else
str = arg.to_s
end

if str
Expand Down
23 changes: 21 additions & 2 deletions spec/ruby/core/io/puts_spec.rb
Expand Up @@ -37,7 +37,17 @@
@io.puts(nil, nil).should == nil
end

it "calls to_ary before writing non-string objects that respond to :to_ary" do
it "calls :to_ary before writing non-string objects, regardless of it being implemented in the receiver" do
object = mock('hola')
object.should_receive(:method_missing).with(:to_ary)
object.should_receive(:to_s).and_return("#<Object:0x...>")

@io.should_receive(:write).with("#<Object:0x...>")
@io.should_receive(:write).with("\n")
@io.puts(object).should == nil
end

it "calls :to_ary before writing non-string objects" do
object = mock('hola')
object.should_receive(:to_ary).and_return(["hola"])

Expand All @@ -46,7 +56,7 @@
@io.puts(object).should == nil
end

it "calls to_s before writing non-string objects that don't respond to :to_ary" do
it "calls :to_s before writing non-string objects that don't respond to :to_ary" do
object = mock('hola')
object.should_receive(:to_s).and_return("hola")

Expand All @@ -55,6 +65,15 @@
@io.puts(object).should == nil
end

it "returns general object info if :to_s does not return a string" do
object = mock('hola')
object.should_receive(:to_s).and_return(false)

@io.should_receive(:write).with(object.inspect.split(" ")[0] + ">")
@io.should_receive(:write).with("\n")
@io.puts(object).should == nil
end

it "writes each arg if given several" do
@io.should_receive(:write).with("1")
@io.should_receive(:write).with("two")
Expand Down

0 comments on commit 135145a

Please sign in to comment.