【问题标题】:How to remove a class method?如何删除类方法?
【发布时间】:2016-11-19 21:38:15
【问题描述】:

我正在使用 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? 

【问题讨论】:

    标签: ruby


    【解决方案1】:

    您的困难不在于方法是类方法,而是因为该方法是在模块中定义的。首先你要清楚remove_methodundef_method的区别。

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

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

    然而,在你扩展类的模块上调用remove_method 会起作用。这将停止使用 bur 的 settings 的实现,如果该类使用另一个模块定义该方法进行扩展,则不会干扰。

    【讨论】:

    • 谢谢!这对我有进一步的帮助。但是,如果我理解得很好,那么执行您的建议只会影响将使用此模块的所有内容,而不仅仅是我试图影响的类。
    • 哦,我明白了,我可以将模块更改为使用extended (base),以便直接在接收器的单例类上定义方法。
    • 它会影响使用该模块的每个人,但正如您所展示的那样,该模块永远不会被重用。
    猜你喜欢
    • 2012-07-12
    • 1970-01-01
    • 2011-02-14
    • 2016-05-28
    • 1970-01-01
    • 2019-10-19
    • 1970-01-01
    • 2021-11-05
    • 2014-04-12
    相关资源
    最近更新 更多