#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/lorem
bundle 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 Rubygems
Rakefile
のコードが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を作成するときは採用を検討してみる価値があるでしょう。