Метод патча обезьяны на одном объекте

Я хотел бы переопределить поведение метода update_attributes на единственном экземпляре класса модели. Предполагая, что переменная называется @alert, как лучше всего это сделать? Чтобы было ясно, я не хочу изменять поведение этого метода для всего класса.


ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ:

Мне нужно сделать это, чтобы заставить метод возвращать false, когда я хочу, чтобы я мог писать модульные тесты для следующего кода обработки ошибок. Я понимаю, что это не лучшая практика.


person Steve    schedule 04.06.2015    source источник
comment
Я собирался исправить ваше использование термина «обезьяний патч» - полагая, что он применяется только к модификациям встроенных методов Ruby, - но после поиска в Google выяснилось, что нет единого мнения относительно его значения. См., Например, этот вопрос SO.   -  person Cary Swoveland    schedule 05.06.2015
comment
@CarySwoveland Исторически денежный патч означает замену существующих методов вашими собственными реализациями, когда они полностью берут верх. В данном случае это скорее фиктивная операция, при которой изменяется только один объект, а другие объекты, как существующие, так и созданные в будущем, не затрагиваются.   -  person tadman    schedule 05.06.2015
comment
Это очень похоже на заглушку метода, которую подойдет любая приличная среда тестирования.   -  person zetetic    schedule 05.06.2015


Ответы (2)


Просто определите метод для объекта:

class Thing
  def greeting
    'yo, man'
  end
end

Thing.instance_methods(false)
  #=> [:greeting]

object = Thing.new
  #=> #<Thing:0x007fc4ba276c90> 

object.greeting
  #=> "yo, man" 

Определите два метода для object (которые будут методами экземпляра в одноэлементном классе object.

def object.greeting
  'hey, dude'
end

def object.farewell
  'see ya'
end

object.methods(false)
  #=> [:greeting, :farewell] 
object.singleton_class.instance_methods(false) #=> [:greeting, :farewell]

object.greeting
  #=> "hey, dude" 
object.farewell
  #=> "see ya"

new_obj = Thing.new
new_obj.greeting
  #=> "yo, man"
new_obj.farewell
  #NoMethodError: undefined method `farewell' for #<Thing:0x007fe5a406f590>

Удалите одноэлементный метод object greeting.

object.singleton_class.send(:remove_method, :greeting)

object.methods(false)
  #=> [:farewell] 
object.greeting
  #=> "yo, man"

Другой способ удалить :greeting из одноэлементного класса object заключается в следующем.

class << object
  remove_method(:greeting)
end
person Cary Swoveland    schedule 04.06.2015
comment
Иногда это делается более чисто, создавая модуль и смешивая его с отдельным объектом. - person tadman; 05.06.2015
comment
Опечатка: Thing.new hi должно быть Thing.new.hi. Тогда исключение будет NoMethodError: undefined method `hi' for #<Thing:0x000000.......> вместо NameError: .... - person nitsas; 02.03.2017

После создания объекта вызовите для него команду "define_method":

object = Thing.new
object.define_method("update_attributes") { return false }

После этого object.update_attributes должен вернуть false

person David Hoelzer    schedule 04.06.2015
comment
Объект наследуется от ActiveRecord::Base, и я получаю NoMethodError попытку вызвать define_method на нем. Любая идея? Это может быть очевидно, но я относительно новичок в тонкостях Ruby on Rails. - person Steve; 04.06.2015
comment
define_method определен только на Module, но object не Module, это Thing. - person Jörg W Mittag; 05.06.2015