RubyGems

作者:Dirk Elmendorf

RubyGems 是一个用于管理 Ruby 软件库的系统。以这种方式打包的 Ruby 代码称为 gem。当您找到想要在项目中使用的 Ruby 软件时,gems 提供了一种下载、安装和管理软件的方法。

历史

Ruby 与 Perl 的联系使转换者提出了一个显而易见的问题:“Ruby 的 CPAN(Comprehensive Perl Archive Network,综合 Perl 档案网络)在哪里?”如果您做过任何 Perl 编程或使用过 Perl 软件,您可能从 CPAN 下载过一些东西以使该软件工作。由于它是 Perl 中共享库的事实标准,因此访问 CPAN 可以更轻松地重用他人开发的代码。这个工具允许开发人员专注于新问题,而不是重新发明轮子。

事实证明,包管理并不像听起来那么简单。当您尝试为各种平台和操作系统(Ruby 在 *nix/*BSD/Mac OS X/WinX 上运行)解决问题时,它会变得更加复杂。已经有几次尝试构建一个可用的系统。

Ryan Leavengood 被认为是 2001 年创建第一个 RubyGems 项目的人(请参阅在线资源)。该项目启动了,但没有真正获得足够的势头来起飞。也尝试过其他解决方案,但它们并没有真正流行到足以在该领域占据主导地位。

2003 年 11 月,Rich Kilmer、Chad Fowler、David Black、Paul Brannan 和 Jim Weirch 在一次 Ruby 会议上聚在一起开始编码。他们的目标是一劳永逸地创建一个解决方案。他们获得了 Leavengood 的许可,可以使用现有的名称 RubyGems,即使他们没有使用之前项目中的任何代码。

RubyGems 着手解决几个问题。重点是简化安装、删除、更新和管理 Ruby 库的过程。开发人员增加了一个有趣的转折,允许系统轻松管理同一库的多个版本。使用 RubyGems 的版本控制方案,可以非常强大地控制您的代码实际将使用哪个版本的库。

入门

有计划将 RubyGems 作为 Ruby 核心发行版的一部分包含在内,但在那之前,您需要安装它。您的 Linux 发行版可能有一个用于 RubyGems 的软件包(RPM、Deb 等)。如果它没有,您可以轻松地从源代码安装它,前提是您的 Linux 机器上已经安装了 Ruby 和 Ruby 的开发头文件。

您可以作为用户执行以下操作:访问 rubyforge.org/projects/rubygems,并下载当前版本(在撰写本文时为 0.8.11)

tar xzf rubygems-0.8.11.tgz
cd rubygems-0.8.11

您必须是 root 用户才能安装该软件(假设您希望所有用户都可以使用它)

ruby setup.rb all

现在 RubyGems 已安装,您应该拥有 gem 命令 (gem是用于与 RubyGems 包系统交互的命令)。通过运行以下命令来测试它

gem list

它应该显示一个已安装的软件包——sources (0.0.1)。gem 命令是您与 RubyGems 包系统交互的方式。

用户任务

现在您有了 gem 命令,您可以开始安装 gem 包了。您需要是 root 用户才能安装或修改 gems,但任何用户都可以查询系统以找出已安装的内容。当您想查找软件时,您可以随时查看 RubyForge(请参阅资源)。它是 Ruby 开源软件的主要交换中心。

RubyForge 最受欢迎的项目之一是 Ruby on Rails。Rails gem(以及它依赖的 gems)可以使用以下命令安装

gem install rails --include-dependencies

另一个非常受欢迎的项目是 RMagick。RMagick 是 ImageMagick 的一个有用的 Ruby 接口(请参阅资源),可以使用以下命令安装

gem install rmagick

此 gem 包括非 Ruby 代码。当您安装它时,它将在安装过程中编译 C 代码。如果您没有安装编译工具,安装将失败。

RubyGems 具有许多有用的功能,包括

gem search rails --remote gems.rubyforge.org

这将返回 RubyForge 上所有软件包和版本的列表,这些软件包的标题中包含单词 rails。这里还有一些,嗯,gems

  • gem update:将 gems 的所有当前版本更新到最新版本。

  • gem cleanup:删除已安装 gems 的旧版本。

  • gem uninstall:从存储库中删除给定的 gem。

因为我试图跟上 gem 软件的最新版本,所以我通常gem update然后gem cleanup存储库以摆脱旧库。这样做可以使 gems 目录更简洁,并且在您需要查看目录时更容易进行排序。

开发者

现在您已经安装了一些软件,您将想要使用它。要开始使用,您可能需要阅读 gems 上的文档以了解其 API。如果您已在系统上安装了 rdoc,gem 会自动为您安装的所有 gems 生成 rdoc(Ruby 文档)。您可以通过两种不同的方式查看此文档。第一种是运行命令

gem_server

这会自动在端口 8808 上启动一个基于 Ruby 的 Web 服务器。您可以添加 -p 选项以在不同的端口上启动服务器。这使您可以轻松地使用 Web 浏览器浏览所有已安装 gems 的文档。可以通过按 Ctrl-C 停止 gem_server。此外,请注意,服务器接受来自所有能够连接到该端口的主机的连接。因此,如果您担心在服务器上打开端口,您可能需要尝试另一种访问方式。

访问此文档的另一种方法是导航到 gem 生成文档的文件系统上的位置。在大多数情况下,它将在 /usr/lib/ruby/gems/1.8/doc 中,但如果 gem 已安装在不同的路径中,您可以询问 gem 正确的目录在哪里

gem environment gemdir

此命令为您提供 gem 安装的基本目录。文档存储在该目录的 doc 子目录中。当您以这种方式访问文件时,您不会获得从 gem_server 获得的摘要概述;相反,您只会获得所有已安装 gems 的目录列表。

为了使您的 Ruby 脚本能够使用您现在安装的 Ruby 库,您需要使用 Ruby 的 require 机制来加载代码。使用 RubyGems 最简单的方法是调用以下行

require 'rubygems'
require 'RMagick'

这会加载所有 RubyGems 代码,并自动允许您使用已安装的最新 gem 版本的 RMagick。如果代码在本地可用,它将从那里包含。

如果您想将您的软件绑定到库的特定版本,则必须调用不同的函数

require 'rubygems'
require_gem 'RMagick' , '>=1.10'
require_gem 'rake', '>=0.7.0', '<0.9.0'

这些语句告诉 Ruby 使用 RMagick,只要它大于或等于 1.10。第二行允许任何版本的 rake,只要它大于或等于 0.7 且小于 0.9.0。版本语句支持许多运算符:=、!=、>、>=、<、<= 和 ~>。最后一个是一个特殊的运算符。它假设您遵循 RubyGems 标准进行版本控制。

X.Y.Z

当您发布与先前版本不兼容的版本时,您增加 X。当您发布具有新功能但其他方面兼容的版本时,您增加 Y。当您发布软件的修复程序时,您增加 Z。

这允许 ~> 要求在特定范围内选择。例如:1.0、1.0.1、1.0.2、1.1 都是 ~> 1.0,而 1.1、1.1.2 都是 ~> 1.1。

这使您可以支持 gem 版本的次要更改,而无需更改代码中的 require 语句。

一个建议:如果您要放入与版本绑定的 require 语句,请确保您有一个中心位置来调用和组织它们。这将使您更容易确定您依赖的其他软件,并在以后需要更改版本要求时进行调整。

构建您自己的

到目前为止,gems 实际上都是关于在您的代码中使用其他人的软件。如果您确定您有一个对其他人可能有用的库,您可以轻松地将其打包为 gem。

现在您知道如何使用 gems,您可能想知道如何构建它们。将您的代码转换为 gem 的过程是一个分为两个部分的过程。该过程的好处是您不必修改代码即可使其作为 gem 可用。第一部分是将您的库设置为适合转换为 gem 的目录结构。我将使用一个名为 IPAdmin 的现有项目(请参阅资源)作为我如何工作的示例。

目录结构组织如下

  • /ipadmin/lib:此目录包含与项目相关的所有 Ruby 代码。

  • /ipadmin/pkg:这是将生成 gem 的位置。

  • /ipadmin/tests:这是应存储任何单元或其他测试的位置。

  • /ipadmin/README:此文件应包含项目摘要——尤其是发布项目的许可证(随意为许可证添加单独的文件)。

这是构建 gem 所需的最基本布局。

更复杂的项目(例如 rake)添加了以下目录

  • /rake/bin:这用于项目中包含的任何命令行脚本。

  • /rake/doc:有关项目的其他文档。

这显示了一些项目(rake、capistrano)如何在系统上安装后添加新的命令行工具。

RMagick 包括一个特殊目录

  • /RMagick/ext:这是应存储非 Ruby 源代码的位置(如果要编译)。

这是另一个强大的选项。RubyGems 支持在 gem 中运送非 Ruby 源代码。当用户在目标计算机上安装此“源”gem 时,gem 会尝试在安装过程中编译额外的代码。以这种方式运送 gem 的优点是,非 Ruby 代码将绑定到目标计算机上安装的实际库。这正是您安装 RMagick 时发生的情况。如果您没有正确的库 (ImageMagick) 或编译器,安装将失败。为了解决无法编译代码的问题,可以运送 gem 的预编译版本。在这种情况下,源文件将被编译,然后简单地包含在 gem 中。

一旦您将代码设置为正确的目录结构,您就可以专注于 gem 构建过程的另一部分——gem 规范。这基本上是一个清单,它为 gem 提供了有关正在构建的 gem 的所有必要信息。您可以将 gem spec 构建为独立文件,但如果将其作为 Rakefile,则更容易使用。这简化了构建过程。

IPAdmin 的主目录中有一个 Rakefile

require 'rubygems'
Gem::manage_gems
require 'rake/gempackagetask'

spec = Gem::Specification.new do |s|
    s.platform  =   Gem::Platform::RUBY
    s.name      =   "ipadmin"
    s.version   =   "0.2.2"
    s.author    =   "Dustin Spinhirne"
    s.email     =   "dspinhir @nospam@ yahoo.com"
    s.summary   =   "A package for manipulating IPv4/IPv6 address space."
    s.files     =   FileList['lib/*.rb', 'test/*'].to_a
    s.require_path  =   "lib"
    s.autorequire   =   "ip_admin"
    s.test_files = Dir.glob('tests/*.rb')
    s.has_rdoc  =   true
    s.extra_rdoc_files  =   ["README"]
end

Rake::GemPackageTask.new(spec) do |pkg|
    pkg.need_tar = true
end

task :default => "pkg/#{spec.name}-#{spec.version}.gem" do
    puts "generated latest version"
end

这是 gem 的标准 Rakefile 的一个很好的示例。在这里您可以看到它包含 RubyGems 并从 rake 添加了一些任务。主要的 spec 处理提供有关正在构建的 gem 的所有信息。最后一个任务添加了一个简单的助手,允许您在目录中运行 rake 并自动构建 gem。

spec 中的每一行都有特殊的含义。可以设置的完整选项列表可从 RubyGems 手册站点上的 Gemspec 参考中获得(请参阅资源)。

规范说明

platform 确定 gem 适用于哪个平台。如果您只是使用纯 Ruby,它可以保持此默认值。当您运送预编译的 gems 时,此标志变得非常重要。

name、version、author、email 和 summary 提供有关 gem 及其作者的基本信息。用户可以通过这种方式了解谁负责该代码。

files 定义了要包含在 gem 中的文件列表。FileList 命令由 rake 提供,它做了两件事使生活更轻松。首先,它处理 globs (*) 和模式,这意味着您可以轻松地抓取大量文件。它还理解应排除某些文件。默认情况下,它排除 CVS、svn、bak 和 core 文件。

require_path 设置为确定应搜索代码的目录。如果您在 ext 中构建扩展,则此值将更改。

autorequire 指定在require ipadmin在代码中调用时将加载哪个文件。此模块中的 ipadmin.rb 处理 require 与 ipadmin 一起提供的其他三个库。

test_files 是一个文件列表,如果用户向 gem install 添加 -t 参数,则应在安装 gem 时执行这些文件。这是一种提供安全检查的方法,以确保在安装 gem 后一切正常。

has_rodc 是一种告诉 gem 您已在代码中包含 rdoc 标记的方法。如果此标志为 false 或缺失,gem 将不会自动生成文档。

extra_rdoc_files 允许您在 gem 生成的文档中包含其他文件。在这种情况下,README 文件被链接到文档中。如果您有其他文档,可以在此处列出它们。

由于 IPAdmin 是一个非常简单的项目,因此它不包含一个非常有用的命令:add_dependency。如果您构建的 gem 依赖于另一个 gem,则此命令允许指定这些依赖项。您甚至可以像使用 require_gem 一样将其绑定到版本号。当您安装具有依赖项的 gem 时,gem 会检查是否满足该依赖项。如果未满足,gem 会提供安装它的选项。要添加对 rake 的依赖项,您可以将其添加到 spec 定义中

s.add_dependency("rake",">=0.7.0")
签名 Gems

感谢 Paul Duncan 的补丁,最新版本的 RubyGems (0.8.11) 现在具有一些功能,可以使用公钥/私钥支持签名您的 gems。这为 gem 规范引入了一些新选项(signing_key 和 cert_chain)。此更改还允许您在高安全性模式下安装 gems,该模式将仅安装由受信任来源签名的 gems。由于该功能本身非常新,因此缺少一些使其在更大范围内有用的基础设施——即,一种建立信任链的简单方法,以便最终用户不必为每个 gem 作者添加证书。话虽如此,如果您想在网络中跨多台服务器控制 gems,这些功能可能会很有用。您可以下载它们一次并使用内部证书对其进行签名。然后,您可以通过从您分发这些签名 gems 的服务器请求 gems 来更新所有服务器。Duncan 在 RubyGems 手册站点上撰写了关于 gem 签名入门的精彩概述(请参阅资源)。

分发

现在您有了一个 gem,您可能想要共享它。有几种方法可以分发您的代码。最简单的方法是托管该文件。当人们想要安装它时,他们可以下载该文件并在同一目录中运行 gem。

第二种选择是在 RubyForge.org 上托管该项目。RubyGems 将 RubyForge 作为 gems 的默认来源。RubyForge 甚至运行一个特殊的脚本,以便一旦您将新的 gem 上传到您的帐户,它就会自动可供 RubyGems 的所有用户使用。

假设您不想使用 RubyForge,那么还有两个选项可以使通过 RubyGems 分发您的 gem 成为可能。首先,您需要运行自己的服务器。最简单的方法是简单地启动 gem_server。它会自动与连接到它的任何人共享 gems。

另一个选项是cd到现有 Web 服务器的 webroot 内的目录。创建一个名为 gems 的目录,并将您要分发的所有 gems 复制到该目录中。

运行以下命令,并将 DIR 替换为 gems 目录上方的目录的完整路径。这将创建 yaml 和 yam.Z 文件

generate_yaml_index.rb -d DIR

当您修改要服务的 gems 时,您需要随时重新运行该脚本。请记住,如果您使用这些选项中的任何一个,您的用户必须将 --source URL_OF_YOUR_SITE 添加到 gem install 命令。这允许 gem 在该站点上搜索 gems。

打包

RubyGems 本身就是一个包管理系统。如果您的系统尚未具有包管理,这是一个巨大的改进。另一方面,如果您的 Linux 系统具有包管理,RubyGems 可能会增加一些复杂性。这在很大程度上是 RubyGems 完全独立于主机打包系统的副作用。根据 RubyGems 网站,问题与每个目录的版本布局有关。这显然与文件系统层次结构标准(请参阅资源)冲突。希望能够找到某种折衷方案,因为拥有一个好的包管理系统的乐趣在于拥有一个单一的位置来确保一切都是最新的并且可以正常协同工作。风险实际上与安装非 Ruby 代码的 gems 有关。例如,我相信有可能安装一个 gem,然后让主机包系统替换由主机系统管理的共享库,使用不兼容的版本,这将使 gem 无用。

从长远来看,我希望有人能想出一个解决这个问题的好的方案。到目前为止,我还没有受到这个潜在问题的严重影响。我使用 apt 来管理 Ruby 和系统的其余部分,我使用 RubyGems 来管理我需要的 gems。我遇到的一个问题更多与用户错误有关。我未能安装 RMagick 所需的库。RMagick 扩展的编译失败了,但我没有看到错误,因为它滚动得太快了,并且 gem 报告它已安装。最终,我弄清楚了发生了什么,并且在此过程中没有计算机受到损害。可以认为,如果我在 apt 中完成所有操作,则可以避免此问题,因为它会在我安装 RMagick 后立即安装缺少的库。另一方面,由于许多 Rails 和其他 Ruby gems 似乎都在频繁更新,因此能够跟上 Ruby 软件的最新版本而不是必须等待新 Debs 发布一直很好。

结论

Ruby 的包管理起步艰难。现在我们有了 RubyGems,很难想象没有它工作。RubyGems 在一个非常小的包中塞入了许多功能。它使查找、分发和管理各种 Ruby 软件变得更加容易。现在您已经完成了这个简短的介绍,您可以开始在自己的开发中使用 gems 了。

本文资源: /article/9019

Dirk Elmendorf 是 Rackspace Managed Hosting ( www.rackspace.com) 的创始人之一。他目前沉迷于 Ruby on Rails,当您阅读本文时,他将与 Annie Tiemann 幸福地结婚!

加载 Disqus 评论