初めてのgem作成
僕はJavaメインでずっと仕事してきたこともありRubyはほとんど書けないし、仕事でRubyのコードを書く機会も今のところ少ないです。ただRubyで実装されたアプリ(例:fluentd)を使うことはあるしchef, vagrantなど興味あるアプリはRubyベースなことも多いので環境周りなんかは少し知っといた方が良いなと思っているわけです。
まあRubyに限らずLL言語で実装されたアプリは(C拡張とか出てくると特に)インストールは大変だという先入観というか偏見を持っているのですが慣れの問題でしょうねえ。その辺ではまらないようにしときたいなと思っている訳です。
Rubyアプリはgemでインストールするのが一般的なことは分かっているので、その辺を理解するためにもいっちょ自分で簡単なtoyプログラムを作ってgemで公開してみましたというのが本エントリです。
gemの作り方に関してはWEB+DB vol74の記事も良いですが無料で読めるものとしては下記のチュートリアルが素晴らしいです。英語ですが。
tech.pro - このウェブサイトは販売用です! - tech リソースおよび情報
僕が今回作ったgemはea_sports_ppiというものです。
https://rubygems.org/gems/ea_sports_ppi
インストール方法および使い方は下記の通り。
$ gem install ea_sports_ppi $ ea_sports_ppi Robin van Persie 790 Gareth Bale 628 Juan Mata 611 Luis Suarez 611 Leighton Baines 579 Eden Hazard 563 Santi Cazorla 562 Steven Gerrard 558 Patrice Evra 556 Wayne Rooney 532 Yaya Toure 529 Michael Carrick 525 Carlos Tevez 522 Marouane Fellaini 513 David Silva 505 Mikel Arteta 500 Steven Pienaar 486 Dimitar Berbatov 467 Rickie Lambert 465 Aaron Lennon 433
内容としては
http://www.premierleague.com/en-gb/players/ea-sports-player-performance-index.html
をparseしてPLAYERとINDEXの値を抜き出しているだけです。
これは今シーズンのプレミアリーグの選手のパフォーマンスを数値化したもので今のところ一位がファンペルシーで790です。これは蓄積された値です。このINDEXというのがEA SPORTS PLAYER PERFORMANCE INDEXでea_sports_ppiというgem名はそこから取りました。
EA SPORTS PLAYER PERFORMANCE INDEXの詳細はこちら
http://www.premierleague.com/en-gb/players/ea-sports-player-performance-index/what-is-the-ea-sports-ppi.html
詳細といっても統計値を求めるアルゴリズムが公開されているわけではなくて以下の6つの観点から数値を出しているみたいです。
1. Winning Performance
2. Player's Performance per match
3. Appearances
4. Goals scored
5. Assists
6. Clean sheets
ちょっと面白いのは上記1でこれは勝ち試合にフィールドにいた時間が長いほど良いようです。それだけ勝利に貢献したってことでしょうね。
このランキングを見るとまあ納得というか上位6人、ファンペルシー、ベイル、マタ、スアレス、ベインズ、アザールはそのままPFA Team of the Year、要は今季プレミアリーグのベストイレブンにも入っています。ちなみにベストイレブンはデヘア、サバレタ、フェルトンゲン、ファーディナント、ベインズ、キャリック、マタ、ベイル、スアレス、アザール、ファンペルシーです。こちらもまあ納得な人選ですね。
閑話休題。では本題のgem作成に入りましょう。
まず環境構築としてbundlerをインストールします。
$ gem install bundler
その前にそもそもsystem rubyの環境を使いたくないよねって場合はrvm, rbenv使っても良いですしxbuildで下記のように別途Rubyをインストールしても良いと思います。
$ git clone git://github.com/tagomoris/xbuild.git $ cd xbuild/ $ ./ruby-install 1.9.3-p392 ~/local/ruby-1.9.3-p392
Ruby環境を構築したらbundle gemでgemのひな形を作成します。
$ bundle gem ea_sports_ppi create ea_sports_ppi/Gemfile create ea_sports_ppi/Rakefile create ea_sports_ppi/LICENSE.txt create ea_sports_ppi/README.md create ea_sports_ppi/.gitignore create ea_sports_ppi/ea_sports_ppi.gemspec create ea_sports_ppi/lib/ea_sports_ppi.rb create ea_sports_ppi/lib/ea_sports_ppi/version.rb Initializating git repo in /home/vagrant/temp/ea_sports_ppi
こうするとgitのindexにも追加された状態になります。言い忘れましたがgitはインストールされていて、GitHubおよびrubygems.orgにアカウントを持っているものとします。
$ git status # On branch master # # Initial commit # # Changes to be committed: # (use "git rm --cached <file>..." to unstage) # # new file: .gitignore # new file: Gemfile # new file: LICENSE.txt # new file: README.md # new file: Rakefile # new file: ea_sports_ppi.gemspec # new file: lib/ea_sports_ppi.rb # new file: lib/ea_sports_ppi/version.rb #
2013/5/2追記
rake releaseのときにgit pushするのでremoteリポジトリにも追加しておきます。
$ git remote add origin git@github.com:wyukawa/ea_sports_ppi.git
では、まずは軽くHello, Worldしてみましょう。lib/ea_sports_ppi.rbがアプリの実装を書く部分なのでここを編集して下記のようにします。
module EaSportsPpi # Your code goes here... def self.run() puts "Hello" end end
動作確認しましょう。
$ bundle console Resolving dependencies... irb(main):001:0> EaSportsPpi.run Hello => nil
OKだったのでea_sports_ppi.gemspecを編集しましょう。ea_sports_ppi.gemspecはgemのメタ情報を書くところですね。TODOの部分を埋めればよいです。
# coding: utf-8 lib = File.expand_path('../lib', __FILE__) $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) require 'ea_sports_ppi/version' Gem::Specification.new do |spec| spec.name = "ea_sports_ppi" spec.version = EaSportsPpi::VERSION spec.authors = ["TODO: Write your name"] spec.email = ["TODO: Write your email address"] spec.description = %q{TODO: Write a gem description} spec.summary = %q{TODO: Write a gem summary} spec.homepage = "" spec.license = "MIT" spec.files = `git ls-files`.split($/) 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.3" spec.add_development_dependency "rake" end
ちなみにgit config --global user.nameとgit config --global user.emailを設定しているとそれがそれぞれspec.authorsとspec.emailになります。spec.descriptionとspec.summaryにgemの説明を書きます。
spec.descriptionに書かれた説明がrubygems.orgに載ります。またspec.homepageに書いたURLがrubygems.orgのLinks Homepageになります。
rake buildでpkgディレクトリ以下にgemができます。rake installでgemがインストールされます。rake releaseするとgitのtag打ち、rubygems.orgへのリリースまで行います。
$ rake build ea_sports_ppi 0.0.1 built to pkg/ea_sports_ppi-0.0.1.gem. $ rake install ea_sports_ppi 0.0.1 built to pkg/ea_sports_ppi-0.0.1.gem. ea_sports_ppi (0.0.1) installed. $ gem list | grep ea_sports_ppi ea_sports_ppi (0.0.1)
バージョン情報はlib/ea_sports_ppi/version.rbに書かれています。
module EaSportsPpi VERSION = "0.0.1" end
ではirbで試してみましょう
$ irb irb(main):001:0> require 'ea_sports_ppi' => true irb(main):002:0> EaSportsPpi.run Hello => nil
おー、できてますね。
実行コマンドもあったほうがいいのでそれも作ります。
bin/ea_sports_ppiを作って下記のようにします。
require 'ea_sports_ppi' EaSportsPpi.run
ただしこのままだとbin以下がgemに含まれません。gemspecのspec.filesにあるようにgit ls-filesに含まれていないとダメなようなのでgit addします。
$ git ls-files .gitignore Gemfile LICENSE.txt README.md Rakefile ea_sports_ppi.gemspec lib/ea_sports_ppi.rb lib/ea_sports_ppi/version.rb $ git add . $ git ls-files .gitignore Gemfile LICENSE.txt README.md Rakefile bin/ea_sports_ppi ea_sports_ppi.gemspec lib/ea_sports_ppi.rb lib/ea_sports_ppi/version.rb
そうやって再びrake installすると、おー、コマンド使えますね。
$ rake install ea_sports_ppi 0.0.1 built to pkg/ea_sports_ppi-0.0.1.gem. ea_sports_ppi (0.0.1) installed. $ ea_sports_ppi Hello
では以下のページをparseしてPLAYERとINDEXを取得してみましょう。
http://www.premierleague.com/en-gb/players/ea-sports-player-performance-index.html
parseするにはHTML parserが必要なのでnokogiriを使いましょう。
gemspecに下記を追加します。
spec.add_runtime_dependency "nokogiri"
そしてbundleを実行してnokogiriをインストールします。
$ bundle Fetching gem metadata from https://rubygems.org/......... Fetching gem metadata from https://rubygems.org/.. Resolving dependencies... Using rake (10.0.4) Using bundler (1.3.5) Installing nokogiri (1.5.9) Using ea_sports_ppi (0.0.1) from source at . Your bundle is complete! Use `bundle show [gemname]` to see where a bundled gem is installed.
ただちょっと注意点なのはCentOSの場合は以下も必要です。nokogiriが依存しているからですね。
sudo yum install libxml2-devel libxslt-devel
そしてlib/ea_sports_ppi.rbを以下のようにすればPLAYERとINDEXを取得できます。
require "ea_sports_ppi/version" require 'nokogiri' require 'open-uri' module EaSportsPpi # Your code goes here... def self.run() doc=Nokogiri::HTML(open("http://www.premierleague.com/en-gb/players/ea-sports-player-performance-index/")) tables=doc.xpath('/html/body/div/div/div/div/div/div/div/form/div/table') tables[0].xpath('tbody/tr').each do |tr| print(tr.xpath('td[4]').inner_text.strip, " ", tr.xpath('td[14]').inner_text.strip, "\n") end end end
あとはrake installして動作確認して問題無ければrake releaseしてrubygems.orgにアップします。
$ rake release ea_sports_ppi 0.0.4 built to pkg/ea_sports_ppi-0.0.4.gem. Tagged v0.0.4. Enter passphrase for key '/home/vagrant/.ssh/id_rsa': Enter passphrase for key '/home/vagrant/.ssh/id_rsa': Pushed git commits and tags. Pushed ea_sports_ppi 0.0.4 to rubygems.org.
ソースはこちらにあります。
https://github.com/wyukawa/ea_sports_ppi
やってみて思ったのは、思ったよりも簡単でしたね。。。自分の書いたプログラムをこうやって気軽に全世界に公開できるって素晴らしいですね。Java文化だとこういうの無いですしね。や、まあmave repositoryへの登録ってどうやるか知らないですけど。。。ともあれgem素晴らしい!
2013/5/2追記
ruportを使って出力をきれいにしたバージョン0.0.5をリリースしました。
gemをリリースするとTwitterでもrubygemsアカウントがつぶやいてくれます。
なおこのgemは以下にインスパイアされて作りました。Thank you!