2010-01-16 8 views
44

Usted puede definir dinámicamente un método de clase para una clase de este modo:Extracción/undefining un método de clase

class Foo 
end 

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

Pero, ¿cómo hacer lo contrario: remove/undefine un método de clase? Sospecho que los métodos remove_method y undef_method del Módulo podrían usarse para este propósito, pero todos los ejemplos que he visto después de buscar en Google durante horas han sido para eliminar/undefinir los métodos de instancia , no los métodos de clase. O tal vez hay una sintaxis que puede pasar al instance_eval para hacer esto también.

Gracias de antemano.

Respuesta

55
#!/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) 

Cuando define un método de clase como Foo.bar, Ruby lo ubica en la clase de usuario de Foo. Ruby no puede ponerlo en Foo, porque entonces sería un método de instancia. Rubí crea eigenclass de Foo (también conocido como "clase singleton"), establece la superclase de los eigenclass a la superclase de Foo, y luego establece la superclase de Foo a los eigenclass:

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

Es por eso que tenemos que abrir eigenclass de Foo usando class <<Foo a eliminar la barra de métodos.

+0

bingo. Gracias Wayne! –

+1

Hubiera pensado que sería posible sin usar Eigenclass, al menos en 1.9. –

+0

@Andrew, Tal vez. Por desgracia, no lo sé. –

-2

Object.send (: remove_const,: Foo)

+2

¿Eso no elimina toda la clase? –

+1

sí, eliminará la clase Foo – edikgat

+3

Técnicamente esta respuesta no es inexacta (es decir, esta es, de hecho, una forma de eliminar métodos de clase), ya que al eliminar la clase Foo también elimina todos los métodos de clase en Foo: P: P :PAG. Es decir, obviamente no es lo que el OP realmente quiere, pero técnicamente no es * falso *. Otras respuestas técnicamente correctas: 1) matar el proceso que contiene Ruby; 2) reiniciar el sistema operativo; 3) arrojar la computadora a un lago; 4) arrojar una bomba nuclear cerca; 5) disparar una supernova; 6) Espera la muerte por calor del universo. –

17

Esto también funciona para mí (no estoy seguro si hay diferencias entre undef y 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 
+0

Esto funcionó para mí. Lo llamé a un objeto y solo lo eliminé en el nivel del objeto. Foo.new.instance_eval {undef: color} también funciona. –

+1

método_muerto quita el método de la clase de receptor donde undef_method quitó todos los métodos de la clase heredada, incluida la clase de receptor. –

6

supongo que no puedo comentar en la respuesta de Adrián porque no tengo suficiente crédito, pero su respuesta me ayudó.

Lo que encontré: undef parece eliminar por completo el método de la existencia, mientras que remove_method lo elimina de esa clase, pero todavía será definido en superclases u otros módulos que se han extened en esta clase, etc.

+0

En Ruby 2.4 parece ser 'undef_method' ahora. – Kris

3

Si desea eliminar método con el nombre de lo que calcular de forma dinámica, se debe utilizar como 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 

esta manera es mejor que otras respuestas, lástima pues aquí he utilizado class_eval con el bloque. Como ahora bloquea, vea el espacio de nombres actual, para poder usar sus variables para eliminar métodos dinámicamente

4

Puede eliminar un método de dos maneras sencillas. El drástico

Module#undef_method() 

elimina todos los métodos, incluidos los heredados. El Kinder

Module#remove_method() 

quita el método del receptor, pero hojas métodos heredados solo.

Ver por debajo de 2 ejemplo sencillo -

Ejemplo 1 usando 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 

resultado - main.rb: 15: en ': undefined method x' para # (NoMethodError)

Ejemplo 2 usando 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 

Resultado - $ rubí main.rb

x de una clase

Cuestiones relacionadas