删除/取消定义类方法

Bri*_*etz 51 ruby metaprogramming

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

class Foo
end

bar = %q{def bar() "bar!" end}
Foo.instance_eval(bar)
Run Code Online (Sandbox Code Playgroud)

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

提前致谢.

Way*_*rad 66

#!/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)
Run Code Online (Sandbox Code Playgroud)

当你定义一个像Foo.bar这样的类方法时,Ruby会把它放到Foo的本征类中.Ruby不能把它放在Foo中,因为那样它就是一个实例方法.Ruby创建了Foo的本征类(又名"单例类"),将本征类的超类设置为Foo的超类,然后将Foo的超类设置为本征类:

Foo -------------> Foo(eigenclass) -------------> Object
        super      def bar             super
Run Code Online (Sandbox Code Playgroud)

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

  • 我本以为不使用 Eigenclass 也是可能的,至少在 1.9 中是这样。 (2认同)
  • @ joseph.hainline - 如果你有超类中的方法,那么在调用removed_method之后,该方法仍然可以调用.您可以使用undef_method来阻止它. (2认同)

Adr*_*eil 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
Run Code Online (Sandbox Code Playgroud)

  • remove_method 删除接收者类的方法,而 undef_method 删除了继承类中的所有方法,包括接收者类。 (2认同)

Jef*_*ran 6

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

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


Ram*_*are 6

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

Module#undef_method( ) 
Run Code Online (Sandbox Code Playgroud)

删除所有方法,包括继承的方法。善良的人

Module#remove_method( ) 
Run Code Online (Sandbox Code Playgroud)

从接收器中删除方法,但它会单独保留继承的方法。

请参阅下面的 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
Run Code Online (Sandbox Code Playgroud)

结果 - main.rb:15:in ': undefined methodx' for # (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
Run Code Online (Sandbox Code Playgroud)

结果 - $ruby main.rb

x 来自 A 类