`
ihuashao
  • 浏览: 4724457 次
  • 性别: Icon_minigender_1
  • 来自: 济南
社区版块
存档分类
最新评论

比较文件清单(Everyday Scripting with Ruby第三章试译)

阅读更多
想尝试翻译《Everyday Scripting with Ruby》,经过几个晚上的鏖战,给对方发出了我的试译稿。很可惜,估计是我英语水平有限、文字功底尚待提高的缘故,无缘本书的翻译工作。
这儿,我贴出我的试稿件,希望大家能够给出意见和建议,也希望有过翻译经验的xdjm提出批评,先谢过。:)
翻译样章下载
试译文如下:

第一个脚本:比较文件清单

在这一章里,我们将创建一个虽简单却很有用的脚本程序。在这个过程中,你会掌握Ruby的一些基本术语,领会它的一些技巧。到第五章,从33页开始,我们将对这个程序进一步完善:作三点改进,修正一个bug

3.1 运行脚本

在命令行状态下,先进入(用cd命令)源代码所在目录的子目录inventory。(如果你忘了如何操作,参见第13页的小贴士)。这时我们会看到一个脚本文件inventory.rb,运行它:

prompt> ruby inventory.rb

我们会看到如下内容:

exercise-differences.rb

inventory.rb

old-inventory.txt

recycler

recycler/inst-39.tmp

snapshots

snapshots/differences-version-1.rb

snapshots/differences-version-2.rb

snapshots/differences-version-3.rb

snapshots/differences-version-4.rb

snapshots/differences-version-5.rb

snapshots/differences-version-6.rb

snapshots/differences-version-7.rb

snapshots/differences-version-8.rb

temp

temp/inst-39

这样,我们就运行了一个脚本。它列出了一份清单,清单中包含了当前工作目录中的所有文件(子目录中的所有目录和文件也包括在内)<!--[if supportFields]><b style='mso-bidi-font-weight:normal'><sup><span lang=EN-US style='font-size: 12.0pt'><span style='mso-element:field-begin'></span> = 1 \* GB3 <span style='mso-element:field-separator'></span></span></sup></b><![endif]--><!--[if supportFields]><b style='mso-bidi-font-weight:normal'><sup><span lang=EN-US style='font-size: 12.0pt'><span style='mso-element:field-end'></span></span></sup></b><![endif]-->。在本章,我们还要创建一个脚本用来比较两份清单。比较什么呢?我想知道第二份清单和第一份相比,加入了哪些内容,删除了哪些内容。如果你是测试人员,这个脚本至少在两方面对你很有用:

<!--[if !supportLists]-->l <!--[endif]-->假设你每周五要编译出一个测试版本,而这周编译的源代码文件跟上周相比可能有些改变。现实情况中,人不是十全十美的,他总会犯错误。有时候,可能源文件的这份清单就是错误的,那么编译出来的测试版本当然就谈不上对了。如果有一份清单能够告诉你增加和删除了哪些文件,那么它就可以防患于未然,帮你决定哪些文件是需要编译的。

<!--[if !supportLists]-->l <!--[endif]-->你想列出整个文件系统的文件清单(比如说,C:\)。安装一个程序,之后又卸载它,然后比较安装前和删除后的文件清单。你可能会发现在文件系统中还残留着尚未完全删除的垃圾文件。

3.2 Ruby的世界

当我们运行脚本inventory.rb的时候,就创建了一个小“Ruby的世界”。这个Ruby的世界本质上包含3种事物:名词、动词和名称。名词,我们通常称之为对象,它们是Ruby世界的“事物”。对象是静止不动的,直到你告诉它需要做什么。因此,我们需要动词。在Ruby世界里,所有的动词都是祈使动词:像“起立”、“坐下”、“打滚”等等。这些动词我们称之为消息。因此,如果告诉一个对象做什么,就说发送消息。

我们没有权限直接访问Ruby世界中的对象。但是想要访问它,怎么办呢?我们就必须使用名称,让程序知道当使用这个名称的时候,实际上就是这个对象。在我们的世界里,我就是一个对象,我儿子涉及到我的时候,称呼我为“爸爸”,妻子称呼我为“丈夫”或昵称,而天河机场的职员可能会说,“31号”或“嘿,说你呢!”,实际上他指的也是我。

3.3 对象发送和接收消息

上一节的内容相当的抽象。在这一节里,我们通过实例来理解什么是名称、对象和消息。现在开始,在命令行中输入如下命令创建一个清单文件:

prompt> ruby inventory.rb > new-inventory.txt

这儿,> new-inventory.txt 告诉命令行解释器把脚本的运行结果保存到一个命名为new-inventory.txt的文件中。> new-inventory.txt并不是Ruby语言的一部分—它对任何命令都管用。(我之所以使用文件new-inventory.txt,是想表明这份清单是在安装一个程序,然后把它卸载之后得到的。你可能已经注意到了,在目录inventory中已经存在文件old-inventory.txt,现在我们假设它是在安装之前的清单。)

打开irb, 然后运行如下命令。注意File的第一个字母F是大写的。Ruby语言是字母大小写敏感的,这就意味着Filefile是不同的。如果写成file,就会得到一条出错信息。

irb(main):001:0> File.open('new-inventory.txt')

=> #<File:new-inventory.txt>

现在,我每一步都讲得比较详细,因此我们的进展非常慢。别着急,慢慢来,很快我们将进入下一个境界。(在Introduction->How the book works中,作者提到前两个例子他会讲得比较慢,后面的例子会讲得比较快。)

FileRuby世界中一个非常特殊的对象。 Ruby世界里有个对象知道如何打开文件,并为使用文件做好各项准备,它就是FileOpen消息告诉File对象打开文件。既然File需要知道应该打开哪个文件,那么open就有个参数,即字符串“new-inventory.txt”。

在收到消息后,File打开这个文件。至此,我们又引入另外一个对象,就是打开的这个文件(我指的对象仅限于Ruby中涉及到的)。File接着把新创建的对象返回给发创建消息的对象(通常我们称之为发送方)。在这个例子中,发送方是irb。(既然irb是一个Ruby脚本,那么它就在Ruby世界里作为一个对象而存在。)当irb得到返回值后,以一种程序员看得懂的方式打印到屏幕上。这儿,#<File:new-inventory.txt>告诉我们,File通过创建一个对象来给它入口以访问文件系统中的new-inventory.txt文件。其它对象的输出方式可能有所不同。事实上,每个对象都能决定如何输出结果。

不过,除了打印文件的信息(这儿的文件信息是指文件本身的信息,而非文件的内容)之外,还有更多的事情要做,你可以让它打印出整个文件的内容,具体操作如下:

irb(main):002:0> File.open('new-inventory.txt').readlines

=> ["exercise-differences.rb\n", "inventory.rb\n", "new-inventory.txt\n", _

"old-inventory.txt\n", "recycler\n", "recycler/inst-39.tmp\n", "snapshots _

\n", "snapshots/differences-version-1.rb\n", "snapshots/differences-versi _

on-2.rb\n", "snapshots/differences-version-3.rb\n", "snapshots/difference _

s-version-4.rb\n", "snapshots/differences-version-5.rb\n", "snapshots/dif _

ferences-version-6.rb\n", "snapshots/differences-version-7.rb\n", "snapsh _

ots/differences-version-8.rb\n", "temp\n", "temp/inst-39\n"]

从前,我们告诉irb发送open信息给FileFile返回了一个打开的文件对象。但是irb并没有打印出结果,我们还得告诉它发送另外一个信息,readlinesreadlines把文件的每一行转换成一个字符串。打印出的“字符串”就是Ruby给字符序列命名的名称。Readlines然后以数组形式返回这些字符串。在这个例子中,它们在文件中出现的顺序是一致的。irb在打印这些字符串时,每个字符串都加上了双引号,不同的字符串以逗号隔开,整个数组最后用方括号括起来。在本书后面的章节中,你将看到更多字符串和数组的例子。

如果仔细地检查一下new-inventory.txt文件,你就会发现它包含的内容的确和打印出来的完全一致,甚至顺序也是一致的。唯一的不同是,每个字符串都加了引号,而且每个结尾用的都是\n。这个符号相当于行结束符,表明\n后面的内容会另起一行。<!--[if supportFields]><sup><span lang=EN-US style='font-size:12.0pt;font-family:宋体'><span style='mso-element: field-begin'></span> = 2 \* GB3 <span style='mso-element:field-separator'></span></span></sup><![endif]--><!--[if supportFields]><sup><span lang=EN-US style='font-size:12.0pt;font-family:宋体'><span style='mso-element: field-end'></span></span></sup><![endif]-->

可能你还注意到了,在输入字符串“new-inventory.txt”的时候,我用的是单引号,但是 irb 打印字符串的时候使用的是双引号。实际上,这是习惯问题,如果你喜欢,你可以在打字符串的时候,用双引号,打文件名时用单引号。在本书中也遵循这个原则。

3.4 变量名对象

在得到文件内容的数组之后,我们可以给数组一个名称 new_inventory。(请注意:这个名称中我们用到的是下划线_,而不是连字符-。)如下所示:

irb(main):003:0> new_inventory = File.open('new-inventory.txt').readlines

=> ["exercise-differences.rb\n", "inventory.rb\n", "new-inventory.txt\n", ←_

"old-inventory.txt\n", "recycler\n", "recycler/inst-39.tmp\n", "snapshots ←_

\n", "snapshots/differences-version-1.rb\n", "snapshots/differences-versi ←_

on-2.rb\n", "snapshots/differences-version-3.rb\n", "snapshots/difference ←_

s-version-4.rb\n", "snapshots/differences-version-5.rb\n", "snapshots/dif ←_

ferences-version-6.rb\n", "snapshots/differences-version-7.rb\n", "snapsh ←_

ots/differences-version-8.rb\n", "temp\n", "temp/inst-39\n"]

在术语上,Rubynew_inventory为变量。(在当计算机在做数学运算时这就变得更有意义。)

项目inventory中包含了一个名为old-inventory.txt的文件。这个文件的内容也是一份清单,只不过这份清单的内容比new-inventory.txt要早。我们可以这样读取它:

irb(main):004:0> old_inventory = File.open('old-inventory.txt').readlines

=> ["exercise-differences.rb\n", "inventory.rb\n", "old-inventory.txt\n", ←_

"financial-records.xls\n", "snapshots\n", "snapshots/differences-version- ←_

1.rb\n", "snapshots/differences-version-2.rb\n", "snapshots/differences-v ←_

ersion-3.rb\n", "snapshots/differences-version-4.rb\n", "snapshots/differ ←_

ences-version-5.rb\n", "snapshots/differences-version-6.rb\n", "snapshots ←_

/differences-version-7.rb\n", "snapshots/differences-version-8.rb\n", "te ←_

mp\n", "temp/junk\n"]

现在,我们已经得到了两个数组,可以比较它们了。

3.5 数组比较

找出两个数组不同的方法很简单,就是给它们做“减法”运算。用其中的一个数组“减去”另外一个,就像这样:

irb(main):005:0> new_inventory - old_inventory

=> ["new-inventory.txt\n", "recycler\n", "recycler/inst-39.tmp\n", "temp/ _

inst-39\n"]

以上显示的是在新的inventory中存在,却在老的inventory中不存在的字符串。如果想找出哪些文件从老的清单中删除了,我们可以把被减数和减数调换位置。<!--[if supportFields]><sup><span lang=EN-US style='font-size:12.0pt;font-family:宋体'><span style='mso-element: field-begin'></span> = 3 \* GB3 <span style='mso-element:field-separator'></span></span></sup><![endif]--><!--[if supportFields]><sup><span lang=EN-US style='font-size:12.0pt;font-family:宋体'><span style='mso-element: field-end'></span></span></sup><![endif]-->

irb(main):006:0> old_inventory - new_inventory

=> ["financial-records.xls\n", "temp/junk\n"]

不妨再回头仔细审查一下文件的内容,你会发现输出的结果是对的。

请注意,我们在做减法的时候,并没有改变这两个数组的内容。把old_inventory减去new_inventory实际上不会影响原来old_inventory的内容。它不仅没有从old_inventory中删掉任何内容,反而还产生了一个新的数组,这个数组的内容的就是做减法的结果。

命名遵循的原则

一个Ruby名称可以包含字符、数字,还有下划线(下划线是“_”,不是连字符“-”)。名称不能以数字开头,也不能包含空格。在大小写方面,my_shipmy_Ship是不同的。如果一个名称以大写字母开头,你就在告诉Ruby,希望它是个常量,至始至终代表一个对象。如果你把这个名称用在另外一个对象上,Ruby就会抱怨你,有没搞错啊!

irb(main):007:0> MyShip = "a cutter"

=> "a cutter"

irb(main):008:0> MyShip = "a bark"

(irb):4: warning: already initialized constant MyShip

=> "a bark"

(当然,抱怨归抱怨,你要求的操作它还得照样执行。)

当一个名称由多个单词组成,而且单词的首字母是小写的时候,为了方便,最好用下划线把它们隔开,像my_fine_name。如果首字母是大写呢,那就把每个单词的首字母都大写,比如MyFineName。不过说实话,我不大明白在这两种不同的写法背后有何理论依据。

还有一种特殊的情况,消息名可以以问号(?)或感叹号(!)结尾。如果以问号结尾。则表明这个信息向它的接收方问一个是非(truefalse)疑问句。如果是感叹号结尾,则是表明这个信息做了些特殊的操作,也有可能进行的操作不是期望中的。

3.6 打印到屏幕

我们期望区分出两份清单的所有的不同之处,现在万事俱备,只欠一个可以把结果打印出来的脚本了。有个工具可以做到,就是称作puts(“put string”的缩写)的消息。如何生成一份报表来展示结果呢,这儿有部分代码:

1_ irb(main):009:0> puts "The following files have been added:"

2_ The following files have been added:

3_ => nil

我们按顺序来分析这三行:

1.尽管它看起来不像,实际上它是另外一个消息。不像什么?对谁来说是另外一个消息?说得更清楚点,不像前面提到的,这个消息没有用点(.)把接收消息的对象和消息名隔开。其实在Ruby中,联系上下文,如果消息的接收方已经很明确了,你根本就没必要再加上消息的接收方。当从命令行运行一个Ruby脚本时,接收方当然就是它本身了。

还有一个原因,puts不像前面的消息那样,把参数先加上单引号,然后用圆括号括起来。为什么呢?如果Ruby知道要把结果输出到哪儿,是没必要加上圆括号的。

2.打印字符串到屏幕。这儿的打印和irb打印结果到屏幕二者完全不相干。

尽管puts也是打印,不过它不像irb那样自动为打印结果加上引号。irb的打印结果是给你——编辑——看的, 而puts打印的结果是给最终读者看的。如果你还是更偏好irb的那种输出格式,好吧,使用inpect 消息可以达到你的要求:

irb(main):010:0> puts "I'd like some quotes, please".inspect

"I'd like some quotes, please"

=> nil

3.这一行是puts的返回值。每个Ruby消息都会有返回值。如果某个消息的确没什么好返回的,一般就返回“nil”了。(“nil”就意味着“空”。)

irb用来打印它发出的上一个消息的返回值。如果从命令行运行一个脚本,就不会这样。你可以看到,脚本行消失了,取而代之的是puts打印的结果。

puts还可以打印数组:

irb(main):011:0> puts old_inventory

exercise-differences.rb

inventory.rb

old-inventory.txt

financial-records.xls

snapshots

snapshots/differences-version-1.rb

snapshots/differences-version-2.rb

snapshots/differences-version-3.rb

snapshots/differences-version-4.rb

snapshots/differences-version-5.rb

snapshots/differences-version-6.rb

snapshots/differences-version-7.rb

snapshots/differences-version-8.rb

temp

temp/junk

=> nil

请注意,数组的元素是如何逐行打印出来的。(这和字符串是否以\n结束无关,puts会自动地进行换行操作。)

3.7 创建脚本

到目前为止,一切都准备就绪,我们可以开始创建一个脚本比较这两份清单了。给这份脚本命名为differences.rb,把这段后面的代码行添加到脚本文件中。(如果你想偷懒,不从键盘中输入代码,你可以从下面的文件代码中直接拷贝过去。不过我敢打赌,如果你手动输入它们,你对它的理解肯定会更加深刻。)在第11页,第二章的第5节 你的编辑器中,列出了你可能会用到的编辑器。不管你选择哪个编辑器,最后别忘了把文件保存在inventory目录中。

inventory/snapshots/differences-version-1.rb

old_inventory = File.open('old-inventory.txt').readlines

new_inventory = File.open('new-inventory.txt').readlines

puts "The following files have been added:"

puts new_inventory - old_inventory

puts ""

puts "The following files have been deleted:"

puts old_inventory - new_inventory

确保你已经退出irb命令状态,然后通过以下命令运行脚本<!--[if supportFields]><sup><span lang=EN-US style='font-size:12.0pt'><span style='mso-element:field-begin'></span> = 4 \* GB3 <span style='mso-element:field-separator'></span></span></sup><![endif]--><!--[if supportFields]><sup><span lang=EN-US style='font-size:12.0pt'><span style='mso-element:field-end'></span></span></sup><![endif]-->

prompt> ruby differences.rb

The following files have been added:

new-inventory.txt

recycler

recycler/inst-39.tmp

temp/inst-39

The following files have been deleted:

financial-records.xls

temp/junk

某些编辑器整合了运行功能,这样让你是用起来更方便。当你在使用SciTE的时候,按下F5你就可以运行它,并把结果显示在另一半分开的窗口里。如果你使用的是TextMate,当你按下#R,它也会运行这个脚本,不同的是,把结果显示在一个新开的窗口里。

不过,这个脚本还是有些不足。比如说,你必须把两份清单的内容都输入到文件名为new-inventory.txtold-inventory.txt的文件中去,而这文件名是死的,不能改变。尽管如此,这是个好的开始,现在,我们回过头来看看我们学到了些什么。

3.8 小结

我们已经有了一个有用的脚本。如果你还没有比较过清单,或者你以前都是手动去做的,现在你学到了一招。

现在,你已经学到了一点Ruby底层的理论:完成任何事情都是通过给对象发消息实现的。更重要的,你还学会了繁多的数据类型中的一种:数组。基本理论和丰富的内嵌工具让使Ruby这个脚本语言变得非常的强大。

3.9 练习

在练习中,我们还得继续使用代码目录中的inventory子目录。

<!--[if !supportLists]-->1. <!--[endif]-->length也是一个消息,这个消息的功能是得到数组的长度,如下:

irb(main):001:0> [1,2,3].length

=> 3

假设在脚本中加入如下一行:

x = (new_inventory - old_inventory).length

猜猜看,x的值是多少?它代表什么意思?变量名用什么代替x会更加直观易懂?

2.在上一题中,如果我们把代码改成

x = new_inventory - old_inventory.length

会发生什么情况呢?为什么会这样呢?

3.修改脚本,给他加入以下功能:new-inventory.txtold-inventory.txt相比,增加了几个文件,删除了几个文件,还有几个文件保持不变(这个有点技巧性)。

4.我们注意到new-inventory.txtold-inventory.txt中的内容都是字母排序的,以它们命名的数组也是如此。它们之间有什么联系没?如果清单的内容是乱序的,结果又如何呢?

1:这个项目的构思来自Chris McMahon.

2:在Windows环境下,这个符号是回车换行符;在Linux/Unix下,它仅仅是个换行符;在Mac下,它又仅仅是回车符。它们之间的区别就像大陆交通法规要求靠右行驶,而香港靠左行驶一样。这个规定有点专横,如果所有的环境中规定都是一样的,那么就不会发生交通意外了,可惜现在改已经太迟了。Ruby尽量让你不去关心操作系统:\n意味着“在这台机器上无论如何都是对的”。

3:如果在Ruby的世界里,只有对象、消息和名称,那么这儿消息又发送到哪儿去呢?不妨这样理解这行代码:给名称为old_inventory的对象发送名称为-的消息,而名称为new-inventory的就是参数。想象一下,如果Ruby没有减法(数字或数组)运算,那么它肯定没有现在这么流行。

4:如果你还没有亲自创建过一个脚本,但是你想运行snapshots目录中的某个脚本,可以把它拷贝到inventory目录中的differences.rb中。在windows下,这样操作:

C:>copy snapshots\differences-version-1.rb differences.rb

Linux下,这样操作:

prompt>cp snapshots/differences-version-1.rb differences.rb


(完)

分享到:
评论

相关推荐

    everyday scripting with ruby

    everyday scripting with ruby

    Everyday Scripting With Ruby

    《Everyday Scripting with Ruby》是一本综合性的Ruby教程,涵盖了从基础知识到高级技术的各个方面。通过实践导向的教学方法,读者不仅可以学习到Ruby的核心概念,还能掌握如何在真实环境中应用这些知识。无论是初学...

    Scripting With AD Scripting With AD

    标题 "Scripting With AD" 暗示了我们即将探讨的是使用脚本语言与Active Directory(AD)进行交互的主题。Active Directory是微软Windows操作系统中的一个关键组件,它用于存储和管理网络资源,如用户账户、计算机...

    Unreal Engine 4 Scripting with C++ Cookbook first edition.pdf

    Unreal Engine 4 Scripting with C++Cookbook Get the best out of your games by scripting them using UE4 William Sherif Stephen Whittle 2016版

    Unreal Engine 4.x scripting with C cookbook

    Unreal Engine 4.x scripting with C cookbook develop quality game components and solve scripting problems with the power of C and UE4 by Stephen Whittle John P. Doran William Sherif (z-lib.org)

    Unreal Engine 4 Scripting with C++.pdf

    描述《Unreal Engine 4 Scripting with C++ Cookbook》表明这是一本“食谱”类型的书籍,通常这类书籍会包含一系列独立的、实用的编程教程或示例,每一章或每一节都像是一道菜谱,指导读者如何一步步实现特定的功能...

    Unreal Engine 4 Scripting with C++ Cookbook

    Unreal Engine 4 Scripting with C++ Cookbook 2016 | ISBN-10: 1785885545 | 431 pages | PDF | 7 MB Key Features A straightforward and easy-to-follow format A selection of the most important tasks and ...

    Linux Shell Scripting with Bash

    ### Linux Shell Scripting with Bash #### 核心知识点解析 **1. Linux Shell Scripting 基础** - **Shell 的概念与作用** - Shell 是一个命令解释器,是用户与操作系统之间的交互界面。 - 用户通过输入命令,...

    Raven Scripting Java Builds With Ruby

    本书介绍了构建简单及方便...CHAPTER 3 Wait, I Have Dependencies!....................19 CHAPTER 4 Divide and Conquer: Multimodule Projects......33 CHAPTER 5 Public or Private Repository..................47

    Unreal Engine 4 Scripting with C++ Cookbook - 2016.pdf (带彩色插图)

    《Unreal Engine 4 Scripting with C++ Cookbook》是一本面向游戏开发者的专业书籍,专门介绍了如何使用C++语言结合Unreal Engine 4(UE4)进行游戏脚本编写。本书在2016年10月发布了新版,并且包含彩色插图,使得...

    Unreal Engine 4 Scripting with C++ Cookbook willam

    《Unreal Engine 4 Scripting with C++ Cookbook》是一本专为游戏开发人员设计的实用指南,旨在帮助读者深入理解并掌握使用C++在Unreal Engine 4(UE4)中进行脚本编程的技术。这本书涵盖了从基础概念到高级技巧的...

    Unreal Engine 4 Scripting with C++ Cookbook pdf 0分

    标题和描述中提到的《Unreal Engine 4 Scripting with C++ Cookbook》是一本关于Unreal Engine 4(UE4)游戏引擎中使用C++编程语言进行脚本编程的实用指导书。这本书以食谱(Cookbook)的形式呈现,为读者提供了许多...

    Microsoft - Windows Scripting With Wmi(2007)

    《Microsoft - Windows Scripting With Wmi(2007)》是关于Windows Management Instrumentation(WMI)技术的一本PDF教程,旨在帮助IT专业人士深入理解和掌握利用WMI进行Windows脚本编程的技术。WMI是微软提供的一种...

    Programming Pig Dataflow Scripting with Hadoop(2nd) 无水印转化版pdf

    Programming Pig Dataflow Scripting with Hadoop(2nd) 英文无水印转化版pdf 第2版 pdf所有页面使用FoxitReader、PDF-XChangeViewer、SumatraPDF和Firefox测试都可以打开 本资源转载自网络,如有侵权,请联系...

Global site tag (gtag.js) - Google Analytics