Gre*_*Cat 153 ruby ruby-1.9 ruby-1.8
如果我想require
在Ruby中使用相关文件并且希望它在1.8.x和> = 1.9.2中工作,那么最佳实践是什么?
我看到几个选项:
$LOAD_PATH << '.'
忘记一切$LOAD_PATH << File.dirname(__FILE__)
require './path/to/file'
RUBY_VERSION
<1.9.2,然后定义require_relative
为require
,require_relative
随后在需要的地方使用require_relative
已存在,如果已存在,请尝试按上一种情况继续操作require File.join(File.dirname(__FILE__), 'path/to/file')
Run Code Online (Sandbox Code Playgroud)
它们似乎不能在Ruby 1.9中工作,因为,例如:$ 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>'
Run Code Online (Sandbox Code Playgroud)require File.join(File.expand_path(File.dirname(__FILE__)), 'path/to/file')
Run Code Online (Sandbox Code Playgroud)
似乎工作,但它很奇怪,不太好看.require
使用相关文件.StackOverflow上有一个密切相关的问题,它给出了一些更多的例子,但它没有给出明确的答案 - 这是一种最佳实践.
是否有任何体面的,被大家接受的通用解决方案使我的应用程序在Ruby <1.9.2和> = 1.9.2上运行?
澄清:我不想只是"你可以做X"这样的答案 - 事实上,我已经提到过大多数有关的选择.我想要理性,即为什么它是一种最佳实践,它的优点和缺点是什么以及为什么应该在其他实践中选择它.
Tra*_*der 64
这个问题的解决方法刚刚添加到'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
Run Code Online (Sandbox Code Playgroud)
这允许您require_relative
像在ruby 1.8和1.9.1中的ruby 1.9.2中那样使用.
The*_*heo 46
在我跳转到1.9.2之前,我使用了以下相关要求:
require File.expand_path('../relative/path', __FILE__)
Run Code Online (Sandbox Code Playgroud)
第一次看到它时有点奇怪,因为它看起来在开始时有一个额外的'..'.原因是expand_path
将扩展相对于第二个参数的路径,第二个参数将被解释为它是一个目录.__FILE__
显然不是一个目录,但这并不重要,因为expand_path
不关心文件是否存在,它只会应用一些规则来扩展像..
,.
和~
.如果你可以克服最初的"等分,那么那里有额外的..
吗?" 我认为上面这条线很有效.
假设__FILE__
是这样/absolute/path/to/file.rb
,会发生什么,expand_path
将构造字符串/absolute/path/to/file.rb/../relative/path
,然后应用一个规则,说明..
应删除之前的路径组件(file.rb
在本例中),返回/absolute/path/to/relative/path
.
这是最佳做法吗?取决于你的意思,但似乎它已经遍布Rails代码库,所以我说它至少是一个常见的习惯用语.
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
Run Code Online (Sandbox Code Playgroud)
它基本上只是使用Theo回答的内容,但你仍然可以使用require_relative
.
Run Code Online (Sandbox Code Playgroud)$LOAD_PATH << '.' $LOAD_PATH << File.dirname(__FILE__)
这不是一个好的安全习惯:为什么要暴露整个目录?
Run Code Online (Sandbox Code Playgroud)require './path/to/file'
如果RUBY_VERSION <1.9.2,则不起作用
使用奇怪的结构,如
Run Code Online (Sandbox Code Playgroud)require File.join(File.dirname(__FILE__), 'path/to/file')
甚至更奇怪的建筑:
Run Code Online (Sandbox Code Playgroud)require File.join(File.expand_path(File.dirname(__FILE__)), 'path/to/file')
使用backports gem - 它有点沉重,它需要rubygems基础设施并包含大量其他变通方法,而我只是想要使用相关文件.
您已经回答了为什么这些不是最佳选择.
检查RUBY_VERSION是否<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
Run Code Online (Sandbox Code Playgroud)
我是使用rbx-require-relative gem(source)的粉丝.它最初是为Rubinius编写的,但它也支持MRI 1.8.7,并且在1.9.2中什么都不做.要求gem很简单,我不必将代码片段放入我的项目中.
将它添加到您的Gemfile:
gem "rbx-require-relative"
Run Code Online (Sandbox Code Playgroud)
然后require 'require_relative'
在你之前require_relative
.
例如,我的一个测试文件如下所示:
require 'rubygems'
require 'bundler/setup'
require 'minitest/autorun'
require 'require_relative'
require_relative '../lib/foo'
Run Code Online (Sandbox Code Playgroud)
这是任何这些IMO中最干净的解决方案,并且宝石不像后退那么重.
归档时间: |
|
查看次数: |
71911 次 |
最近记录: |