在ruby中重新打开命名空间的类 - 初始化重写?

时间:2014-06-30 16:29:31

标签: ruby-on-rails ruby

我在命名空间中使用一些方法获得了一个类

module Foo
  module Bar
    class Baz
      def initialize(arg1, arg2, arg3)
        # do stuff
      end

      def delete
        File.delete(@path)
      end
    end
  end
end

在我的测试环境中,我不希望delete删除任何文件,所以在TestHelper中我会这样做

class Foo::Bar::Baz
  def delete
    puts "no delete in test"
  end
end

当我在测试中初始化此类时,我得到ArgumentError: wrong number of arguments (3 for 0)。也就是说,Baz的初始化方法已经消失。可以肯定的是,如果我在测试助手中查看self,则Baz根本没有定义任何方法。它已被class关键字完全覆盖。

我可以使用class_eval而不是class来实现它,我,e。

Foo::Bar::Baz.class_eval do
  def delete
    # etc
  end
end

我的问题是,有什么区别?为什么后者有效而不是前者?

1 个答案:

答案 0 :(得分:1)

我可能错了,但我认为您不小心打破了自动加载器。以下是我认为您的工作案例(使用.class_eval):

  1. 某处,某处,加载定义Foo::Bar的代码(如果没有发生,您将收到其他错误)
  2. 解析测试代码;明确要求TestHelper
  3. TestHelper引用Foo::Bar::Baz,但不存在
  4. 自动加载器查找并加载foo/bar/baz.rb
  5. TestHelper运行class_eval并重新定义#delete
  6. 运行测试代码
  7. 这是我对非工作案例的猜测:

    1. 同样,在某处,某些内容会加载定义Foo::Bar
    2. 的代码
    3. 解析测试代码;明确要求TestHelper
    4. TestHelper 创建 Foo::Bar::Baz,因为它尚未存在
    5. 运行测试代码
    6. 请注意,在第二种情况下,自动加载器从未被触发,因此永远不会加载您的实际类定义。

      我不确定解决此问题的最佳方法。您可以在测试中执行明确的要求,或者在重新定义之前仅在助手中引用该类:

      Foo::Bar::Baz # trigger autoloading before we muck with the definition
      class Foo::Bar::Baz
        def delete
          puts "no delete in test"
        end
      end
      
相关问题