LoginSignup
5
4

More than 5 years have passed since last update.

gem パッケージのバージョン番号は gemspec で定義すれば良い

Last updated at Posted at 2013-04-11

bundle gem でテンプレートを生成すると、version.rb というファイルに Package::Name::Version::VERSION という定数を作ってそこにバージョン番号を定義してくれる。gemspec では version.rbrequire して、VERSION 定数を参照することで gem パッケージのバージョンを設定する。

この方法は、バージョン番号の定義が一カ所だけになって DRY だが、Package::Name をモジュールではなく、Objectではないクラスのサブクラスにしたい場合に問題を発生させる。

その問題とは、lib/package/name.rblib/package/name/version.rb の2つのファイルで、以下のようにスーパークラスを二重に書く必要があることだ。

# lib/package/name.rb
module Package
  class Name < SuperClass
  end
end

# lib/package/name/version.rb
module Package
  class Name < SuperClass
    module Version
      VERSION = '1.0.0'.freeze
    end
  end
end

SuperClassArray などの組み込みクラスなら、スーパークラスの指定が DRY じゃないというだけなんだが、他のライブラリで定義されているクラスだったりするともっと困る。version.rb をロードするだけで SuperClass を提供しているライブラリもロードしてしまうからだ。version.rb は gemspec でロードされるので、gemspec をロードしただけで依存するライブラリをロードしてしまう困ったちゃんになってしまい、ユーザが激おこプンプン丸に変身してしまう。

これを解決する方法として、バージョン番号を gemspec に直接書く方法を発見した。

原理は簡単だ。gem パッケージ内のファイルをロードできるということは、そのパッケージの gemspec が既にロードされていることを意味する。だから、ライブラリ内では Gem.loaded_specs['package-name'] で自分自身の Gem::Specification オブジェクトが取り出せる。

よって、以下のように lib/package/name.rb の中で VERSION 定数を直接定義してしまえばよい。

# lib/package/name.rb
module Package
  class Name < SuperClass
    VERSION = Gem.loaded_specs['package-name'].version.to_s.freeze
  end
end

version.rb はもう必要無い。

5
4
5

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
4