操 作 | 例 子 | 注 释 |
在屏幕上输出 | puts "Hello" print "Hello" x = "Hello" puts x x = "Hello" print x x = "Hello" p x | 如果字符串不是以换行结束,puts给它输出的字符串加一个换行 print精确地输出被要求输出的东西,光标会停在被输出内容的行尾(请注意:在某些平台上,程序末尾会自动添加一个附加的换行) p输出一个inspect字符串, 它可能包含关于它正在输出的是什么的附加信息 |
获取一行键盘输入 | gets string = gets | 可以将输入行直接赋值给一个变量(如第二个例子中的变量string) |
将字符串转换为整数 | x = "100".to_i s = "100" x = s.to_i | 为了执行算术运算,要确保使用的是数值而不是字符串。to_i执行从字符串到整数的转换 |
比较两个值 | x == y | 请注意使用的是双等号(不像在赋值语句中,用的是一个等号) |
条件执行 | if x == y # 执行此处的代码 else # 执行此处的代码 end | 条件语句永远用单词end结束 |
在代码文件中放置注释 | #This is a comment line. X = 1 # Comment to end of line | 注释被解释器忽略 |
1.1.3 方法调用和Ruby对象的简单介绍
你在Ruby程序中看到的和编写的多是方法调用(method call)。方法调用有时仅仅由以裸词形式出现的方法名构成,其后可能带一个或多个参数。举例来说,下面的代码用一个参数调用puts方法。
另外一种方法调用使用一个特殊的语法——点操作符,它在其左侧的值或表达式和其右侧的方法名之间建立一个关系。如表1-1中的
其中的点意味着给字符串“100”发送消息“to_i”,或者说在字符串“100”上调用to_i方法。字符串“100”称为消息的接收者。
下面是一个使用完整的点记法的方法调用,它也带一个参数。它从九进制数100产生一个十进制整数。
x现在等于十进制的81。
从这个例子也可看到,方法参数由圆括号括起来。这些圆括号通常是可选的,但在较复杂的情况下,为消除可能的语法歧义性,它们可能是必需的。很多程序员在大多数或全部的方法调用中使用圆括号,就是为了安全(以及视觉上的清晰性)。
在这些例子中,字符串“100”是消息“to_i”的接收者。本质上,你在要求该字符串将自己转换成整数。字符串自身是一个对象。Ruby程序完全由发送到对象的消息组成。对象可以是一个字符串(如刚才的例子),也可以是一个整数——可能是一个想要转换成字符串的整数。
在编写Ruby程序时,大多数的时间要么花在告诉Ruby你希望对象能够做什么,即你希望它们能理解什么消息上,要么花在给对象发送消息上。你的对象世界并不局限于Ruby已有的那些对象,如字符串和整数。如果你正在编写Rails应用,其中的一个实体模型是Customer,那么当你编写代码来触发一些操作,如客户登录一个站点,更新客户的电话号码,在客户的购物车中加入商品,所有这些可能的操作,实际上都是在给Customer对象发送消息。
在本书后面我们将更深入地探讨这些问题。再重复一下,这个简单的描述只是为了达到Ruby起步的目的。当你看到圆点位于一个不这样就无法解释的位置时,你应该把它理解为:正在给(左边的)对象发送(右边的)消息。
1.1.4 编写和保存示例程序
在具备了某些Ruby的知识(以及一张可以在遇到问题时查阅的总结表)之后,让我们遍历运行一个程序的各步骤。强烈建议读者把本书的例子单独做成一个目录。类似于下面这样的就可以了:
从现在起,本书将假设所有的示例程序都保存在这个目录中。某些情况下,这无关紧要,但在很多情况下这么做很重要,特别是当你开始编写使用多个文件的程序时,这些文件必须能够容易地找到彼此。
现在,你将生成一个程序文件。该程序是一个摄氏—华氏温度转换程序。我们将分阶段地完成这个例子,每个阶段为它增加功能或修改它。第一版非常简单,因为重点是生成文件和运行程序的过程。
生成第一个程序文件
为生成下面这个Ruby程序文件以及以后的Ruby程序文件,你可以使用任意的文本编辑器(vi、Emacs、记事本等);本书所有说明和解释都与特定编辑器无关。请记住,如果你使用了字处理程序,你必须将文件保存为纯文本文件。
请在文本文件中键入代码清单1-1中的代码,并在ruby4rails目录下用文件名c2f.rb将其保存。
代码清单1-1 简单、功能有限的摄氏—华氏温度转换程序(c2f.rb)
现在,在你的硬盘上就有了一个完整的小Ruby程序,你可以运行它了。
注释 运行独立的Ruby程序 也许你的操作系统允许运行独立的Ruby程序——即仅仅使用文件名或一个不带扩展名的短文件名(如c2f)。但是请记住,就文件命名来说,.rb扩展名在某些情况下是必需的,主要是在涉及多文件程序时(你将在后面详述地学习),这些文件需要一个机制找到彼此。在本书中,所有的Ruby程序都使用.rb后缀,以确保这些例程可以工作在尽可能多的平台上。
1.1.5 提交Ruby程序
编写和运行Ruby程序这一过程的中心工作是向Ruby解释器(ruby)提交程序的源文件。你现在就要这样做。你将向ruby提交程序,但不是让它运行该程序,而是让它检查程序代码(文件中的Ruby代码行)的语法错误。
1.语法错误检查
如果你不小心在c2f.rb中的方法调用print的中间键入了一个空格(pr int),这就构成了一个语法错误。如果你忘记在注释行前面键入#字符,肯定就引入了一个语法错误。(除非凑巧这个注释正好是正确的Ruby代码!)
Ruby解释器可以很方便地在不运行程序的情况下检查程序的语法错误。它遍历整个文件并且告诉你语法是否正确。请使用下面的命令文件进行语法检查:
-c标志的意思是检查,即检查语法错误。-w标志激活更高级别的警告。如果你所编写的Ruby代码,虽然合法但有疑问,Ruby会提示你。
假设编写的文件是正确的,屏幕上会出现这条消息
2.运行程序
再次向解释器提交文件运行程序,但是这次没有–c和–w标志:
如果顺利,计算结果如下:
3.一点小问题
计算结果是正确的,但是输出分散在三行,看起来不是很好。你希望它们都出现在一行里。
4.修正第一个Ruby错误
问题可以追溯到puts命令和print命令的差别上。如果被输出字符串不是以换行符结尾的,puts会在输出的字符串后面加一个换行。print正好相反,输出你让它输出的字符串就停止,不会自动跳到下一行。
为修正这个问题,可以将头两个puts命令改为print。
(注意is后的空格,它保证is和数字之间留有间距。)现在输出是这样的:
puts是put(即Print)string的缩写。尽管put这个记法可能不能直观地表达跳到下一行的意思,但那就是puts的功能。和print一样,它输出你要求的东西,但是它还自动跳到下一行。如果你让puts输出以换行符结尾的行,它不会再加一个换行。
如果你习惯了其他语言中的不自动加换行的输出设施(如Perl的print函数),那么当你想输出后面带换行的值时,你可能会在Ruby中这样写代码:
puts就是为你做这个的。往后你会慢慢习惯puts,以及其他的Ruby惯用法和约定。
警告 你可能不想要的额外的换行 在一些平台(特别是Windows)上,当运行完程序时,会输出一个额外的换行符。这意味着一个本来应该是puts的print很难被发现,因为它表现得就像一个puts。意识到它们的差别,按惯例进行选择,应该足以保证得到想要的结果。
与输出相对应的就是数据的输入。不是每个程序都会像之前的程序,带着所有它需要编入自身的数据出现。数据有很多来源。在一般的Rails应用中,它来自数据库。在普通的Ruby用法中,程序数据常常来自键盘和文件。下面我们将介绍Ruby如何处理这些形式的输入。
1.1.6 键盘和文件输入
Ruby为在程序执行过程中的数据读写提供了很多技术。你可能会发现,作为一个Rails开发者,相对来说很少使用这些设施,因为Rails为你做了数据获取工作。而你的用户,当他们用键盘输入时,通常都是在Web表单中输入。
尽管如此,还是需要学习基本的Ruby键盘输入和文件I/O操作。如果虽然你不是在编写每一个Rails应用时都用到,但是在编写Ruby代码来维护、转换、日常管理或操纵你所工作的环境的时候,你肯定会用到它们。
1.键盘输入
一个只能一遍一遍告诉你100°C相当于212°F的程序没有什么实用价值。更有价值的程序可以让你任意指定一个摄氏温度,然后告诉你相应的华氏温度。
要改变程序以实现此功能,涉及增加几个步骤以及使用两个方法(其中一个你已经熟悉):
gets暂停程序并等待来自键盘的一行输入。(敲击回车键产生的换行符作为最后一个字符包含在输入行中。)
to_i将字符串转换为整数。为了使输入的字符串可以与计算华氏结果时用到的其他数值协调工作,你需要这个方法。
因为这是一个新程序,而不仅仅是一个修正,所以请将代码清单1-2中的程序版本放入一个新文件(c2fi.rb;i表示交互的,即interactive):
代码清单1-2 交互式温度转换程序(c2fi.rb)
注意这里使用了print而不是puts以控制输出的换行。
以下几个运行结果说明了新程序的行为:
注释 缩减代码 通过合并输入、计算和输出操作,可以大幅度地缩减代码。一个重写的压缩过的代码是这样的:
这个版本节省了变量——未用任何变量,但是要求读它的人理解一个更密集也更短的表达式。任何程序中通常有些地方需要你在长而清晰和短而隐晦之间进行选择。也有些时候,短的可能更清晰。这都是形成Ruby编码风格所需要考虑的。
2.文件输入的例子
从Ruby程序读入文件并不比从键盘读入一行困难多少。你将在这里尝试:从文件中读入一个数,并将其从摄氏转换到华氏。(有时从文件中读数据确实比这要麻烦一些,但该例子展现了基本的操作。)
首先,生成一个叫temp.dat的新文件(温度数据文件),该文件仅包含一行,该行只有一个数:
现在,生成如代码清单1-3所示的名为c2fin.rb(in表示[文件]输入)的第三个程序文件。
代码清单1-3 使用文件输入的温度转换程序(c2fin.rb)
这一次,例子的运行和它的输出是这样的:
很自然地,如果你改变文件中的数,结果就会不同。
因为对称的原因——也考虑到实用性,因为你可能在某些时候想这么做——让我们看看,编写一个将结果保存到文件的程序,需要做些什么。
3.文件输出的例子
最简单的写文件操作比最简单的读文件操作要复杂一点(但不是复杂很多)。如果细查代码,你可以看到,在打开文件准备写的时候,需要额外指定的主要就是文件打开模式——在这个例子里是w(表示写)。
将代码清单1-4中的程序版本保存到c2fout.rb,然后运行它。
代码清单1-4 使用文件输出的温度转换程序(c2fout.rb)
(变量fh表示文件句柄。请注意你使用puts——实际上是fh.puts,指向文件句柄fh的引用将输出引导到文件流中而不是屏幕上——向文件句柄所代表的文件中输出一行。)
如果检查文件temp.out,应该看到它包含了输入的数的华氏温度对应数。
4.读者练习
根据前面的例子,你可以编写一个从文件中读出一个数,并将华氏转换结果保存到另一个文件中的Ruby程序吗?
1.1.7 一个程序,多个文件
到此为止,我们已经动手编写和执行了一个Ruby程序,这涉及两个实体:程序文件和Ruby解释器。当你开始编写更长的程序时,或者当你读更长、更复杂的应用程序包括Rails应用程序和Rails本身时,你会很快发现,很少有程序只有一个文件。除非你在编写某些确实很小巧的东西,如摄氏—华氏转换程序,否则你的程序很可能超过两三个文件,在某些情况下会多达几十个文件。
信不信由你,这是一个好消息。
确实,将程序放在一个文件中,可以让你一次看到全部东西。但当你有成百上千或几十万行代码时,这就变成负担而不是好处了。将程序拆成多个单独的文件是很有意义的。
1.请求加载文件
当你的程序分散在多个文件中时,作为一个程序来运行最常用的技术是require命令(更准确地说是require方法),它在一个文件运行过程中读入另一个文件。
为了说明require的使用方法,你需要一个编写在两个文件上的程序(这不奇怪)。第一个文件reqdemo.rb应该包含以下Ruby代码:
当碰到require方法调用时,Ruby读入第二个文件,即requiree.rb,它应该是这样的:
现在,用Ruby运行reqdemo.rb,可以看到如下结果:
这个程序没有太多功能,它只是对于使用多文件程序过程的一个概念验证式的说明,但是你可以从输出的信息看到,第二个文件requiree.rb是在第一个文件中require语句所在的位置开始执行的。
实质上,require查找另一个文件并执行它(假设找到的话)。如果没有找到,程序将以一个致命错误终止。
2.加载文件
load是require的近亲。它们的主要区别在于,如果执行下面的代码:
第二次执行require什么都不会发生,而如果执行下面的代码:
Ruby会两次读入该文件。
在同一个文件中的一行中两次加载同一个文件几乎是毫无意义的,但在某些时候,这种多次加载是有用的。举例来说,在开发模式下,相对于require,Rails更倾向于使用load——这意味着,在浏览器中试运行应用程序的同时修改代码,这些修改会被重新加载,覆盖Web服务器部分的缓存行为。如果应用程序已经加载了一次文件,在同样的地方多次调用require不会有这样的效果。
在通常的Ruby编程和Rails框架中,多个文件可以一起工作的设施非常重要。你将在本书的第四部分特别是第17章看到多文件交互的例子,在那里,我们将深入学习Rails的源代码。不管是合在一起还是分开来看,文件到文件的连接使得Ruby和Rails是内聚的。
现在,让我们回到基本的Ruby过程场景。
===========================================
1.2 激活解释器的方法
你大概已经经历了一次Ruby程序的整个过程。现在可以回去看看更多的内容。
正如已经提到过的,当你运行Ruby程序时,实际上是在运行一个叫ruby的程序,并将你的程序作为输入提交给它。在这里,我们将看一下在此过程中你可以得到的更多的选择。这些选择包括命令行开关(如你已经看到过的–cw语法检查标志的例子),不用在命令行激活ruby也可以将你的程序定向到Ruby解释器的技术,以及如何运行irb解释器的详细信息。
1.2.1 命令行开关
从命令行启动Ruby解释器时,你不仅可以提供程序文件的名字,而且可以提供一个或多个命令行开关。你选择的开关指示解释器以一种特定的方式运转,并且/或者执行特定的操作。
Ruby命令行开关有20多个,其中有些很少使用,有些则每天被很多Ruby程序员使用。在这里我们将再看几个最常用的。(你已经看到过其中的两个,-c和–w,它们结合在一起使用。)这些常用的开关总结在表1-2中,我们将分别给予解释。
表1-2 常用的Ruby命令行开关总结
命令行开关 | 描 述 | 例 子 |
-c | 不执行程序,只检查(check)程序文件的语法 | ruby –c c2f.rb |
-w | 在程序执行过程中给出警告(warnig)信息 | ruby –w c2f.rb |
-e | 执行(execute)在命令行中引号内的代码 | ruby –e 'puts"code demo! "' |
-v | 显示Ruby版本(version)信息,在详信(verbose)模式下执行程序 | ruby –v |
-l | 行(line)模式:如果没有换行则在每一行输出后输出一个换行 | ruby –l –e 'print "Will jump down! "' |
-rname | 加载指定的扩展(require) | ruby –rprofile |
--version | 显示Ruby版本(version)信息 | ruby --version |
1. 语法检查(-c)
-c开关告诉Ruby检查一个或多个文件中代码语法的正确性而不用执行代码。它常常与–w标志一起使用。
2.打开警告(-w)
用-w运行程序使得解释器在警告模式中运行。这意味着你将看到比不用该开关时更多的警告输出到屏幕上,这会将你的注意力吸引到程序中虽然语法正确、但风格和逻辑让人怀疑的地方。这相当于Ruby在说:“你已经完成的没有语法错误,但是很怪异。你确信要这么做吗?”(即使没有设置这个开关,Ruby也会发出某些警告,但是比在完全的警告模式中要少。)
3.执行字面脚本(-e)
-e开关告诉解释器:命令行包含了Ruby代码,它们在引号中,解释器应该执行这些代码而不是文件中的代码。这便于执行快速的脚本任务,在这种情况下,如果把代码输入到一个文件中,并使用ruby来执行该文件,很是麻烦。
举例来说,你想要倒过来看你的名字。以下是使用执行开关,以一个命令行的命令来快速实现此功能的代码。
单引号中的内容是一个完整的Ruby程序(虽然很短)。如果你想提交超过一行的程序给-e开关,你可以在这个小程序中使用字面分行。
或者,你可以使用分号来分隔行。
注释 在反转的字符串中的换行符 为什么在这个两行代码的反转程序示例中,在程序代码和输出之间有一个空行?这是因为你通过键盘输入的行以一个换行符结尾——那么当反转输入时,新的字符串是以一个换行符开始的。当你让Ruby处理和输出数据时,它总是字面地理解你的意思。
4.在行模式下运行(-l)
回顾第一版摄氏温度转换程序的执行结果,可以看到Ruby的输出——数值212——与shell的命令提示符($字符)连在一起出现在屏幕上。原因正如你前面所看到过的,是因为你使用的是print而不是puts,所以在该数值后面没有换行符。
-l开关确保各输出行放到单独的行里。当你不确定要输出的行是否以换行符结尾时,这是很方便的。在大多数情况下,你可以使用puts,但是在对代码没有控制权的情况下–l开关可以帮助你。
比如说某人编写了一个程序,该程序遍历文件中的所有姓名并输出名。不知为何,他使用了print而不是puts,于是,用一般的姓名文件来运行此程序,其输出是这样的:
现在,你想要使用该程序,但你想让每一个名出现在不同的行中。你可以告诉Ruby以行模式运行,这样你将得到你想要的:
你不会像使用puts那样经常地使用–l标志来达到类似的效果。但是它是有用的,而且你也需要了解它。
5.请求加载指定的文件或扩展名
-r开关在命令行指定请求加载(require)的文件。正如你将看到的,require更大的用途是激活扩展(外加的程序功能)。你也可以用–r标志来实现require的这种特点。
6.在verbose模式下运行(-v)
运行-v做两件事:输出当前使用的Ruby的版本信息,然后打开与–w一样的警告机制。-v最常用于给出Ruby的版本号:
(在这个例子中,我们使用的是Ruby 1.8.2,它是2004年圣诞节发布的,是针对运行Linux的基于i686的机器编译的。)因为没有程序或代码需要运行,Ruby在输出完版本号后立即退出。
7.输出Ruby版本
很明显,--version这个标志与–v很像,但是它只输出Ruby版本信息。它不继续执行任何代码,即使你提供了代码或文件名。它只输出版本信息然后就退出。相对于ruby--version,ruby–v更常用。
8. 组合开关
常常需要在一次Ruby运行中组合使用多个命令行开关。
你已经见过cw组合,它检查程序文件的语法但不执行,同时还给出警告。
另一个常见的开关组合是–v和–e,它给出当前Ruby的版本信息并运行引号中给出的代码。你经常会在邮件列表或别的地方的Ruby讨论中看到这个组合人们用它来说明同样的代码在不同版本的Ruby中的不同的行为。举例来说,如果你想说明Ruby 1.6.8没有而Ruby 1.8.2有lstrip操作(剥去一个字符串左侧的所有空白字符),你可以先用第一个版本的Ruby来运行一个例子程序,然后换另一个版本的Ruby:
第一遍运行时(使用版本1.6.8)给出消息“undefined method 'lstrip'”,意味着我们试图执行一个不存在的指定操作。但当使用Ruby 1.8.2来运行同样的代码片段时,它可运行,Ruby输出abc(不带开头的空白)。这个办法可以用来解释和展示Ruby从一个版本到另一个版本所做的改变方面的信息和问题。
至此,我们将回过头去更详细地介绍交互式Ruby解释器:irb。你可能已经看过这一节,在本章的开始我们提到过它。如果还没有,现在你可以借此机会学习一下这个非常有用的Ruby工具。
1.2.2 进一步了解交互式Ruby解释器irb
使用Ruby最开心的事之一就是使用irb了。irb是一个交互式的解释器,即它不是处理文件,而是在会话中处理你键入的内容。irb是测试Ruby代码的一个很好的工具,也是学习Ruby的一个很好的工具。
为启动一个irb会话,可以使用命令irb。irb会输出提示符:
现在,就可以键入Ruby命令了。甚至可以运行摄氏—华氏转换程序的只执行一次的版本。正如你将看到的,irb的行为像一台袖珍计算器:它可求出所键入的任意的数的值,然后输出结果。不需要使用print或者puts命令:
为计算一年中有多少分钟,请键入相应的乘法表达式:
irb当然也处理你键入的任意的Ruby指令。举例来说,如果想将天数、小时数或分钟数赋值给变量,然后相乘这些变量,则可以在irb中这样做:
最后的计算结果是你所的期望的。但是看一下输入的前三行。当键入days = 365时,irb输出365作为应答。这是为什么?
表达式days = 365是一个赋值表达式:你将值365赋给days变量。赋值表达式主要任务是赋值,以后你就可以使用被赋值的变量。但是赋值表达式自身days = 365作为一个整体也有一个值。赋值表达式的值就是等号右侧的值。当irb碰到任意的表达式时,它输出该表达式的值。所以,当irb碰到days = 365时,它输出365。这个输出看起来是过于热心了,但它有它的原因;这与你在irb中键入2+2然后不必显式地使用print语句就能看到结果的做法是一样的。
一旦你掌握了irb输出每一个东西的值的方式,你会发现它是一个非常有用的工具(也是玩具)。
提示 退出irb(有意的或无意的) 如果irb在一个循环或僵局中卡住了,敲Ctrl-c强制退出。要正常退出,敲Ctrl-d或键入exit。偶尔,irb可能会“发脾气”(碰到一个致命错误而终止)。但大多数时候,它会捕获自己的错误,让你继续工作。
我们关于Ruby全景的下一个旅程是Ruby扩展和库。看一下这些设施将使你了解核心语言怎么与外部扩展交互——这些外部扩展要么与Ruby绑定在一起发行,要么由有志于丰富Ruby开发环境的第三方程序员独立发行。