bundle gemは何をしてくれるのか?

必要最小のgemパッケージの作り方は大体理解できた。

  1. rubyコードをlib/とbin/に振り分けて、
  2. .gemspecファイルに設定を記述して、
  3. gem build、gem installしてテスト、
  4. 問題なければgem pushで公開。

とっても簡単である。

初回のみ.gemspecファイルの追加とRubyGems.orgへの登録が必要だが、手間はかからない。
一旦公開してしまえば、コード修正して、gem build、gem install、gem pushの繰り返しだ。
これ以上何を求めてbundlerを使うのか?探ってみた。

bundle gemが生成するもの

  • sampleという名のgemプロジェクトを始めてみる。
$ bundle gem sample
      create  sample/Gemfile
      create  sample/Rakefile
      create  sample/LICENSE.txt
      create  sample/README.md
      create  sample/.gitignore
      create  sample/sample.gemspec
      create  sample/lib/sample.rb
      create  sample/lib/sample/version.rb
Initializing git repo in /Users/zari/Desktop/sample
  • sampleフォルダ以下に、8個のファイルが追加された!
  • sampleフォルダは最初からGit管理されている。
$ cd sample
.git		.gitignore	Gemfile		LICENSE.txt	README.md	Rakefile	lib		sample.gemspec
  • 追加されたファイルは既にgit addされた状態。
(master)$ git status
On branch master

Initial commit

Changes to be committed:
  (use "git rm --cached ..." to unstage)

	new file:   .gitignore
	new file:   Gemfile
	new file:   LICENSE.txt
	new file:   README.md
	new file:   Rakefile
	new file:   lib/sample.rb
	new file:   lib/sample/version.rb
	new file:   sample.gemspec
  • その状態を"bundle gem sample"としてcommitしておいた。
(master)$ git commit 
[master (root-commit) deb38cd] bundle gem sample
 8 files changed, 104 insertions(+)
 create mode 100644 .gitignore
 create mode 100644 Gemfile
 create mode 100644 LICENSE.txt
 create mode 100644 README.md
 create mode 100644 Rakefile
 create mode 100644 lib/sample.rb
 create mode 100644 lib/sample/version.rb
 create mode 100644 sample.gemspec

(master)$ git log --oneline
deb38cd (HEAD, master) bundle gem sample


それぞれのファイルの中身を覗いてみた。

sample.gemspec
  • 最も重要な.gemspecファイルは以下のように生成されている。
    • TODO:の部分は、必ず自分で修正すべき所。
# coding: utf-8
lib = File.expand_path('../lib', __FILE__)
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
require 'sample/version'

Gem::Specification.new do |spec|
  spec.name          = "sample"
  spec.version       = Sample::VERSION
  spec.authors       = ["zariganitosh"]
  spec.email         = ["XXXX@example.com"]
  spec.summary       = %q{TODO: Write a short summary. Required.}
  spec.description   = %q{TODO: Write a longer description. Optional.}
  spec.homepage      = ""
  spec.license       = "MIT"

  spec.files         = `git ls-files -z`.split("\x0")
  spec.executables   = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
  spec.test_files    = spec.files.grep(%r{^(test|spec|features)/})
  spec.require_paths = ["lib"]

  spec.add_development_dependency "bundler", "~> 1.7"
  spec.add_development_dependency "rake", "~> 10.0"
end
  • 眺めていると、いくつかの特徴的な書き方が気になってくる。
lib = File.expand_path('../lib', __FILE__)
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
require 'sample/version'
  spec.version       = Sample::VERSION
  • versionにSample::VERSIONという定数を指定している。
  • そして定数Sample::VERSIONを設定するために、専用のlib/sample/version.rbを追加している。
  spec.files         = `git ls-files -z`.split("\x0")
  • gemに含めるファイルを指定する時に、`git ls-files`を利用している。
  • `git ls-files`はGitが管理しているファイルリストを出力するコマンド。
  • プロジェクトに必要なファイルは必ずコミットされているはずだから、git ls-filesですべてのファイルを漏れなく設定できるのだ。
  • これならファイルの追加や削除があった場合も、.gemspecファイルを修正する必要がなくなる。とても賢いやり方だと思った。
  spec.add_development_dependency "bundler", "~> 1.7"
  spec.add_development_dependency "rake", "~> 10.0"
  • spec.add_development_dependencyは、この開発プロジェクトに必要なgemを指定している。
    • bundler 1.7.xの最新バージョンと、
    • rake 10.0.xの最新バージョンが必要なのだ。
lib/sample/version.rb
  • 上記.gemspecファイルのversionを設定するための専用ファイル。
  • .gemspecの中でrequireされ、Sample::VERSIONが参照されている。
module Sample
  VERSION = "0.0.1"
end
lib/sample.rb
  • ライブラリを定義する本体である。
  • ここに独自のmoduleやclassを追加して、便利な機能を実現するライブラリとするのだ。
require "sample/version"

module Sample
  # Your code goes here...
end
Rakefile
  • require "bundler/gem_tasks"することで、bundlerがデフォルトで提供するRakeタスクが追加される。
    • Rakeとは、makeをRubyで実装したもの。Ruby版のmakeのようなもの。
    • Rakefileとはmakefileのようなものである。ビルドなど、実行環境に合わせた作業を行うスクリプトである。
    • 一連の面倒な作業を素早く処理するスクリプトを提供してくれるのだ。
require "bundler/gem_tasks"
  • require "bundler/gem_tasks"によって、デフォルトのrakeタスクは以下の3つが追加された。
(master)$ rake -T
rake build    # Build sample-0.0.1.gem into the pkg directory
                pkgディレクトリの中にsample-0.0.1.gemをビルドする。
rake install  # Build and install sample-0.0.1.gem into system gems
                sample-0.0.1.gemをビルドして、`gem env home`にインストールする。
rake release  # Create tag v0.0.1 and build and push sample-0.0.1.gem to Rubygems
                v0.0.1タグを作成して、sample-0.0.1.gemをビルドして、git pushとgem push(RubyGemsへ公開)する。
  • もし、rakeタスクの内容を手作業で操作したら、以下のようなコマンドが実行されるのだと思う。
実行内容1 実行内容2 実行内容3 実行内容4
rake build gem build sample.gemspecして...
pkg/sample-0.0.1.gemへ出力する
rake install 必要に応じてreke build gem install pkg/sample-0.0.1.gem
rake release 必要に応じてreke build git tag -a -m "Version 0.0.1" v0.0.1 git push gem push pkg/sample-0.0.1.gem
  • これらのrakeタスクは、リリースの度に必要となる一連の操作を、バージョン番号まで管理しながら、素早く完了してくれるのだ。
    • Sample::VERSIONのバージョン番号さえちゃんと設定しておけば、面倒なバージョン指定は不要になる。
README.md
  • READMEの雛形は以下のようになっていた。
    • TODO:の部分は、必ず自分で修正すべき所。
# Sample

TODO: Write a gem description
このgemの説明を書くこと。

## Installation--インストール

Add this line to your application's Gemfile:
アプリケーションのGemfileにこの1行を追加します:

```ruby
gem 'sample'
```

And then execute:
それから実行します。

    $ bundle

Or install it yourself as:
あるいは、次のように自分でインストールします。

    $ gem install sample

## Usage--使い方

TODO: Write usage instructions here
ここに使用方法を書くこと。

## Contributing--貢献

1. Fork it ( https://github.com/[my-github-username]/sample/fork )
  1. フォークしてください。
2. Create your feature branch (`git checkout -b my-new-feature`)
  2. フィーチャー(新機能)ブランチを作成します。
3. Commit your changes (`git commit -am 'Add some feature'`)
  4. 変更してコミットします。
4. Push to the branch (`git push origin my-new-feature`)
  4. ブランチをプッシュします。
5. Create a new Pull Request
  5. プルリクエストを新規作成します。
LICENSE.txt
  • .gemspecがデフォルトで設定するMITライセンスの定義文を保存したファイル。
Copyright (c) 2014 zariganitosh

MIT License

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Gemfile
  • Gemfileは、bundlerが利用する。Railsアプリケーションなどに必要な「厳密な依存関係」を定義しておくファイル。
  • 一方、sample.gemspecは、gemが利用する。そのgemに必要な「ゆるい依存関係」などを定義しておくファイル。(依存関係だけでなくgemパッケージの設定ファイル)
  • どちらも依存関係を定義するファイルである。
  • Gem開発時には、gem由来のsample.gemspecに依存関係を書いておく。
  • Gem開発時のGemfileは、特に必要がない限り、デフォルトの以下の設定のままでOK。
    • sourceは、gemを探しに行くURLを指定している。
    • gemspecは、依存関係については.gemspecファイルを参照することを指定している。
source 'https://rubygems.org'

# Specify your gem's dependencies in sample.gemspec
gemspec
  • 一方、Gem以外(Railsアプリケーションなど)の開発では、Gemfileに依存関係を書いておく。
  • bundle installすると、bundlerはGemfileを元に指定されたディレクトリにインストールする。
    • と同時に、インストールしたgemとそのバージョンをGemfile.lockに記録する。
  • そして、Gemfile.lockがある環境でbundle installすると、bundlerはGemfile.lockに記録されたバージョンのgemを正確にインストールしてくれる。
  • よって、Gemfile.lockを配布することで、bundlerはまったく同じgem環境を再現できるのだ。
.gitignore
  • Git管理しないファイルを定義してある。
  • git add .やgit add -Aした時に、以下のファイルは除外されるのだ。
/.bundle/       # Gitプロジェクトルートの.bundleフォルダは無視する
/.yardoc        # Gitプロジェクトルートの.yardocファイル・フォルダは無視する
/Gemfile.lock   # GitプロジェクトルートのGemfile.lockファイル・フォルダは無視する
/_yardoc/       # Gitプロジェクトルートの_yardocフォルダは無視する
/coverage/      # Gitプロジェクトルートのcoverageフォルダは無視する
/doc/           # Gitプロジェクトルートのdocフォルダは無視する
/pkg/           # Gitプロジェクトルートのpkgフォルダは無視する
/spec/reports/  # Gitプロジェクトルートのspec/reportsフォルダは無視する
/tmp/           # Gitプロジェクトルートのtmpフォルダは無視する
*.bundle        # .bundleで終わるファイル・フォルダは無視する
*.so            # .soで終わるファイル・フォルダは無視する
*.o             # .oで終わるファイル・フォルダは無視する
*.a             # .aで終わるファイル・フォルダは無視する
mkmf.log        # mkmf.logという名前のファイル・フォルダは無視する
      • "/abc"の"/"は、.gitignoreと同じ階層、あるいはGitプロジェクトルートを意味する。この場合、Gitプロジェクトルートのabcというファイルまたはフォルダを無視する設定。
      • "abc/"の"/"は、フォルダ(ディレクトリ)であることを意味する。この場合、abcというフォルダを無視する設定。
      • "abc"の場合は、abcというファイルまたはフォルダを無視する設定。

jcalプロジェクトをbundlerでGem化

  • jcalプロジェクトをjpdateという名称でコピーしておいた。
    • Gem名とプロジェクトのフォルダ名を一致させておく。
$ cd ~/Desktop
$ cp -r jcal jpdate
$ cd jpdate
$ ls
.git/           README.md	jcal.rb		jpdate/		jpdate.rb

$ find -E . \! -regex "\./\.git.*"
./jcal.rb
./jpdate
./jpdate/era.rb
./jpdate/holiday.rb
./jpdate.rb
./README.md
  • libフォルダとbinフォルダを作って、必要なファイルを移動させた。
$ mkdir lib
$ mkdir bin
$ mv jpdate/ lib/
$ mv jpdate.rb lib/
$ mv jcal.rb bin/
$ ls
.git/           README.md  bin/       lib/

$ find -E . \! -regex "\./\.git.*"
./bin
./bin/jcal.rb
./lib
./lib/jpdate
./lib/jpdate/era.rb
./lib/jpdate/holiday.rb
./lib/jpdate.rb
./README.md
  • bundle gem jpdateを実行して、bundler管理のGemプロジェクトにする。
    • 既存のファイルは上書きしない。
$ cd ~/Desktop
$ bundle gem jpdate
      create  jpdate/Gemfile
      create  jpdate/Rakefile
      create  jpdate/LICENSE.txt
    conflict  jpdate/README.md
Overwrite /Users/zari/Desktop/jpdate/README.md? (enter "h" for help) [Ynaqdh] n
        skip  jpdate/README.md
      create  jpdate/.gitignore
      create  jpdate/jpdate.gemspec
    conflict  jpdate/lib/jpdate.rb
Overwrite /Users/zari/Desktop/jpdate/lib/jpdate.rb? (enter "h" for help) [Ynaqdh] n
        skip  jpdate/lib/jpdate.rb
      create  jpdate/lib/jpdate/version.rb
Initializing git repo in /Users/bebe/Desktop/jpdate
warning: You ran 'git add' with neither '-A (--all)' or '--ignore-removal',
whose behaviour will change in Git 2.0 with respect to paths you removed.
Paths like 'jcal.rb' that are
removed from your working tree are ignored with this version of Git.

 * 'git add --ignore-removal ', which is the current default,
  ignores paths you removed from your working tree.

 * 'git add --all ' will let you also record the removals.

Run 'git status' to check the paths you removed from your working tree.
  • jpdateフォルダに移動して、すべてのファイルの変更をコミットした。
$ cd jpdate
$ ls
.git/           .gitignore      Gemfile         LICENSE.txt     README.md       Rakefile        bin/            jpdate.gemspec  lib/

$ git status
On branch master
Your branch is behind 'origin/master' by 8 commits, and can be fast-forwarded.
  (use "git pull" to update your local branch)

Changes to be committed:
  (use "git reset HEAD ..." to unstage)

	new file:   .gitignore
	new file:   Gemfile
	new file:   LICENSE.txt
	new file:   Rakefile
	new file:   bin/jcal.rb
	new file:   jpdate.gemspec
	new file:   lib/jpdate.rb
	new file:   lib/jpdate/era.rb
	new file:   lib/jpdate/holiday.rb
	new file:   lib/jpdate/version.rb

Changes not staged for commit:
  (use "git add/rm ..." to update what will be committed)
  (use "git checkout -- ..." to discard changes in working directory)

	deleted:    jcal.rb
	deleted:    jpdate.rb
	deleted:    jpdate/era.rb
	deleted:    jpdate/holiday.rb

$ git add -A
$ git status
On branch master
Your branch is behind 'origin/master' by 8 commits, and can be fast-forwarded.
  (use "git pull" to update your local branch)

Changes to be committed:
  (use "git reset HEAD ..." to unstage)

	new file:   .gitignore
	new file:   Gemfile
	new file:   LICENSE.txt
	new file:   Rakefile
	renamed:    jcal.rb -> bin/jcal.rb
	new file:   jpdate.gemspec
	renamed:    jpdate.rb -> lib/jpdate.rb
	renamed:    jpdate/era.rb -> lib/jpdate/era.rb
	renamed:    jpdate/holiday.rb -> lib/jpdate/holiday.rb
	new file:   lib/jpdate/version.rb

$ git commit -m 'bundle gem jpdate'
[master 13ccef0] bundle gem jpdate
 10 files changed, 68 insertions(+)
 create mode 100644 .gitignore
 create mode 100644 Gemfile
 create mode 100644 LICENSE.txt
 create mode 100644 Rakefile
 rename jcal.rb => bin/jcal.rb (100%)
 create mode 100644 jpdate.gemspec
 rename jpdate.rb => lib/jpdate.rb (100%)
 rename {jpdate => lib/jpdate}/era.rb (100%)
 rename {jpdate => lib/jpdate}/holiday.rb (100%)
 create mode 100644 lib/jpdate/version.rb
  • jpdate.gemspecを修正した。
    • TODO:の部分に記入した。
    • homepageにgithubのURLを記入した。
$ git diff
diff --git a/jpdate.gemspec b/jpdate.gemspec
index e6bf339..983f743 100644
 --- a/jpdate.gemspec
 +++ b/jpdate.gemspec
 @@ -8,8 +8,8 @@ Gem::Specification.new do |spec|
    spec.version       = Jpdate::VERSION
    spec.authors       = ["zariganitosh"]
    spec.email         = ["XXXX@example.com"]
 -  spec.summary       = %q{TODO: Write a short summary. Required.}
 -  spec.description   = %q{TODO: Write a longer description. Optional.}
 -  spec.homepage      = ""
 +  spec.summary       = %q{日本の祝日を出力するJPDateクラス}
 +  spec.description   = %q{明治6年1月1日以降の日本の祝日を出力可能なJPDateクラス}
 +  spec.homepage      = "https://github.com/zarigani/jcal"
    spec.license       = "MIT"
  • README.mdも修正した。
    • bundlerがデフォルトで生成する項目(jpdateの概要・インストール・使い方・貢献)を漏れなく記載するようにした。
  • 以上の作業をコミットしておく。
$ git add .
$ git commit -m 'Setting gem.'
[master 0920920] Setting gem.
 2 files changed, 16 insertions(+), 7 deletions(-)
  • gemをインストールしてテスト。
    • テストコードはまだないので、irbで手作業でテストしてみた。
    • また、jcalコマンドでカレンダーが正常に出力されるか確認した。
$ sudo rake install
Password:
jpdate 0.0.1 built to pkg/jpdate-0.0.1.gem.
jpdate (0.0.1) installed.
  • テストに問題なければ、gemを公開するのだ。
    • rake releaseによって、gem build、git tag、git push、gem pushという一連の作業が一気に処理されるのだ。
$ rake release

以降のルーチンワーク

  • bundle gemで管理した場合
    • バージョンの指定は、jpdate/version.rbの修正のみ。
    • .gitignoreの設定がきちんと行われる。
# 機能の追加や修正
# jpdate/version.rbの、gemパッケージのバージョンを修正
$ git add .
$ git commit
$ sudo rake install
# テストして問題なければ...
$ rake release
  • 自分で管理した場合
    • バージョンやタグの指定を4回繰り返すことになる。
    • 全般的にコマンド引数やオプションの指定が多い。
    • 特にバージョン番号を含んだコマンド引数を毎回指定するのは面倒。
    • .gitignoreの設定が曖昧になりがち。後日、余分なコミットを発見して幻滅する。
# 機能の追加や修正
# jpdate.gemspecの、gemパッケージのバージョンを修正
$ git add .
$ git commit
$ gem build jpdate.gemspec
$ sudo gem install jpdate-X.X.X.gem
# テストして問題なければ...
$ git tag vX.X.X
$ git push --tags
$ gem push jpdate-X.X.X.gem
  • bundlerは、お決まりの手順で面倒な部分や、疎かになりがちな部分をしっかりサポートしてくれるのであった。

gemを作る時は、bundle gemで始めた方が楽!

陥りがちなこと

gem名からファイル名・モジュール名・クラス名への命名規則に気を付ける
  • gemには、その名前から推奨される命名規則がある。
  • 例えば、gem名がappleの場合、ファイル名はapple.rb、クラス・モジュール名はApple、となる。
  • この辺りのことは、本家Gemのページに詳しく例が掲載されている。
Gem名 requireの記述(ファイル・パス名) クラス・モジュール名
fancy_require require 'fancy_require' FancyRequire
ruby_parser require 'ruby_parser' RubyParser
net-http-persistent require 'net/http/persistent' Net::HTTP::Persistent
rdoc-data require 'rdoc/data' RDoc::Data
autotest-growl require 'autotest/growl' Autotest::Growl
net-http-digest_auth require 'net/http/digest_auth' Net::HTTP::DigestAuth
Name your gem - RubyGems Guides

つまり...

  • ハイフン"-"は、ネームスペースを区切る階層を意味する。
    • ネームスペースとディレクトリ階層は一致させておく作法。
    • ファイルパス名では、"/"に変換される。
    • クラス・モジュール名では、"::"に変換される。
    • 既存のgemを拡張する時などに使うのかな?
  • アンダースコア"_"は、単語の区切りを意味する。
    • クラス・モジュール名は、アンダースコア"_"を取り除いて、各単語の先頭を大文字にする。
  • gem名とファイル・パス名はすべて小文字。クラス・モジュール名の各単語の先頭は大文字。
  • bundle gemは、上記の命名規則を忠実に守ってgem開発プロジェクトの雛形を生成する。
  • よって、bundle gem jpdateを実行するとどうなるか?
$ bundle gem jpdate
      create  jpdate/Gemfile
      create  jpdate/Rakefile
      create  jpdate/LICENSE.txt
      create  jpdate/README.md
      create  jpdate/.gitignore
      create  jpdate/jpdate.gemspec
      create  jpdate/lib/jpdate.rb
      create  jpdate/lib/jpdate/version.rb
Initializing git repo in /Users/zari/Desktop/jpdate
  • jpdate.rbとjpdate/version.rbが生成されるが、そのモジュール名は"Jpdate"となっているのだ!
  • ところが、当初から自分が作っていたのは"JPDate"であった。
  • "Jpdate"と"JPDate"。クラス名が違っていたのだ。
  • bundle gemを使い始めたのは開発の途中からだったので、libフォルダにはjpdate/version.rbのみ追加された。
  • bundle gem直後は正常に動くのだけど、モジュール名を"JPDate"に変更すると、とたんにエラーが出て動かなくなった...。


なぜか?

  • jpdateでは、元々JPDateクラスを定義していた。
class JPDate < Date
...中略...
  • 一方bundler gemは、Jpdateモジュールを定義する。
module Jpdate
  VERSION = "0.0.1"
end
  • 名称の違いに気付いて、JpdateモジュールをJPDateモジュールに変更してしまうと...
module JPDate
  VERSION = "0.0.1"
end
  • 同じネームスペースに、class JPDate < Dateとmodule JPDateを定義することになってしまうのだ。
  • 対策として、自分の場合は"JPDate"を活かしたいので、モジュール定義をクラス定義に変更した。
class JPDate < Date
  VERSION = "0.0.1"
end
  • 本来は、最初からgemの命名規則に注意して、このような悩ましい名前を付けるべきではなかった?
  • では、どのような名前にすべきだったのか?
    • "bundle gem jpdate"で、"Jpdate"か?
    • "bundle gem jp_date"で、"JpDate"か?
    • "bundle gem j_p_date"で、"JPDate"か?
  • "jpdate"に固執する限り、解決できない気がした。
    • "bundle gem japanese_date"で、"JapaneseDate"か?

悩ましい...。

ERROR: While executing gem ... (Gem::InvalidSpecificationException)に悩む
  • rake buildするとエラーが発生!
$ rake build
rake aborted!
WARNING:  See http://guides.rubygems.org/specification-reference/ for help
ERROR:  While executing gem ... (Gem::InvalidSpecificationException)
    jpdate-0.0.1 contains itself (jpdate-0.0.1.gem), check your files list
/Library/Ruby/Gems/2.0.0/gems/bundler-1.7.3/lib/bundler/gem_helper.rb:149:in `sh'
/Library/Ruby/Gems/2.0.0/gems/bundler-1.7.3/lib/bundler/gem_helper.rb:57:in `build_gem'
/Library/Ruby/Gems/2.0.0/gems/bundler-1.7.3/lib/bundler/gem_helper.rb:39:in `block in install'
Tasks: TOP => build
(See full trace by running task with --trace)
  • gem buildで試すも同様のエラー。
$ gem build jpdate.gemspec
WARNING:  See http://guides.rubygems.org/specification-reference/ for help
ERROR:  While executing gem ... (Gem::InvalidSpecificationException)
    jpdate-0.0.1 contains itself (jpdate-0.0.1.gem), check your files list


エラーメッセージをよく読んでみると...

  • Gemパッケージにまとめるファイルリストの中に、自分自身であるjpdate-0.0.1.gemが含まれていると。
    • Gemパッケージに含めるファイルリストをチェックしてくださいと。


ああ、なるほど。

  • bundlerで管理する以前に、gem buildした時のjpdate-0.0.1.gemが、Gitプロジェクト(jpdate)のルート直下に残っていた...。
  • bundlerは`git ls-files`でGemパッケージに含めるファイルを決定するので、git add .によって追加されてしまったのだ。
    • bundlerは、gem buildしたGemパッケージをpkgフォルダに出力する。
    • .gitignoreには、pkgフォルダは除外する設定になっているが、.gemファイル自体は除外設定されていないのだ。
  • jpdateフォルダ直下のjpdate-0.0.1.gemをgit rmすることで、エラー解消。
$ git rm jpdate-0.0.1.gem
rm 'jpdate-0.0.1.gem'

$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD ..." to unstage)

	deleted:    jpdate-0.0.1.gem

$ git commit -m 'rm "jpdate-0.0.1.gem"'
[master b4f9068] rm
 1 file changed, 0 insertions(+), 0 deletions(-)
 delete mode 100644 jpdate-0.0.1.gem


ビルドできるようになった!

$ rake build
jpdate 0.0.1 built to pkg/jpdate-0.0.1.gem.