Edited at

Bundlerを使ったGem管理について

食べログAdventCalendar23日目は、DevOpsチームの@mochikichi321が「Bundlerを使ったGem管理について」をお届けします。

食べログ Advent Calendar 2018 に書くのは2度目です。

1度目の記事も読んでいただけると嬉しいです。

30代未経験からWEBエンジニアへなった私の1年間の学び


こんな方に読んでいただきたい


  • Ruby歴の浅い方

  • GemとかBundlerをなんとなく使ってきたけど実はあんまりよくわかってないから知りたい


Gemとは

Ruby言語用のライブラリのこと。

主なGem達。


  • Rails(Webアプリケーションフレームワーク)

  • Rspec(テストフレームワーク)

  • Unicorn(アプリケーションサーバ)

  • Bundler(Gem依存管理)


RubyGemsとは

Rubyのためのパッケージ管理ツール(yumとかと似ている)。

下記のようにするとgemをインストールしたりできる。

$ gem install gem_name

詳細は公式のrubygemsライブラリ参照。


RubyGemsの保存先

Gemのインストールをすると、下記の場所に保存される。(私の場合)

/usr/local/ruby-X.Y.Z/lib/ruby/gems/X.Y.Z

X.Y.Z: バージョン番号。X.Y.ZはMajor.Minor.Patchを表す。

保存場所確認方法

下記の中の


「INSTALLATION DIRECTORY: /usr/local/ruby-X.Y.Z/lib/ruby/gems/X.Y.Z」

$ gem environment

RubyGems Environment:
- RUBYGEMS VERSION: X.Y.Z
- RUBY VERSION: X.Y.Z
- INSTALLATION DIRECTORY: /usr/local/ruby-X.Y.Z/lib/ruby/gems/X.Y.Z #ここ
  (省略)



Gemが保管されている場所

代表的な場所は下記。(それ以外にもいろいろ作れる)

rubygems.org


Bundlerとは

Gemの依存関係とバージョンを管理するためのツール

公式の言葉を引用すると「exit from dependency hell(依存地獄からの脱出)」だそう。


Bundlerを使わないとどうなる?

上述のように、gemのインストールは$ gem install gem_nameでできるが以下のような問題がある。


一つずつgemをインストールするのが大変

ただし、Aというgemを使うためにはBというgemが必要で、Bというgemを使うためにはCというgemが必要といった形で依存関係があるので一つずつ依存関係を確認してインストールするのはかなり大変。


gemのバージョン依存問題

"Aというgemのver1.0.0"と"Bというgemのver2.0.0"はうまく動くけど、最新バージョン同士(例:"Aというgemのver2.0.0"と"Bというgemのver2.0.0")だとうまく動かない。という互換性の問題が出てくる場合がある。

gemの数が多いほどバージョン依存関係は複雑化する。


開発者の環境によってgem(バージョン含む)が統一されない

開発環境によってgem(バージョン含む)が統一されていないと、挙動が異なることがあり問題である。


同一サーバ上で複数の ruby コード群から異なるバージョンの gem を使い分けられない

gem だと空間が1個しかないので、同一サーバ上で複数の ruby コード群から異なるバージョンの gem を使い分けられない。


Aというrubyコード群ではgemのバージョン1.0.0を使いたいけど、Bというrubyコード群ではgemのバージョン2.0.0を使うといった使い方はできない。


Bundlerの役割

上記の問題を解決してくれるのがBundler


  • 一つずつgemをインストールするのが大変

    =>依存関係のあるgemを一括でインストールしてくれる!! :clap:


  • gemのバージョン依存問題

    =>適用する全てのgemの依存関係を見てバージョンを調整してインストールしてくれる!! :clap:


  • 開発者の環境によってgem(バージョン含む)が統一されない

    =>プロジェクト毎にgemの保存先を指定できるのですべての開発環境で同じgemの条件を適用できる!! :clap:


  • 同一サーバ上で複数の ruby コード群から異なるバージョンの gem を使い分けられない

    =>bundlerを使うことで、Aというrubyコード群ではgemのバージョン1.0.0を使いたいけど、Bというrubyコード群ではgemのバージョン2.0.0を使うといった指定ができる!! :clap:



bundlerのインストールと使い方

$ gem install bundler

詳細は公式のBundler参照。


知っておくと得するポイント


group

下記のようにgroupで環境を指定して--withoutオプションで、指定した環境のgemインストールを除外することができる。

# These gems are in the :default group

gem 'nokogiri'
gem 'sinatra'

gem 'wirble', :group => :development

group :test do
gem 'faker'
gem 'rspec'
end

group :test, :development do
gem 'capybara'
gem 'rspec-rails'
end

gem 'cucumber', :group => [:cucumber, :test]

$ bundle install --without test development

公式情報:

How to manage groups of gems | Bundler


Gemのバージョン指定

gem 'hoge', "X.Y.Z"   #X.Y.ZはMajor.Minor.Patch

よく混乱するのが下記

gem 'hoge', "~> 2.1.8"   # 2.1.8以上2.2.0未満の最新のものを使用

参考:RubyGems version specifiers


ローカルでgemを変更したい時に

gemの保存場所であるBUNDLE_PATHはgitignore(git管理外)していると思うので、ローカルで変更して戻すを忘れたり間違えると思わぬ挙動を示しハマリどころとなる。

なので、ローカルでgemを変更したい時はBUNDLE_PATH以外の場所にgemをコピーして編集するとよい

詳細



  • vendor/extracted_libraryのようなディレクトリを用意する

$ mkdir vendor/extracted_library


  • 編集したいgemをvendor/extracted_libraryへコピー

$ cp -rf vendor/bundle/ruby/X.Y.Z/gems/dalli-X.Y.Z/ vendor/extracted_library/


  • Gemfileのpathを変更する

[Gemfile]

-gem "dalli"
+gem "dalli", path: "./vendor/extracted_library"



  • git statusに表示されているので編集したことが明確(忘れにくい)

$ git status

On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)

modified: Gemfile

Untracked files:
(use "git add <file>..." to include in what will be committed)

#BUNDLE_PATH

no changes added to commit (use "git add" and/or "git commit -a")



公式情報


まとめ

GemとかBundlerについて少しは理解が深まりましたでしょうか。

今後、更に学習していくきっかけになれば嬉しいです。

明日の食べログAdventCalendar24日目は@fdashさんによる「Kotlinに流れ着いたエンジニアがハマりがちなもの」です。

そちらも楽しみにしておいてください!