исправление обезьяны vs class_eval? - PullRequest
14 голосов
/ 22 февраля 2012
class String
  def hello
    "world"
  end
end

String.class_eval {
  def world
    "hello"
  end
}

"a".world
=> "hello"
"b".hello
=> "world"

Кажется, они делают то же самое - добавление метода в существующий класс. Так в чем же разница?

Ответы [ 3 ]

13 голосов
/ 24 апреля 2012

class_eval сделать концептуально повторное открытие класса (или исправление обезьяны). В основном это синтаксические различия. Если вы передаете строку в class_eval (как в примере Майкла), у вас в основном тот же синтаксис внутри строки, что и в class String; ... end. Если вы передаете блок: String.class_eval { ... }, он сравнивается следующим образом:

  • внутри блока class_eval видны внешние локальные переменные
  • внутри вновь открытого класса внешние локальные переменные НЕ видимы
  • внутри class_eval вы НЕ МОЖЕТЕ присваивать константы и переменные класса в пределах класса
  • внутри вновь открытого класса вы можете

Было бы интересно узнать другие различия

13 голосов
/ 22 февраля 2012

С class_eval вы можете делать более динамичные вещи:

>> met = "hello" #=> "hello"
>> String.class_eval "def #{met} ; 'hello' ; end" #=> nil
>> "foo".hello #=> "hello"
0 голосов
/ 29 июня 2016

Другие ответы хороши. Хочу добавить, что class_eval можно использовать, когда вы хотите, чтобы ссылочный класс не являлся его константой или исправлял определенный объект.

, например

huh = String
class huh
end
SyntaxError: (eval):2: class/module name must be CONSTANT

huh.class_eval <<-eof
def mamma
puts :papa
end
eof

"asdff".mamma
=> papa

Вы можете использовать class_eval для исправления определенного объекта, не затрагивая весь корневой класс.

obj = "asd"
obj.singleton_class.class_eval <<-eof
def asd
puts "gah"
end
undef_method :some_method

Вышеуказанное совпадает с:

class << obj
  ...
end

instance_eval будет иметь немного другое поведение при некотором использовании.

Я нахожу этот вопрос и ответы интересными: Как обезьяна пропатчить класс ruby ​​внутри метода

Также были вопросы по поводу instance_eval против class_eval, но у меня нет удобной ссылки.

...