Удаление/определение метода класса
Вы можете динамически определить метод класса для такого класса:
class Foo
end
bar = %q{def bar() "bar!" end}
Foo.instance_eval(bar)
Но как вы делаете обратное: удалить/не определить метод класса? Я подозреваю, что для этой цели могут быть использованы методы Module remove_method
и undef_method
, но все примеры, которые я видел после Googling в течение нескольких часов, были для удаления/исключения методов экземпляра, а не методов класса. Или, возможно, есть синтаксис, который вы можете передать в instance_eval
, чтобы сделать это.
Спасибо заранее.
Ответы
Ответ 1
#!/usr/bin/ruby1.8
class Foo
def Foo.bar
puts "bar"
end
end
Foo.bar # => bar
class <<Foo
remove_method :bar
end
Foo.bar # => undefined method `bar' for Foo:Class (NoMethodError)
Когда вы определяете метод класса, такой как Foo.bar, Ruby помещает его в Foo eigenclass. Ruby не может поместить его в Foo, потому что тогда это будет метод экземпляра. Ruby создает Foo eigenclass (aka "singleton class" ), устанавливает суперкласс класса eugenclass в суперкласс Foo и затем устанавливает суперкласс Foo в eigenclass:
Foo -------------> Foo(eigenclass) -------------> Object
super def bar super
Вот почему нам нужно открыть Foo eigenclass, используя class <<Foo
, чтобы удалить панель методов.
Ответ 2
Это также работает для меня (не уверен, есть ли различия между undef и remove_method):
class Foo
end
Foo.instance_eval do
def color
"green"
end
end
Foo.color # => "green"
Foo.instance_eval { undef :color }
Foo.color # => NoMethodError: undefined method `color' for Foo:Class
Ответ 3
Думаю, я не могу прокомментировать ответ Адриана, потому что у меня недостаточно кредитов, но его ответ помог мне.
Что я нашел: undef
, кажется, полностью удаляет этот метод из существования, а remove_method
удаляет его из этого класса, но он все равно будет определен на суперклассах или других модулях, которые были расширены в этом классе и т.д.
Ответ 4
Если вы хотите удалить метод с именем, который вычисляется динамически, вы должны использовать eigenclasses, например:
class Foo
def self.bar
puts "bar"
end
end
name_of_method_to_remove = :bar
eigenclass = class << Foo; self; end
eigenclass.class_eval do
remove_method name_of_method_to_remove
end
этот способ лучше, чем другие ответы, потому что здесь я использовал class_eval с блоком. Поскольку теперь вы блокируете просмотр текущего пространства имен, чтобы вы могли использовать свои переменные для динамического удаления методов
Ответ 5
Вы можете удалить метод двумя способами. Резкий
Module#undef_method( )
удаляет все методы, включая унаследованные. Более добрый
Module#remove_method( )
удаляет метод из приемника, но он
оставляет только унаследованные методы.
См. ниже 2 простых примера -
Пример 1 с использованием undef_method
class A
def x
puts "x from A class"
end
end
class B < A
def x
puts "x from B Class"
end
undef_method :x
end
obj = B.new
obj.x
результат -
main.rb: 15: in
': undefined method
x 'для # (NoMethodError)
Пример 2 с использованием remove_method
class A
def x
puts "x from A class"
end
end
class B < A
def x
puts "x from B Class"
end
remove_method :x
end
obj = B.new
obj.x
Результат -
$ ruby main.rb
x из класса A
Ответ 6
Object.send(: remove_const,: Foo)