Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In ruby, custom method does not work on File builtin class

I want to create a custom method on Object class and Array class. It works perfectly with array of Integer, Strings, etc. but not for File. Weird!

class Object
    def foo
        puts("Object#foo on #{self.inspect}")
    end
end

class Array
    def foo
        puts("Array#foo on #{self.inspect}")
        self.each do |e| 
            e.foo
        end
    end
end

Then,

a = [1,2]
a.foo

Displays:

Array#foo on [1, 2]
Object#foo on 1
Object#foo on 2

But,

b = [File.new('f1','w'),File.new('f2','w')]
b.foo

Only displays:

Array#foo on [#<File:f1>, #<File:f2>]

like image 887
jean marc Avatar asked Sep 17 '25 23:09

jean marc


1 Answers

Your issue is not Object#foo, instead it is the fact that you are assuming puts is Kernel#puts; however, in the context of File it is actually IO#puts.

puts(obj, ...) → nil

Writes the given object(s) to ios. Writes a newline after any that do not already end with a newline sequence. Returns nil.

The stream must be opened for writing. If called with an array argument, writes each element on a new line. Each given object that isn’t a string or array will be converted by calling its to_s method. If called without arguments, outputs a single newline.

So instead of outputting to STDOUT as you are expecting it is writing that puts statement to the file (which is the ios in this case).

To solve this you can call Kernel#puts explicitly:

class Object
  def foo
    Kernel.puts("Object#foo on #{self.inspect}")
  end
end

Then

b = [File.new('f1','w'),File.new('f2','w')]
b.foo
# Array#foo on [#<File:f1>, #<File:f2>]
# Object#foo on #<File:f1>
# Object#foo on #<File:f2>
# => [#<File:f1>, #<File:f2>]

Pedantic implementation detail

Technically speaking Kernel#puts is $stdout.puts, which is IO#puts where $stdout is the ios but when you call puts (without a receiver) in the general context of Object (including main) it is the Kernel#puts method you are calling because of the Kernel module's inclusion in Object.

like image 141
engineersmnky Avatar answered Sep 19 '25 17:09

engineersmnky