#245 New Gem with Bundler
- Download:
- source codeProject Files in Zip (3.62 KB)
- mp4Full Size H.264 Video (20.1 MB)
- m4vSmaller H.264 Video (9.2 MB)
- webmFull Size VP8 Video (22.5 MB)
- ogvFull Size Theora Video (16.8 MB)
Ruby gemの作成および管理の方法は、ここ数年で進化を続けています。エピソード135 [動画を見る, 読む] ではgemの作成にechoe gemを使用しました。その約1年後のエピソード183 [動画を見る, 読む]ではJewelerを使用しました。どちらのツールもgemのリリース毎にGemspecファイルを生成する手段と、そのGemspecファイルを管理するツールを提供します。今回は、Gemspecファイルの管理を、手作業で全体的にずっと簡単な方法で行うことにします。
今回の方法でも、gemごとに最初にGemspecファイルを作成する必要があります。これを手作業で行うこともできるし、Bundlerなどのツールを使うこともできます。Bundlerは、アプリケーションの依存関係を管理する一手法だと一般的にとらえられていますが、gemを作成するための便利なコマンドも備えています。それがbundle gemというコマンドで、実行時は作成したいgemの名前を渡します。今回のエピソードのために、ダミーテキストを生成するためのloremという簡単なgemを作成してみましょう。
$ bundle gem lorem
create lorem/Gemfile
create lorem/Rakefile
create lorem/.gitignore
create lorem/lorem.gemspec
create lorem/lib/lorem.rb
create lorem/lib/lorem/version.rb
Initializating git repo in /Users/eifion/code/ep245/lorembundle gemコマンドで、新しいディレクトリとその中にいくつかのファイルが生成されます。それと同時に、その場所でgitのリポジトリを初期化します。これは、gitを利用できる環境があることを前提にしているのですが、その理由は後ほど説明します。その前に、生成されたファイルを簡単に説明します。まず、lorem.gemspecファイルを見てみましょう。
# -*- encoding: utf-8 -*- $:.push File.expand_path("../lib", __FILE__) require "lorem/version" Gem::Specification.new do |s| s.name = "lorem" s.version = Lorem::VERSION s.platform = Gem::Platform::RUBY s.authors = ["TODO: Write your name"] s.email = ["TODO: Write your email address"] s.homepage = "" s.summary = %q{TODO: Write a gem summary} s.description = %q{TODO: Write a gem description} s.rubyforge_project = "lorem" s.files = `git ls-files`.split("\n") s.test_files = `git ls-files -- ? {test,spec,features}/*`.split("\n") s.executables = `git ls-files -- bin/*`.split("\n").map{ ? |f| File.basename(f) } s.require_paths = ["lib"] end
TODOと書いてある項目を見れば、このファイルが手作業で編集されることを想定しているのがわかるでしょう。これらの項目を編集することで、実際に動作するGemspecファイルを準備できます。このファイルの注意を引く部分は、末尾近くにあるファイル属性の記述です。gemに含まれるファイルを決定するために、gitを用いてgit ls-filesコマンドを使用することで、これらの属性が実行時に決定されます。bundle gemがgitリポジトリを作成するのはこのためです。これの利点として、.gitignoreファイルの振る舞いを自動的に引き継ぐので、一時ファイルやgitリポジトリに置きたくない(つまりgemに加えたくない)ファイルが除外されます。上記のデフォルト設定でほとんどのgemはうまくいくはずですが、違う振る舞いをさせたい場合はいつでも編集が可能です。
もう一つ触れておくべきなのが、バージョン番号の決まり方です。バージョンはLorem::VERSIONという定数として定義されますが、この値はlib/loremディレクトリのversion.rbという別のファイルで定義されています。このファイルの役目はバージョン番号を定義するだけです。
module Lorem VERSION = "0.0.1" end
gemを新しいバージョンにアップデートする時になったら、このバージョン番号を変えてgemを再発行します。
libディレクトリに生成されるもう一つのファイルはlorem.rbという名前で、ユーザがこのgemをrequireしたときに読み込まれるものです。このファイルに好きなコードを入れるかlibディレクトリに別のファイルを作成し、ここからrequireすることができます。今回の簡単なLorem gemのためには、単にダミーテキストを返すだけのipsumというクラスメソッドを作成します。
module Lorem def self.ipsum "Lorem ipsum dolor sit amet, consectetur adipisicing ...." end end
発行
これでgemが完成したので、最初のバージョンを発行する準備ができました。その前にGemspecファイルを更新してTODOの部分を置き換えます。
# -*- encoding: utf-8 -*- $:.push File.expand_path("../lib", __FILE__) require "lorem/version" Gem::Specification.new do |s| s.name = "lorem" s.version = Lorem::VERSION s.platform = Gem::Platform::RUBY s.authors = ["Eifion Bedford"] s.email = ["eifion@asciicasts.com"] s.homepage = "" s.summary = %q{Lorem ipsum generator} s.description = %q{Simply generates lorem ipsum text.} s.rubyforge_project = "lorem" s.files = `git ls-files`.split("\n") s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n") s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) } s.require_paths = ["lib"] end
次にgem buildコマンドを、Gemspecファイルを指定して実行します。
$ gem build lorem.gemspec WARNING: no homepage specified Successfully built RubyGem Name: lorem Version: 0.0.1 File: lorem-0.0.1.gem
このコマンドで.gemファイルが生成されます。ここでgem pushコマンドを実行すると、gemがRubyGems.orgにアップロードされて公開され、他のユーザがインストールできる状態になります。
アップデートする
Gemspecファイルでgemを発行する方法はこのように本当に簡単です。新しいバージョンを公開したければ、コードに必要な修正を加えた後、version.rbのバージョン番号を更新します。
module Lorem VERSION = "0.0.2" end
gem buildとgem pushを実行し、新バージョンのビルドと公開をおこないます。
GemfileとRakefile
Bundlerが作成したファイルで、まだ触れていないものが2つあります。GemfileとRakefileです。まずGemfileを見てみましょう。Railsアプリケーションでは、GemfileがBundlerと共にgemの依存関係を管理します。Gemfileの中を見てみると、そこにはgemspecというコマンドが一つあるだけです。
source "http://rubygems.org" # Specify your gem's dependencies in lorem.gemspec gemspec
このコマンドはgemのGemspecファイルでgemの依存関係を見て、Bundlerを介してそれらをロードします。通常はこのファイルを直接編集する必要はありません。gemの依存関係はGemspecファイル内で管理し、Gemfileを介してBundlerに自動的にロードさせるのがいいでしょう。例えば、このgemをテストするためにRSpecを使用したいとしましょう。GemfileにRSpecへの参照を追記する代わりに、lorem.gemspecに開発用の依存関係(development dependency)として追記します。
Gemspecファイルの管理方法がわからない場合はドキュメントを見ることをお勧めします。ドキュメントにはGemspecで属性を設定するための多くのメソッドがリストされています。その中のadd_development_dependencyメソッドを今回RSpecを追加するために使います。
# -*- encoding: utf-8 -*- $:.push File.expand_path("../lib", __FILE__) require "lorem/version" Gem::Specification.new do |s| s.add_development_dependency "rspec" # Other attributes omitted end
GemspecファイルはGemfileを介して参照されるので、bundleを実行することで必要なgemがすべてインストールされていることが保証されます。
$ bundle Fetching source index for http://rubygems.org/ Using diff-lcs (1.1.2) Using lorem (0.0.1) from source at /Users/eifion/Desktop/Dropbox/rails/apps_for_asciicasts/ep245/lorem Installing rspec-core (2.3.1) Installing rspec-expectations (2.3.0) Installing rspec-mocks (2.3.0) Installing rspec (2.3.0) Using bundler (1.0.7) Your bundle is complete!/Users/eifion/.rvm/gems/ruby-1.9.2-p0にインストールされました。
gemを公開して他の開発者の協力を受ける場合に、READMEファイルにbundleコマンドを実行するように指示しておけば、必要な環境と依存関係が設定されるのでとても便利です。
Gemfileについては以上です。ではRakefileはどうでしょうか? なぜBundlerはRakefileを作成するのでしょうか? ファイルの中を見てみると、Bundlerからgem helperのタスクが追加されています。
require 'bundler' Bundler::GemHelper.install_tasks
rake -Tを実行してタスクを見てみます。
$ rake -T
(in /Users/eifion/code/ep245/lorem)
rake build # Build lorem-0.0.2.gem into the pkg directory
rake install # Build and install lorem-0.0.2.gem into system gems
rake release # Create tag v0.0.2 and build
# and push lorem-0.0.2.gem to RubygemsRakefileのコードが3つのタスクを作成します。これらは、gemのビルド(build)、インストール(install)、発行(release)という一般的なタスクのための目印のタグです。一般的な作業の流れは、次のとおりです。gemが希望の形に設定されたらrake installを呼び出してローカルマシンにインストールして十分にテストします。その後でrake releaseを呼び出してそのリリースをタグ付けし、gemをRubyGemsに公開します。
既存のgemを更新する
Bundlerはgemを一から設定するための便利な方法を提供します。では既存のgemにこの作業手順を適用したい場合はどうすればいいでしょうか? ファイルをいくつかコピーすれば、簡単に既存のgemにこの方法を適用できます。コピーをするファイルは、Gemfileと.gemspecファイル、さらにrakeタスクを加えたい場合はRakefileも追加します。既存のgemにこれらのファイルを追加することで、同じような方法で作業を行うことができます。
全体的にみて、Bundlerはgemの作成・管理に適した優れた方法です。これまでのエピソードで紹介した他のツールと比べて非常にシンプルですので、新しいgemを作成するときは採用を検討してみる価値があるでしょう。


