如何创建一个简单的gem包

gem_example

通过rubygem内置的工具可以轻松地把代码打包成gem。下面创建一个简单的gem_example案例.

开始

首先,新建一个目录,并创建一个gem_example.rubygem_example.gemspec的文件,具体的目录结构如下:

1
2
3
-gem_example.gemspec
`--lib
`--gem_example.rb

注意

  1. 代码一般放在lib目录中
  2. 约定俗成,lib内有一个文件的文件名与gem名称一样

下面开始在lib/gem_example.rb中编写一点内容,具体如下:

1
2
3
4
5
class GemExample
def self.hi
puts "Hello world!"
end
end

最后,介绍一下gemspec。其内部主要定义改gem的版本、依赖等。示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Gem::Specification.new do |s|
s.name = 'gem_example'
s.version = '0.0.1'
s.date = '2015-02-24'
s.summary = "An Simple Gem Example!"
s.description = "A simple example of introducing how to use gem"
s.authors = ["Changlong Wu"]
s.email = 'clongbupt@gmail.com'
s.files = ["lib/gem_example.rb", "lib/gem_example/translator.rb"]
s.executables << 'gem_example'
s.homepage =
'http://github.com/clongbupt/gem_example'
s.license = 'MIT'
end

gem build会读取gemspec,并以此标识和分发gem。具体命令如下:

1
gem build gem_example.gemspec

控制台输出的结果为:

1
2
3
4
5
$ gem build gem_example.gemspec
Successfully built RubyGem
Name: gem_example
Version: 0.0.1
File: gem_example-0.0.1.gem

irb中可以对其进行测试。示例如下:

1
2
3
4
irb 
require ‘gem_example’
true
GemExample.hi

输出结果为hello world

发布

发布之前,首先要配置登录到rubygem的信息:

1
2
3
4
5
> curl -u yourusername_on_rubygem
https://rubygems.org/api/v1/api_key.yaml >
~/.gem/credentials; chmod 0600 ~/.gem/credentials

Enter host password for user 'yourusername_on_rubygem':

如果系统限制等,无法使用curlopenssl等,可以通过浏览器访问链接https://rubygems.org/api/v1/api_key.yaml,它会让你登录的,
成功则会下载一个认证信息文件api_key.yaml,完了直接把它放到~/.gem/文件夹下,重命名为credentials
一切设置妥当之后,就可以push你的gem了。具体示例如下:

1
2
3
gem push hola-0.0.0.gem
Pushing gem to RubyGems.org...
Successfully registered gem: hola (0.0.0)

上传成功后,你就可以通过下面命令check到自己的gem了:

1
gem list -r gem_example

然后尝试安装:

1
gem install gem_example

进阶

修改文件lib/gem_example.rb中的内容为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class GemExample
def self.hi(language = "english")
translator = Translator.new(language)
translator.hi
end
end

class GemExample::Translator
def initialize(language)
@language = language
end

def hi
case @language
when "spanish"
"hola mundo"
else
"hello world"
end
end
end

其中,可以将Translator进行拆分。一般推荐把目录结构调整为如示例所示样子:

1
2
3
4
5
├── gem_example.gemspec
└── lib
├── gem_example
│ └── translator.rb
└── gem_example.rb

接着,修改lib/gem_example.rb文件:

1
2
3
4
5
6
7
require 'lib/translator'
class GemExample
def self.hi(language = "english")
translator = Translator.new(language)
translator.hi
end
end

注意同时还需要修改gemspec文件, 把新添加的目录和文件索引进去, 否则打包时无法找到新文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Gem::Specification.new do |s|
s.name = 'gem_example'
s.version = '0.0.1'
s.date = '2015-02-24'
s.summary = "An Simple Gem Example!"
s.description = "A simple example of introducing how to use gem"
s.authors = ["Changlong Wu"]
s.email = 'clongbupt@gmail.com'
s.files = ["lib/gem_example.rb", "lib/gem_example/translator.rb"]
s.executables << 'gem_example'
s.homepage =
'http://github.com/clongbupt/gem_example'
s.license = 'MIT'
end

添加可执行文件

在与lib/目录同级的地方新建bin/目录。然后在gemspec里添加他们。具体操作如下:

1
2
3
mkdir bin
touch bin/gem_example
chmod a+x bin/gem_example

在文件中添加如下代码。

1
2
3
4
#!/usr/bin/env ruby

require 'gem_example'
puts GemExample.hi(ARGV[0])

之后在gemspec文件里添加可执行的文件配置说明:

1
2
3
s.name        = 'gem_example'
s.version = '0.0.1'
s.executables << 'gem_example' #可执行文件

测试

TEST YOUR GEM!
一般会用TEST::Unit。它是ruby内置的测试框架,有很多的教程在网上可以找到。
首先创建文件Rakefile和文件夹test,如下所示:

1
2
3
4
5
6
7
8
9
10
11
.
├── Rakefile
├── bin
│ └── gem_example
├── gem_example.gemspec
├── lib
│ ├── gem_example
│ │ └── translator.rb
│ └── gem_example.rb
└── test
└── test_gem_example.rb

编辑test_gem_example.rb。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
require 'test/unit'
require 'gem_example'

class GemExampleTest < Test::Unit::TestCase
def test_english_hello
assert_equal "hello world",
GemExample.hi("english")
end

def test_any_hello
assert_equal "hello world",
GemExample.hi("ruby")
end

def test_spanish_hello
assert_equal "hola mundo",
GemExample.hi("spanish")
end
end

Rakefile里添加一些简单的测试用例。

1
2
3
4
5
6
7
8
require 'rake/testtask'

Rake::TestTask.new do |t|
t.libs << 'test'
end

desc "Run tests"
task :default => :test

之后执行命令rake test或者直接rake,执行结果如下:

1
2
3
4
5
6
7
8
9
% rake test
Loaded suite
Started
....
Finished in 0.000943 seconds.

4 tests, 4 assertions, 0 failures, 0 errors, 0 skips

Test run options: --seed 15331

文档

大部分的gem会使用默认内建RDoc来生成文档.有很多的教程可以学习.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class GemExample
# Say hi to the world!
#
# Example:
# >> Hola.hi("spanish")
# => hola mundo
#
# Arguments:
# language: (String)

def self.hi(language = "english")
translator = Translator.new(language)
puts translator.hi
end
end

参考资料

  1. http://guides.rubygems.org/gems-with-extensions/
  2. http://qiita.com/xiangzhuyuan/items/7d3659bcebbaf52a1f12