《Ruby程序员修炼之道》(第2版)—第1章1.4节易用的Ruby工具和应用程序

本节书摘来自异步社区《Ruby程序员修炼之道》一书中的第1章,第1.4节易用的Ruby工具和应用程序,作者【美】David A. Black(戴维 A. 布莱克),更多章节内容可以访问云栖社区“异步社区”公众号查看。

1.4 易用的Ruby工具和应用程序
安装Ruby后,就可以得到一组重要的命令行工具,它们被安装在配置信息bindir所指定的文件夹中,通常是/usr/local/bin、/usr/bin或者/opt同等的目录中。(可以使用require "rbconfig"去测试一下RbConfig::CONFIG["bindir"]返回的结果。)这些命令行工具具体是以下几个。

  • ruby:解释器。
  • irb:Ruby交互式解释器。
  • rdoc和ri:Ruby文档工具。
  • rake:Ruby的make工具,一套任务管理实用工具。
  • gem:一套Ruby库和应用程序包管理实用工具。
  • erb:一套模版系统。
  • testrb:一个用于测试框架的高级工具。

这一节将会讲述除erb和testrb之外的所有工具。它们在特定的条件下都很有用,但是不作为学习Ruby语言首要的目标和基础知识。

在这里读者可以不必记住本节的所有技术点,而是通读之后先留下感性认识。不久之后将会经常(尤其是一些命令行参数和ri实用工具)用到这些内容,随着使用频率的提高,对Ruby语言的理解会逐步加深。

1.4.1 解释器的命令行开关
从命令行启动Ruby解释器时,不仅可以提供程序的名称,也可以提供一个或多个命令行开关,正如在本章中所见那样。用户选择的开关将会通知解释器使用不同的特殊行为方式,抑或使用特殊的功能。

Ruby有超过20个命令行开关。其中一些用得很少,而另外一些对于Ruby程序员来说使用频率较高。表1-6概括了最常用的一些Ruby命令行开关。


《Ruby程序员修炼之道》(第2版)—第1章1.4节易用的Ruby工具和应用程序

接下来仔细看一看每一个开关的使用细节。

1.语法检查(-c)
开关-c通知Ruby对一个或者多个文件的语法精确性进行代码检查,但不执行代码。它通常会和-w开关一起使用。

2.开启警告(-w)
使用-w开关运行程序,解释器将会进入警告模式(warning mode)。这意味着用户将会看到比预期更多的警告输出,从而提示用户在程序中需要注意的地方,尽管这些不是语法错误,但都有文体上和逻辑上值得斟酌的地方。根据Ruby的设计:“你所编写的程序没有语法错误,但是它很怪异。你确定你所编写的程序吗?”甚至不用添加这个开关,Ruby也会给出确定的警告,只是相对而言要少于完全警告模式。

3.执行字符串脚本(-E)
开关-e会通知解释器,命令行中的引号内包含了Ruby的代码,应该去执行这段真实的代码,而不是执行文件中的代码。这样可以很方便地用于快速执行脚本代码,而不用把代码写在文件中再去执行文件。

例如,将自己的名字逆向地打印输出。在下面的例子中,添加执行开关(execute switch)可以快速地使用一条命令行工具实现这个功能:

$ ruby -e 'puts "David A. Black".reverse'
kcalB .A divaD

单引号中包含的内容是一个Ruby程序的整体(虽然很短)。假如想要运行多于一行的程序并使用-e开关,需要在小程序中使用文本换行符(回车):

$ ruby -e 'print "Enter a name: "
puts gets.reverse'
Enter a name: David A. Black

kcalB .A divaD

或者可以使用分号进行行分隔:

$ ruby -e 'print "Enter a name: "; print gets.reverse'

**注意
为什么在两行的reverse例子中,在程序代码的输出结果的两行之间会有一个空格呢?因为用键盘输入的一行是以一个换行符结束的,所以当反转输入的时候,新字符串就伴随新一行产生了。当请求Ruby操作和打印数据的时候,Ruby是非常遵循文字本身的。**

4.行模式运行(-L)
开关-l将会产生一个效果:程序的每一次字符串输出都会被它自身的一行所替代,即使通常情况不是这样的。通常情况下,使用print打印输出不会自动以一个换行符结束,它与puts的使用不一样,但是使用了开关-l后,print也会以换行符结束。

下面使用温度转换器的程序作为例子来对比print和puts的区别,用以确信程序不会在它们的输出中间插入额外的换行符(见1.1.5节)。可以使用-l开关逆向实现这个效果,这甚至将致使print打印输出的每一行都在它们自己所属的那一行中。下面展示了差别:

$ ruby c2f-2.rb
The result is 212.
$ ruby -l c2f-2.rb
The result is
212
.

在这个例子中,使用-l的结果并不是期望的。但是这个例子展示出了开关的效果。

如果某一行已经存在换行符,使用-l开关会添加另一个换行符。通常-l开关是不常使用的,因为puts的功能已经足够达到按需添加换行符的需求,不过了解-l的用途还是有益的。

5.请求名称文件和扩展(-rname)
开关-r用于调用require,并依赖其命令行参数,ruby -rscanf将会在运行开始时加载scanf。可以放置多个-r在单行的命令行参数中。

6.运行在详细模式之下(-v和--verbose)
使用-v运行程序将会执行两个任务:打印输出当前使用Ruby的版本信息,然后开启与-w开关相同的警告机制。最常使用-v的场景是找出Ruby的版本号:

$ ruby -v
ruby 2.1.0p0 (2013-12-25 revision 44422) [x86_64-darwin12.0]

本例中使用的是Ruby 2.1.0(补丁级别0),于2013年12月25日发布,并基于i686机器编译,运行在Mac OS X系统上。这里因为没有程序需要运行,所以Ruby立刻就打印输出了版本信息。

7.打印Ruby版本信息(--version)
这个开关可以让Ruby打印一次版本信息,然后退出。就算指定了程序文件名,也不会执行任何的代码。可以回忆一下-v开关在详细模式下打印版本信息并执行代码的过程。可以说,-v开关是悄悄地完成了打印版本和运行代码的模式,而-- version仅仅输出了版本  信息。

8.打印帮助信息(-h和--help)
这两个开关(-h和--help)将会打印输出一个包含全部可用的命令行开关的列表,并概述它们的功能。

除了可以单独使用这些开关,也可以在Ruby调用的时候合并两个或者多个一起使用。

9.合并使用开关(-cw)
之前已经介绍过-cw这样的合并使用方式了,它会检查文件的语法错误而不执行文件,当然也会给出警告:

$ ruby -cw filename

另一个很常用的合并使用的例子是-v和-e,这将显示运行的Ruby的版本,同时运行单引号内的代码内容。有很多关于Ruby合并开关使用的讨论,如邮件列表和其他地方,人们使用它来验证相同的代码在不同版本之间的差异。例如,如果想要清晰地显示一个字符串调用方法start_with?在Ruby 1.8.6中不能运行而在Ruby 2.0中可以,那么可以分别运行这两个版本:

$ ruby-1.8.6-p399 -ve "puts 'abc'.start_with?('a')"
ruby 1.8.6 (2010-02-05 patchlevel 399) [x86_64-linux]
-e:1: undefined method `start_with?' for "abc":String (NoMethodError)  
$ ruby-2.1.0p0 -ve "puts 'abc'.start_with?('a')"
ruby 2.1.0p0 (2013-12-25 revision 44422) [x86_64-linux]
true  

(当然,这要求系统中安装了两个版本)第一次运行(使用1.8.6版本)程序获得了undefined method 'start_with?'消息,这意味着执行了一个不存在的操作。但是使用Ruby2.1.0运行相同的代码段时,运行就正常了,Ruby打印输出了true。这是一个非常便捷的方式去分享和提出关于Ruby版本切换时的问题。

现在,将讲述前面所提到的交互式Ruby解释器irb,并进一步地了解它。这一部分在本章的一开头已经有过叙述,所以读者可能已经有所了解。如果没有,那么借此机会可以学习一下这个特殊且有用的Ruby工具。

指定开关

可以给Ruby提供分隔式的开关,例如:

$ ruby -c -w

或者

$ ruby -v -e "puts 'abc'.start_with?('a')"

但是通常将它们合并在一起使用,正如正文中所讲述的例子。
1.4.2 走近Ruby的交互式解释器irb
正如本书中所见,irb是一个交互式的Ruby解释器,这意味着它不用处理文件,而是处理会话中所输入的代码。irb是一个很好的工具,可以用于测试Ruby代码,同时也是一个学习Ruby的好工具。

在命令行中输入irb,就可以开启irb会话,irb将显示以下提示符:

$ irb
2.1.0 :001 >

正如之前所述,还可以使用--simple-prompt选项使irb输出更为简单明了:

$ irb --simple-prompt
>>

irb一旦启动,便可以输入Ruby命令。这里可以运行单次摄氏-华氏度转换程序。在本例中,irb就像一个可装入口袋的计算器:它能计算任何输入并打印结果。因此不必使用print或者puts命令:

>> 100 * 9 / 5 + 32
=> 212

如果想要知道一年有多少分钟(假如读者手边没有Rent乐队热门金曲的CD④),就输入适当的乘法计算表达式:

>> 365 * 24 * 60
=> 525600

当然,irb也会处理输入的Ruby指令。比如,将天数、小时数、分钟数赋值给变量,然后将这些变量的值相乘,可以在irb中这样做:

>> days = 365
=> 365
>> hours = 24
=> 24
>> minutes = 60
=> 60
>> days * hours * minutes
=> 525600

上面就是期望的计算结果。但是看一下上面条目的前3行,当输入days = 365的时候,irb会相应输出365,为什么?

表达式days = 365是一个赋值表达式:将值365赋给了名为days的变量。赋值表达式最重要的任务就是将值赋给变量,因此可以在之后使用该变量。但是赋值表达式(days = 365这一整行)也有一个值,赋值表达式的值就是它右边的值。当irb发现任何表达式时,它就会输出这个表达式的值。因此,当irb发现days = 365时,它就输出365。这看起来有些输出过度,这是因为其处在irb之中,与在irb中输入2+2就看到了结果,而没有显式地使用print语句去打印结果是同样的道理。

同样,调用puts方法也有一个返回值,名为nil。假如在irb中输入一个puts语句,irb将会严格地执行它,同时还会打印输出puts的返回值。

$ irb --simple-prompt
>> puts "Hello"
Hello
=> nil

这里有一种方法可以让irb不再喋喋不休,即使用-noecho参数。下面展示它如何使用:

$ irb --simple-prompt --noecho
>> 2 + 2
>> puts "Hi"
Hi

幸好有-noecho,附加的表达式不会回显其结果了。puts命令确实被执行了(可以看到输出"Hi"),但是puts的返回值(nil)被屏蔽了。

中断irb

在irb中可能会卡在一个循环中,或者会话看起来像是失去响应(就好像是输入了左双引号而没有输入右双引号,或者类似的代码行)。重新回到控制的方法取决于系统本身,在最常见的系统中,使用Ctrl+C组合键可以达到这一目的。另一个方法是使用Ctrl+Z组合键。这是用户的系统中直接作用于irb上,最优、最通用的中断信息的方式。当然,如果任务被真的冻结,无响应,可以到进程或者任务管理器工具中终止irb进程。

要从irb中正常退出,输入exit即可。在许多系统中,Ctrl+D组合键同样适用。

偶然情况下,会遇到irb出现问题(那是说遇到致命错误然后结束进程),而大多数时候它会捕获自己的错误,然后让用户继续操作。
一旦掌握了使用irb的窍门并用于打印输出一切的值,以及如何关闭它,就会发现irb是一个极为有用的工具(和玩具)。

Ruby的源代码采用一种能自动生成文档的方式进行标记,然后通过一些工具解析和显示它们,这些工具是ri和RDoc,下面就会讲述到。

1.4.3 ri和RDoc
最早由Dave Thomas编写的ri(Ruby索引)和RDoc(Ruby文档)是为Ruby程序提供文档的关系很紧密的一对工具。ri是一个命令行工具,而RDoc体系中包含了命令行工具rdoc。ri和rdoc是独立的程序,通过命令行来运行。(虽然用户也可以使用Ruby程序内所提供的工具,但这里暂时不讨论这方面的内容。)

RDoc是一个文档系统。假如在程序文件(Ruby或者C)中使用规定的RDoc格式编写了注释,rdoc会扫描程序文件,并抽取这些注释,智能地(通过注释的内容进行索引)组织它们,最后创建出漂亮的格式化文档。在Ruby源码树以及许多Ruby安装目录的Ruby文件中,在许多的源码文件中可以看到RDoc标记,包括了Ruby文件和C语言文件。

ri与RDoc相互配合:它提供了一种方式用于查看RDoc萃取过和组织过的文档信息。具体来说(虽然不是唯一的,除非用户定制它),ri被用于组织和显示从Ruby源文件而来的RDoc的信息。在完全安装好Ruby的任何系统中,都可以使用一个简单的命令行工具ri获得关于Ruby语言的详细信息。

例如,下面是请求关于string对象的upcase方法的信息的方法:

$ ri String#upcase

显示如下结果:

= String#upcase
(from ruby core)
------------------------------------------------------------------------------
str.upcase -> new_str
------------------------------------------------------------------------------
Returns a copy of str with all lowercase letters replaced with their
uppercase counterparts. The operation is locale insensitive---only characters
``a'' to ``z'' are affected. Note: case replacement is effective only in
ASCII region.
"hEllO".upcase #=> "HELLO"

在String和upcase中间的散列标记(#),用于在ri命令中表明查找的实例方法,并与类方法区分。要查询类方法,可以使用分隔符::替换#。第3章将会讲述实例方法和类方法的区分。这里的要点是通过命令去处理大量的文档。

**注意
默认情况下,运行ri会通过一个分页器(如UNIX中的more命令)输出结果。它会在输出的末端暂停,直到用户点击空格或者其他按键才会展示下一屏的信息,或者当所有的信息显示完毕就会完全退出。准确地说,在这个例子中,用户必须按下的按键因操作系统和分页器不同会有所变化。空格键、回车键、Esc键、Ctrl+C组合键、Ctrl+D组合键和Ctrl+Z组合键都是很好的选择。如果想要使用ri而不进行分页显示,可以在命令行使用的时候加入-T开关(ri –Ttopic)。**

下一节将会讲述Ruby命令行工具中的rake。

1.4.4 任务管理实用工具:rake
正如其名字所代表的含义(由“Ruby make”而来),rake是一个极具make特性的任务管理实用工具。它是由已故的Jim Weirich编写完成的。同make一样,rake读取和执行定义在一个文件中的任务,这个文件名为Rakefile。和make不同,rake必须使用Ruby语法定义任务。

代码清单1-5显示了一个Rakefile。假如列表中的内容保存到一个称为Rakefile的文件,就能够在命令行中运行它:

$ rake admin:clean_tmp
rake执行了admin命名空间中的clean_tmp任务。
<div style="text-align: center">
 <img src="https://yqfile.alicdn.com/ffcfff9b66d3e3792fecdcefc30d08cd2442052a.jpeg" >
</div>

这里,rake定义任务的时候用到了许多本书中还没出现的Ruby技术,但其基本逻辑是非常简单的。

(1)循环进入/tmp目录下的每一个目录条目。

(2)除非当前条目是一个文件,否则跳出当前的循环。提示一下,隐藏文件也不会被删除,因为列出目录的操作不会包括它们。

(3)提示删除文件。

(4)假如用户输入y(或者任何以y开头的字符串),则删除文件。

(5)假如用户输入q,中断循环,任务结束。

主要的编程逻辑是这样组成的:通过循环目录列表中的条目(参见“使用each遍历一个集合类型”),然后通过case语句进行条件判断并执行(这些技术将会在第6章中讲述)。

使用each遍历一个集合类型

表达式Dir["/tmp/*"].each do |f|调用了一个包含目录条目名称的数组的each方法。整个代码块从do开始并在end处结束(end与Dir使用统一缩进整齐排列),并对每数组中每一项执行一次。每一次执行,当前项都会绑定到参数f,这就是|f|语句的意义。在接下来的章节中,将会看到许多使用each的地方。在第9章讲述迭代器(iterator)的时候,将会对each进行详细的讲述。
上面任务定义中的命令desc提供了对任务描述的方式。这不仅在用户研究文件的时候可以派上用场,还可以用于在特定时间查看rake可以执行的所有任务。假如所处的目录中包含一个代码清单1-5中的Rakefile,便可以使用如下命令:

$ rake --tasks

可以看到所有定义过的任务列表。

$ rake --tasks
(in /Users/ruby/hacking)
rake admin:clean_tmp   # Interactively delete all files in /tmp

对于rake的命名空间和任务名称可以任意命名。甚至可以不需要一个命名空间,可以在*命名空间定义一个任务,如下所示:

task :clean_tmp do
 # etc.
end
然后使用简单的名称调用它:

$ rake clean_tmp

但是,在任务中使用命名空间是个好主意,尤其是在用户定义的任务数量成倍增长的时候。可以定义命名空间至任意的深度,例如,下面的结构是合法的:

namespace :admin do
 namespace :clean do
  task :tmp do
   # etc.
  end
 end
end

定义好的任务是这样调用的:

$ rake admin:clean:tmp

正如目录清理的例子所示,rake任务不会被限制在与Ruby编程相关的操作中。使用rake,用户可以随意使用Ruby语言以达到编写任何所需任务的目的。

下一个将要讲述的是gem命令,它使得安装第三方Ruby组件包变得非常容易。

本节书摘来自异步社区《Ruby程序员修炼之道》一书中的第1章,第1.4节使用gem命令安装组件包,作者【美】David A. Black(戴维 A. 布莱克),更多章节内容可以访问云栖社区“异步社区”公众号查看。

1.4.5 使用gem命令安装组件包
RubyGems库和实用工具集合包括了打包、安装Ruby库和应用程序的工具。这里不会覆盖创建gem的内容,只是先看一下gem安装程序和使用的方法。

使用gem安装一个Ruby的程序包通常是很简单的,在gem之后使用简单的install命令即可

$ gem install prawn

这个命令将会输出如下内容(这依赖于已经安装的gem和新安装的gem的依赖包):

Fetching: Ascii85-1.0.2.gem (100%)
Fetching: ruby-rc4-0.1.5.gem (100%)
Fetching: hashery-2.1.0.gem (100%)
Fetching: ttfunk-1.0.3.gem (100%)
Fetching: afm-0.2.0.gem (100%)
Fetching: pdf-reader-1.3.3.gem (100%)
Fetching: prawn-0.12.0.gem (100%)
Successfully installed Ascii85-1.0.2
Successfully installed ruby-rc4-0.1.5
Successfully installed hashery-2.1.0
Successfully installed ttfunk-1.0.3
Successfully installed afm-0.2.0
Successfully installed pdf-reader-1.3.3
Successfully installed prawn-0.12.0
7 gems installed

这些状态报告之后跟随着许多行信息,它展示了对于已经安装好的不同gem的ri和RDoc文档信息。(文档的安装是通过RDoc与正在处理的gem源文件关联,所以要耐心等待这个过程,它通常是gem安装中最长的过程。)

在gem安装的过程中,gem从rubygem.org(www.rubygems.org)下载所需的gem文件。这些文件都是使用.gem格式,被保存在用户gems目录下的缓存子目录中。当然也可以安装存放在本地磁盘或者其他媒介中的gem文件。指定文件的名称即可安装:

$ gem install /home/me/mygems/ruport-1.4.0.gem

假如指定安装的gem名称没有使用完全文件名(如ruport),gem将会查找当前目录和RubyGems系统中的本地缓存。本地安装仍然会搜索远程的依赖包,除非使用-l(local)作为gem的命令行参数,它严格限制所有的操作都在本地进行。假如想要仅使用远程安装gem并包含依赖包,可以使用-r(remote)参数。在大多数情况下,简单地使用“gem install包名”这样的方式即可(要卸载一个gem包,使用“gem uninstall包名”命令)。

一旦安装了一个gem包,就可以通过require方法使用它。

加载和使用gem包
此刻不会看到gem包位于初始化加载路径($:)之中,但仍然可以使用require请求它们。这里列出了怎样请求“hoe”(帮助用户打包自己的gem实用工具)的方式,并确保Hoe gem包已经安装:

>> require "hoe"
=> true

在这里,hoe的关联目录将会出现在加载路径中,假如使用grep匹配“hoe”模式打印输出$:的值,如下:

>> puts $:.grep(/hoe/)
/Users/dblack/.rvm/gems/ruby-2.1.0/gems/hoe-3.8.1/lib

假如为了特殊的库安装了一个库的多个版本的gem,然后想要强制使用其中一个版本而不是最常用的版本,也可以使用gem方法。(注意,这个方法和命令行工具中的gem不是一个工具。)在这个例子中,展示了如何强制使用非当前版本的Hoe:

E:00在线编撰系统图书830种以外的电子书4050329.png

当然,更多时候都会使用最新gem。只是gem系统给出了可以微调gem使用的工具,这也应该如用户所需。

关于RubyGems就讲述到这里,至此已经学完了bin/目录的知识,接下来将进一步学习Ruby语言的核心部分。

上一篇:一个地址的旅程


下一篇:使IFRAME在iOS设备上支持滚动