我已经看到了两种常用的技术,用于将当前正在执行的文件的目录添加到$ 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__)
任何理由与其中一个相提并论?
答案 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命令。
对于我来说,这是我一直在寻找的解决方案,我想我可以将其添加到此答案中以传递信息。