$ LOAD_PATH(Ruby)にディレクトリを追加する


95

現在実行中のファイルのディレクトリを$ LOAD_PATH(または$ :)に追加するために一般的に使用される2つのテクニックを見てきました。宝石を扱っていない場合に備えて、これを行うことの利点がわかります。明らかに、どちらか一方がもう一方よりも冗長であるように見えますが、どちらか一方を他方と重ねる理由はありますか?

最初の詳細な方法(やり過ぎかもしれません):

$LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__))) unless $LOAD_PATH.include?(File.expand_path(File.dirname(__FILE__)))

そして、より簡単で迅速かつ汚い:

$:.unshift File.dirname(__FILE__)

どちらか一方を使う理由はありますか?


2
わずか 1冗長の少ない冗長バージョンがある:File.expand_path(File.dirname(__FILE__)).tap {|pwd| $LOAD_PATH.unshift(pwd) unless $LOAD_PATH.include?(pwd)}
ネイサンロング

「unless」節はどうですか?上記の2つをどのように同等にすることができますか?
歌手2014

これを使用する方法を理解しようとここに来た誰かとして、それは超不可解です。例では、ディレクトリ名がどこから来ているのかわかりません。誰かがこれを明確にしていただければ幸いです。
SlySherZ、2015年

1
使い方__dir__(ルビー2.0のよう)はこれらより簡潔なのいずれかを行うことができます。
Nathan Long

回答:


50

私は$:.unshift File.dirname(__FILE__)他のものよりも一緒に行くと言います、それは私がコードでそれよりもはるかに多くの使用法を見たから$LOAD_PATHであり、それもあまりにも短いです!


最初にRubyを使い始めたとき、$ LOAD_PATHの方がいいと思いました。しかし、初心者のステータスを卒業したら、初心者がコードを読みやすくするために$ LOAD_PATHを使用します。そのトレードオフです。メモリ使用量が同じである限り、コードがどの程度「公開」されているかによって異なりますが、基本的には同じです。
boulder_ruby

9
プロジェクトで使用するスタイルガイドによって異なります。人気のあるRubyスタイルガイドでは、「Perlスタイルの特殊変数($:、$;など)の使用を避けます。これらは非常に暗号化されており、ワンライナースクリプト以外での使用はお勧めしません。」
bobmagoo

152

Rubyのロードパスは、$:と書かれているのが一般的ですが、短いためといって、改善されることはありません。賢明さよりも明快さを好む場合、またはそれ自体が簡潔であるためにかゆい場合は、他の人がそうであるという理由だけでそれを行う必要はありません。こんにちは...

$LOAD_PATH

...そして別れを告げる...

# I don't quite understand what this is doing...
$:

29
また、「$:」のような記号のみを含む文字列を検索することは、Googleにとって非常に困難です。
DSimon 2012

23

私は「素早い」方法であまり好きではありません。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を閲覧しているときに、さまざまなルビープロジェクトでたくさん見ました。

慣習のようです?


@LukeAntins、これは本当に素晴らしいですが、アプリケーションのどこでload_pathを「ブートストラップ」する必要がありますか?
gaussblurinc 2014

@gaussblurinc lib /アプリケーションのどこか「トップ近く」ですが、それは実際に依存します。あなたは持っていた場合はbin、常にあなたの相対したファイルをcode、それは今までで実行されたbinファイル...ブートストラップをビンに。ライブラリがある場合は、ライブラリコードの上部にあるブートストラップをlib/code.rb使用して、の下にあるすべてにアクセスできますlib/code/。この騒動がお役に立てば幸いです。
Luke Antins 2014

1
RuboCopは__dir__、現在のファイルのディレクトリへのパスを取得するために使用できることを通知します。
ラファエル

8

あなたが入力した場合script/console、あなたのRailsプロジェクトにと入力して$:、あなたは、Rubyをロードするために必要なすべてのディレクトリが含まれて配列を取得します。この小さな演習の要点は、これ$:が配列であることです。そのため、unshiftメソッドや<<演算子を他のディレクトリの前に付けるなどの機能を実行できます。あなたがあなたの声明で暗示するように、$:そして$LOAD_PATH同じです。

あなたが述べたようにそれを迅速で汚い方法で行うことの欠点はこれです:ブートパスにディレクトリが既にある場合、それは繰り返されます。

例:

私が作成したプラグインはtodoです。私のディレクトリは次のように構成されています:

/ - -ベンダー
  |
  | --- /プラグイン
        |
        | --- / todo
              |
              | --- / lib
                    |
                    | --- /アプリ
                          |
                          | --- /モデル
                          | --- / 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に文字列の配列を保持するように伝えるもう1つの方法です)。を実行するとき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プログラマーであれば、あなたは自分が何をしているのかを非常によく理解していて、パスを繰り返すミスを犯さないでしょう。あなたが初心者であれば、あなたが何をしているかを本当に理解するまで、私はもっと長い道を行くでしょう。


あなたの応答は非常に役に立ち、また十分に説明されています。推奨される編集:メソッドload_pathsload_once_paths.deleteあり、非推奨となっています。それらを参照する行を次のように更新するのに役立ちます: ActiveSupport::Dependencies.autoload_paths << path ActiveSupport::Dependencies.autoload_once_paths.delete(path)
Uzzar

8

Rspecを使用するときに相対パスを介してディレクトリを追加することに遭遇したのが最善です。私はそれが十分に冗長であることを見つけますが、それでも素晴らしいワンライナーです。

$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))


-2

この質問が最初に尋ねられてから久しぶりのことですが、共有したい追加の回答があります。

別のプログラマーが数年かけて開発した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コマンドを使用する必要はありません。

私にとって、これは私が探していた解決策であり、この回答に追加して情報を渡すことを考えました。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.