[ruby-on-rails] 로드는 Ruby의 require와 어떻게 다릅니 까?

Ruby on Rails 애플리케이션 사이에 load와 사이에 큰 차이점이 require있습니까? 아니면 둘 다 동일한 기능을 가지고 있습니까?



답변

require정의 된 모든 검색 경로에서 라이브러리를 검색하고 입력 한 파일 이름에 .rb 또는 .so를 추가합니다. 또한 라이브러리가 한 번만 포함되도록합니다. 따라서 응용 프로그램에 라이브러리 A와 B가 필요하고 라이브러리 B가 라이브러리 A도 필요하면 A는 한 번만로드됩니다.

으로 load당신은 라이브러리의 전체 이름을 추가 할 필요가 그것을 당신이 호출 할 때마다로드되는 load– 이미 메모리에있는 경우에도 마찬가지입니다.


답변

또 다른 차이점 Kernel#requireKernel#loadKernel#load익명 빈 모듈에로드 된 코드를 포장 할 수있는 옵션은 2 개의 인자를 가지고.

불행히도 그다지 유용하지 않습니다. 첫째, load글로벌 네임 스페이스에 액세스하기 만하면 ed 코드가 모듈 에서 쉽게 빠져 나올 수 있습니다 class ::String; def foo; end end. 즉, 여전히 . 둘째, load코드를 래핑 한 모듈을 반환하지 않으므로 기본적으로 ObjectSpace::each_object(Module)손으로 빼내야합니다.


답변

저는 Rails 애플리케이션을 실행하고 있었고 Gemfile에서 “require : false”옵션으로 만든 특정 사용자 지정 gem을 가지고있었습니다. 이제 Rails 서버 또는 Rails 콘솔을로드 할 때 이니셜 라이저에서 gem을 요구할 수 있었고 gem이로드되었습니다. 그러나 rspec 및 capybara로 사양 기능 테스트를 실행했을 때로드 오류가 발생했습니다. 그리고 테스트를 실행할 때 왜 $ LOAD_PATH에서 Gem을 찾을 수 없는지 완전히 당황했습니다.

그래서로드, 요구, rubygems 및 번 들러가 상호 작용하는 모든 다른 방법을 검토했습니다. 다음은 내 특정 문제에 대한 해결책을 찾는 데 도움이 된 내 결과 요약입니다.

하중

1) 루비 파일의 절대 경로를 전달할 수 있으며 해당 파일의 코드를 실행합니다.

load('/Users/myuser/foo.rb')

2)로드 할 상대 경로를 전달할 수 있습니다. 파일과 동일한 디렉토리에 있으면 다음을 찾습니다.

> load('./foo.rb')
foo.rb loaded!
=> true

그러나 load ()를 사용하여 다른 디렉토리에서 파일을로드하려고하면 현재 작업 디렉토리 (예 : ./)에 기반한 상대 경로로 파일을 찾지 못합니다.

> load('./foo.rb')
LoadError: cannot load such file -- foo.rb

3) 위와 같이 load는 항상 true를 반환합니다 (파일을로드 할 수없는 경우 LoadError).

4) 전역 변수, 클래스, 상수 및 메서드는 모두 가져 오지만 로컬 변수는 가져 오지 않습니다.

5) 동일한 파일에서 load를 두 번 호출하면 해당 파일의 코드가 두 번 실행됩니다. 지정된 파일이 상수를 정의하면 해당 상수를 두 번 정의하여 경고를 생성합니다.

6) $ LOAD_PATH는 절대 경로의 배열입니다. 파일 이름 만로드하면 $ LOAD_PATH를 반복하고 각 디렉토리에서 파일을 검색합니다.

> $LOAD_PATH.push("/Users/myuser")
> load('foo.rb')
foo.rb loaded!
 => true

요구하다

1) 동일한 파일에서 require를 두 번 호출하면 한 번만 실행됩니다. 또한 상대 경로로 한 번, 절대 경로로 한 번 참조하면 동일한 파일을 두 번로드하지 않을만큼 똑똑합니다.

2) require는 파일이 실행 된 경우 true를 반환하고 그렇지 않은 경우 false를 반환합니다.

3) require는 전역 변수 $ LOADED_FEATURES에 이미로드 된 파일을 추적합니다.

4) 파일 확장자를 포함 할 필요가 없습니다.

require 'foo'

5) require는 foo.rb뿐만 아니라 foo.so, foo.o 또는 foo.dll과 같은 동적 라이브러리 파일도 찾습니다. 이것이 루비에서 C 코드를 호출하는 방법입니다.

6) require는 현재 디렉토리가 기본적으로 $ LOAD_PATH에 없기 때문에 현재 디렉토리를 확인하지 않습니다.

7) require_relative는 프로세스의 작업 디렉토리가 아닌 현재 파일에 상대적인 경로를 취합니다.

Rubygems

1) Rubygems는 gems라는 Ruby 라이브러리 설치를 쉽게 관리 할 수 ​​있도록 설계된 패키지 관리자입니다.

2) 일부 메타 데이터와 함께 코드에서 가져올 수있는 루비 파일 및 / 또는 동적 라이브러리 파일이 포함 된 zip 파일로 콘텐츠를 패키징합니다.

3) Rubygems는 기본 require 메소드를 자체 버전으로 대체합니다. 이 버전은 $ LOAD_PATH의 디렉토리 외에 설치된 gem을 살펴 봅니다. Rubygems가 gem에서 파일을 찾으면 해당 gem을 $ LOAD_PATH에 추가합니다.

4) gem install 명령은 gem의 모든 종속성을 파악하여 설치합니다. 사실, gem 자체를 설치하기 전에 모든 gem의 의존성을 설치합니다.

번 들러

1) Bundler를 사용하면 프로젝트에 필요한 모든 gem을 지정하고 선택적으로 해당 gem의 버전을 지정할 수 있습니다. 그런 다음 bundle 명령은 모든 gem과 종속성을 설치합니다.

2) Gemfile이라는 파일에서 필요한 gem을 지정합니다.

3) bundle 명령은 Gemfile.lock에 나열된 모든 gem을 나열된 특정 버전으로 설치합니다.

4) 명령 앞에 bundle exec를 넣으면 (예 : bundle exec rspec) require가 Gemfile.lock에 지정된 gem의 버전을로드하도록합니다.

레일 및 번 들러

1) config / boot.rb에서 require ‘bundler / setup’이 실행됩니다. Bundler는 Ruby가 Gemfile의 모든 gem (및 모든 종속성)을 찾을 수 있도록합니다. require ‘bundler / setup’은 자동으로 Gemfile을 발견하고 Gemfile의 모든 gem을 Ruby에서 사용할 수 있도록합니다 (기술적 인 측면에서 gem을 “로드 경로”에 배치). ‘루비 젬’을 필요로하는 추가 능력을 추가하는 것으로 생각할 수 있습니다.

ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])

2) 이제 Ruby에서 코드를 사용할 수 있으므로 필요한 gem을 요구할 수 있습니다. 예를 들어 ‘sinatra’가 필요할 수 있습니다. 의존성이 많다면“내 Gemfile에 모든 gem이 필요합니다”라고 말하고 싶을 것입니다. 이렇게하려면 require ‘bundler / setup’바로 뒤에 다음 코드를 넣으십시오.

Bundler.require(:default)

3) 기본적으로 Bundler.require를 호출하려면 Gemfile의 각 gem이 필요합니다. Gemfile의 줄에 gem ‘foo’, : ​​require => false가 표시되면 foo가 설치되어 있는지 확인하지만 require를 호출하지는 않습니다. gem을 사용하려면 require ( ‘foo’)를 호출해야합니다.

그래서이 지식의 폭을 감안할 때, 나는 내 테스트 문제로 돌아가서 Bundler.setup이 그것을 $ LOAD_PATH에 추가했지만 다음이 필요하기 때문에 rails_helper.rb에 gem을 명시 적으로 요구해야한다는 것을 깨달았습니다. . 그리고 문제가 해결되었습니다.


답변