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_method
和undef_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的本征类.
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)
我想我无法评论阿德里安的回答,因为我没有足够的信誉,但他的答案对我有帮助.
我发现:undef
似乎完全删除了该方法,同时remove_method
将其从该类中删除,但它仍将在超类或已在此类上扩展的其他模块上定义,等等.
您可以通过两种简单的方式删除方法。激烈的
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 method
x' 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 类