Подтвердить что ты не робот

Удаление/определение метода класса

Вы можете динамически определить метод класса для такого класса:

class Foo
end

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

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

Спасибо заранее.

4b9b3361

Ответ 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)