简体   繁体   中英

Cannot override to_s in irb

I defined a function :to_s in pry, but I am not able to call it. Where does this method go and how can I call it?

pry(main)> def to_s
pry(main)*   'hello'
pry(main)* end
pry(main)> to_s
=> "main"

My ruby version is 2.1.2

After reading some answers and searching, I think I have got the right answer:

  1. Where does this method to?

when define a method in irb or pry, it goes to Object.instance_methods

[1] pry(main)> def to_s
[1] pry(main)*   'hello'
[1] pry(main)* end
=> :to_s
[2] pry(main)> def hello
[2] pry(main)*   'world'
[2] pry(main)* end
=> :hello
[4] pry(main)> Object.instance_methods(false)
=> [:pry, :__binding__, :to_s, :hello]
  1. How can I call it?

These new methods can be called in a new object.

[6] pry(main)> Object.new.to_s
=> "hello"

The reason I'm not able to call to_s in top-level is that main is a special object which defined a #to_s and #inspect method.

[5] pry(main)> singleton_class.instance_methods(false)
=> [:to_s, :inspect]

@Anthony's answer explains the context. To define your own to_s at this level, you could do it this way:

pry(main)> to_s
=> "main"
pry(main)> def self.to_s
pry(main)*   'hello'
pry(main)* end
pry(main)> to_s
=> "hello"

You're actually at the top level Object class#to_s method which as the docs states:

Returns a string representing obj. The default to_s prints the object's class and an encoding of the object id. As a special case, the top-level object that is the initial execution context of Ruby programs returns “main”.

Methods defined at the toplevel become private instance methods of Object .

So,

def to_s; 'hello' end

is equivalent to

class Object; private def to_s; 'hello' end end

And message sends without an explicit receiver are implicitly sent to self .

So,

to_s

is equivalent to

self.to_s

At the top-level, self is the nameless top-level object, usually called main .

Now, if any of the classes of main override Object#to_s , then the overridden version will be called. And in fact, to_s is overridden in the singleton class of main :

method(:to_s).owner
# => #<Class:#<Object:0x007fb5210c1c68>>

Another, admittedly verbose, way to accomplish what you're trying to do is to manipulate the "current" class, like so:

class << self
  def to_s
    "hello"
  end
end

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM