如何開發一個自己的 RubyGem?

jopen 10年前發布 | 47K 次閱讀 RubyGem Ruby開發

什么是 RubyGem

RubyGem是Ruby語言的標準源碼打包格式。

大家一直都在用gem這個命令,但是很少有人知道這個東西是怎么來的,這里我從網上扒下一些資料匯總一下,分享給大家。最后面會有這些鏈接,想進一步了解的,可以點進去看看。Ruby語言深受其他幾種腳本語言的影響,其中就有Perl,而Perl有個 CPAN(Comprehensive Perl Archive Network),這個東西也就像是現在的RubyGems.org,但是當時Ruby是沒有這樣一個東西的。像CPAN和RubyGem,它們僅僅是定義好的一種源碼的打包和安裝方式,另外還有一些組織,會提供這種免費的公共的源碼包的存儲,這也就現在大家每天都要使用的安裝方式:

gem install rails

在RubyGem的發展歷史當中,有幾位重要的人物,這里也作為八卦知識給大家曬一曬,就當做大家茶余飯后的談點吧。Ruby社區的人應該都知道 Jim Weirich這個人,他已經在2014年2月份去世了,是一個可愛的白胡子大叔,他和另外的四位Rich Kilmer, Chad Fowler, David Black, Paul Brannan在2003年制定了RubyGem的基本規范和實現,但是其實RubyGem最早是Ryan Leavengood在2001年開發的,可惜沒有流行起來,最后到了2003年,前面的5個人經過Ryan Leavengood的同意,使用了RubyGem這個名稱,開發了新版的RubyGem,其中并沒有使用Ryan Leavengood的代碼。這里附上rubygems的執行文件鏈接,看看注釋,里面有上面幾個人的名字 rubygems/blob/master/bin/gem

rubygems有默認的源,也可以更改,國內的基本就是https://rubygems.taobao.org了,有些公司有自己的需求,也會搭建自己的私源。當前的官方源為https://rubygems.org,這個源也是幾經輾轉,早期的Ruby用戶都知道http://gems.rubyforge.org和http://gemcutter.org,甚至github都曾經作為源使用過,也就是http://gems.github.com,這三個現在都已經棄用了。

看看,一個簡單的gem install歷史還不少啊。

RubyGem的基本使用方法

gem install rails  //安裝rails
gem install rails -v 4.2.0   //安裝指定版本的rails
gem search rails  //查找所有名稱中含有rails的gem
gem search ^rails  //查找所有名稱中以rails開頭的gem
gem search ^rails -d  //查找所有名稱中以rails開頭的gem,并顯示描述
gem build package.gemspec  //構建一個gem,就是把你自己寫的gem源碼,打包成一個.gem文件
gem push pack-1.0.gem  //發布到源上,默認是rubygems.org

這里只是簡單列出了最常用的使用方法,大家看看就好,命令很有限,也很簡單,執行gem --help,基本上所有的東西你都能10分鐘內學會。

如何制作一個自己的RubyGem

前幾年還是有這樣那樣的工具,現在用bundler就夠了。

$ bundler gem mygem
      create  mygem/Gemfile
      create  mygem/Rakefile
      create  mygem/LICENSE.txt
      create  mygem/README.md
      create  mygem/.gitignore
      create  mygem/mygem.gemspec
      create  mygem/lib/mygem.rb
      create  mygem/lib/mygem/version.rb
Initializing git repo in /home/lizhe/Workspace/mygem

一個bundler命令就搞定了。來看看mygem這個文件夾下的東西:

total 24
-rw-rw-r-- 1 lizhe lizhe   90  7月  2 15:52 Gemfile
drwxrwxr-x 3 lizhe lizhe 4096  7月  2 15:52 lib
-rw-rw-r-- 1 lizhe lizhe 1062  7月  2 15:52 LICENSE.txt
-rw-rw-r-- 1 lizhe lizhe  850  7月  2 15:52 mygem.gemspec
-rw-rw-r-- 1 lizhe lizhe   29  7月  2 15:52 Rakefile
-rw-rw-r-- 1 lizhe lizhe  556  7月  2 15:52 README.md

現在來看看gemspec這個文件,它描述了這個Gem的各種信息

# coding: utf-8
lib = File.expand_path('../lib', __FILE__)
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
require 'mygem/version'

Gem::Specification.new do |spec|
  spec.name          = "mygem"
  spec.version       = Mygem::VERSION
  spec.authors       = ["lizhe"]
  spec.email         = ["lizhe@oneapm.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"
end

我發現有人看到這個文件的內容時,倒是關心那個'git ls-files -z'.split("\x0")是什么意思?以及那個\x0是什么?附上一個鏈接,解釋一下,參考鏈接。這個文件最上面先把lib文件夾添加到load path中,Gem::Specification的第一部分主要是描述這個gem的信息,包括名稱,版本等等,第二部分是這個gem都包括哪些文件,執行文件,測試文件以及哪些路徑下的文件可以添加到load path中。第三部分是開發mygem需要依賴的其他gem。這些信息都可以自定義,先按照默認走。讓我們build第一個gem吧。

$ rake build

rake aborted!
WARNING:  See http://guides.rubygems.org/specification-reference/ for help
ERROR:  While executing gem ... (Gem::InvalidSpecificationException)
    "FIXME" or "TODO" is not a description
/home/lizhe/.rvm/gems/ruby-2.1.5@global/gems/bundler-1.7.12/lib/bundler/gem_helper.rb:149:in `sh'
/home/lizhe/.rvm/gems/ruby-2.1.5@global/gems/bundler-1.7.12/lib/bundler/gem_helper.rb:57:in `build_gem'
/home/lizhe/.rvm/gems/ruby-2.1.5@global/gems/bundler-1.7.12/lib/bundler/gem_helper.rb:39:in `block in install'
/home/lizhe/.rvm/gems/ruby-2.1.5@global/bin/ruby_executable_hooks:15:in `eval'
/home/lizhe/.rvm/gems/ruby-2.1.5@global/bin/ruby_executable_hooks:15:in `<main>'
Tasks: TOP => build
(See full trace by running task with --trace)

這個警告是提醒我們需要替換gemspec中的FIXME和TODO,這個警告如果不解決是無法build一個gem的,直接刪除掉summary和description中的TODO:

  spec.summary       = %q{Write a short summary. Required.}
  spec.description   = %q{Write a longer description. Optional.}

再來執行:

$ rake build

mygem 0.0.1 built to pkg/mygem-0.0.1.gem.

好了,第一個gem誕生了。它就在當前目錄的pkg下:mygem-0.0.1.gem。如何使用呢?不考慮bundler的情況下,如果你開起了一個irb或者pry的session時,一般都會這樣寫:require "mygem",如果你現在這樣做,那肯定不行,因為它還沒有被安裝到ruby的load path中,那就把它安裝上。

$ rake install

mygem 0.0.1 built to pkg/mygem-0.0.1.gem.
mygem (0.0.1) installed.

安裝好了,那就來使用一下,打開irb:

require "mygem"
=> true
Mygem
=> Mygem

看,已經可以使用這個module了,不過這個gem啥也干不了,那么我們就給它添加一個方法吧,打開lib/mygem.rb,添加一個方法:

require "mygem/version" module Mygem def self.hello p "hello from my gem" end end 

保存,然后執行rake install,這個命令會先build然后install,再重新打開irb:

require "mygem"
=> true
Mygem.hello
=> "hello from my gem"

能夠正常運行了,那就來發布第一個gem吧:

rake release
// 輸入你在rubygems.org上的賬號和密碼

如果你的一個rails應用正好需要輸出一個hello from my gem,那么現在你可以在Gemfile中添加這個gem了:

gem 'mygem' 

添加完執行bundle install,你就可以在你的rails應用中使用它了。

參考鏈接:

本文由OneAPM工程師原創文章 ,想閱讀更多技術文章,請訪問OneAPM官方技術博客

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!