bundle gemは何をしてくれるのか?
必要最小のgemパッケージの作り方は大体理解できた。
- rubyコードをlib/とbin/に振り分けて、
- .gemspecファイルに設定を記述して、
- gem build、gem installしてテスト、
- 問題なければ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'
- File.expand_path('../lib', __FILE__)は、常に"gem名称/lib"の絶対パスを返してくれる。
- $LOAD_PATH(requireする時のサーチパス)に"gem名称/lib"の絶対パスを追加して、
- require 'sample/version'を可能にして、以下の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タスクが追加される。
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環境を再現できるのだ。
- 参考:LangTurn: gemspecとGemfileの役割をはっきりさせておく(感謝です!)
.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のページに詳しく例が掲載されている。
Name your gem - RubyGems Guides
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
つまり...
- ハイフン"-"は、ネームスペースを区切る階層を意味する。
- ネームスペースとディレクトリ階層は一致させておく作法。
- ファイルパス名では、"/"に変換される。
- クラス・モジュール名では、"::"に変換される。
- 既存の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.