100

我已经看到了两种常用的技术,用于将当前正在执行的文件的目录添加到 $LOAD_PATH(或 $:)。如果您不使用 gem,我会看到这样做的好处。显然,一个似乎比另一个更冗长,但是有理由选择一个而不是另一个吗?

第一种,冗长的方法(可能是矫枉过正):

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

和更直接,快速和肮脏的:

$:.unshift File.dirname(__FILE__)

有什么理由选择一个而不是另一个?

4

7 回答 7

156

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

$LOAD_PATH

……和……说再见

# I don't quite understand what this is doing...
$:
于 2009-09-21T21:01:50.273 回答
55

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

于 2009-05-07T23:44:19.890 回答
25

我不太喜欢“快速而肮脏”的方式。任何刚接触 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​​ 项目中看到了它。

好像是约定?

于 2009-07-11T03:26:14.753 回答
8

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

正如您提到的那样以快速而肮脏的方式执行此操作的缺点是:如果您的引导路径中已经有该目录,它将重复自己。

例子:

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

/ - -小贩
  |
  |---/插件
        |
        |---/待办事项
              |
              |---/库
                    |
                    |---/应用
                          |
                          |---/型号
                          |---/控制器
              |
              |---/导轨
                    |
                    |---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 程序员,您可能非常清楚自己在做什么,并且可能不会犯重复路径的错误。如果您是新手,我会走更长的路,直到您真正了解自己在做什么。

于 2009-12-06T19:41:37.087 回答
8

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

$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
于 2015-11-05T04:09:51.590 回答
0

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

它也有很好的文档

于 2013-09-26T01:11:21.443 回答
-2

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

我有几个 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 命令。

对我来说,这是我正在寻找的解决方案,我想我会将它添加到这个答案中以传递信息。

于 2018-10-24T19:12:19.963 回答