如何删除类方法?

时间:2016-07-17 01:18:56

标签: ruby

我正在使用Mash.to_module(来自Hashie)来设置类。这工作正常,单元测试我的配置系统我希望能够重置此类方法。经过5个小时的挣扎,我终于找到了一种方法来删除类方法设置,但是我不能把它重新放回去...在undef之后是否有生命,或者是另一种删除类方法的方法? this question的解决方案似乎不起作用。我正在使用ruby 2.1.5。

以下是一些测试代码:

class Mash < Hash
    def to_module(mash_method_name = :settings)
      mash = self
      Module.new do |m|
        m.send :define_method, mash_method_name.to_sym do
          mash
        end
      end
    end
end

class B

    class << self

        def reset

            # singleton_methods.include? :settings               # true
            # methods.include? :settings                         # true
            # remove_method :settings                            # method `settings' not defined in #<Class:B>
            # send :remove_method, :settings                     # method `settings' not defined in #<Class:B>
            # singleton_class.remove_method, :settings           # method `settings' not defined in #<Class:B>

            # B.singleton_methods.include? :settings             # true
            # B.methods.include? :settings                       # true
            # B.send :remove_method, :settings                   # method `settings' not defined in #<Class:B>
            # B.singleton_class.send :remove_method, :settings   # method `settings' not defined in #<Class:B>

            # methods.include?( :settings ) and undef :settings  # unexpected keyword undef
            undef :settings if methods.include?( :settings )     # works

        end
    end

end

B.extend Mash.new.to_module
b = B.new

B.settings # {}
# b.settings # undefined method `settings' <- intented behaviour

# B.instance_eval { remove_method :settings } # `remove_method': method `settings' not defined in B
# B.instance_eval { undef :settings } # WORKS !
B.reset

# B.settings # # undefined method `settings' <- GOOD!

B.extend Mash.new.to_module
B.settings # undefined method `settings' => OOPS, is there life after undef? 

1 个答案:

答案 0 :(得分:1)

您的难点不在于方法是类方法,而是因为该方法是在模块中定义的。首先,您需要明确remove_methodundef_method之间的区别。

remove_method从定义它的类/模块中删除一个方法(即包含相应def或调用define_method的方法)。如果您尝试调用该方法,ruby仍会尝试搜索超类和包含的模块。这里remove_method不适合你,因为接收器是B的单例类,但是那里没有定义方法(它是在匿名模块上定义的),因此没有在类上定义方法的错误。

undef_method阻止类响应方法,无论该方法的定义位置如何。这就是为什么在调用undef_method之后扩展新模块不起作用的原因:你告诉ruby不要搜索祖先的那个方法。

然而,在您扩展课程的模块上调用remove_method会起作用。这将停止使用settings正在使用的bur的执行不会干扰如果类扩展而另一个模块定义了该方法。