bundlerを使ってrubygem「Tupper」を作る
仕事でformによるファイルアップローダを作っていた。これはヘルパーライブラリとして切り出すと他のところでも使い回せるなーとか思っていたら、「社内ライブラリを OSS 化すべきだ」という記事のことを思い出した。
一方、QA@ITで「今時rubygems作るんならBundlerだよねー」というご指摘をたくさんいただいたことも思い出した。
ということで、仕事のために書いたけれどもビジネスロジックは含んでいないライブラリを「Tupper」として切り出し、Bundlerを使ってrubygemsとして公開するところまでの作業記録を晒してみる。
スケルトンを作る
% bundle gem tupper
create tupper/Gemfile
create tupper/Rakefile
create tupper/LICENSE
create tupper/README.md
create tupper/.gitignore
create tupper/tupper.gemspec
create tupper/lib/tupper.rb
create tupper/lib/tupper/version.rb
Initializating git repo in /path/to/current_dir/tupper
Gemfile.lockはバージョン管理すべき?
スケルトンを作った時点ですでにGemfile.lockは.gitignoreに書かれているので、「バージョン管理しちゃダメだよ」というメッセージが込められている。今回まるっと参考にさせていただいている「Bundlerを使ったGem作成メモ (自分用) – ただのにっき(2012-02-18)」では、
ところで.gitignoreに「Gemfile.lock」が含まれている(つまりリポジトリには含めない)んだけど、これをリポジトリに含める場合と含めない場合の判断基準がよくわからん。
と迷っておられた。同じくQA@ITから「Gemfile.lockをバージョン管理するかどうかの指針はありますか – QA@IT」→「Clarifying the Roles of the .gemspec and Gemfile « Katz Got Your Tongue?」→「LangTurn: gemspecとGemfileの役割をはっきりさせておく」…とたどり、
Gemを開発するときは、Gemfileにはgemspecを使って重複を回避しましょう。普通、GemfileにはRubygemsのソースとgemspecの一行だけが書かれるべきです。Gemfile.lockはバージョン管理にチェックインしてはいけません。
…とあったので納得。
各種ファイルを編集する
すっきりしたところで続き。bundlerが作った各種ファイルを編集していく。
tupper.gemspec
tupper.gemspecには…
- gemのメタ情報
- 開発時に依存するgem
…を記述する。順に見ていこう。
gemのメタ情報を書く
gem.authorsとgem.emailは(たぶん)gitのグローバル設定から取得して入れてくれてる。最低限書くのは「TODO」の表示があるgem.descriptionとgem.summary。gem.homepageにはとりあえずGitHubのリポジトリのURLを書いておいた。
開発時に依存するgemを書く
「テストを書かない奴は屑だ!テストを書く奴はよく訓練された屑だ!」ということなので、テストを添付することにする。今時はもうRSpecで書きたいよね、ということで、依存するgemも.gemspecに書いておく。
Gem::Specification.new do |gem|
# snip
gem.add_development_dependency "rspec"
gem.add_development_dependency "fakefs"
end
Tupperの場合はファイルを取り扱うので、ファイルシステムのモックライブラリである「fakefs」も追加してある。これでbundle installするとrspec / fakefsがインストールされるので、テストを実行できるようになる。
あ、gem本体の動作が依存するgemはちゃんとGemfileに書くこと。Tupperは特に依存gemが存在しないので何も追記していない。
Rakefile
デフォルトの状態では…
% rake -T
rake build # Build tupper-0.0.1.gem into the pkg directory
rake install # Build and install tupper-0.0.1.gem into system gems
rake release # Create tag v0.0.1 and build and push tupper-0.0.1.gem to Rubygems
build, install, releaseの3タスクが用意されている。
specのタスクを書く
ビルドしてリリースするにはデフォルトでも十分だが、せっかくRSpecでテストを実行できるよう.gemspecを書いたのだし、テストの実行手段も準備しておこう。
% bundle exec rspec spec/
としてもテストを実行することはできるが、どうせRakefileがあるならテストを実行できるようにしておきたい。bundlerが作ってくれるRakefileには最初の2行しか書かれていないので、RSpecを走らせるタスクを追加しておく。
4行目以降が追加した部分。
#!/usr/bin/env rake
require "bundler/gem_tasks"
Bundler.setup
require 'rspec/core/rake_task'
desc "run spec"
RSpec::Core::RakeTask.new(:spec) do |t|
t.rspec_opts = ["-c", "-fs"]
end
これでrake specとすると、spce/以下のテストケースがすべて実行される。
lib/tupper.rb
本体のコードを書く。スケルトンでは「module Tupper」と定義されるが、「class Tupper」に修正して実装コードを追記した。
spec/tupper.rb
テストコードを書く。特に変わったことはしていない。fakefsはまだ最低限の使い方しかしていないが、なかなか便利に使える。
lib/tupper/version.rb
バージョン情報を書くだけのファイルが用意されているので、適切なバージョンを設定する。デフォルトだと0.0.1なので、ちょっとプロダクトコードに使うのはためらわれる雰囲気。Tupperはこのままプロダクトに突っ込む予定なので、1.0.0でリリースしてしまう。
class Tupper
VERSION = "1.0.0"
end
本体同様moduleをclassに変更してある。
README.md
GitHubで公開したときのトップページになるので、descriptionとusageぐらいは書いておこう。
git / GitHub
スケルトンを作った段階で、すでにgit initはされた状態になっている。だいたい整ったらコミットしておこう。
書いたコードは当然GitHubで公開する前提なので、GitHubにリモートリポジトリを作り、pushしておく。Webから新しいリポジトリを作っておき…
% git remote add origin git@github.com:kwappa/tupper.git
% git push -u origin master
gemのビルド / インストール / リリース
ビルド
% rake build
tupper 1.0.0 built to pkg/tupper-1.0.0.gem
% ls pkg
tupper-1.0.0.gem
インストール
% rake install
tupper 1.0.0 built to pkg/tupper-1.0.0.gem
tupper (1.0.0) installed
リリース
% rake release
tupper 1.0.0 built to pkg/tupper-1.0.0.gem
Tagged v1.0.0
Pushed git commits and tags
Pushed tupper 1.0.0 to rubygems.org
コマンド一発は簡単すぎないか?ということで、GitHubを確認してみると…おおタグが打たれている。RubyGems.orgを確認してみると…おお公開されている。
というわけで拍子抜けするほど簡単だった。rubygems.orgへのアップロードはたぶん~/.gem/credentialsに書いてあるAPI keyで認証されているはずなので、うまく行かないときはRubyGems.orgのプロフィールページを参考に、API keyをローカルに取り込んでおこう。
まとめとLinks
Tupperの使い方は あとで書く サンプル書いた。公開するつもりで書くと結合度は疎になるし、よいコード / わかりやすいコードを書こうという心理が働くし、テストもきちんと書くし、社内ライブラリをOSS化すべき理由は3つどころかもっとたくさんあるような気がする。
ということで今後も可能な限り晒していこうと思う。pebblesばっかりなのも切ないしね。
Links
- Rubyのライブラリをrubygemsとして公開するには? – QA@IT
- Bundlerを使ったGem作成メモ (自分用) – ただのにっき(2012-02-18)
- QAへの回答として紹介いただいた記事。手順はほとんどここに書いてあるのをなぞっただけ。簡単でびっくりした。
- Gemfile.lockをバージョン管理するかどうかの指針はありますか – QA@IT
- たださんの記事でも言及されていた、「Gemfile.lockをバージョン管理するべきかどうか?」という問題も、QA@ITに投稿されていた。回答としてClarifying the Roles of the .gemspec and Gemfile « Katz Got Your Tongue?が紹介されており、日本語に翻訳された記事(LangTurn: gemspecとGemfileの役割をはっきりさせておく)も見つかった。
- デブサミで僕が話したことの簡単なまとめ – YoshioriのBlog
- 「テストを書かない奴は屑だ!テストを書く奴はよく訓練された屑だ!」ということなので、練度を少しでも上げるためにテストについて書いてみた。
- 僕が社内ライブラリを OSS 化すべきだと思う3つの理由 – 宇宙線
- この記事を読んでなければOSSにしたりせず、社内のどこかのリポジトリに埋もれさせていたんだろうなーと思う。公開することによるコストもデメリットもほぼゼロだし、うっかり誰かの役に立ったりすれば幸福総量が増加するので、今後も可能な限り公開していこうと思う。