Skip to content

Instantly share code, notes, and snippets.

@xiangzhuyuan
Created July 20, 2014 14:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save xiangzhuyuan/11e9c8a4caebfdcb4fdf to your computer and use it in GitHub Desktop.
Save xiangzhuyuan/11e9c8a4caebfdcb4fdf to your computer and use it in GitHub Desktop.
创建你自己的gem
<h1 id="make-your-own-gem">make your own gem</h1>
<p><a href="http://guides.rubygems.org/make-your-own-gem/">从头到尾学习如果将自己的代码打包成gem</a></p>
<ul>
<li>Introduction</li>
<li>Your first gem</li>
<li>Requiring more files</li>
<li>Adding an executable</li>
<li>Writing tests</li>
<li>Documenting your code</li>
<li>Wrapup</li>
</ul>
<!-- more -->
<h2 id="介绍">介绍</h2>
<p>通过rubygem内置的工具就能够轻松的打包代码为gem.让我们来创建一个简单的<code>hello world</code>的gem.</p>
<h2 id="第一个gem">第一个gem</h2>
<p>创建一个名为hola的gem.还有一个gemspec,目录结构如下:</p>
<pre><code> -hola.gemspec
`--lib
`--hola.rb
</code></pre>
<p>其实关键的你代码是放在lib文件夹里面的,有一个约定就是要有一个和你的gem名称一样的ruby文件. <br>
这样的话,就可以直接通过<code>require 'hola'</code>来引用此gem了.此文件就是gem的入口. <br>
看看在<code>lib/hola.rb</code>的内容:</p>
<pre><code>class Hola
def self.hi
puts "Hello world!"
end
end
</code></pre>
<p>下面来看一些gemspec文件里定义了什么内容,其他不外乎就是谁写的,版本,依赖等.</p>
<pre><code>Gem::Specification.new do |s|
s.name = 'hola'
s.version = '0.0.0'
s.date = '2010-04-28'
s.summary = "Hola!"
s.description = "A simple hello world gem"
s.authors = ["Nick Quaranto"]
s.email = 'nick@quaran.to'
s.files = ["lib/hola.rb"]
s.homepage =
'http://rubygems.org/gems/hola'
s.license = 'MIT'
end
</code></pre>
<p>看着眼熟?其实就是ruby代码了. <br>
关于到底有什么能够放在里面,可以<a href="http://guides.rubygems.org/specification-reference">参照这里</a>. <br>
创建gemspec之后,就可以build一个gem 了.之后就可以安装build之后的gem了. <br>
通过此命令</p>
<blockquote>
<p>gem build hola.gemspec</p>
</blockquote>
<p>你可以看见如下的控制台输出:</p>
<pre><code>Successfully built RubyGem
Name: hola
Version: 0.0.0
File: hola-0.0.0.gem
% gem install ./hola-0.0.0.gem
Successfully installed hola-0.0.0
1 gem installed
</code></pre>
<p>当然要确保能够使用,还需实际的使用它啊,通过<code>reuqire</code></p>
<blockquote>
<p>irb <br>
require ‘hola’ <br>
true <br>
Hola.hi</p>
</blockquote>
<p>可以看见输出<em>hello world</em>了.那就表示成功了一大步.之后就可以准备发布到rubygem了. <br>
首先要配置登录到rubygem的信息:</p>
<pre><code>&gt; curl -u yourusername_on_rubygem
https://rubygems.org/api/v1/api_key.yaml &gt;
~/.gem/credentials; chmod 0600 ~/.gem/credentials
Enter host password for user 'yourusername_on_rubygem':
如果系统限制等,无法使用curl,openssl等,可以通过浏览器访问链接`https://rubygems.org/api/v1/api_key.yaml`,它会让你登录的,
成功则会下载一个认证信息文件`api_key.yaml`,完了直接把它放到~/.gem/文件夹下,重命名为**credentials**
</code></pre>
<p>一切设置妥当之后,就可以push你的gem了</p>
<blockquote>
<p>gem push hola-0.0.0.gem</p>
</blockquote>
<pre><code> Pushing gem to RubyGems.org...
Successfully registered gem: hola (0.0.0)
</code></pre>
<p>上传过一会儿你就可以通过下面命令check到你的gem了:</p>
<blockquote>
<p>gem list -r hola</p>
</blockquote>
<p>然后尝试安装:</p>
<p>gem install hola</p>
<p>一切OK~</p>
<h2 id="我们来个复杂点的">我们来个复杂点的</h2>
<p>修改<code>lib/hola.rb</code></p>
<pre><code>class Hola
def self.hi(language = "english")
translator = Translator.new(language)
translator.hi
end
end
class Hola::Translator
def initialize(language)
@language = language
end
def hi
case @language
when "spanish"
"hola mundo"
else
"hello world"
end
end
end
</code></pre>
<p>上面的代码已经很拥挤了.我们把<code>Translator</code>这个类拆分到单独的文件中,之前提到的是把所有的ruby文件都放到lib <br>
目录. 我们可以把目录结构调整成下面的样子:</p>
<pre><code> ├── hola.gemspec
└── lib
├── hola
│ └── translator.rb
└── hola.rb
</code></pre>
<p>之后在原来lib/hola.rb的文件需要修改一下:</p>
<pre><code> require 'lib/translator'
class Hola
def self.hi(language = "english")
translator = Translator.new(language)
translator.hi
end
end
</code></pre>
<p>接着还要修改一下gemspec文件,把新添加的目录和文件索引进去,不然到时候打包的时候新文件不会被打包进去:</p>
<pre><code> ...
s.files = ["lib/hola.rb", "lib/hola/translator.rb"]
...
</code></pre>
<h2 id="添加一个可执行的文件">添加一个可执行的文件</h2>
<p>gem不仅仅只是提供一些ruby code. 同时还暴漏了一些可执行的文件到你当前的shell目录下.如<code>rake</code>. 还有一个比较有趣的工具就是 <br>
<code>prettify_json.rb</code>,包含在json的gem包,它能够用来format输出json.</p>
<pre><code> curl -s http://jsonip.com/ | \
prettify_json.rb
{
"ip": "24.60.248.134"
}
</code></pre>
<p>其实往gem里添加可执行的文件也很简单.把他们放到<code>bin/</code>目录.然后在gemspec里添加他们.让我们继续在hola的gem里修改:</p>
<pre><code> % mkdir bin
% touch bin/hola
% chmod a+x bin/hola
</code></pre>
<p>这个<code>bin/hola</code>文件第一行要添加<code>#!</code>来告诉机器用什么目录执行它.</p>
<pre><code>#!/usr/bin/env ruby
require 'hola'
puts Hola.hi(ARGV[0])
</code></pre>
<p>之后在gemspec文件里添加可执行的文件配置说明:</p>
<pre><code> s.name = 'hola'
s.version = '0.0.1'
s.executables &lt;&lt; 'hola' #可执行文件
</code></pre>
<h2 id="编写测试">编写测试</h2>
<p>测试自己的gem非常重要,不仅仅是确保自己的代码能够工作,而且能够帮助别人.很多人通过测试用例的质量来衡量 <br>
代码质量.gem支持如果在gem里有测试的话在下载完之后自动执行测试的功能.</p>
<p><strong>TEST YOUR GEM!</strong></p>
<p><code>TEST::Unit</code>是ruby内置的测试框架,有很多的教程在网上可以找到.同样还有很多其他的测试框架如<code>RSpec</code>. <br>
不管怎么样,我们来添加测试吧. <br>
首先创建文件<code>Rakefile</code>和文件夹<code>test</code>:</p>
<pre><code> .
├── Rakefile
├── bin
│ └── hola
├── hola.gemspec
├── lib
│ ├── hola
│ │ └── translator.rb
│ └── hola.rb
└── test
└── test_hola.rb
</code></pre>
<p>编辑<code>test_hola.rb</code>:</p>
<pre><code>require 'test/unit'
require 'hola'
class HolaTest &lt; Test::Unit::TestCase
def test_english_hello
assert_equal "hello world",
Hola.hi("english")
end
def test_any_hello
assert_equal "hello world",
Hola.hi("ruby")
end
def test_spanish_hello
assert_equal "hola mundo",
Hola.hi("spanish")
end
end
</code></pre>
<p>在<code>Rakefile</code>里添加一些简单的测试test task:</p>
<pre><code>require 'rake/testtask'
Rake::TestTask.new do |t|
t.libs &lt;&lt; 'test'
end
desc "Run tests"
task :default =&gt; :test
</code></pre>
<p>之后执行<code>rake test</code>或者直接<code>rake</code>来执行测试:</p>
<pre><code> % rake test
(in /Users/qrush/Dev/ruby/hola)
Loaded suite
Started
...
Finished in 0.000736 seconds.
3 tests, 3 assertions, 0 failures, 0 errors, 0 skips
Test run options: --seed 15331
</code></pre>
<p><strong>you made it!</strong></p>
<h2 id="文档">文档</h2>
<p>大部分的gem会使用默认内建RDoc来生成文档.有很多的<a href="http://docs.seattlerb.org/rdoc/RDoc/Markup.html">教程</a>可以学习.</p>
<pre><code># The main Hola driver
class Hola
# Say hi to the world!
#
# Example:
# &gt;&gt; Hola.hi("spanish")
# =&gt; hola mundo
#
# Arguments:
# language: (String)
def self.hi(language = "english")
translator = Translator.new(language)
puts translator.hi
end
end
</code></pre>
<h2 id="结尾">结尾</h2>
<p>至此已经完成了一个简单的gem,很多东西需要继续学习深究,ENJOY IT!</p>
<blockquote>
<p>Written with <a href="https://stackedit.io/">StackEdit</a>.</p>
</blockquote>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment