4

我正在为一个复杂的项目使用一堆 Rake 任务做一些诡计,一次逐步地重构掉一些复杂性。这暴露了前一个项目维护者留下的奇怪的依赖网络。

我想做的是将项目中的特定路径添加require到要搜索的路径列表中,即$:. 但是,我只希望在一种特定方法的上下文中搜索该路径。现在我正在做这样的事情:

def foo()
  # Look up old paths, add new special path.
  paths = $:
  $: << special_path

  # Do work ...
  bar()
  baz()
  quux()

  # Reset.
  $:.clear
  $: << paths
end

def bar()
  require '...' # If called from within foo(), will also search special_path.
  ...
end

这显然是一个可怕的黑客攻击。有没有更好的办法?

4

2 回答 2

3

因为$:是一个数组,所以你必须小心你在做什么。您需要复制(通过dup),replace然后再复制。但是,简单地删除您添加的内容会更简单:

def foo
  $: << special_path

  # Do work ...
  bar()

ensure
  # Reset.
  $:.delete(special_path)
end

没有更多信息,很难知道是否有更好的方法。

于 2010-04-24T20:26:26.767 回答
0

require实际上是一种方法,它是Kernel#require(调用rb_require_safe)所以你至少可以在猴子补丁版本中执行你的hackery。如果你喜欢那种东西。

  • 原始要求的别名
  • 如果传递的是绝对路径,调用原来的require方法
  • 否则通过创建绝对路径并调用原始 require 方法来迭代加载路径。

只是为了好玩,我对此进行了快速的抨击,原型如下。这没有经过全面测试,我还没有检查 的语义rb_require_safe,您可能还需要查看#loadand#include以确保完整性——这仍然是Kernel模块的猴子补丁。它可能并不完全是可怕的,但它肯定是一个黑客。如果它比弄乱全局$:变量好还是坏,您的电话。

module Kernel

  alias original_require require

  # Just like standard require but takes an
  # optional second argument (a string or an
  # array of strings) for additional directories
  # to search.
  def require(file, more_dirs=[])
    if file =~ /^\// # absolute path
      original_require(file)
    else
      ($: + [ more_dirs ].flatten).each do |dir|
        path = File.join(dir, file)
        begin
          return original_require(path)
        rescue LoadError
        end
      end
      raise LoadError,
        "no such file to load -- #{file}"
    end
  end

end

例子:

require 'mymod'
require 'mymod', '/home/me/lib'
require 'mymod', [ '/home/me/lib', '/home/you/lib' ]
于 2010-04-25T09:31:18.230 回答