Pack gem and publish to RubyGems

這篇記錄寫完 Ruby 程式後如何包成 gem 並丟到 RubyGems 上分享。

基本流程:

  1. source code 放到 lib/
    lib/ 底下通常有 <gem_name>.rb<gem_name>/
    <gem_name>.rb 放此 gem 最主要的 class 及 require,其餘 source code 放在 <gem_name>/
  2. test 放到 test/
  3. 在根目錄新增 <gem_name>.gemspec
  4. gem build xxx.gemspec 生出 xxx-x.x.x.gem
  5. gem push xxx-x.x.x.gem publish 到 RubyGems

以下以玩具 booksr 為例。

檔案結構:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
│  booksr.gemspec
│ Gemfile

├─lib/
│ │ booksr.rb
│ │
│ └─booksr/
│ api_handler.rb
│ book.rb
│ parser.rb

└─test/
tc_search_isbn.rb
tc_search_title.rb
ts_google_api.rb

booksr.rb 的內容:

1
2
3
4
5
6
7
8
9
10
require 'json'
require 'rest-client'

require 'booksr/api_handler'
require 'booksr/parser'
require 'booksr/book'

class Booksr
...
end

booksr.gemspec 內容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Gem::Specification.new do |s|
s.name = 'booksr'
s.version = '0.1.0'
s.date = '2015-01-21'
s.summary = 'A simple book searcher'
s.description = 'Search book with title, author, isbn or keyword by Google Book API.'
s.authors = ['cjwind']
s.email = 'cwentsai@gmail.com'
s.files = Dir['lib/*.rb', 'lib/booksr/*.rb', 'Gemfile', 'README.md', 'Rakefile', '*.gemspec', 'test/*.rb'] # 此 gem 包含的 source file
s.homepage = 'https://github.com/cjwind/booksr'
s.license = 'MIT'

# depend 的 gem
s.add_runtime_dependency 'bundler'
s.add_runtime_dependency 'rest-client'

s.add_development_dependency 'rake'
s.add_development_dependency 'test-unit'
end

runtime dependency 跟 development dependency 的差別是預設上不會安裝 development dependency 的 gem。

如果有 Gemfile,要改寫成吃 .gemspec

1
2
source 'https://rubygems.org'
gemspec

它會將 runtime dependency 當作基本的 dependency,development dependency 則會開個 development group。

生 gem:

1
2
3
4
5
$ gem build booksr.gemspec`
Successfully built RubyGem
Name: booksr
Version: 0.1.0
File: booksr-0.1.0.gem

要 publish 到 RubyGems.org 前要先註冊帳號,publish 時需要輸入 Email 跟密碼驗證。

1
2
3
4
$ gem push booksr-0.1.0.gem
Enter your RubyGems.org credentials.
Don't have an account yet? Create one at https://rubygems.org/sign_up
Email:

Troubleshooting

在 win7 底下 publish 遇到以下錯誤:

1
2
3
ERROR:  While executing gem ... (Gem::RemoteFetcher::FetchError)
SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certif
icate verify failed (https://rubygems.org/api/v1/api_key)

Solution:抓 cacert.pem 放到 C:\Users\<username> 底下,並且增加檔案 .gemrc,內容為:

1
:ssl_ca_cert: c:\users\xxx\cacert.pem

碎念時間

我是先寫好 code 才開始調這些檔案結構(真相是寫 code 的時候根本不知道這些結構),跟 require 啊、bundler 啊、gem 啊不熟到爆炸,中間 unit test 還亂入,混亂了好一陣子。弄完稍微多懂一點,希望這篇沒有漏掉什麼,漏掉就再補囉!

Ref