如何开发一个自己的 RubyGem?
什么是 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应用中使用它了。
参考链接: