Ruby:require vs require_relative - 在Ruby <1.9.2和> = 1.9.2中运行的解决方法的最佳实践

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_relativerequire,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)
    似乎工作,但它很奇怪,不太好看.
  • 使用backports gem - 它有点沉重,它需要rubygems基础设施并包含大量其他变通方法,而我只想require使用相关文件.

StackOverflow上有一个密切相关的问题,它给出了一些更多的例子,但它没有给出明确的答案 - 这是一种最佳实践.

是否有任何体面的,被大家接受的通用解决方案使我的应用程序在Ruby <1.9.2和> = 1.9.2上运行?

UPDATE

澄清:我不想只是"你可以做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中那样使用.

  • `require_relative`函数包含在Ruby核心库的扩展项目中,可在此处找到:http://www.rubyforge.org/projects/extensions您应该可以使用`gem install extensions`安装它们.然后在你的代码中在`require_relative`之前添加以下行:require'extension/all'(来自Aurril的帖子[here](http://stackoverflow.com/questions/2681031/why-doesnt-relative-require-work -on-红宝石1-8-6)) (7认同)
  • 你如何需要require_relative.rb文件?您必须要求require_relative.rb然后require_relative其余的要求.或者我错过了什么? (3认同)

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代码库,所以我说它至少是一个常见的习惯用语.

  • 有点清洁:需要File.expand_path('relative/path',File.dirname(__ FILE__)) (12认同)
  • 似乎File.expand_path('../ relpath.x',File.dirname(__ FILE__))是一个更好的习语,即使它更详细.依赖于可解释的文件路径被破坏的功能被解释为具有额外不存在的目录的目录路径可能会在/当该功能被修复时中断. (6认同)

Pau*_*fer 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
Run Code Online (Sandbox Code Playgroud)

它基本上只是使用Theo回答的内容,但你仍然可以使用require_relative.


Cla*_*ani 6

$LOAD_PATH << '.'

$LOAD_PATH << File.dirname(__FILE__)
Run Code Online (Sandbox Code Playgroud)

这不是一个好的安全习惯:为什么要暴露整个目录?

require './path/to/file'
Run Code Online (Sandbox Code Playgroud)

如果RUBY_VERSION <1.9.2,则不起作用

使用奇怪的结构,如

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')
Run Code Online (Sandbox Code Playgroud)

使用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)


Edw*_*son 5

我是使用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中最干净的解决方案,并且宝石不像后退那么重.