gemの作り方を学ぶ
About
chefやServerspecなどを使うようになって、ここの部分の動きってどうなってるんだろう?とか、こういう機能あったら便利だっていうときにはgemのソースを見たり・改造したりしたいと思うことが増えて来ました。ここでgemってそもそもどうやって作るんだろうと気になったので、まとめてみたいと思います。
リポジトリを作る
適当なディレクトリでgemを作成するコマンドを叩く
$ bundle gem test-gem -t create test-gem/Gemfile create test-gem/Rakefile create test-gem/LICENSE.txt create test-gem/README.md create test-gem/.gitignore create test-gem/test-gem.gemspec create test-gem/lib/test/gem.rb create test-gem/lib/test/gem/version.rb create test-gem/.rspec create test-gem/spec/spec_helper.rb create test-gem/spec/test/gem_spec.rb create test-gem/.travis.yml
commitしてリモートリポジトリに登録する
$ cd test-gem $ git commit -m "Initial commit" $ hub create $ git push origin master
hubコマンドが入っているとCLIからリモートリポジトリを作成できるので簡単です。
Gemを開発する
gem.specにmeta情報を記述する
自動で下記のように作成されるので、最低限埋めます。
# coding: utf-8 lib = File.expand_path('../lib', __FILE__) $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) require 'test/gem/version' Gem::Specification.new do |spec| spec.name = "test-gem" spec.version = Test::Gem::VERSION spec.authors = ["krossblack777"] spec.email = ["krossprogram@gmail.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" spec.add_development_dependency "rspec" end
下記3点を最低限編集すればいいようです。
spec.summary = %q{test} spec.description = %q{test} spec.homepage = "https://github.com/krossblack777/test-gem"
開発する
今回はhello world!!!と出力するだけの簡単なものです。
require "test/gem/version" module Test def hello 'hello world!!!' end end
メソッドを呼び出すとhello worldと表示されるはずです。
$ bundle install Fetching gem metadata from https://rubygems.org/......... Resolving dependencies... Installing rake 10.4.2 Using bundler 1.7.11 Installing diff-lcs 1.2.5 Installing rspec-support 3.3.0 Installing rspec-core 3.3.2 Installing rspec-expectations 3.3.1 Installing rspec-mocks 3.3.2 Installing rspec 3.3.0 Using test-gem 0.0.1 from source at . Your bundle is complete! It was installed into ./work $ bundle list Gems included by the bundle: * bundler (1.7.11) * diff-lcs (1.2.5) * rake (10.4.2) * rspec (3.3.0) * rspec-core (3.3.2) * rspec-expectations (3.3.1) * rspec-mocks (3.3.2) * rspec-support (3.3.0) * test-gem (0.0.1)
bundle install
の時にtest-gemはfrom source at .
と表示されていて、ローカルのソースを指定しているようです。これでtest-gemが追加されました。実際に使ってみます。
$ be irb irb(main):001:0> require 'test/gem' => true irb(main):002:0> Test => Test irb(main):003:0> Test.hello => "hello world!!!"
問題なさそうです。これで開発が完了しました。
gemをパッケージ化する
パッケージングはrakeが定義されているので、それを使います。定義されているタスクを確認すると
$ bundle exec rake -T rake build # Build test-gem-0.0.1.gem into the pkg directory rake install # Build and install test-gem-0.0.1.gem into system gems rake release # Create tag v0.0.1 and build and push test-gem-0.0.1.gem to Rubygems rake spec # Run RSpec code examples
この中でrake build
を実行すればいいはずです。
$ bundle exec rake build test-gem 0.0.1 built to pkg/test-gem-0.0.1.gem. $ ls pkg/ test-gem-0.0.1.gem
これでpackage化したgemができました。
作ったパッケージを使ってみる
やり方がよくわからなかったですが、一応できたので。
$ gem unpack test-gem-0.0.1.gem $ cat Gemfile # A sample Gemfile source "https://rubygems.org" # gem "rails" gem "test-gem", :path => "~/work/test/test-gem-0.0.1"
これでインストールの準備ができました。
$ bundle install irb(main):001:0> require 'test/gem' => true irb(main):002:0> Test.hello => "hello world!!!"
うまく実行できました。インストールの仕方は何通りかあるみたいです。bundlerを使わない方法はうまく行きませんでした。
gemを登録する
rakeを実行すればいいみたいです(試してない)。
$ rake release
終わりに
これでgemが作れるようになっちゃいましたね!後は作る能力さえつければいいんだ…!!
参考
- 君がOpsでもRubyで書いたライブラリはGemで配ろう - Qiita
- Gemの作り方まとめ 普通のgem編 - masarakki's blog
- RubyGemはめっちゃ簡単に作れる! - 酒と泪とRubyとRailsと
- ruby - How do I specify local .gem files in my Gemfile? - Stack Overflow
番外編
作ったgemがirbで実行できない。
gemコマンド使って作ったpackageからインストールします
$ gem install -l pkg/test-gem-0.0.1.gem
-lでローカルのパッケージを指定しています。
$ ruby -e "require 'test/gem';puts Test.hello" hello world!!!
上記のように実行できるのですが、irbだと
$ irb irb(main):001:0> require 'test/gem' LoadError: cannot load such file -- test/gem irb(main):002:0> Gem.path => ["~/work/ruby/2.1.0"]
となり、変な所にPATHが設定されているようです(謎)