Ruby 如何开发一个 Gem

lanzhiheng · 2021年05月17日 · 850 次阅读

最近刚写完一个 Gem,似乎也没有想象中那么难。之前总觉得写 Gem 难是因为怕麻烦。毕竟写 Gem 意味着要跟原项目抽离,代码调试起来会相当地不便,这篇文章会简单分享一下作者编写 Gem 的经验。原文链接:https://www.lanzhiheng.com/posts/tips-for-write-a-gem

编写测试

习惯了测试驱动开发之后发现不写测试都不知道该如何写代码了,写 Gem 的时候这个方法特别有帮助。官方 Gem 文档也有推荐我们为 Gem 写测试,一方面是为了保证代码的质量,另一方面也是方便开发工作的进行,降低调试成本。

简单起见可以采用Minitest来写测试用例,并辅以Rake把运行测试的工作封装成一个任务。

# Rakefile
require 'rake/testtask'

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

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

测试代码都会放在test目录中,具体代码需要自己定制,文档也有相关的参考用例,这里就不贴了。测试任务通过下面的指令便可运行

% rake test

OR

% rake

Rake 会从指定的目录读取测试相关的代码并运行。配合 Github Action,CircleCI 等工具,可以做到每次提交代码,或者提交合并请求之前都自动运行测试,整个过程还是挺舒畅的。

高可用文档

代码即文档,注释即文档

我们可以利用Rdoc来做到这一点,很多时候我们写代码都会顺手给代码加上注释。一般来说这些注释是用来警示后面的维护者“这些代码你可能要注意一下”

def profit_sharing_return_process
  ## ...

  # 不需要重复补款
  return if profit_sharing_return.finished?

  # ...
end

说白了这种注释是面向源码阅读者的。然而并不是所有的用户都愿意去阅读源代码,因此我们需要另外提供一份针对接口的文档。Gem 的开发者可以在编写代码的时候,顺便针对公共的 API 编写注释,然后通过 Rdoc 的命令即可生成对应的 API 文档。Rdoc 支持的格式很多,笔者这里用的是自己比较熟悉的 Markdown 格式

#
# 余额实时查询
#
# Document: https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_7_1.shtml
#
# Example:
#
# ``` ruby
# WechatPay::Ecommerce.query_realtime_balance(sub_mchid: '1600000')
# ```
def query_realtime_balance(params)
  sub_mchid = params.delete(:sub_mchid)
  url = "/v3/ecommerce/fund/balance/#{sub_mchid}"
  method = 'GET'

  make_request(
    path: url,
    method: method,
    extra_headers: {
      'Content-Type' => 'application/x-www-form-urlencoded'
    }
  )
end

上面是我在wechat-pay里封装的,实时查询余额的接口。文档生成好之后会以 HTML 的形式存放在某个目录中,效果如下

rdoc-result.png

文档自动化

最完美的情况就是我们写完 README 以及代码注释之后就什么都不用管了,文档会自动生成在线版本,这种可能性是存在的。RubyDocInfo这个网站就是为此而生,主要借助了Yard这门工具。它能够兼容 Rdoc 的语法,每次我们的 Gem 发布新版本,它都会根据我们的 Gem 版本自动生成对应的文档,如今wechat-pay的最新文档链接在此可以在 Gem 的首页找到对应入口

gem-page.png

开发者可以专注于代码跟文档的编写,而不用考虑后面文档的发布过程,还是蛮方便的。

调试

很多人对 Gem 望而却步主要是怕调试麻烦,调试不够方便的话开发的热情就会大减,人之常情。不过如果 Gem 是项目源码的一部分,会不会调试就简单很多了呢?Gem 通过 bundle 载入项目之后,其实它是以文件夹的形式存放于系统的某处,也就是说它其实也是你源码的一部分,只不过存放的路径并不在当前的项目目录中(当然你也可以通过配置让它存放在你的项目目录——记住别提交到仓库就好)。

一般来说我们会在 Gemfile 里面这样去引入 Gem,Ruby 会根据自己的搜索路径加载对应的 Gem

# Gemfile
# ....
gem 'chinese_pinyin'
gem 'wechat-pay', '>= 1.0.1'

而如果你本地正在开发的 Gem 想要利用当前项目的代码进行调试,其实你也可以直接把开发中的 Gem 加载到项目中去,并利用项目已有的逻辑进行调试。

gem 'chinese_pinyin'
# gem 'wechat-pay', '>= 1.0.1'

gem 'wechat-pay', path: '../../OpenSource/wechat-pay'

这样项目就会加载本地开发中的 Gem 了,我们可以直接给 Gem 打断点进行调试。只不过调试完并提交代码的时候记得

  1. 把调试完成,并改完代码的 Gem 推送到远端的源码库。
  2. 项目的 Gemfile 要回退,线上环境不能依赖本地的 Gem 版本。
  3. 如果有需要的话可以把项目依赖的 Gem 升级到最新的开发版本。

如果想要用 Github 上对应 Gem 最新的开发版本可以像这样去做

gem 'wechat-pay', :github => 'lanzhiheng/wechat-pay'

最后

这篇文章不能算是完整的 Gem 开发教程,只是针对自己开发 Gem 的经验进行了总结,简单分享了一些小技巧罢了。

暂无回复。
需要 登录 后方可回复, 如果你还没有账号请 注册新账号