删除/取消定义类方法

时间:2010-01-16 23:00:34

标签: ruby metaprogramming

您可以动态定义类的类方法,如下所示:

class Foo
end

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

但是你如何做相反的事情: 删除/取消定义 一个类方法?我怀疑Module的remove_methodundef_method方法可以用于此目的,但是我在谷歌搜索几个小时之后看到的所有示例都是用于删除/取消定义实例方法,而不是类方法。或者也许有一种语法可以传递给instance_eval来执行此操作。

提前致谢。

6 个答案:

答案 0 :(得分:61)

#!/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的本征类(又名“单例类”),将本征类的超类设置为Foo的超类,然后将Foo的超类设置为本征类:

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

这就是为什么我们必须使用class <<Foo打开Foo的本征类来删除方法栏。

答案 1 :(得分:18)

这对我也有用(不确定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

答案 2 :(得分:6)

我想我无法评论阿德里安的回答,因为我没有足够的信誉,但他的回答对我有帮助。

我发现:undef似乎完全删除了该方法,而remove_method将该类从该类中删除,但它仍将在超类或其他已扩展的模块上定义上课等。

答案 3 :(得分:4)

您可以通过两种简单的方法删除方法。激烈的

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: ': 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

来自A类

答案 4 :(得分:3)

如果您想删除名称为dinamically计算的方法,您应该使用如下的特征类:

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和block。正如您现在阻止查看当前命名空间,因此您可以使用您的变量来删除方法

答案 5 :(得分:-2)

Object.send(:remove_const,:Foo)