$ LOAD_PATH (Ruby)에 디렉토리 추가


96

현재 실행중인 파일의 디렉토리를 $ LOAD_PATH (또는 $ :)에 추가하는 데 일반적으로 사용되는 두 가지 기술을 보았습니다. gem을 사용하지 않는 경우이 작업의 장점을 확인했습니다. 하나는 다른 것보다 더 장황 해 보이지만, 다른 하나와 함께 갈 이유가 있습니까?

첫 번째, 장황한 방법 (과도 할 수 있음) :

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

더 간단하고 빠르고 더럽습니다.

$:.unshift File.dirname(__FILE__)

다른 하나와 함께 갈 이유가 있습니까?


2
약간 하나 자세한의 덜 장황 버전입니다 :File.expand_path(File.dirname(__FILE__)).tap {|pwd| $LOAD_PATH.unshift(pwd) unless $LOAD_PATH.include?(pwd)}
나단 긴

"unless"절은 어떻습니까? 위의 두 가지가 어떻게 동등 할 수 있습니까?
inger

이것을 사용하는 방법을 이해하려고 여기에 온 사람 으로서는 매우 비밀 스럽습니다. 예제에서 디렉토리 이름이 어디에서 오는지 알 수 없습니다. 누군가 이것을 분명히 할 수 있다면 감사하겠습니다.
SlySherZ

1
__dir__(Ruby 2.0에서) 사용하면 이러한 것들을 더 간결하게 만들 수 있습니다.
Nathan Long

답변:


52

나는 $:.unshift File.dirname(__FILE__)다른 것보다 코드에서 더 많이 사용하는 것을 보았 기 때문에 다른 것보다 가라고 말할 것입니다 $LOAD_PATH.


Ruby를 처음 시작했을 때 $ LOAD_PATH가 더 낫다고 생각했습니다. 하지만 일단 초보자 상태에서 졸업하면 초보자가 내 코드를 더 읽기 쉽게 만들려고 할 때만 $ LOAD_PATH를 사용합니다. Meh 그것의 트레이드 오프. 메모리 사용량이 각각에 대해 동일하다면 코드가 얼마나 "공개"인지에 따라 달라집니다.
boulder_ruby

9
프로젝트를 위해 따르는 스타일 가이드에 따라 다릅니다. 인기있는 Ruby 스타일 가이드 는 "Perl 스타일 특수 변수 (예 : $ :, $; 등)를 사용하지 마십시오. 매우 비밀스럽고 한 줄짜리 스크립트 이외의 용도로 사용하는 것은 권장하지 않습니다."라고 말합니다.
bobmagoo

153

Ruby로드 경로는 일반적으로 $ :로 작성되는 것으로 보이지만 짧다고해서 더 나아지지는 않습니다. 영리함보다 명료 함을 선호하거나 그 자체로 간결함이 당신을 가렵 게 만든다면, 다른 모든 사람들이 그렇다고해서 그렇게 할 필요는 없습니다. 인사 ...

$LOAD_PATH

... 그리고 작별 인사를 ...

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

29
또한 기호 만 포함 된 "$ :"와 같은 문자열에 대해서는 Google이 훨씬 더 어렵습니다.
DSimon

23

나는 '빠르고 더러운'방식을 너무 좋아하지 않습니다. 루비를 처음 접하는 사람이라면 누구나 무엇을 고민 할 것 $:.입니다.

나는 이것이 더 분명하다고 생각합니다.

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-08-06

@gaussblurinc lib / application의 '상단 근처'어딘가에 있지만 실제로는 다릅니다. bin항상 당신 code과 관련된 파일 이 있고 파일 에 의해서만 실행 되었다면 bin... bin의 부트 스트랩. 당신이 라이브러리가있는 경우처럼, 당신의 상단에있어 라이브러리 코드를 부트 스트랩 lib/code.rb에서 모든 액세스를 얻을 lib/code/. 이 헛소리가 도움이되기를 바랍니다!
Luke Antins

1
RuboCop은 __dir__현재 파일의 디렉토리 경로를 얻는 데 사용할 수 있다고 알려줍니다 .
Raphael

8

당신이 입력하면 script/console레일스 프로젝트를 입력 $:, 당신은 루비를로드하는 데 필요한 모든 디렉토리를 포함하는 배열을 얻을 것이다. 이 작은 연습에서 빼놓을 수없는 것은 그것이 $:배열이라는 것입니다. 따라서 다른 디렉토리 앞에 unshift메서드 나 <<연산자를 추가하는 것과 같은 기능을 수행 할 수 있습니다 . 당신은 당신의 문에 묵시적으로 $:$LOAD_PATH동일합니다.

앞서 언급했듯이 빠르고 더러운 방식으로 수행 할 때의 단점은 다음과 같습니다. 부팅 경로에 이미 디렉토리가있는 경우 자체적으로 반복됩니다.

예:

내가 만든 todo라는 플러그인이 있습니다. 내 디렉토리는 다음과 같이 구성됩니다.

/ --- 공급 업체
  |
  | --- / 플러그인
        |
        | --- / 할일
              |
              | --- / lib
                    |
                    | --- / 앱
                          |
                          | --- / 모델
                          | --- / 컨트롤러
              |
              | --- / 레일
                    |
                    | --- 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가 문자열 배열을 보유하도록 지시하는 또 다른 방법입니다.) 를 실행할 때 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을 사용할 때 상대 경로를 통해 dir을 추가하는 것이 가장 좋습니다. 나는 그것이 충분히 장황하지만 여전히 좋은 라이너라고 생각합니다.

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


-2

이 질문이 처음 제기 된 지 오래되었지만 공유하고 싶은 추가 답변이 있습니다.

몇 년에 걸쳐 다른 프로그래머가 개발 한 Ruby 애플리케이션이 여러 개 있으며 동일한 데이터베이스에 액세스 할 수 있지만 다른 애플리케이션에서 동일한 클래스를 재사용합니다. 이것은 DRY 규칙을 위반하기 때문에 모든 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.