2010-04-24 103 views
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 

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

回答

0

require实际上是一种方法,它是Kernel#require(它调用rb_require_safe),这样你至少可以在猴子打补丁的版本执行您的两轮牛车。如果你喜欢那种事情。

  • 别名一部开拓创新要求的方式进行
  • 如果传递的绝对路径,调用原始创建一个绝对路径并调用原来需要方法
  • 否则迭代过载路径需要方法。

只是为了好玩,我有一个快速打击,原型在下面。这没有完全测试,我没有检查rb_require_safe的语义,你可能也需要看#load#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' ] 
+0

尽管有额外的代码,但它好得多比不得不使用全局变量。 – 2010-04-25 18:54:39

3

由于$:是一个数组,你必须小心你正在做什么。您需要稍后复印(通过dup)和replace。这是简单简单地删除已添加的东西,虽然:

def foo 
    $: << special_path 

    # Do work ... 
    bar() 

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

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

+0

这似乎稍微比较明智的,但我希望有会是一种 “作用域” $'的版本:'。否则,如果你能以某种方式请求'require'来搜索一个特定的路径列表(也就是你指定的列表,而不是从'$:'中获取它),那么也是很好的。尽管如此,+1! – 2010-04-24 20:42:29

+1

@John,你可以很容易地创建你自己的作用域的版本$ :(虽然它不会在词汇范围内:如果“scoped $:”内的函数在该作用域之外进行调用,修改后的$:将会生效。只需使用“begin; $:<< special_path; yield;确保$ :. delete(special_path)end”。将它转换为一个方法,将其折腾成一个Module,让它休息五分钟,然后用一个漂亮的红色 – 2010-04-25 05:41:59

+0

案例:'$:'_already_包含'special_path'('#delete'将删除所有出现的'special_path') – 2010-04-25 08:21:47