bundle exec은 왜 필요한가?
bundle exec
TL;DR
한마디로 bundle exec
를 붙이면 Gemfile.lock
에 쓰여진 대로 require
Gemfile.lock
에 기재되어 있는 gem 은, 서로의 의존관계를 채우도록(듯이) 버젼이 선택되어 있으므로, Gem:: ConflictError
를 막을 수가 있습니다.
좀 더 자세히
번들러가 없으면 무슨 일이 일어나는지
구체적인 예에서 설명합니다. 다음과 같은 종속성을 가진 gem, "GemA", "GemB"가 있다고 가정합시다. 둘 다 설치되어 있다고 가정합니다.
gem_a.rbmodule GemA
Version = "1.0.0"
end
gem_b.rbrequire 'gem_a'
module GemB
Version = '1.0.0'
def self.say
puts "I'm using GemA ver. #{::GemA::Version}!"
end
end
# gem list
*** LOCAL GEMS ***
gem_a (1.0.0)
gem_b (1.0.0)
물론 둘 다 require
가능합니다.
irb(main):001:0> require 'gem_a'
=> true
irb(main):002:0> GemA::Version
=> "1.0.0"
irb(main):003:0> require 'gem_b'
=> true
irb(main):004:0> GemB::Version
=> "1.0.0"
irb(main):005:0> GemB::say
I'm using GemA ver. 1.0.0!
=> nil
이제 GemA를 2.0.0으로 업데이트합니다.
# gem update gem_a
Updating installed gems
Updating gem_a
Fetching: gem_a-2.0.0.gem (100%)
Successfully installed gem_a-2.0.0.gem
Gems updated: gem_a
# gem list
*** LOCAL GEMS ***
gem_a (2.0.0, 1.0.0)
gem_b (1.0.0)
업데이트할 수 있었습니다. irb에서 조금 전과 같은 것을 시도합니다.
irb(main):001:0> require 'gem_a'
=> true
irb(main):002:0> GemA::Version
=> "2.0.0"
제대로 업데이트되었습니다. GemB도 사용해 봅시다.
irb(main):003:0> require 'gem_b'
Traceback (most recent call last):
8: from /usr/local/bin/irb:11:in `<main>'
7: from (irb):3
6: from /usr/local/Cellar/ruby/2.5.1/lib/ruby/2.5.0/rubygems/core_ext/kernel_require.rb:39:in `require'
5: from /usr/local/Cellar/ruby/2.5.1/lib/ruby/2.5.0/rubygems/core_ext/kernel_require.rb:128:in `rescue in require'
4: from /usr/local/Cellar/ruby/2.5.1/lib/ruby/2.5.0/rubygems.rb:217:in `try_activate'
3: from /usr/local/Cellar/ruby/2.5.1/lib/ruby/2.5.0/rubygems.rb:224:in `rescue in try_activate'
2: from /usr/local/Cellar/ruby/2.5.1/lib/ruby/2.5.0/rubygems/specification.rb:1438:in `activate'
1: from /usr/local/Cellar/ruby/2.5.1/lib/ruby/2.5.0/rubygems/specification.rb:2325:in `raise_if_conflicts'
Gem::ConflictError (Unable to activate gem_b-1.0.0, because gem_a-2.0.0 conflicts with gem_a (= 1.0.0))
죄송합니다... 곤란했습니다. GemB가 망가졌습니다. 이미 GemA (2.0.0)를 require
했으므로 GemB에 필요한 GemA (1.0.0)를로드 할 수 없어 오류가 발생했습니다. 1
어떻게 되면 기쁜가?
GemB를 사용하는 프로젝트에서는 업데이트한 GemA(2.0.0)를 사용하지 않고 GemA(1.0.0)를 그대로 사용할 수 있으면 좋았습니다.
irb(main):001:0> require 'gem_a'
=> true
irb(main):002:0> GemA::Version
=> "1.0.0"
irb(main):003:0> require 'gem_b'
=> true
irb(main):004:0> GemB::Version
=> "1.0.0"
한편, GemB를 사용하지 않는 프로젝트에서는 최신 GemA (2.0.0)를 사용하고 싶네요.
irb(main):001:0> require 'gem_a'
=> true
irb(main):002:0> GemA::Version
=> "2.0.0"
이것을 실현하는 것이 Bundler이며, bundle exec
라는 명령입니다.
번들러가 있으면 어떻게 될까
GemA와 GemB를 사용하고 싶은 프로젝트에 이런 느낌의 Gemfile을 준비합니다.
gem 'gem_a'
gem 'gem_b'
그리고 bundle
를 실행하면 Gemfile.lock
가 생성됩니다.
# bundle
Fetching gem metadata from https://rubygems.org/.
Fetching gem metadata from https://rubygems.org/.
Resolving dependencies...
Using bundler 1.16.2
Using gem_a 1.0.0
Using gem_b 1.0.0
Bundle complete! 2 Gemfile dependencies, 3 gems now installed.
Use `bundle info [gemname]` to see where a bundled gem is installed.
# cat Gemfile.lock
GEM
remote: https://rubygems.org/
specs:
gem_a (1.0.0)
gem_b (1.0.0)
gem_a (= 1.0.0)
PLATFORMS
ruby
DEPENDENCIES
gem_a
gem_b
BUNDLED WITH
1.16.2
이 상태에서 bundle exec irb
해 봅시다.
irb(main):001:0> require 'gem_a'
=> true
irb(main):002:0> GemA::Version
=> "1.0.0"
irb(main):003:0> require 'gem_b'
=> true
irb(main):004:0> GemB::Version
=> "1.0.0"
irb(main):005:0> GemB::say
I'm using GemA ver. 1.0.0!
=> nil
제대로 움직입니다!
일반적으로 irb를 시작하면 새로운 버전의 GemA (2.0.0)도 제대로 사용할 수 있습니다.
irb(main):001:0> require 'gem_a'
=> true
irb(main):002:0> GemA::Version
=> "2.0.0"
Gemfile
에서 gem_b
gem 'gem_a'
# bundle
Using bundler 1.16.2
Using gem_a 2.0.0
Bundle complete! 1 Gemfile dependency, 2 gems now installed.
Use `bundle info [gemname]` to see where a bundled gem is installed.
# cat Gemfile.lock
GEM
remote: https://rubygems.org/
specs:
gem_a (2.0.0)
PLATFORMS
ruby
DEPENDENCIES
gem_a
BUNDLED WITH
1.16.2
Bundler는 훌륭합니다.
요약
Bundler가 있다면 다양한 버전의 gem을 많이 설치해도 충돌하지 않도록 bundle
할 수 있습니다.
(여담입니다만, 위와 같은 움직임이므로, 기본적으로는 require
"왜 GemB는 GemA (2.0.0)를 사용하지 않고 GemA (1.0.0)를 읽으려고 할 수 있습니까? 그렇다면 Bundler의 일이 아닙니까?"라고 생각하는 사람은 아마 Gem과 Bundler 의 기능을 혼동합니다. gem 종속성은 gem별로 정의됩니다 (gem 내에 .gemspec이라는 정의 파일이 있습니다). 이 때문에, gem을 1개 사용하는 것만이라면 보통으로 bundle --path=vendor/bundle
하면(자), 의존하고 있는 gem도 함께 적절한 버젼이 로드됩니다. 한편, Bundler는 "여러 개의 gem을 동시에 사용할 때 어떻게 의존관계를 해결하면 require
를 피할 수 있을까?"라는 문제를 해결하기 위한 것입니다. ↩
Reference
이 문제에 관하여(bundle exec은 왜 필요한가?), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://qiita.com/diskkid/items/0d000a42df04c561ca0f
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
번들러가 없으면 무슨 일이 일어나는지
구체적인 예에서 설명합니다. 다음과 같은 종속성을 가진 gem, "GemA", "GemB"가 있다고 가정합시다. 둘 다 설치되어 있다고 가정합니다.
gem_a.rb
module GemA
Version = "1.0.0"
end
gem_b.rb
require 'gem_a'
module GemB
Version = '1.0.0'
def self.say
puts "I'm using GemA ver. #{::GemA::Version}!"
end
end
# gem list
*** LOCAL GEMS ***
gem_a (1.0.0)
gem_b (1.0.0)
물론 둘 다
require
가능합니다.irb(main):001:0> require 'gem_a'
=> true
irb(main):002:0> GemA::Version
=> "1.0.0"
irb(main):003:0> require 'gem_b'
=> true
irb(main):004:0> GemB::Version
=> "1.0.0"
irb(main):005:0> GemB::say
I'm using GemA ver. 1.0.0!
=> nil
이제 GemA를 2.0.0으로 업데이트합니다.
# gem update gem_a
Updating installed gems
Updating gem_a
Fetching: gem_a-2.0.0.gem (100%)
Successfully installed gem_a-2.0.0.gem
Gems updated: gem_a
# gem list
*** LOCAL GEMS ***
gem_a (2.0.0, 1.0.0)
gem_b (1.0.0)
업데이트할 수 있었습니다. irb에서 조금 전과 같은 것을 시도합니다.
irb(main):001:0> require 'gem_a'
=> true
irb(main):002:0> GemA::Version
=> "2.0.0"
제대로 업데이트되었습니다. GemB도 사용해 봅시다.
irb(main):003:0> require 'gem_b'
Traceback (most recent call last):
8: from /usr/local/bin/irb:11:in `<main>'
7: from (irb):3
6: from /usr/local/Cellar/ruby/2.5.1/lib/ruby/2.5.0/rubygems/core_ext/kernel_require.rb:39:in `require'
5: from /usr/local/Cellar/ruby/2.5.1/lib/ruby/2.5.0/rubygems/core_ext/kernel_require.rb:128:in `rescue in require'
4: from /usr/local/Cellar/ruby/2.5.1/lib/ruby/2.5.0/rubygems.rb:217:in `try_activate'
3: from /usr/local/Cellar/ruby/2.5.1/lib/ruby/2.5.0/rubygems.rb:224:in `rescue in try_activate'
2: from /usr/local/Cellar/ruby/2.5.1/lib/ruby/2.5.0/rubygems/specification.rb:1438:in `activate'
1: from /usr/local/Cellar/ruby/2.5.1/lib/ruby/2.5.0/rubygems/specification.rb:2325:in `raise_if_conflicts'
Gem::ConflictError (Unable to activate gem_b-1.0.0, because gem_a-2.0.0 conflicts with gem_a (= 1.0.0))
죄송합니다... 곤란했습니다. GemB가 망가졌습니다. 이미 GemA (2.0.0)를
require
했으므로 GemB에 필요한 GemA (1.0.0)를로드 할 수 없어 오류가 발생했습니다. 1어떻게 되면 기쁜가?
GemB를 사용하는 프로젝트에서는 업데이트한 GemA(2.0.0)를 사용하지 않고 GemA(1.0.0)를 그대로 사용할 수 있으면 좋았습니다.
irb(main):001:0> require 'gem_a'
=> true
irb(main):002:0> GemA::Version
=> "1.0.0"
irb(main):003:0> require 'gem_b'
=> true
irb(main):004:0> GemB::Version
=> "1.0.0"
한편, GemB를 사용하지 않는 프로젝트에서는 최신 GemA (2.0.0)를 사용하고 싶네요.
irb(main):001:0> require 'gem_a'
=> true
irb(main):002:0> GemA::Version
=> "2.0.0"
이것을 실현하는 것이 Bundler이며,
bundle exec
라는 명령입니다.번들러가 있으면 어떻게 될까
GemA와 GemB를 사용하고 싶은 프로젝트에 이런 느낌의 Gemfile을 준비합니다.
gem 'gem_a'
gem 'gem_b'
그리고
bundle
를 실행하면 Gemfile.lock
가 생성됩니다.# bundle
Fetching gem metadata from https://rubygems.org/.
Fetching gem metadata from https://rubygems.org/.
Resolving dependencies...
Using bundler 1.16.2
Using gem_a 1.0.0
Using gem_b 1.0.0
Bundle complete! 2 Gemfile dependencies, 3 gems now installed.
Use `bundle info [gemname]` to see where a bundled gem is installed.
# cat Gemfile.lock
GEM
remote: https://rubygems.org/
specs:
gem_a (1.0.0)
gem_b (1.0.0)
gem_a (= 1.0.0)
PLATFORMS
ruby
DEPENDENCIES
gem_a
gem_b
BUNDLED WITH
1.16.2
이 상태에서
bundle exec irb
해 봅시다.irb(main):001:0> require 'gem_a'
=> true
irb(main):002:0> GemA::Version
=> "1.0.0"
irb(main):003:0> require 'gem_b'
=> true
irb(main):004:0> GemB::Version
=> "1.0.0"
irb(main):005:0> GemB::say
I'm using GemA ver. 1.0.0!
=> nil
제대로 움직입니다!
일반적으로 irb를 시작하면 새로운 버전의 GemA (2.0.0)도 제대로 사용할 수 있습니다.
irb(main):001:0> require 'gem_a'
=> true
irb(main):002:0> GemA::Version
=> "2.0.0"
Gemfile
에서 gem_b
gem 'gem_a'
# bundle
Using bundler 1.16.2
Using gem_a 2.0.0
Bundle complete! 1 Gemfile dependency, 2 gems now installed.
Use `bundle info [gemname]` to see where a bundled gem is installed.
# cat Gemfile.lock
GEM
remote: https://rubygems.org/
specs:
gem_a (2.0.0)
PLATFORMS
ruby
DEPENDENCIES
gem_a
BUNDLED WITH
1.16.2
Bundler는 훌륭합니다.
요약
Bundler가 있다면 다양한 버전의 gem을 많이 설치해도 충돌하지 않도록 bundle
할 수 있습니다.
(여담입니다만, 위와 같은 움직임이므로, 기본적으로는 require
"왜 GemB는 GemA (2.0.0)를 사용하지 않고 GemA (1.0.0)를 읽으려고 할 수 있습니까? 그렇다면 Bundler의 일이 아닙니까?"라고 생각하는 사람은 아마 Gem과 Bundler 의 기능을 혼동합니다. gem 종속성은 gem별로 정의됩니다 (gem 내에 .gemspec이라는 정의 파일이 있습니다). 이 때문에, gem을 1개 사용하는 것만이라면 보통으로 bundle --path=vendor/bundle
하면(자), 의존하고 있는 gem도 함께 적절한 버젼이 로드됩니다. 한편, Bundler는 "여러 개의 gem을 동시에 사용할 때 어떻게 의존관계를 해결하면 require
를 피할 수 있을까?"라는 문제를 해결하기 위한 것입니다. ↩
Reference
이 문제에 관하여(bundle exec은 왜 필요한가?), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://qiita.com/diskkid/items/0d000a42df04c561ca0f
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
Reference
이 문제에 관하여(bundle exec은 왜 필요한가?), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/diskkid/items/0d000a42df04c561ca0f텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)