Почему Ruby не выполняет автоматически to_s? - PullRequest
0 голосов
/ 14 июня 2009

У меня есть авторский класс:

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 ]

18 голосов
/ 14 июня 2009

Во-первых, нет, не будет. Я не хочу, чтобы 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); хорошо это или нет, может быть вопросом вкуса)

2 голосов
/ 17 июня 2009
2 голосов
/ 14 июня 2009

Не было бы лучше, если бы Ruby автоматически пытался to_s перед строковым методом в подобных случаях?

Вы идете по скользкому склону, прося язык «просто делать то, что я имею в виду (большую часть времени)». Хотя это может иметь смысл во многих случаях, оно неизбежно запутывает вещи по краям. В вашем случае, кто скажет, что rjust не является методом, определенным в Author (или одном из его суперклассов).

1 голос
/ 15 июня 2009

На самом деле ... есть метод, который сделал бы что-то неопределенно похожее на это: to_str

Однако, это все еще не будет вызвано неявно для этого конкретного случая. Существование метода to_str в Ruby фактически эквивалентно высказыванию: «Любой метод, который обычно принимает строку в качестве параметра, может неявно преобразовать этот объект в строку, вызвав метод to_str». Большинство методов в стандартной библиотеке будут пытаться использовать эту технику для приведения к String, как и многие сторонние библиотеки.

В приведенном вами примере, однако, было бы совершенно неуместно, чтобы Ruby обнаруживал, что необработанное сообщение было String-like, и конвертировал. Это может привести к всевозможным ошибкам, ошибкам и общему неправильному поведению во многих кодах, не относящихся к String, особенно к любому коду, подобному Builder, который использует обычное поведение отсутствующего метода.

...