如果我想在{<1>}中使用Ruby 和中的相对文件,我希望它能在1.8.x和&gt; = 1.9.2中工作,那么最佳做法是什么?
我看到了几个选项:
require
而忘记一切$LOAD_PATH << '.'
$LOAD_PATH << File.dirname(__FILE__)
require './path/to/file'
&lt; 1.9.2,然后将RUBY_VERSION
定义为require_relative
,在之后需要的地方使用require
require_relative
是否已存在,如果已存在,请尝试按上一个案例继续进行require_relative
- 唉它们似乎在Ruby 1.9中完全不起作用,因为,例如:require File.join(File.dirname(__FILE__), 'path/to/file')
require File.join(File.dirname(__FILE__), 'path/to/file')
似乎有用,但它很奇怪而且不太好看。$ cat caller.rb
require File.join(File.dirname(__FILE__), 'path/to/file')
$ cat path/to/file.rb
puts 'Some testing'
$ ruby caller
Some testing
$ pwd
/tmp
$ ruby /tmp/caller
Some testing
$ ruby tmp/caller
tmp/caller.rb:1:in 'require': no such file to load -- tmp/path/to/file (LoadError)
from tmp/caller.rb:1:in '<main>'
使用相关文件。有一个closely related question at StackOverflow可以提供更多示例,但它没有给出明确答案 - 这是最佳做法。
是否有任何体面的,全民接受的通用解决方案使我的应用程序在Ruby&lt; 1.9.2和&gt; = 1.9.2上运行?
答案 0 :(得分:63)
这个问题的解决方法刚刚添加到'aws'宝石中,所以我认为我会分享这篇文章的灵感。
https://github.com/appoxy/aws/blob/master/lib/awsbase/require_relative.rb
unless Kernel.respond_to?(:require_relative)
module Kernel
def require_relative(path)
require File.join(File.dirname(caller[0]), path.to_str)
end
end
end
这允许您像在ruby 1.8和1.9.1中的ruby 1.9.2中一样使用require_relative
。
答案 1 :(得分:45)
在我跳转到1.9.2之前,我使用了以下相关要求:
require File.expand_path('../relative/path', __FILE__)
第一次看到它时有点奇怪,因为它看起来在开始时有一个额外的'..'。原因是expand_path
将扩展相对于第二个参数的路径,第二个参数将被解释为它是一个目录。 __FILE__
显然不是目录,但这并不重要,因为expand_path
并不关心文件是否存在,它只会应用一些规则来扩展..
之类的内容,.
和~
。如果你可以克服最初的“waitaminute不存在额外的..
吗?”我认为上面这一行很有效。
假设__FILE__
是/absolute/path/to/file.rb
,会发生什么expand_path
将构造字符串/absolute/path/to/file.rb/../relative/path
,然后应用一条规则..
应该删除之前的路径组件(在本例中为file.rb
),返回/absolute/path/to/relative/path
。
这是最佳做法吗?取决于你的意思,但它似乎已经遍布Rails代码库,所以我认为它至少是一个常见的习惯用语。
答案 2 :(得分:6)
Pickaxe为1.8提供了一个代码片段。这是:
def require_relative(relative_feature)
c = caller.first
fail "Can't parse #{c}" unless c.rindex(/:\d+(:in `.*')?$/)
file = $`
if /\A\((.*)\)/ =~ file # eval, etc.
raise LoadError, "require_relative is called in #{$1}"
end
absolute = File.expand_path(relative_feature, File.dirname(file))
require absolute
end
它基本上只使用Theo回答的内容,但您仍然可以使用require_relative
。
答案 3 :(得分:6)
$LOAD_PATH << '.' $LOAD_PATH << File.dirname(__FILE__)
这不是一个好的安全习惯:为什么要公开整个目录?
require './path/to/file'
如果RUBY_VERSION&lt;这不起作用。 1.9.2
使用奇怪的结构,例如
require File.join(File.dirname(__FILE__), 'path/to/file')
甚至更奇怪的建筑:
require File.join(File.expand_path(File.dirname(__FILE__)), 'path/to/file')
使用backports gem - 它有点沉重,它需要rubygems 基础设施,包括大量其他解决方法,而我只是 希望需要使用相关文件。
您已经回答了为什么这些不是最佳选择。
检查RUBY_VERSION&lt; 1.9.2,然后将require_relative定义为 require,在之后需要的地方使用require_relative
检查require_relative是否已经存在,如果存在,请尝试继续 与前一案例一样
这可能有效,但有更安全,更快捷的方法:处理LoadError异常:
begin
# require statements for 1.9.2 and above, such as:
require "./path/to/file"
# or
require_local "path/to/file"
rescue LoadError
# require statements other versions:
require "path/to/file"
end
答案 4 :(得分:5)
我喜欢使用rbx-require-relative gem(source)。它最初是为Rubinius编写的,但它也支持MRI 1.8.7,并且在1.9.2中什么都不做。要求gem很简单,我不必将代码片段放入我的项目中。
将其添加到您的Gemfile:
gem "rbx-require-relative"
然后require 'require_relative'
之前require_relative
。
例如,我的一个测试文件如下所示:
require 'rubygems'
require 'bundler/setup'
require 'minitest/autorun'
require 'require_relative'
require_relative '../lib/foo'
这是任何这些IMO中最干净的解决方案,并且宝石不像后退那么重。
答案 5 :(得分:4)
backports
宝石现在允许单独加载backports。
然后你可以简单地说:
require 'backports/1.9.1/kernel/require_relative'
# => Now require_relative works for all versions of Ruby
此require
不会影响较新的版本,也不会更新任何其他内置方法。
答案 6 :(得分:3)
另一种选择是告诉口译员要搜索哪些路径
ruby -I /path/to/my/project caller.rb
答案 7 :(得分:3)
我没有看到基于__FILE__的解决方案指出的一个问题是它们在符号链接方面有所突破。比如说我有:
~/Projects/MyProject/foo.rb
~/Projects/MyProject/lib/someinclude.rb
主脚本,入口点,应用程序是foo.rb.这个文件链接到我的$ PATH中的〜/ Scripts / foo。执行'foo'时,此require语句被破坏:
require File.join(File.dirname(__FILE__), "lib/someinclude")
因为__FILE__是〜/ Scripts / foo所以上面的require语句查找〜/ Scripts / foo / lib / someinclude.rb,这显然不存在。解决方案很简单。如果__FILE__是符号链接,则需要将其解除引用。路径名#realpath将帮助我们解决这种情况:
require "pathname" require File.join(File.dirname(Pathname.new(__FILE__).realpath), "lib/someinclude")
答案 8 :(得分:2)
如果您正在构建gem,则不希望污染加载路径。
但是,对于独立应用程序,只需将当前目录添加到加载路径就像在前两个示例中一样。
我的投票将转到列表中的第一个选项。
我希望看到一些可靠的Ruby最佳实践文献。
答案 9 :(得分:1)
我会定义自己的relative_require
如果它不存在(即在1.8下),然后在任何地方使用相同的语法。
答案 10 :(得分:0)
Ruby on Rails方式:
config_path = File.expand_path("../config.yml", __FILE__)