我不喜欢你(当然这不是真的,实际上~~我非常的喜欢你),你不分享代码。我知道,我知道,您有充分理由──你不知道如何打包gem,如何把gem上传到一个像rubyforge一样的gem server,你是一个菜鸟。今天我们就用一个新的gem生成器(New Gem Generator)来清除这些路障的第一项!
现在你可以拿出一些ruby library,rails plugin或者一些ruby命令行程序,把它们打包成gem,然后方便地与所有人共享。gem可以给你提供内建的版本支持(你通过require_gem来调用这些library的时候你可以指定你所需要的版本),统一的目录结构(bin/lib/test)以及夸平台的支持,说不完的好处,真的…
上文所提到的”新的gem生成器(New Gem Generator)”跟rails框架提供的的rails命令差不多,不过,他创建的目录和文件是为打包一个gem所准备的,这个命令叫做”newgem”。

Tutorial:

1.目标:
把 Map by Method(曾经叫做 Map by Pluralisation) library 打包成gem。
查看我们将要打包的代码的相关链接:original and demo

2.安装:
用命令

gem install newgem

从rubyforge网络安装,如果你因为网络原因不能安装的话,先想办法获取newgem的gem,然后在它所在的目录运行上述命令即可。

3.创建新的GEM:

>newgem map_by_method
creating: map_by_method
creating: map_by_method/CHANGELOG
creating: map_by_method/README
creating: map_by_method/lib
creating: map_by_method/lib/map_by_method
creating: map_by_method/lib/map_by_method.rb
creating: map_by_method/lib/map_by_method/version.rb
creating: map_by_method/Rakefile
creating: map_by_method/test
creating: map_by_method/test/all_tests.rb
creating: map_by_method/test/test_helper.rb
creating: map_by_method/test/map_by_method_test.rb
creating: map_by_method/examples
creating: map_by_method/bin

4.将你的代码拷贝进新的GEM:
newgem生成的lib/map_by_method.rb文件内容如下:

  1. Dir['map_by_method/**/*.rb'].sort.each { |lib| require lib }

这行代码使得程序按字母顺序自动引入(require)了lib/map_by_method目录下的所有文件。如果你需要引入指定目录下的文件,你可以显式地require它们,例如:

  1. require 'foo'
  2. require 'bar'
  3. require 'tar'

或者

  1. %w(foo bar tar).each {|lib| require lib}

对于这个例子将要打包的gem来说,我们不需要其他的库文件,只需要将下面的代码拷贝到lib/map_by_method.rb中并把那些”require”删除即可:

  1. module MapByMethod
  2.   def self.included(base)
  3.     super
  4.  
  5.     base.module_eval <<-EOS
  6.       def method_missing(method, *args, &block)
  7.         super
  8.       rescue NoMethodError
  9.         error = $!
  10.         begin
  11.           re = /(map|collect|select|each|reject)_([\w\_]+\??)/
  12.           if (match = method.to_s.match(re))
  13.             iterator, callmethod = match[1..2]
  14.             return self.send(iterator) {|item| item.send callmethod}
  15.           end
  16.           return self.map {|item| item.send method.to_s.singularize.to_sym}
  17.         rescue NoMethodError
  18.           nil
  19.         end
  20.         raise error
  21.       end
  22.     EOS
  23.   end
  24. end
  25.  
  26. unless String.instance_methods.include? "singularize"
  27.   class String
  28.     def singularize
  29.       self.gsub(/e?sZ/,'')
  30.     end
  31.   end
  32. end
  33.  
  34. Array.send :include, MapByMethod

5.打包:
在新生成gem项目的根目录运行命令”rake package”:

$rake package(in /home/killy/map_by_method)
rm -r .config
Successfully built RubyGem
Name: map_by_method
Version: 0.0.1
File: map_by_method-0.0.1.gem
mv map_by_method-0.0.1.gem pkg/map_by_method-0.0.1.gem

大功告成,你终于有了自己的gem了!

6.安装你刚做好的GEM:
只有把你的gem安装到你的机器上之后,你的Ruby(或者Rails)程序才能调用你的gem library,这也正是别人要用到你的gem的原因。通常你会通过网络安装方式来安装rubyforge或其他地方的 gem,现在你要进行本地安装了:

>gem install pkg/map_by_method-0.0.1.gem
Attempting local installation of ‘pkg/map_by_method-0.0.1.gem’
Successfully installed map_by_method, version 0.0.1
Installing RDoc documentation for map_by_method-0.0.1…

你可以看到gem为你的library生成并安装了RDoc文档,每个用到你的gem用户都会拥有一份这样的文档,当然前提是你的源码中进行了文档注释。

7.单元测试:
看看你的项目目录下的test文件夹,你会发现一个map_by_method_test.rb文件,这就是newgem为你生成的单元测试的起点,将你的其他单元测试文件放到test目录下,然后在项目根目录下运行”rake test”来运行你的单于测试,祝你好运!

8.版本号:
你可能已经注意到了,newgem给你生成的gem叫做map_by_method-0.0.1.gem,这个0.0.1就是版本号,当你的library有了新的功能或者修正了bug的时候,你可以方便的更改版本号。
通常有两种格式的版本号:

  • X.Y.Z : X = 主版本号, Y = 次版本号, Z = 修正版本号
  • X.Y.Z.svn : svn 是gem发布时的 subversion number

后者是newgem的默认实现,如果你想要得是前者,把你的rakfile里面的这行代码(大约是第13行)去掉就可以了:

  1. REV = File.read(".svn/entries")[/committed-rev="(d+)"/, 1] rescue nil

有一个prebuilt机制可以指定你的gem的版本号,找到文件”lib/map_by_method/version.rb”:

  1. module MapByMethod #:nodoc:
  2.   module VERSION #:nodoc:
  3.     MAJOR = 0
  4.     MINOR = 0
  5.     TINY  = 1
  6.  
  7.     STRING = [MAJOR, MINOR, TINY].join(’.')
  8.   end
  9. end

作如下修改:

  1. MINOR = 1
  2. TINY  = 0

重新打包,安装:

>rake package
(in C:/InstantRails/ruby_apps/map_by_method)
rm -r .config
Successfully built RubyGem
Name: map_by_method
Version: 0.1.0
File: map_by_method-0.1.0.gem
mv map_by_method-0.1.0.gem pkg/map_by_method-0.1.0.gem

>gem install pkg/map_by_method-0.1.0.gem
Attempting local installation of ‘pkg/map_by_method-0.1.0.gem’
Successfully installed map_by_method, version 0.1.0
Installing RDoc documentation for map_by_method-0.1.0…

接下来你就可以把你的gem上传到rubyforge之类的或者你们内部的gem server,然后用gem install来分享你的gem library了。

*map_by_method已经放在rubuforge上了:
如果你想要map_by_method gem,这么安装就好了: gem install map_by_method 。

*启发:
Jay Fields 作的NB脚本”ruby application setup“。


注:本文为Dr Nic的 [ANN] Generating new gems for graceful goodliness的翻译,由KDr2完成,不当之处请在下面回复指出,保持文档完整,转载注明出处,谢谢。