Удаление / отмена определения метода класса - PullRequest
48 голосов
/ 17 января 2010

Вы можете динамически определить метод класса для класса следующим образом:

class Foo
end

bar = %q{def bar() "bar!" end}
Foo.instance_eval(bar)

Но как сделать наоборот: удалить / отменить определение метод класса? Я подозреваю, что для этой цели можно было бы использовать методы модуля remove_method и undef_method, но все примеры, которые я видел после Googling в течение нескольких часов, касались удаления / отмены определения instance методов, а не методы класса. Или, может быть, есть синтаксис, который вы можете передать instance_eval, чтобы сделать это тоже.

Заранее спасибо.

Ответы [ 6 ]

61 голосов
/ 17 января 2010
#!/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. Ruby не может поместить это в Foo, потому что тогда это будет метод экземпляра. Ruby создает собственный класс Foo (он же «класс singleton»), устанавливает суперкласс собственного класса в суперкласс Foo, а затем устанавливает суперкласс Foo в собственный класс:

Foo -------------> Foo(eigenclass) -------------> Object
        super      def bar             super

Вот почему мы должны открыть собственный класс Foo, используя class <<Foo для удаления панели методов.

18 голосов
/ 28 марта 2012

Это также работает для меня (не уверен, если есть различия между 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
6 голосов
/ 01 июня 2012

Полагаю, я не могу комментировать ответ Адриана, потому что мне не хватает доверия, но его ответ мне помог.

То, что я нашел: undef, кажется, полностью удаляет метод из существования, в то время как remove_method удаляет его из этого класса, но он все равно будет определен в суперклассах или других модулях, которые были расширены в этом классе и т. Д.

4 голосов
/ 15 декабря 2015

Вы можете удалить метод двумя простыми способами.Drastic

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

result - 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

3 голосов
/ 17 октября 2013

Если вы хотите удалить метод с именем, которое вычисляет динамически, вы должны использовать собственные классы, такие как:

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 с блоком. Теперь, когда вы блокируете текущее пространство имен, вы можете использовать свои переменные для динамического удаления методов

0 голосов
/ 19 июля 2011

Object.send (: remove_const,: Foo)

...