require
Rubyandの相対ファイルにしたい場合のベストプラクティスは何ですか? 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')
</ code>
-残念ながら、彼らは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>'
</ code>
require File.join(File.expand_path(File.dirname(__FILE__)), 'path/to/file')
</ code>
動作しているように見えますが、奇妙で見栄えがよくありません。require
で相対ファイルを操作したいだけです。StackOverflowで密接に関連した質問 がありますが、これはさらに例を示しますが、明確な答えを与えません-これはベストプラクティスです。
Ruby <1.9.2および> = 1.9.2の両方でアプリケーションを実行するための、誰でも受け入れられるまともなユニバーサルソリューションはありますか?
明確化:「Xを実行できます」のような回答だけが必要なわけではありません。実際、問題の選択肢のほとんどについては既に述べました。私は理論的根拠、すなわちwhyがベストプラクティスですその長所と短所、および他の中で選択する理由。
この問題の回避策が「aws」gemに追加されたので、この投稿に触発されたので共有したいと思いました。
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.9.2にジャンプする前に、相対要件に次を使用しました。
require File.expand_path('../relative/path', __FILE__)
最初に追加の「..」があるように見えるので、初めて見たときは少し奇妙です。その理由は、expand_path
が2番目の引数に相対してパスを展開し、2番目の引数がディレクトリであるかのように解釈されるためです。 __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
基本的には、Theoが答えたものだけを使用しますが、require_relative
を引き続き使用できます。
$LOAD_PATH << '.' $LOAD_PATH << File.dirname(__FILE__)
それは良いセキュリティ習慣ではありません。なぜディレクトリ全体を公開する必要があるのですか?
require './path/to/file'
Ruby_VERSION <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 <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
私はrbx-require-relative gem( source )の使用が好きです。もともとはRubinius用に書かれていましたが、MRI 1.8.7もサポートしており、1.9.2では何もしません。 gemを必要とするのは簡単で、プロジェクトにコードスニペットを挿入する必要はありません。
Gemfileに追加します。
gem "rbx-require-relative"
次に、require 'require_relative'
をrequire_relative
の前に配置します。
たとえば、私のテストファイルの1つは次のようになります。
require 'rubygems'
require 'bundler/setup'
require 'minitest/autorun'
require 'require_relative'
require_relative '../lib/foo'
これは、これらのIMOの中で最もクリーンなソリューションであり、gemはバックポートほど重くありません。
backports
gemにより、バックポートを個別にロードできるようになりました。
次に、単純にできます:
require 'backports/1.9.1/kernel/require_relative'
# => Now require_relative works for all versions of Ruby
このrequire
は新しいバージョンには影響せず、他の組み込みメソッドも更新しません。
別のオプションは、インタープリターに検索するパスを伝えることです
Ruby -I /path/to/my/project caller.rb
__FILE__に基づくソリューションで指摘されていない問題の1つは、シンボリックリンクに関して破損していることです。たとえば、私が持っていると言う:
~/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__がシンボリックリンクの場合、逆参照する必要があります。 Pathname#realpathは、この状況に役立ちます。
require "pathname" require File.join(File.dirname(Pathname.new(__ FILE __)。realpath)、 "lib/someinclude")
Gemを構築している場合、ロードパスを汚染したくないでしょう。
ただし、スタンドアロンアプリケーションの場合、最初の2つの例で行うように、現在のディレクトリをロードパスに追加するだけで非常に便利です。
私の投票はリストの最初のオプションに行きます。
いくつかの堅実なRubyベストプラクティスの文献を参照してください。
存在しない場合(つまり1.8未満の場合)独自のrelative_require
を定義し、どこでも同じ構文を使用します。
RailsウェイのRuby:
config_path = File.expand_path("../config.yml", __FILE__)