为什么Ruby不自动执行to_s?

时间:2009-06-13 23:25:36

标签: ruby string metaprogramming

我有一个作者类:

class Author < ActiveRecord::Base
  def to_s
    name
  end
end

定义to_s允许我执行puts Author.first,但不能puts Author.first.rjust(10)

NoMethodError: undefined method `rjust' for #<Author:0x21eb5d4>

如果像这样的情况下Ruby在字符串方法之前自动尝试to_s,那会不会更好?有没有办法解决这个问题?

4 个答案:

答案 0 :(得分:18)

首先,不,它不会。我不希望ruby只是说“嘿,也许这是一个字符串方法,让我看看我是否可以在任意对象上运行to_s后运行它。话虽这么说,你想做的事情有两种解决方案:

如果你想说“在任何Author个实例上,如果有人调用了一个它没有的方法,但是String会这样做,那么它应该神奇地调用to_s” ,然后这样做:

class Author < ActiveRecord::Base
  def to_s
    name
  end

  def method_missing(s, *a)
    x = to_s
    if x.respond_to? s then
      return x.send(s, *a)
    else
      super
    end
  end
end

如果你想对任何不是字符串的任何内容说“rjust应该首先调用to_s”,那么:

class Object
  def rjust(*a)
    to_s.rjust(*a)
  end
end

(根据需要重复其他方法;请注意,这可以让您执行86.rjust(10)之类的事情;这是否是好事可能是品味问题)

答案 1 :(得分:2)

如果像这样的情况下Ruby在字符串方法之前自动尝试to_s会不会更好?

你要求一种语言“只是做我的意思(大部分时间)”,这是一个滑坡。“虽然在许多情况下它可能有意义,但它必然会在边缘附近弄脏东西。在你的情况下,谁说 rjust 不是在Author(或其中一个超类)上定义的方法。

答案 2 :(得分:2)

答案 3 :(得分:1)

实际上......有一种方法可以做一些与此类似的事情:to_str

但是,对于这种特殊情况,它仍然不会被隐式调用。 Ruby中存在to_str方法实际上等同于说:“通常将String作为参数的任何方法都可以通过调用to_str方法将该对象隐式转换为String。”标准库中的大多数方法都会尝试使用这种技术来强制转换为String,而且许多第三方库也会这样做。

但是,在您给出的示例中,Ruby检测到未处理的消息是类似字符串并进行转换是绝对不合适的。这将导致许多非String相关代码中的各种错误,错误和一般错误行为,尤其是那些像Builder一样依赖于正常缺失方法行为的代码。