将目录添加到$ LOAD_PATH(Ruby)

时间:2009-05-07 21:26:51

标签: ruby rubygems load-path

我已经看到了两种常用的技术,用于将当前正在执行的文件的目录添加到$ LOAD_PATH(或$ :)。如果你不使用宝石,我会看到这样做的好处。显然,一个看起来比另一个看起来更冗长,但是有理由与另一个相提并论吗?

第一个详细的方法(可能是过度杀伤):

$LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__))) unless $LOAD_PATH.include?(File.expand_path(File.dirname(__FILE__)))

更直接,快速和肮脏:

$:.unshift File.dirname(__FILE__)

任何理由与其中一个相提并论?

7 个答案:

答案 0 :(得分:144)

Ruby加载路径通常被视为写为$:,但仅仅因为它很短,不会使它变得更好。如果你喜欢清晰到聪明,或者因为简洁本身就会让你发痒,你不需要仅仅因为其他人都这样做。 跟你打招呼......

$LOAD_PATH

......告别......

# I don't quite understand what this is doing...
$:

答案 1 :(得分:48)

我会说$:.unshift File.dirname(__FILE__)超过另一个,只是因为我在代码中看到它比$LOAD_PATH更多地使用它,而且它也更短了!

答案 2 :(得分:21)

我不太喜欢“快速而肮脏”的方式。 任何刚接触Ruby的人都会思考$:.是什么。

我发现这更明显。

libdir = File.dirname(__FILE__)
$LOAD_PATH.unshift(libdir) unless $LOAD_PATH.include?(libdir)

或者如果我关心完整的路径...

libdir = File.expand_path(File.dirname(__FILE__))
$LOAD_PATH.unshift(libdir) unless $LOAD_PATH.include?(libdir)

更新 2009/09/10

最近我一直在做以下事情:

$:.unshift(File.expand_path(File.dirname(__FILE__))) unless
    $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))

我在浏览GitHub时在一大堆不同的ruby项目中看过它。

似乎是惯例?

答案 3 :(得分:8)

如果在Rails项目中键入script/console并输入$:,您将获得一个包含加载Ruby所需的所有目录的数组。这个小练习的结果是$:是一个数组。既然如此,您可以在其上执行函数,例如使用unshift方法或<<运算符添加其他目录。正如您在陈述中所暗示的那样$:$LOAD_PATH是相同的。

如上所述,以快速和脏的方式执行此操作的缺点是:如果您的引导路径中已有目录,则它将重复出现。

示例:

我创建了一个名为todo的插件。我的目录结构如下:

/---vendor
  |
  |---/plugins
        |
        |---/todo
              |
              |---/lib
                    |
                    |---/app
                          |
                          |---/models
                          |---/controllers
              |
              |---/rails
                    |
                    |---init.rb

在init.rb文件中,我输入了以下代码:

## In vendor/plugins/todo/rails/init.rb
    %w{ models controllers models }.each do |dir|
      path = File.expand_path(File.join(File.dirname(__FILE__), '../lib', 'app', dir))
      $LOAD_PATH << path
      ActiveSupport::Dependencies.load_paths << path
      ActiveSupport::Dependencies.load_once_paths.delete(path)
    end 

请注意我如何告诉代码块执行块内部对字符串'models','controllers'和'models'的操作,我重复'models'。 (仅供参考,%w{ ... }只是告诉Ruby保存字符串数组的另一种方法)。当我运行script/console时,我输入以下内容:

>> puts $:

我输入这个以便更容易阅读字符串中的内容。我得到的输出是:

...
...
./Users/Me/mySites/myRailsApp/vendor/plugins/todo/lib/app/models
./Users/Me/mySites/myRailsApp/vendor/plugins/todo/lib/app/controllers
./Users/Me/mySites/myRailsApp/vendor/plugins/todo/lib/app/models

正如您所看到的,虽然这是一个简单的示例,我可以在使用我正在处理的项目时创建,如果您不小心,快速和脏的方式将导致重复路径。较长的方法将检查重复的路径并确保它们不会发生。

如果你是一位经验丰富的Rails程序员,你可能对你正在做的事情非常了解,并且可能不会错误地重复路径。如果你是一个新手,我会选择更长的路,直到你真正理解你在做什么。

答案 4 :(得分:6)

最好我在使用Rspec时通过相对路径添加dir。我发现它足够冗长,但仍然是一个很好的衬垫。

$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))

答案 5 :(得分:1)

有一个gem可以让你用更好更清晰的代码设置你的加载路径。看看这个:https://github.com/nayyara-samuel/load-path

它还有很好的文档

答案 6 :(得分:-1)

我知道第一次提出这个问题已经有很长时间了,但是我想分享一个额外的答案。

我有另一位程序员几年来开发的几个Ruby应用程序,尽管它们可能访问相同的数据库,但它们在不同的应用程序中重用了相同的类。由于这违反了DRY规则,因此我决定创建一个类库,以供所有Ruby应用程序共享。我可以将其放在主要的Ruby库中,但这会在我不想做的通用代码库中隐藏自定义代码。

我遇到了一个问题,即我已经定义的名称“ profile.rb”与我正在使用的类之间存在名称冲突。在我尝试创建通用代码库之前,这个冲突才不是问题。通常,Ruby首先搜索应用程序位置,然后转到$ LOAD_PATH位置。

application_controller.rb找不到我创建的类,并且由于它不是一个类而在原始定义上引发了错误。由于我从应用程序的app / models部分中删除了类定义,因此Ruby在此处找不到它,并继续在Ruby路径中寻找它。

因此,我修改了$ LOAD_PATH变量,以包含指向我正在使用的库目录的路径。这可以在初始化时在environment.rb文件中完成。

即使将新目录添加到搜索路径中,Ruby也会抛出错误,因为它优先采用系统定义的文件。 $ LOAD_PATH变量中的搜索路径优先优先搜索Ruby路径。

因此,我需要更改搜索顺序,以便Ruby在搜索内置库之前在我的公共库中找到该类。

这段代码是在environment.rb文件中完成的:

Rails::Initializer.run do |config|

* * * * *

path = []
path.concat($LOAD_PATH)
$LOAD_PATH.clear
$LOAD_PATH << 'C:\web\common\lib'
$LOAD_PATH << 'C:\web\common'
$LOAD_PATH.concat(path)

* * * * *

end

我认为您不能在此级别上使用之前提供的任何高级编码结构,但是如果您想在应用程序的初始化时进行设置,它就可以正常工作。将$ LOAD_PATH变量添加回新变量时,必须保持其原始顺序,否则某些主要的Ruby类会丢失。

在application_controller.rb文件中,我仅使用

require 'profile'
require 'etc' #etc

这将为整个应用程序加载自定义库文件,即,我不必在每个控制器中都使用require命令。

对于我来说,这是我一直在寻找的解决方案,我想我可以将其添加到此答案中以传递信息。