Repository: BadTudou/RubyUsersGuide-zh
Branch: master
Commit: 9010c8c1f59b
Files: 33
Total size: 134.9 KB
Directory structure:
gitextract_mh9e3o7z/
├── License.txt
├── README.md
└── markdown/
├── about.md
├── accesscontrol.md
├── accessors.md
├── arrays.md
├── backtoexamples.md
├── classes.md
├── constants.md
├── contributor.md
├── control.md
├── copyright.md
├── ensure.md
├── examples.md
├── getstarted.md
├── globalvars.md
├── index.md
├── inheritance.md
├── instancevars.md
├── iterators.md
├── localvars.md
├── methods.md
├── misc.md
├── modules.md
├── objinitialization.md
├── oothinking.md
├── procobjects.md
├── redefinemethods.md
├── regexp.md
├── rescue.md
├── singletonmethods.md
├── strings.md
└── variables.md
================================================
FILE CONTENTS
================================================
================================================
FILE: License.txt
================================================
GNU Free Documentation License
Version 1.3, 3 November 2008
Copyright (C) 2000, 2001, 2002, 2007, 2008 Free Software Foundation, Inc.
<http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
0. PREAMBLE
The purpose of this License is to make a manual, textbook, or other
functional and useful document "free" in the sense of freedom: to
assure everyone the effective freedom to copy and redistribute it,
with or without modifying it, either commercially or noncommercially.
Secondarily, this License preserves for the author and publisher a way
to get credit for their work, while not being considered responsible
for modifications made by others.
This License is a kind of "copyleft", which means that derivative
works of the document must themselves be free in the same sense. It
complements the GNU General Public License, which is a copyleft
license designed for free software.
We have designed this License in order to use it for manuals for free
software, because free software needs free documentation: a free
program should come with manuals providing the same freedoms that the
software does. But this License is not limited to software manuals;
it can be used for any textual work, regardless of subject matter or
whether it is published as a printed book. We recommend this License
principally for works whose purpose is instruction or reference.
1. APPLICABILITY AND DEFINITIONS
This License applies to any manual or other work, in any medium, that
contains a notice placed by the copyright holder saying it can be
distributed under the terms of this License. Such a notice grants a
world-wide, royalty-free license, unlimited in duration, to use that
work under the conditions stated herein. The "Document", below,
refers to any such manual or work. Any member of the public is a
licensee, and is addressed as "you". You accept the license if you
copy, modify or distribute the work in a way requiring permission
under copyright law.
A "Modified Version" of the Document means any work containing the
Document or a portion of it, either copied verbatim, or with
modifications and/or translated into another language.
A "Secondary Section" is a named appendix or a front-matter section of
the Document that deals exclusively with the relationship of the
publishers or authors of the Document to the Document's overall
subject (or to related matters) and contains nothing that could fall
directly within that overall subject. (Thus, if the Document is in
part a textbook of mathematics, a Secondary Section may not explain
any mathematics.) The relationship could be a matter of historical
connection with the subject or with related matters, or of legal,
commercial, philosophical, ethical or political position regarding
them.
The "Invariant Sections" are certain Secondary Sections whose titles
are designated, as being those of Invariant Sections, in the notice
that says that the Document is released under this License. If a
section does not fit the above definition of Secondary then it is not
allowed to be designated as Invariant. The Document may contain zero
Invariant Sections. If the Document does not identify any Invariant
Sections then there are none.
The "Cover Texts" are certain short passages of text that are listed,
as Front-Cover Texts or Back-Cover Texts, in the notice that says that
the Document is released under this License. A Front-Cover Text may
be at most 5 words, and a Back-Cover Text may be at most 25 words.
A "Transparent" copy of the Document means a machine-readable copy,
represented in a format whose specification is available to the
general public, that is suitable for revising the document
straightforwardly with generic text editors or (for images composed of
pixels) generic paint programs or (for drawings) some widely available
drawing editor, and that is suitable for input to text formatters or
for automatic translation to a variety of formats suitable for input
to text formatters. A copy made in an otherwise Transparent file
format whose markup, or absence of markup, has been arranged to thwart
or discourage subsequent modification by readers is not Transparent.
An image format is not Transparent if used for any substantial amount
of text. A copy that is not "Transparent" is called "Opaque".
Examples of suitable formats for Transparent copies include plain
ASCII without markup, Texinfo input format, LaTeX input format, SGML
or XML using a publicly available DTD, and standard-conforming simple
HTML, PostScript or PDF designed for human modification. Examples of
transparent image formats include PNG, XCF and JPG. Opaque formats
include proprietary formats that can be read and edited only by
proprietary word processors, SGML or XML for which the DTD and/or
processing tools are not generally available, and the
machine-generated HTML, PostScript or PDF produced by some word
processors for output purposes only.
The "Title Page" means, for a printed book, the title page itself,
plus such following pages as are needed to hold, legibly, the material
this License requires to appear in the title page. For works in
formats which do not have any title page as such, "Title Page" means
the text near the most prominent appearance of the work's title,
preceding the beginning of the body of the text.
The "publisher" means any person or entity that distributes copies of
the Document to the public.
A section "Entitled XYZ" means a named subunit of the Document whose
title either is precisely XYZ or contains XYZ in parentheses following
text that translates XYZ in another language. (Here XYZ stands for a
specific section name mentioned below, such as "Acknowledgements",
"Dedications", "Endorsements", or "History".) To "Preserve the Title"
of such a section when you modify the Document means that it remains a
section "Entitled XYZ" according to this definition.
The Document may include Warranty Disclaimers next to the notice which
states that this License applies to the Document. These Warranty
Disclaimers are considered to be included by reference in this
License, but only as regards disclaiming warranties: any other
implication that these Warranty Disclaimers may have is void and has
no effect on the meaning of this License.
2. VERBATIM COPYING
You may copy and distribute the Document in any medium, either
commercially or noncommercially, provided that this License, the
copyright notices, and the license notice saying this License applies
to the Document are reproduced in all copies, and that you add no
other conditions whatsoever to those of this License. You may not use
technical measures to obstruct or control the reading or further
copying of the copies you make or distribute. However, you may accept
compensation in exchange for copies. If you distribute a large enough
number of copies you must also follow the conditions in section 3.
You may also lend copies, under the same conditions stated above, and
you may publicly display copies.
3. COPYING IN QUANTITY
If you publish printed copies (or copies in media that commonly have
printed covers) of the Document, numbering more than 100, and the
Document's license notice requires Cover Texts, you must enclose the
copies in covers that carry, clearly and legibly, all these Cover
Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on
the back cover. Both covers must also clearly and legibly identify
you as the publisher of these copies. The front cover must present
the full title with all words of the title equally prominent and
visible. You may add other material on the covers in addition.
Copying with changes limited to the covers, as long as they preserve
the title of the Document and satisfy these conditions, can be treated
as verbatim copying in other respects.
If the required texts for either cover are too voluminous to fit
legibly, you should put the first ones listed (as many as fit
reasonably) on the actual cover, and continue the rest onto adjacent
pages.
If you publish or distribute Opaque copies of the Document numbering
more than 100, you must either include a machine-readable Transparent
copy along with each Opaque copy, or state in or with each Opaque copy
a computer-network location from which the general network-using
public has access to download using public-standard network protocols
a complete Transparent copy of the Document, free of added material.
If you use the latter option, you must take reasonably prudent steps,
when you begin distribution of Opaque copies in quantity, to ensure
that this Transparent copy will remain thus accessible at the stated
location until at least one year after the last time you distribute an
Opaque copy (directly or through your agents or retailers) of that
edition to the public.
It is requested, but not required, that you contact the authors of the
Document well before redistributing any large number of copies, to
give them a chance to provide you with an updated version of the
Document.
4. MODIFICATIONS
You may copy and distribute a Modified Version of the Document under
the conditions of sections 2 and 3 above, provided that you release
the Modified Version under precisely this License, with the Modified
Version filling the role of the Document, thus licensing distribution
and modification of the Modified Version to whoever possesses a copy
of it. In addition, you must do these things in the Modified Version:
A. Use in the Title Page (and on the covers, if any) a title distinct
from that of the Document, and from those of previous versions
(which should, if there were any, be listed in the History section
of the Document). You may use the same title as a previous version
if the original publisher of that version gives permission.
B. List on the Title Page, as authors, one or more persons or entities
responsible for authorship of the modifications in the Modified
Version, together with at least five of the principal authors of the
Document (all of its principal authors, if it has fewer than five),
unless they release you from this requirement.
C. State on the Title page the name of the publisher of the
Modified Version, as the publisher.
D. Preserve all the copyright notices of the Document.
E. Add an appropriate copyright notice for your modifications
adjacent to the other copyright notices.
F. Include, immediately after the copyright notices, a license notice
giving the public permission to use the Modified Version under the
terms of this License, in the form shown in the Addendum below.
G. Preserve in that license notice the full lists of Invariant Sections
and required Cover Texts given in the Document's license notice.
H. Include an unaltered copy of this License.
I. Preserve the section Entitled "History", Preserve its Title, and add
to it an item stating at least the title, year, new authors, and
publisher of the Modified Version as given on the Title Page. If
there is no section Entitled "History" in the Document, create one
stating the title, year, authors, and publisher of the Document as
given on its Title Page, then add an item describing the Modified
Version as stated in the previous sentence.
J. Preserve the network location, if any, given in the Document for
public access to a Transparent copy of the Document, and likewise
the network locations given in the Document for previous versions
it was based on. These may be placed in the "History" section.
You may omit a network location for a work that was published at
least four years before the Document itself, or if the original
publisher of the version it refers to gives permission.
K. For any section Entitled "Acknowledgements" or "Dedications",
Preserve the Title of the section, and preserve in the section all
the substance and tone of each of the contributor acknowledgements
and/or dedications given therein.
L. Preserve all the Invariant Sections of the Document,
unaltered in their text and in their titles. Section numbers
or the equivalent are not considered part of the section titles.
M. Delete any section Entitled "Endorsements". Such a section
may not be included in the Modified Version.
N. Do not retitle any existing section to be Entitled "Endorsements"
or to conflict in title with any Invariant Section.
O. Preserve any Warranty Disclaimers.
If the Modified Version includes new front-matter sections or
appendices that qualify as Secondary Sections and contain no material
copied from the Document, you may at your option designate some or all
of these sections as invariant. To do this, add their titles to the
list of Invariant Sections in the Modified Version's license notice.
These titles must be distinct from any other section titles.
You may add a section Entitled "Endorsements", provided it contains
nothing but endorsements of your Modified Version by various
parties--for example, statements of peer review or that the text has
been approved by an organization as the authoritative definition of a
standard.
You may add a passage of up to five words as a Front-Cover Text, and a
passage of up to 25 words as a Back-Cover Text, to the end of the list
of Cover Texts in the Modified Version. Only one passage of
Front-Cover Text and one of Back-Cover Text may be added by (or
through arrangements made by) any one entity. If the Document already
includes a cover text for the same cover, previously added by you or
by arrangement made by the same entity you are acting on behalf of,
you may not add another; but you may replace the old one, on explicit
permission from the previous publisher that added the old one.
The author(s) and publisher(s) of the Document do not by this License
give permission to use their names for publicity for or to assert or
imply endorsement of any Modified Version.
5. COMBINING DOCUMENTS
You may combine the Document with other documents released under this
License, under the terms defined in section 4 above for modified
versions, provided that you include in the combination all of the
Invariant Sections of all of the original documents, unmodified, and
list them all as Invariant Sections of your combined work in its
license notice, and that you preserve all their Warranty Disclaimers.
The combined work need only contain one copy of this License, and
multiple identical Invariant Sections may be replaced with a single
copy. If there are multiple Invariant Sections with the same name but
different contents, make the title of each such section unique by
adding at the end of it, in parentheses, the name of the original
author or publisher of that section if known, or else a unique number.
Make the same adjustment to the section titles in the list of
Invariant Sections in the license notice of the combined work.
In the combination, you must combine any sections Entitled "History"
in the various original documents, forming one section Entitled
"History"; likewise combine any sections Entitled "Acknowledgements",
and any sections Entitled "Dedications". You must delete all sections
Entitled "Endorsements".
6. COLLECTIONS OF DOCUMENTS
You may make a collection consisting of the Document and other
documents released under this License, and replace the individual
copies of this License in the various documents with a single copy
that is included in the collection, provided that you follow the rules
of this License for verbatim copying of each of the documents in all
other respects.
You may extract a single document from such a collection, and
distribute it individually under this License, provided you insert a
copy of this License into the extracted document, and follow this
License in all other respects regarding verbatim copying of that
document.
7. AGGREGATION WITH INDEPENDENT WORKS
A compilation of the Document or its derivatives with other separate
and independent documents or works, in or on a volume of a storage or
distribution medium, is called an "aggregate" if the copyright
resulting from the compilation is not used to limit the legal rights
of the compilation's users beyond what the individual works permit.
When the Document is included in an aggregate, this License does not
apply to the other works in the aggregate which are not themselves
derivative works of the Document.
If the Cover Text requirement of section 3 is applicable to these
copies of the Document, then if the Document is less than one half of
the entire aggregate, the Document's Cover Texts may be placed on
covers that bracket the Document within the aggregate, or the
electronic equivalent of covers if the Document is in electronic form.
Otherwise they must appear on printed covers that bracket the whole
aggregate.
8. TRANSLATION
Translation is considered a kind of modification, so you may
distribute translations of the Document under the terms of section 4.
Replacing Invariant Sections with translations requires special
permission from their copyright holders, but you may include
translations of some or all Invariant Sections in addition to the
original versions of these Invariant Sections. You may include a
translation of this License, and all the license notices in the
Document, and any Warranty Disclaimers, provided that you also include
the original English version of this License and the original versions
of those notices and disclaimers. In case of a disagreement between
the translation and the original version of this License or a notice
or disclaimer, the original version will prevail.
If a section in the Document is Entitled "Acknowledgements",
"Dedications", or "History", the requirement (section 4) to Preserve
its Title (section 1) will typically require changing the actual
title.
9. TERMINATION
You may not copy, modify, sublicense, or distribute the Document
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense, or distribute it is void, and
will automatically terminate your rights under this License.
However, if you cease all violation of this License, then your license
from a particular copyright holder is reinstated (a) provisionally,
unless and until the copyright holder explicitly and finally
terminates your license, and (b) permanently, if the copyright holder
fails to notify you of the violation by some reasonable means prior to
60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, receipt of a copy of some or all of the same material does
not give you any rights to use it.
10. FUTURE REVISIONS OF THIS LICENSE
The Free Software Foundation may publish new, revised versions of the
GNU Free Documentation License from time to time. Such new versions
will be similar in spirit to the present version, but may differ in
detail to address new problems or concerns. See
http://www.gnu.org/copyleft/.
Each version of the License is given a distinguishing version number.
If the Document specifies that a particular numbered version of this
License "or any later version" applies to it, you have the option of
following the terms and conditions either of that specified version or
of any later version that has been published (not as a draft) by the
Free Software Foundation. If the Document does not specify a version
number of this License, you may choose any version ever published (not
as a draft) by the Free Software Foundation. If the Document
specifies that a proxy can decide which future versions of this
License can be used, that proxy's public statement of acceptance of a
version permanently authorizes you to choose that version for the
Document.
11. RELICENSING
"Massive Multiauthor Collaboration Site" (or "MMC Site") means any
World Wide Web server that publishes copyrightable works and also
provides prominent facilities for anybody to edit those works. A
public wiki that anybody can edit is an example of such a server. A
"Massive Multiauthor Collaboration" (or "MMC") contained in the site
means any set of copyrightable works thus published on the MMC site.
"CC-BY-SA" means the Creative Commons Attribution-Share Alike 3.0
license published by Creative Commons Corporation, a not-for-profit
corporation with a principal place of business in San Francisco,
California, as well as future copyleft versions of that license
published by that same organization.
"Incorporate" means to publish or republish a Document, in whole or in
part, as part of another Document.
An MMC is "eligible for relicensing" if it is licensed under this
License, and if all works that were first published under this License
somewhere other than this MMC, and subsequently incorporated in whole or
in part into the MMC, (1) had no cover texts or invariant sections, and
(2) were thus incorporated prior to November 1, 2008.
The operator of an MMC Site may republish an MMC contained in the site
under CC-BY-SA on the same site at any time before August 1, 2009,
provided the MMC is eligible for relicensing.
ADDENDUM: How to use this License for your documents
To use this License in a document you have written, include a copy of
the License in the document and put the following copyright and
license notices just after the title page:
Copyright (c) YEAR YOUR NAME.
Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.3
or any later version published by the Free Software Foundation;
with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
A copy of the license is included in the section entitled "GNU
Free Documentation License".
If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts,
replace the "with...Texts." line with this:
with the Invariant Sections being LIST THEIR TITLES, with the
Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST.
If you have Invariant Sections without Cover Texts, or some other
combination of the three, merge those two alternatives to suit the
situation.
If your document contains nontrivial examples of program code, we
recommend releasing these examples in parallel under your choice of
free software license, such as the GNU General Public License,
to permit their use in free software.
================================================
FILE: README.md
================================================
# 简介

**Ruby** : *A PROGRAMMER'S BEST FRIEND*
这是 [Ruby User’s Guide]( http://www.rubyist.net/~slagell/ruby/ "Ruby User’s Guide")的简体中文版本:**Ruby用户指南**。
本指南基于[Mark Slagell](mailto:slagell@ruby-lang.org)的英文译本翻译而来,指南最初的版本由[Ruby](https://www.ruby-lang.org/)的发明者[Yukihiro Matsumoto](mailto:matz@netlab.co.jp)用日语编写完成。
为了减少翻译过程中的错误,我保留了英文版本的内容。因此不要对本文档有任何的抱怨或不满,**Fork**并完善它才是更有意义的事情!
>只要眼睛多,bug容易捉。——李纳斯法则
不要对错误和缺陷视而不见,任何建议或修正,请提交**Issues**,你的任何细微贡献,都将被提名感谢。
**向所有为本指南添砖加瓦的人[致敬](./markdown/contributor.md)!**
## 目录
[Ruby是什么?](./markdown/index.md "What is ruby?")
[起步](./markdown/getstarted.md "Getting started")
[简单示例](./markdown/examples.md "Simple examples")
[字符串](./markdown/strings.md "Strings")
[正则表达式](./markdown/regexp.md "Regular expressions")
[数组](./markdown/arrays.md "Arrays")
[再读“简单示例”](./markdown/backtoexamples.md "Back to the simple examples")
[流程控制](./markdown/control.md "Control structures")
[迭代器](./markdown/iterators.md "Iterators")
[面向对象的思考](./markdown/oothinking.md "Object-oriented thinking")
[方法](./markdown/methods.md "Methods")
[类](./markdown/classes.md "Classes")
[继承](./markdown/inheritance.md "Inheritance")
[重新定义方法](./markdown/redefinemethods.md "Redefinition of methods")
[访问控制](./markdown/accesscontrol.md "Access control")
[单例方法](./markdown/singletonmethods.md "Singleton methods")
[模块](./markdown/modules.md "Modules")
[过程对象](./markdown/procobjects.md "Procedure objects")
[变量](./markdown/variables.md "Variables")
[全局变量](./markdown/globalvars.md "Global variables")
[实例变量](./markdown/instancevars.md "Instance variables")
[局部变量](./markdown/localvars.md "Local variables")
[类常量](./markdown/constants.md "Class constants")
[异常处理:rescue](./markdown/rescue.md "Exception processing: rescue")
[异常处理:ensure](./markdown/ensure.md "Exception processing: ensure")
[访问器](./markdown/accessors.md "Accessors")
[对象初始化](./markdown/objinitialization.md "Object initialization")
[其他](./markdown/misc.md "misc")
[关于本指南](./markdown/about.md "About the guide")
[版权信息](./markdown/copyright.md "Copyright")
[贡献者名单](./markdown/contributor.md "Contributor")
**Copyright (c) 2017-2017 BadTudou**
**本文档遵循[GNU Free Documentation License](./License.txt "GNU Free Documentation License]")**。
##
================================================
FILE: markdown/about.md
================================================
# 关于本指南
**About the guide**
**关于本指南**
This introductory user's guide is mirrored in various places and is available in several translations.
这个介绍性的用户指南在不同的地方都有镜像,并且有几个翻译版本。
The current English language version is kept on rubyist.net.
当前的英语版本保存在rubyist.net上。
If you come across an out-of-date version, please notify the webmaster where the mirror is hosted.
如果你遇到一个过期的版本,请通知网站管理员。
**Document history**
**文档历史**
Original Japanese version by matz.
最初的日文版由<matz@netlab.co.jp>编写。
First English translation by GOTO Kentaro & Julian Fondren.
第一个英文版由[GOTO Kentaro](http://www.math.sci.hokudai.ac.jp/~gotoken/ruby/ruby-uguide/)与[Julian Fondren](mailto:gotoken@notwork.org)翻译。
Re-translation and added material by Mark Slagell.
[Mark Slagell](mailto:slagell@ruby-lang.org)重译并补充了材料。
[BadTudou](mailto:badtudou@gmail.com)翻译了简体中文版。
[上一章 其他](./misc.md "misc")
[下一章 版权信息](./copyright.md "Copyright")
================================================
FILE: markdown/accesscontrol.md
================================================
# 访问控制
**Access control**
**访问控制**
Earlier, we said that ruby has no functions, only methods.
之前我们曾说,**Ruby**没有**函数**,只有**方法**。
However there is more than one kind of method. In this chapter we introduce access controls.
然而,有不止一种方法。在本章节中,我们将介绍访问控制。
Consider what happens when we define a method in the "top level", not inside a class definition.
考虑一下,当我们在“顶层”中定义一个**方法**,而不是在类定义中时,发生了什么。
We can think of such a method as analogous to a function in a more traditional language like C.
我们可以把这种**方法**想象成像**C**这样的更传统的语言的**函数**。
```
ruby> def square(n)
| n * n
| end
nil
ruby> square(5)
25
```
Our new method would appear not to belong to any class, but in fact ruby gives it to the Object class, which is a superclass of every other class.
我们的新方法似乎不属于任何类,但是事实上**Ruby**将给它**Object**类,这是其他类的父类。
As a result, any object should now be able to use that method. That turns out to be true, but there's a small catch: it is a private method of every class.
作为结果,任何对象现在都能使用这个方法。这是事实,但是有一个小问题:它是每个类的私有方法。
We'll discuss some of what this means below, but one consequence is that it may be invoked only in function style, as here:
我们将在下面讨论这是什么意思,但一个结果是,它可能只在函数样式中被调用,如下:
```
ruby> class Foo
| def fourth_power_of(x)
| square(x) * square(x)
| end
| end
nil
ruby> Foo.new.fourth_power_of 10
10000
```
We are not allowed to explicitly apply the method to an object:
我们不允许显式地将该方法应用于对象:
```
ruby> "fish".square(5)
ERR: (eval):1: private method `square' called for "fish":String
```
This rather cleverly preserves ruby's pure-OO nature (functions are still object methods, but the receiver is self implicitly) while providing functions that can be written just as in a more traditional language.
这很巧妙地保留了**Ruby**的纯**OO**特性(函数仍然是对象方法,但是接收方是隐式的),同时提供了可以用更传统的语言编写的函数。
A common mental discipline in OO programming, which we have hinted at in an earlier chapter, concerns the separation of specification and implementation, or what tasks an object is supposed to accomplish and how it actually accomplishes them.
在**OO**编程中,一个常见的心智规则,我们在前面的章节中已经提到过,它关注的是规范和实现的分离,或者对象应该完成什么任务,以及它是如何实现的。
The internal workings of an object should be kept generally hidden from its users; they should only care about what goes in and what comes out, and trust the object to know what it is doing internally.
对象内部的工作状态对使用者而言,应该保持在隐藏状态。使用者只关心传进去的是什么,得到的又是什么,并且信任这个对象知道它自己在内部做什么。
As such it is often helpful for classes to have methods that the outside world does not see, but which are used internally (and can be improved by the programmer whenever desired, without changing the way users see objects of that class). In the trivial example below, think of engine as the invisible inner workings of the class.
因此,对于类来说,拥有外部世界不可见但是在内部被使用的方法通常是有用的(并且可以在需要的时候由程序员改进,而不会改变用户查看该类的对象的方式)。
在下面的简单例子中,将**engine**看作是类中不可见的内部工作。
```
ruby> class Test
| def times_two(a)
| puts "#{a} times two is #{engine(a)}"
| end
| def engine(b)
| b*2
| end
| private:engine # this hides engine from users
| end
Test
ruby> test = Test.new
#<Test:0x4017181c>
ruby> test.engine(6)
ERR: (eval):1: private method `engine' called for #<Test:0x4017181c>
ruby> test.times_two(6)
6 times two is 12.
nil
```
We might have expected test.engine(6) to return 12, but instead we learn that engine is inaccessible when we are acting as a user of a Test object.
我们可能期望`Test.engine(6)`返回`12`,但是我们知道当我们作为一个`Test`对象的用户时,`engine`是不可访问的。
Only other Test methods, such as times_two, are allowed to use engine.
只有其他的`Test`的方法,比如`times_two`,被允许使用`engine`。
We are required to go through the public interface, which consists of the times_two method.
我们需要通过公共接口,它由`times_tow`方法组成。
The programmer who is in charge of this class can change engine freely (here, perhaps by changing b*2 to b+b, assuming for the sake of argument that it improved performance) without affecting how the user interacts with Test objects.
负责这个类的程序员可以自由地改变engine(在这里,可能是通过将`b*2`修改为`b+b`,假设是为了提高性能),而不影响用户与Test对象的交互。
This example is of course much too simple to be useful; the benefits of access controls become more clear only when we begin to create more complicated and interesting classes.
这个例子当然太简单了,不可能有用;只有当我们开始创建更复杂、更有趣的类时,访问控制的好处才会变得更加明显。
[上一章 重新定义方法](./redefinemethods.md "Redefinition of methods")
[下一章 单例方法](./singletonmethods.md "Singleton methods")
================================================
FILE: markdown/accessors.md
================================================
# 访问器
**Accessors**
**访问器**
What is an accessor?
**访问器**是什么?
We briefly discussed instance variables in an earlier chapter, but haven't done much with them yet.
我们在前面的章节中简要地讨论了**实例变量**,但是还没有对它们做过多的讨论。
An object's instance variables are its attributes, the things that distinguish it from other objects of the same class.
对象的实例变量是它的属性,实例变量将它与同类的其他对象区分开来。
It is important to be able to write and read these attributes; doing so requires methods called attribute accessors.
能够读写这些属性是很重要的,这样做需要称为属性访问器的方法。
We'll see in a moment that we don't always have to write accessor methods explicitly, but let's go through all the motions for now. The two kinds of accessors are writers and readers.
稍后我们会看到,我们并不总是需要显式地编写访问器方法,但是现在先让我们来看看所有的动作。这两种访问器分别是**writers**和**readers**。
```
ruby> class Fruit
| def set_kind(k) # a writer
| @kind = k
| end
| def get_kind # a reader
| @kind
| end
| end
nil
ruby> f1 = Fruit.new
#<Fruit:0xfd7e7c8c>
ruby> f1.set_kind("peach") # use the writer
"peach"
ruby> f1.get_kind # use the reader
"peach"
ruby> f1 # inspect the object
#<Fruit:0xfd7e7c8c @kind="peach">
```
Simple enough; we can store and retrieve information about what kind of fruit we're looking at. But our method names are a little wordy. The following is more concise, and more conventional:
很简单;我们可以储存和获取关于我们正在研究的水果的信息。但是我们的方法名称有点冗长。下面的内容更简洁,更传统:
```
ruby> class Fruit
| def kind=(k)
| @kind = k
| end
| def kind
| @kind
| end
| end
nil
ruby> f2 = Fruit.new
#<Fruit:0xfd7e7c8c>
ruby> f2.kind = "banana"
"banana"
ruby> f2.kind
"banana"
```
The inspect method
**inspect**方法
A short digression is in order. You've noticed by now that when we try to look at an object directly, we are shown something cryptic like #<anObject:0x83678>.
小小的题外话。你已经注意到当我们试着直接看对象时,我们会看到一些像`#<anObject:0x83678> `这样神秘的东西。
This is just a default behavior, and we are free to change it.
这只是一个默认的行为,我们可以自由地改变它。
All we need to do is add a method named inspect.
我们所要做的便是添加一个名为`inspect`的方法。
It should return a string that describes the object in some sensible way, including the states of some or all of its instance variables.
它应该返回一个以某种合理方式描述对象的字符串,包括一些或全部实例变量的状态。
```
ruby> class Fruit
| def inspect
| "a fruit of the #{@kind} variety"
| end
| end
nil
ruby> f2
"a fruit of the banana variety"
```
A related method is to_s (convert to string), which is used when printing an object.
一个相关的方法是`to_s`(转换成字符串),在打印对象时使用该方法。
In general, you can think of inspect as a tool for when you are writing and debugging programs, and to_s as a way of refining program output. eval.rb uses inspect whenever it displays results. You can use the p method to easily get debugging output from programs.
一般来说,你可以将`inspect`看作是编写和调试程序时的工具,并将`to_s`作为改进程序输出的一种方法。eval.rb在显示结果时使用`inspect`。你可以使用`p`方法轻松地从程序中调试输出。
```
# These two lines are equivalent:
p anObject
puts anObject.inspect
```
Making accessors the easy way
使访问器变得简单
Since many instance variables need accessor methods, Ruby provides convenient shortcuts for the standard forms.
由于许多实例变量需要访问器方法,所以**Ruby**为标准样式提供了方便的快捷方式。
| 快捷方法 | 效果 |
| -------------------: | ---------------------------------: |
| attr_reader :v | def v; @v; end |
| attr_writer :v | def v=(value); @v=value; end |
| attr_accessor :v | attr_reader :v; attr_writer :v |
| attr_accessor :v, :w | attr_accessor :v; attr_accessor :w |
Let's take advantage of this and add freshness information.
让我们利用这一点并添加新鲜信息。
First we ask for an automatically generated reader and writer, and then we incorporate the new information into inspect:
首先,我们自动生成的**reader**和**writer**,然后我们将这些新信息整合到`inspect`中:
```
ruby> class Fruit
| attr_accessor :condition
| def inspect
| "a #{@condition} #{@kind}"
| end
| end
nil
ruby> f2.condition = "ripe"
"ripe"
ruby> f2
"a ripe banana"
```
More fun with fruit
给水果添加更多乐趣
If nobody eats our ripe fruit, perhaps we should let time take its toll.
如果没有人吃我们成熟的水果,也许我们应该让时间来慢慢腐烂它。
```
ruby> class Fruit
| def time_passes
| @condition = "rotting"
| end
| end
nil
ruby> f2
"a ripe banana"
ruby> f2.time_passes
"rotting"
ruby> f2
"a rotting banana"
```
But while playing around here, we have introduced a small problem.
但是在这里玩的时候,我们已经引入了一个小问题。
What happens if we try to create a third piece of fruit now? Remember that instance variables don't exist until values are assigned to them.
如果我们现在尝试制作第3种水果,会发生什么呢?记住,实例变量在赋值给它们之前是不存在的。
```
ruby> f3 = Fruit.new
ERR: failed to convert nil into String
```
It is the inspect method that is complaining here, and with good reason.
这是是在抱怨`inspect`方法,而且有很好的理由。
We have asked it to report on the kind and condition of a piece of fruit, but as yet f3 has not been assigned either attribute.
我们已经要求它报告一种水果的种类和状况,但是迄今为止,`f3`还没有被分配到任何一种属性。
If we wanted to, we could rewrite the inspect method so it tests instance variables using the defined? method and then only reports on them if they exist, but maybe that's not very useful;
如果我们想,我们可以重写`inspect`方法,以便它使用`defined?`方法测试实例变,然后只报告它们是否存在,但也许这不是很有用;
since every piece of fruit has a kind and condition, it seems we should make sure those always get defined somehow. That is the topic of the next chapter.
因为每一种水果都有种类和环境,似乎我们应该确保它们总是被定义的。这是下一章的主题。
[上一章 异常处理:ensure](./ensure.md "Exception processing: ensure")
[下一章 对象初始化](./objinitialization.md "Object initialization")
================================================
FILE: markdown/arrays.md
================================================
# 数组
**Arrays**
**数组**
You can create an array by listing some items within square brackets ([]) and separating them with commas. Ruby's arrays can accomodate diverse object types.
您可以通过在**方括号**中列出一些以逗号分隔的项来创建**数组**。
```
ruby> ary = [1, 2, "3"]
[1, 2, "3"]
```
Arrays can be concatenated or repeated just as strings can.
**数组**可以同**字符串**一样被连接或重复。
```
ruby> ary + ["foo", "bar"]
[1, 2, "3", "foo", "bar"]
ruby> ary * 2
[1, 2, "3", 1, 2, "3"]
```
We can use index numbers to refer to any part of a array.
我们可以通过数字索引来引用**数组**的任何部分。
```
ruby> ary[0]
1
ruby> ary[0,2]
[1, 2]
ruby> ary[0..1]
[1, 2]
ruby> ary[-2]
2
ruby> ary[-2,2]
[2, "3"]
ruby> ary[-2..-1]
[2, "3"]
```
(Negative indices mean offsets from the end of an array, rather than the beginning.)
(负数的索引代表从数组的末尾开始,而不是从头开始。)
Arrays can be converted to and from strings, using join and split respecitvely:
数组可以被转换为字符串,字符串也可以被转换为数组,分别使用join方法和split方法:
```
ruby> str = ary.join(":")
"1:2:3"
ruby> str.split(":")
["1", "2", "3"]
```
**Hashes**
**散列**
An associative array has elements that are accessed not by sequential index numbers, but by keys which can have any sort of value. Such an array is sometimes called a hash or dictionary;
关联数组有一些元素,这些元素不是通过顺序索引号访问的,而是通过**键**来访问,这些**键**可以是任何类型的值。这样的数组有时被称为**散列**或**字典**。
In the ruby world, we prefer the term hash. A hash can be constructed by quoting pairs of items within curly braces ({}). You use a key to find something in a hash, much as you use an index to find something in an array.
在**Ruby**的世界里,我们更喜欢将它称之为**散列**。可以通过在**花括号中**引用成对的**散列项**来构造**散列**。你通过**键**在**散列**中查找**散列项**,就如同你用**索引**在**数组中**查找**数组元素**一样。
```
ruby> h = {1 => 2, "2" => "4"}
{1=>2, "2"=>"4"}
ruby> h[1]
2
ruby> h["2"]
"4"
ruby> h[5]
nil
ruby> h[5] = 10 # appending an entry 添加一个哈希项
10
ruby> h
{5=>10, 1=>2, "2"=>"4"}
ruby> h.delete 1 # deleting an entry by key 通过键删除一个哈希项
2
ruby> h[1]
nil
ruby> h
{5=>10, "2"=>"4"}
```
[上一章 正则表达式](./regexp.md "Regular expressions")
[下一章 再读“简单示例”](./backtoexamples.md "Back to the simple examples")
================================================
FILE: markdown/backtoexamples.md
================================================
# 再读“简单示例”
**Back to the simple examples**
**再读“简单示例”**
Now let's take apart the code of some of our previous example programs.
现在,让我们把之前“示例代码”中的代码剖析一下。
The following appeared in the simple examples chapter.
“简单示例”中有以下代码。
```
def fact(n)
if n == 0
1
else
n * fact(n-1)
end
end
puts fact(ARGV[0].to_i)
```
Because this is the first explanation, we examine each line individually.
由于这是对代码的第一个解释说明,所以我们为每一行代码都做了单独的解释。
**Factorials**
**阶乘**
```
def fact(n)
```
In the first line, def is a statement to define a function (or, more precisely, a method; we'll talk more about what a method is in a later chapter).
第1行中,`def`是定义函数的声明(或者更确切地说,是一个方法。我们将在后面的章节中更多地讨论方法是什么)。
Here, it specifies that the function fact takes a single argument, referred to as n.
这里,它指定了函数在实际运行中将接收一个称之为n的参数。
```
if n == 0
```
The if is for checking a condition. When the condition holds, the next bit of code is evaluated; otherwise whatever follows the else is evaluated.
`if`用于检查条件。当条件成立时,执行`if`之后的代码块,否则执行`else`之后的代码块。
`1`
The value of if is 1 if the condition holds.
如果条件成立,则值为1.
`else`
If the condition does not hold, the code from here to end is evaluated.
如果条件不成立,从这里到`end`之间的代码将被执行。
`n * fact(n-1)`
If the condition is not satisfied, the value of if is the result of n times fact(n-1).
如果条件不满足,则`if`的值是`n`乘以`fact(n-1)`的结果。
`end`
The first end closes the if statement.
第1个`end`用于结束`if`语句。
`end`
The second end closes the def statement.
第2个`end`用于结束`def`语句。
`puts fact(ARGV[0].to_i)`
This invokes our fact() function using a value specified from the command line, and prints the result.
此处调用了我们的`fact()`函数,它从命令行接收一个值,然后将结果输出。
ARGV is an array which contains command line arguments. The members of ARGV are strings, so we must convert this into a integral number by to_i. Ruby does not convert strings into integers automatically like perl does.
`ARGV`是一个包含了命令行参数的数组。`ARGV`的成员都是字符串,所以我们必须用`to_i`将其转换成整数。**Ruby**不会像**Perl**那样自动将一个字符串转换为整数。
What would happen if we fed this program a negative number? Do you see the problem? Can you fix it?
如果我们给这个程序一个负数,会发生什么呢?
你找到问题所在了么?能够完善它么?
Strings
字符串
Next we examine the puzzle program from the chapter on strings. As this is somewhat longer, we number the lines for reference.
接下来,我们将从**字符串**的章节中研究这个谜题程序。由于花费的时间更长,所以我们为代码标注了行号。
```
01 words = ['foobar', 'baz', 'quux']
02 secret = words[rand(3)]
03
04 print "guess? "
05 while guess = STDIN.gets
06 guess.chop!
07 if guess == secret
08 puts "You win!"
09 break
10 else
11 puts "Sorry, you lose."
12 end
13 print "guess? "
14 end
15 puts "the word is ", secret, "."
```
In this program, a new control structure, while, is used.
这个程序中使用了一个新的控制结构`while`。
The code between while and its corresponding end will execute repeatedly as long as some specified condition remains true.
当指定的条件满足时,`while`和它对应的`end`之间的代码就会一直被执行。
In this case, guess=STDIN.gets is both an active statement (collecting a line of user input and storing it as guess), and a condition (if there is no input, guess, which repesents the value of the whole guess=STDIN.gets expression, has a nil value, causing while to stop looping).
在这里,`guess=STDIN.gets`既是一个活动语句(收集用户输入并将其保存在guess中),又是一个条件(如果没有输入,执行表达式`guess=STDIN.gets`所得到的`guess`,其值将为`nil`,进行导致循环被终止)。
STDIN is the standard input object. Usually, guess=gets does the same thing as guess=STDIN.gets.
`STDIN`是**标准输入设备**,通常情况下,`guess=gets`与`guess=STDIN.gets`是等价的。
rand(3) in line 2 returns a random number in the range 0 to 2. This random number is used to extract one of the members of the array words.
第2行的`rand(3)`将返回一个0到2之间的随机数,这个随机数被用来提取单词数组的一个成员。
In line 5 we read one line from standard input by the method STDIN.gets. If EOF (end of file) occurs while getting the line, gets returns nil. So the code associated with this while will repeat until it sees ^D (try ^Z or F6 under DOS/Windows), signifying the end of input.
在第5行,我们通过`STDIN.gets`方法从`标准输入设备`中读取1行内容,当读取的内容为`EOF`(end of file)时,`gets`返回`nil`。所以与`while`有关的代码会重复执行,直到遇到`^D`(在**DOS**/**Windows**上为`^Z`或`F6`)才结束。
guess.chop! in line 6 deletes the last character from guess; in this case it will always be a newline character, gets includes that character to reflect the user's Return keystroke, but we're not interested in it.
第6行的`guess.chop!`将会删除`guess`的最后一个字符,在这里,它将始终为换行符,`gets`包含该字符以反映用户的返回键,但我们对它不感兴趣。
In line 15 we print the secret word. We have written this as a puts (put string) statement with two arguments, which are printed one after the other; but it would have been equally effective to do it with a single argument, writing secret as #{secret} to make it clear that it is a variable to be evaluated, not a literal word to be printed:
在第15行我们打印出了机密单词,我们将它写成了一个有2个参数的`puts`(put string)语句,它们都会依次打印出来。但是它完全可以用一个语句来完成,将`secret`写作`#{secret}`,以明确表示它是一个被计算的变量,而不是一个被原样打印的单词。
`puts "the word is #{secret}."`
Many programmers feel this is a cleaner way to express output; it builds a single string and presents it as a single argument to puts.
许多程序员觉得这是一种更清晰地表达输出的方式,它构建了一个单独的字符串,并将其作为一个单独的参数来表示。
Also, we are by now used to the idea of using puts for standard script output, but this script uses print instead, in lines 4 and 13.
而且,我们现在已经习惯了使用`puts`来作为脚本输出的概念,但是我们在第4行和第13行仍然使用的是`print`。
They are not quite the same thing. print outputs exactly what it is given; puts also ensures that the output line ends. Using print in lines 4 and 13 leaves the cursor next to what was just printed, rather than moving it to the beginning of the next line. This creates a recognizable prompt for user input. In general, the four output calls below are equivalent:
它们并不是完全相同,`print`将给它的东西完全输出,`puts`确保会输出行结束符。在第4行和第13行中使用`print`将光标放在刚刚打印的内容旁边,而不是把它移到下一行的开头,以为用户输入创建一个可辨别的提示。通常情况下,下面4个输出调用是等价的:
```
# 隐式地添加新行:
puts "Darwin's wife, Esmerelda, died in a fit of penguins."
```
```
# 新行必须显式地在print命令中给出
print "Darwin's wife, Esmerelda, died in a fit of penguins.\n"
```
```
# 你可以使用+将输出连接起来
print 'Darwin's wife, Esmerelda, died in a fit of penguins.'+"\n"
```
```
# 或者通过提供多个字符串来将它们连接起来:
print 'Darwin's wife, Esmerelda, died in a fit of penguins.', "\n", "
One possible gotcha: sometimes a text window is programmed to buffer output for the sake of speed, collecting individual characters and displaying them only when it is given a newline character. So if the guessing game script misbehaves by not showing the prompt lines until after the user supplies a guess, buffering is the likely culprit. To make sure this doesn't happen, you can flush the output as soon as you have printed the prompt. It tells the standard output device (an object named STDOUT), don't wait; display what you have in your buffer right now."
```
```
04 print "guess? "; STDOUT.flush
...
13 print "guess? "; STDOUT.flush
```
And in fact, we were more careful with this in the next script.
事实上,在下一个脚本中我们显得更小心。
**Regular expressions**
**正则表达式**
Finally we examine this program from the chapter on regular expressions.
最后,我们将从**正则表达式**的章节来研究这个程序。
```
01 st = "\033[7m"
02 en = "\033[m"
03
04 puts "Enter an empty string at any time to exit."
05
06 while true
07 print "str> "; STDOUT.flush; str=gets.chop
08 break if str.empty?
09 print "pat> "; STDOUT.flush; pat=gets.chop
10 break if pat.empty?
11 re = Regexp.new(pat)
12 puts str.gsub(re, "#{st}\\&#{en}")
13 end
```
In line 6, the condition for while is hardwired to true, so it forms what looks like an infinite loop.
在第6行中,`while`的条件始终为`true`,所以它形成了一个`无限循环`。
However we put break statements in the 8th and 10th lines to escape the loop.
然后我们在第8行和第10行放置了`break`语句来跳出循环。
These two breaks are also an example of "if modifiers." An if modifier executes the statement on its left hand side if and only if the specified condition is satisfied.
这2个`break`也是`if`修饰符的一个例子。当指定条件得到满足时,`if`修饰符将执行它左边的语句。
This construction is unusual in that it operates logically from right to left, but it is provided because for many people it mimics a similar pattern in natural speech.
这种在逻辑上是从右到左的结构并不常用,但是我们仍提供了它,是因为对许多人来说,它模仿了自然语言中所存在的类似的模式。
It also has the advantage of brevity, as it needs no end statement to tell the interpreter how much of the following code is supposed to be conditional.
它同样也有简洁的优点,因为它不需要`end`语句来告诉解释器其下有多少代码是有条件的。
An if modifier is conventionally used in situations where a statement and condition are short enough to fit comfortably together on one script line.
如果语句和条件足够短,可以在一个脚本行中轻松地组合在一起,就使用`if`修饰符。
Note the difference in the user interface compared to the string-guessing script. This one lets the user quit by hitting the Return key on an empty line. We are testing for emptiness of the input string, not for its nonexistence.
请注意用户界面与"猜单词"脚本的区别。这个允许用户在空行上输入回车键来退出,我们正在测试的是输入的字符串为空,而不是没有任何输入。
In lines 7 and 9 we have a "non-destructive" chop; again, we're getting rid of the unwanted newline character we always get from gets.
在第7行和第9行,我们有一个“非破坏性”的`chop`。再一次,我们去掉了从`gets`中得到的不需要的换行符。
Add the exclamation point, and we have a "destructive" chop. What's the difference?
加上感叹号`!`,我们就得到了一个“破坏性”的`chop`,它们有何不同?
In ruby, we conventionally attach '!' or '?' to the end of certain method names. The exclamation point (!, sometimes pronounced aloud as "bang!") indicates something potentially destructive, that is to say, something that can change the value of what it touches.
在**Ruby**中,我们习惯于给某些方法名的末尾加上`!`或者`?`,感叹号`!`(!,有时也被读作"bang!")表示可能具有破坏性,也就是说,可以改变它所访问的值。
chop! affects a string directly, but chop gives you a chopped copy without damaging the original. Here is an illustration of the difference.
`chop!`直接更改一个字符串,而`chop`会给你一个截好的副本而不会破坏原始的字符串。这里是一个解释它们差异的例子:
```
ruby> s1 = "forth"
"forth"
ruby> s1.chop! # 改变了s1.
"fort"
ruby> s2 = s1.chop # 这会在s2中放置一个修改过的副本,
"for"
ruby> s1 # ... 没有修改s1.
"fort"
```
You'll also sometimes see chomp and chomp! used. These are more selective: the end of a string gets bit off only if it happens to be a newline. So for example, "XYZ".chomp! does nothing.
有时你也会看到`chomp`和`chomp!`被使用。这两个方法具有更强的选择性:只有当字符串的末尾是换行符时,才会认为它已经结束了。举个例子,`"XYZ".chomp!"`就会什么也不做。
If you need a trick to remember the difference, think of a person or animal tasting something before deciding to take a bite, as opposed to an axe chopping indiscriminately.
如果你需要一个技巧来记住它们的不同,想想一个人或动物在品尝什么东西之前,会决定咬一口,而不是不加选择地使用砍斧。
The other method naming convention appears in lines 8 and 10. A question mark (?, sometimes pronounced aloud as "huh?") indicates a "predicate" method, one that can return either true or false.
另一种方法命名约定出现在第8行和第10行中。一个问号`?`(?,有时也被读作“huh?”)表明一个`断言`方法,即是可以返回`true`或`false`。
Line 11 creates a regular expression object out of the string supplied by the user. The real work is finally done in line 12, which uses gsub to globally substitute each match of that expression with itself, but surrounded by ansi markups; also the same line outputs the results.
第11行从用户提供的字符串中创建了一个**正则表达式**对象,真正的工作最终在第12行完成,使用`gsub`来全局地替换该表达式的每个匹配,但是被ANSI标记所包围。然后在同一行中输出结果。
We could have broken up line 12 into separate lines like this:
我们可以把第12行分解成这样的单独的行:
```
highlighted = str.gsub(re,"#{st}\\&#{en}")
puts highlighted
```
or in "destructive" style:
或者使用“破坏性”风格:
```
str.gsub!(re,"#{st}\\&#{en}")
puts str
```
Look again at the last part of line 12. st and en were defined in lines 1-2 as the ANSI sequences that make text color-inverted and normal, respectively.
再看看第12行的最后一部分。在1-2行中,**st**和**en**被定义为**ANSI**序列,其文本颜色分别为颠倒和正常。
In line 12 they are enclosed in #{} to ensure that they are actually interpreted as such (and we do not see the variable names printed instead).
在第12行中,它们被用`#{}`封闭起来以确保它们被解释为变量(我们没有看到变量名被打印出来)。
Between these we see \\&. This is a little tricky. Since the replacement string is in double quotes, the pair of backslashes will be interpreted as a single backslash;
在这些之间我们可以看到`\&`,这有点棘手。由于替换字符串被包含在双引号中,因此`\\`将被解释为一个反斜杠。
What gsub actually sees will be \&, and that happens to be a special code that refers to whatever matched the pattern in the first place.
**gsub**实际上看到的将是`\&`,而这恰好是一种特殊的代码,它指的是一种首先匹配的模式。
So the new string, when displayed, looks just like the old one, except that the parts that matched the given pattern are highlighted in inverse video.
因此当新的字符串被显示时,除了那些与给定模式匹配的部分将在显示器中被高亮显示外,其他的看起来和旧的字符串是一样的。
[上一章 数组](./arrays.md "Arrays")
[下一章 流程控制](./control.md "Control structures")
================================================
FILE: markdown/classes.md
================================================
# 类
**Classes**
**类**
The real world is filled by objects, and we can classify them.
现实世界中充满了对象,并且我们还可以给它们分类。
For example, a very small child is likely to say "bow-wow" when seeing a dog, regardless of the breed; we naturally see the world in terms of these categories.
举个例子,当一个小孩子看到了一条狗,他可能会说“汪汪”,而不管这条狗是什么品种。我们自然地会从这些类别中看到世界。
In OO programming terminology, a category of objects like "dog" is called a class, and some specific object belonging to a class is called an instance of that class.
在**OO编程**的术语中,像“狗”这样的一类**对象**,被称为**类**,属于**类**的某些特定**对象**称为该**类**的一个**实例**。
Generally, to make an object in ruby or any other OO language, first one defines the characteristics of a class, then creates an instance. To illustrate the process, let's first define a simple Dog class.
通常,在Ruby或任何其他OO语言中,想要创造一个对象,第一步是定义一个**类**的特征,然后再创建一个**实例**。为了阐述这个过程,让我们先定义一个简单的**Dog**类。
```
ruby> class Dog
| def speak
| puts "Bow Wow"
| end
| end
nil
```
In ruby, a class definition is a region of code between the keywords class and end.
在**Ruby**中,类定义是关键字`class`和`end`之间的代码区域。
A def inside this region begins the definition of a method of the class, which as we discussed in the previous chapter, corresponds to some specific behavior for objects of that class.
区域内的`def`是定义类方法的开始,正如我们在前一章中所讨论的,类方法对应于该类对象的某些特定行为。
Now that we have defined a Dog class, we can use it to make a dog:
现在我们已经定义了一个Dog类,我们可以用它来生成一条狗:
```
ruby> pochi = Dog.new
#<Dog:0xbcb90>
```
We have made a new instance of the class Dog, and have given it the name pochi.
我们生成了类Dog的一个新实例,并且给它取名为**pochi**。
The new method of any class makes a new instance. Because pochi is a Dog according to our class definition, it has whatever properties we decided a Dog should have. Since our idea of Dog-ness was very simple, there is just one trick we can ask pochi to do.
任何类的`new`方法都是生成一个新实例。因为**pochi**是根据我们的类定义而来的一个**Dog**,它有任何我们认为**Dog**应该拥有的属性。因为我们对**Dog**的想法非常简单,所以我们能让**pochi**做的只有一个小把戏。
```
ruby> pochi.speak
Bow Wow
nil
```
Making a new instance of a class is sometimes called instantiating that class. We need to have a dog before we can experience the pleasure of its conversation; we can't merely ask the Dog class to bark for us.
生成一个类的新实例有时被称为实例化该类。在我们能体会到狗的对话的乐趣之前,我们需要有一条狗才行;我们不能只是要求Dog类为我们吠叫。
```
ruby> Dog.speak
ERR: (eval):1: undefined method `speak' for Dog:class
```
It makes no more sense than trying to eat the concept of a sandwich.
吃三明治的概念是没有意义的。
On the other hand, if we want to hear the sound of a dog without getting emotionally attached, we can create (instantiate) an ephemeral, temporary dog, and coax a little noise out of it before it disappears.
换句话说,如果我们想要听到狗的叫声而无需感情上的依恋,我们可以生成(实例化)一条短暂的、临时的狗,在它消失之前,让它发出一点声音。
```
ruby> (Dog.new).speak # 或者更常见的, Dog.new.speak
Bow Wow
nil
```
"Wait," you say, "what's all this about the poor fellow disappearing afterwards?"
“等等”,你说道:“这个可怜的家伙到底是怎么消失的呢?”
It's true: if we don't bother to give it a name (as we did for pochi), ruby's automatic garbage collection decides it is an unwanted stray dog, and mercilessly disposes of it. Really it's okay, you know, because we can make all the dogs we want.
事实是:如果我们不费心给它取一个名字(就像我们给它取名**pochi**),**Ruby**的自动垃圾回收便判定它是一条不再需要的流浪狗,并且残忍地处理它。真的这没问题,你知道的,我们可以制造所有我们想要的狗。
[上一章 方法](./methods.md "Methods")
[下一章 继承](./inheritance.md "Inheritance")
================================================
FILE: markdown/constants.md
================================================
# 类常量
**Class constants**
**类常量**
A constant has a name starting with an uppercase character.
常量的名称以大写字母开头。
It should be assigned a value at most once.
它应该最多赋值一次。
In the current implementation of ruby, reassignment of a constant generates a warning but not an error (the non-ANSI version of eval.rb does not report the warning):
在**Ruby**的当前实现中,重新给一个常量赋值将产生一个警告,而不是一个错误(非ansi版本的eval.rb不报告警告):
```
ruby>fluid=30
30
ruby>fluid=31
31
ruby>Solid=32
32
ruby>Solid=33
(eval):1: warning: already initialized constant Solid
33
```
Constants may be defined within classes, but unlike instance variables, they are accessible outside the class.
常量可能在类中被定义,但是不同于实例变量,它们可以在类外部被访问。
```
ruby> class ConstClass
| C1=101
| C2=102
| C3=103
| def show
| puts "#{C1} #{C2} #{C3}"
| end
| end
nil
ruby> C1
ERR: (eval):1: uninitialized constant C1
ruby> ConstClass::C1
101
ruby> ConstClass.new.show
101 102 103
nil
```
Constants can also be defined in modules.
常量同样可以在模块中被定义。
```
ruby> module ConstModule
| C1=101
| C2=102
| C3=103
| def showConstants
| puts "#{C1} #{C2} #{C3}"
| end
| end
nil
ruby> C1
ERR: (eval):1: uninitialized constant C1
ruby> include ConstModule
Object
ruby> C1
101
ruby> showConstants
101 102 103
nil
ruby> C1=99 # 这不是一个好主意
99
ruby> C1
99
ruby> ConstModule::C1
101
ruby> ConstModule::C1=99 # 更早的版本中不允许这样做
(eval):1: warning: already initialized constant C1
99
ruby> ConstModule::C1 # "enough rope to shoot yourself in the foot"
99
```
[上一章 局部变量](./localvars.md "Local variables")
[下一章 异常处理:rescue](./rescue.md "Exception processing: rescue")
================================================
FILE: markdown/contributor.md
================================================
# 贡献者名单
>如果我比别人看得远,那是因为我站在巨人的肩膀上。——艾萨克·牛顿
感谢以下人员为[《Ruby用户指南》](https://github.com/BadTudou/RubyUsersGuide-zh)做出的巨大贡献!(**排名不分先后**)
1.[松本行弘](matz@netlab.co.jp)
作为**Ruby**语言的发明者与本指南的**日文版**原作者,松本行弘先生的贡献不可估量。
2.[GOTO Kentaro](http://www.math.sci.hokudai.ac.jp/~gotoken/ruby/ruby-uguide/) && [Julian Fondren](mailto:gotoken@notwork.org)
**GOTO Kentaro**与**Julian Fondren**完成了本指南的第一个**英文**译本,使得本指南开始在全世界推广开来。
3.[Mark Slagell](mailto:slagell@ruby-lang.org)
**Mark Slagell**重译了英文译本,并补充了有关资料,使得本文档更加完善。
4.[Kun Liu](https://github.com/liukgg)
**Kun Liu**纠正了 [《起步》](./getstarted.md "Getting started")、[《简单示例》](./examples.md "Simple examples")、[《字符串》](./strings.md "Strings")等众多章节中不优雅的中文翻译与错别字,并将之前不严谨的名词替换成了更严谨的专业术语,以及其他未能在此处一一列举出来的众多贡献。:clap:
5.[genghisun](https://github.com/genghisun)
**genghisun**对[《局部变量》](./localvars.md "Local variables")的翻译稍加润色。:clap:
6.[GuangyuLeo](https://github.com/GuangyuLeo)
**GuangyuLeo**对[《起步》](./getstarted.md.md "Getting started")的细小错误进行了修正。:clap:
7.[clownf](https://github.com/clownf)
**clownf**对[《起步》](./getstarted.md.md "Getting started")的细小错误进行了修正。:clap:
================================================
FILE: markdown/control.md
================================================
# 流程控制
**Control structures**
**流程控制**
This chapter explores more of ruby's control structures.
本章节探究了更多的**Ruby**流程控制。
**case**
We use the case statement to test a sequence of conditions. This is superficially similar to switch in C and Java but is considerably more powerful, as we shall see.
我们使用`case`语句来测试一个条件序列。表面上看它与**C**和**JAVA**中的`switch`类似,但正如我们将要看到的,实际上它要比`switch`强大得多。
```
ruby> i=8
ruby> case i
| when 1, 2..5
| puts "1..5"
| when 6..10
| puts "6..10"
| end
6..10
nil
```
2..5 is an expression which means the range between 2 and 5, inclusive. The following expression tests whether the value of i falls within that range:
`2..5`是一个表达式,它表示2到5的范围(包括2和5)。下面的表达式测试了我的值是否在这个范围内:
```
(2..5) === i
```
case internally uses the relationship operator === to check for several conditions at a time.
`case`在内部使用了关系运算符`===`来一次检查多个条件。
In keeping with ruby's object oriented nature, === is interpreted suitably for the object that appeared in the when condition.
为了与**Ruby**面向对象的特性保持一致,`===`会对出现在`when`条件下的对象进行适当解释。
For example, the following code tests string equality in the first when, and regular expression matching in the second when.
举个例子,下面的代码在第1个`when`中会检测字符串是否相等,在第2个`when`中会检测字符串是否与正则表达式匹配。
```
ruby> case 'abcdef'
| when 'aaa', 'bbb'
| puts "aaa or bbb"
| when /def/
| puts "includes /def/"
| end
includes /def/
nil
while
```
Ruby provides convenient ways to construct loops, although you will find in the next chapter that learning how to use iterators will make it unnecessary to write explicit loops very often.
**Ruby**提供了非常便捷的方法来构建循环,尽管你将在下一章中发现,学习如何使用**迭代器**将使编写显式的循环变得不再必要。
A while is a repeated if. We used it in our word-guessing puzzle and in the regular expression programs (see the previous chapter); there, it took the form while condition ... end surrounding a block of code to be repeated while condition was true. But while and if can as easily be applied to individual statements:
一个`while`就是一个重复的`if`。我们在“猜谜语”和正则表达式中使用了`while`(参见上一章节)。这里,它以`while 条件 … end`的形式出现。在条件为真的情况下,重复执行代码块中的代码。但是`while`和`if`都可以很容易地应用于单个语句。
```
ruby> i = 0
0
ruby> puts "It's zero." if i==0
It's zero.
nil
ruby> puts "It's negative." if i<0
nil
ruby> puts i+=1 while i<3
1
2
3
nil
```
Sometimes you want to negate a test condition. An unless is a negated if, and an until is a negated while. We'll leave it up to you to experiment with these.
有时你想要否定一个测试条件,`unless`就是`否定的if`,并且`until`就是`否定的while`。我们把它留给你来做实验。
There are four ways to interrupt the progress of a loop from inside.
有四种方法可以从内部中断循环的进程。
First, break means, as in C, to escape from the loop entirely.
**1**,`break`意味着,就像在C中一样,会完全终止循环。
Second, next skips to the beginning of the next iteration of the loop (corresponding to C's continue).
**2**,`next`跳到循环的下一次迭代的开始(相当于**C**的`continue`)。
Third, ruby has redo, which restarts the current iteration.
**3**.Ruby有`redo`,这将重新启动当前的迭代。
The following is C code illustrating the meanings of break, next, and redo:
下面用**C语言**代码说明了`break`,`next`以及`redo`的含义。
```
while (condition) {
label_redo:
goto label_next; /* ruby's "next" */
goto label_break; /* ruby's "break" */
goto label_redo; /* ruby's "redo" */
...
...
label_next:
}
label_break:
...
```
The fourth way to get out of a loop from the inside is return. An evaluation of return causes escape not only from a loop but from the method that contains the loop. If an argument is given, it will be returned from the method call, otherwise nil is returned.
**4**.从内部退出循环的第4种方法是`return`。对`return`的运算不仅会导致终止循环,还会从包含循环的方法中退出,否则将返回`nil`。
**for**
C programmers will be wondering by now how to make a "for" loop.
**C**程序员现在可能想知道该如何如何创建一个`for`循环。
Ruby's for can serve the same purpose, but adds some flexibility.
**Ruby**的`for`可以达到同样的目的,而且还增加了一些灵活性。
The loop below runs once for each element in a collection (array, hash, numeric sequence, etc.), but doesn't make the programmer think about indices:
下面的循环为**集合**(**数组**,**散列**,**数字序列**等等)中的每个元素运行一次,但是并不需要程序员考虑**索引**。
```
for elt in collection
# ... 此处,elt引用了集合中的每一个元素
end
```
The collection can be a range of values (this is what most people mean when they talk about a for loop):
这个**集合**也可以是某个范围内的值(这也是大多数人在谈论`for`循环时的意思):
```
ruby> for num in (4..6)
| puts num
| end
4
5
6
4..6
```
In this example we step through some array elements:
在这个例子中,我们逐步介绍了一些**数组元素**:
```
ruby> for elt in [100,-9.6,"pickle"]
| puts "#{elt}\t(#{elt.class})"
| end
100 (Fixnum)
-9.6 (Float)
pickle (String)
[100, -9.6, "pickle"]
```
But we're getting ahead of ourselves. for is really another way of writing each, which, it so happens, is our first example of an iterator. The following two forms are equivalent:
但是我们已经超越了自己。`for`确实是另一种写`each`的方法,它是我们第一个**迭代器**的例子。以下两种形式是等价的:
```
#如果你曾使用C或JAVA,你可能倾向于这种.
for element in collection
...
end
```
```
#一个Smalltalk程序员可能更钟爱这种
collection.each {|element|
...
}
```
Iterators can often be substituted for conventional loops, and once you get used to them, they are generally easier to deal with. So let's move on and learn more about them.
**迭代器**通常被用来代替传统的**循环**,并且一旦你习惯了它们,它们通常更容易处理。因此,让我们继续学习,更多地了解它们。
[上一章 再读“简单示例”](./backtoexamples.md "Back to the simple examples")
[下一章 迭代器](./iterators.md "Iterators")
================================================
FILE: markdown/copyright.md
================================================
# 版权信息
**Copyright (c) 2005-2014 Mark Slagell**
**版权所有 (c) 2005-2014 Mark Slagell**
Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
允许在**GNU**自由文档许可证、版本1.2或由自由软件基金会发布的任何后续版本的条款下,复制、发布和/或修改该文档;没有不变的部分,没有不可变章节,没有前封面文字,没有后封面文字。
A copy of the license is included in the section entitled "GNU Free Documentation License."
许可证的副本包含在“**GNU自由文档许可证**”一节中。
[返回目录](../README.md "Ruby用户指南")
================================================
FILE: markdown/ensure.md
================================================
# 异常处理:ensure
**Exception processing: ensure**
**异常处理:ensure**
There may be cleanup work that is necessary when a method finishes its work.
当方法完成工作时,可能会有一些清理工作。
Perhaps an open file should be closed, buffered data should be flushed, etc.
也许是一个打开的文件需要关闭,缓存的数据需要刷新,等等。
If there were always only one exit point for each method, we could confidently put our cleanup code in one place and know that it would be executed;
如果每个方法总是只有一个出口点,那么我们可以自信地将我们的清理代码放在一个地方,并知道它将被执行;
however, a method might return from several places, or our intended cleanup code might be unexpectedly skipped because of an exception.
但是,一个方法可能从几个地方返回,或者我们准备的清理代码可能会因为异常而被意外地跳过。
```
file = open("/tmp/some_file", "w")
begin
# ... write to the file ...
file.close
end
```
In the above, if an exception occurred during the section of code where we were writing to the file, the file would be left open. And we don't want to resort to this kind of redundancy:
在上面,如果一个异常发生在我们写入文件的代码段中,那么这个文件就会被一直打开。我们不想采用这种冗余的方式:
```
file = open("/tmp/some_file", "w")
begin
# ... write to the file ...
file.close
rescue
file.close
fail # raise an exception
end
```
It's clumsy, and gets out of hand when the code gets more complicated because we have to deal with every return and break.
它很笨拙,当代码变得更加复杂的时候就会失去控制,因为我们必须处理每一个返回和中断。
For this reason we add another keyword to the "begin...rescue...end" scheme, which is ensure.
出于这个原因,我们在`begin...rescue...end`中添加了另一个关键字:`ensure`。
The ensure code block executes regardless of the success or failure of the begin block.
无论`begin`块是成功还是失败,`ensure`代码块都将被执行。
```
file = open("/tmp/some_file", "w")
begin
# ... write to the file ...
rescue
# ... handle the exceptions ...
ensure
file.close # ... and this always happens.
end
```
It is possible to use ensure without rescue, or vice versa, but if they are used together in the same begin...end block, the rescue must precede the ensure.
可以在没有`rescue`的情况下使用`ensure`,反之亦然,但是如果它们在同一`begin...end`块中一起使用,`rescue`必须出现在`ensure`之前。
[上一章 异常处理:rescue](./rescue.md "Exception processing: rescue")
[下一章 访问器](./accessors.md "Accessors")
================================================
FILE: markdown/examples.md
================================================
# 简单示例
**Simple examples**
**简单示例**
Let's write a function to compute factorials. The mathematical definition of `n` factorial is:
让我们来写一个计算阶乘的函数。`n`的阶乘在数学上的定义是:
```
n! = 1 (when n==0)
= n * (n-1)! (otherwise)
```
In ruby, this can be written as:
在**Ruby**中,我们可以这样写:
```
def fact(n)
if n == 0
1
else
n * fact(n-1)
end
end
```
You may notice the repeated occurrence of `end`. Ruby has been called "Algol-like" because of this. (Actually, the syntax of ruby more closely mimics that of a langage named Eiffel.)
你可能注意到了上面反复出现的`end`,正是由于这个原因,**Ruby**也被称为“**类Algol**”语言(事实上,**Ruby**的语法更接近模仿一门叫做**Eiffel**的语言)。
You may also notice the lack of a `return` statement. It is unneeded because a ruby function returns the last thing that was evaluated in it. Use of a `return` statement here is permissible but unnecessary.
你可能还注意到了没有`return`语句,因为它并不是必须要有的,**Ruby**中函数将自动返回最后一个求得的值。在这里使用`return`指令是可以的,但是却是多余的。
Let's try out our factorial function. Adding one line of code gives us a working program:
让我们试用一下我们的阶乘函数。给我们的程序添加一行:
```
# 这个程序用来计算一个数字的阶乘
# 将其保存到fact.rb
def fact(n)
if n == 0
1
else
n * fact(n-1)
end
end
puts fact(ARGV[0].to_i)
```
Here, `ARGV` is an array which contains the command line arguments, and `to_i` converts a character string to an integer.
这里,`ARGV`是一个包含了**命令行参数**的**数组**,`to_i`则将一个字符转换成了整数。
```
ruby fact.rb 1
1
ruby fact.rb 5
120
```
Does it work with an argument of 40? It would make your calculator overflow...
如果参数是40它仍会正常工作么?嗯,它可能会让你的计算器**溢出**......
```
ruby fact.rb 40
815915283247897734345611269596115894272000000000
```
It does work. Indeed, ruby can deal with any integer which is allowed by your machine's memory. So 400! can be calculated:
没问题,**Ruby**甚至还可以处理你机器内存所允许的任何整数,所以400的阶乘也可以被计算出来:
```
ruby fact.rb 400
64034522846623895262347970319503005850702583026002959458684445942802397169186831436278478647463264676294350575035856810848298162883517435228961988646802997937341654150838162426461942352307046244325015114448670890662773914918117331955996440709549671345290477020322434911210797593280795101545372667251627877890009349763765710326350331533965349868386831339352024373788157786791506311858702618270169819740062983025308591298346162272304558339520759611505302236086810433297255194852674432232438669948422404232599805551610635942376961399231917134063858996537970147827206606320217379472010321356624613809077942304597360699567595836096158715129913822286578579549361617654480453222007825818400848436415591229454275384803558374518022675900061399560145595206127211192918105032491008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
```
We cannot check the correctness at a glance, but it must be right. :-)
我们显然不能通过匆匆一瞥就能判断其是否正确,但它应该是没有问题的。:-)
## The input/evaluation loop
## 输入/执行 交互环境
When you invoke ruby with no arguments, it reads commands from standard input and executes them after the end of input:
当你调用**Ruby**时没有传递参数,它将从**标准输入设备**读取命令,并在输入结束后执行输入的命令。
```% ruby
puts "hello world"
puts "good-bye world"
^D
```
**hello world**
**good-bye world**
The *^D* above means control-D, a conventional way to signal end-of-input in a Unix context. In DOS/Windows, try pressing *F6* or *^Z* instead.
上面的 **^D** 代表 **Ctrl+D**,它是一种用于在**Unix**上下文中表示结束输入的传统方法,在**DOS/Windows**上,对应的则应该输入**F6**或**Ctrl+Z**。
Ruby also comes with a program called `eval.rb` that allows you to enter ruby code from the keyboard in an interactive loop, showing you the results as you go. It will be used extensively through the rest of this guide.
**Ruby**还附带了一个名为`eval.rb`的程序,它允许你在一个交互环境中从键盘输入**Ruby**代码,并且在退出后将结果返回给你。在本指南的其他章节,我们将广泛使用它。
If you have an ANSI-compliant terminal (this is almost certainly true if you are running some flavor of UNIX; under old versions of DOS you need to have installed `ANSI.SYS` or `ANSI.COM`; Windows XP, unfortunately, has now made this nearly impossible), you should use this [enhanced `eval.rb`](http://www.rubyist.net/~slagell/ruby/eval.txt)that adds visual indenting assistance, warning reports, and color highlighting.
如果您有一个兼容**ANSI**的终端,那么你就应该使用这个[增强版的`eval.rb`](http://www.rubyist.net/~slagell/ruby/eval.txt)。(如果你运行的是**UNIX**系列的系统,这几乎是肯定的;在旧版本的**DOS**下,那么你需要安装`ANSI.SYS`或`ANSI.COM`;不幸的是,**Windows XP**现在几乎还不可能实现这一点了)。增强版的`eval.rb`增加了视觉缩进帮助,警告提醒以及颜色高亮。
Otherwise, look in the `sample` subdirectory of the ruby distribution for the non-ANSI version that works on any terminal. Here is a short `eval.rb` session:
如果不是的话,请查看在任何终端上工作的**非ANSI**版本的**Ruby**的`sample`子目录。以下是一个简短的`eval.rb`会话:
```% ruby eval.rb
ruby> puts "Hello, world."
Hello, world.
nil
ruby> exit
```
`hello world` is produced by `puts`. The next line, in this case `nil`, reports on whatever was last evaluated; ruby does not distinguish between *statements* and *expressions*, so evaluating a piece of code basically means the same thing as executing it.
`hello world`是由`puts`产生的。在这个例子中下一行是`nil`,它代表最后一次计算的结果;**Ruby**没有区分语句和表达式,因此对一段代码进行计算基本上等同于执行它。
Here, `nil` indicates that `puts` does not return a meaningful value. Note that we can leave this interpreter loop by saying `exit`, although `^D` still works too.
这里的`nil`表示`puts`没有返回一个有意义的值。注意,我们可以通过`exit`命令来离开这个解释器交互环境,或者也使用之前的`Ctrl+D`。
Throughout this guide, "`ruby>`" denotes the input prompt for our useful little `eval.rb` program.
在本指南中,当我们正在运行`eval.rb`这个有用的程序时,就会有`ruby>`这个输入提示。
[上一章 起步](./getstarted.md "起步")
[下一章 字符串](./strings.md "字符串")
================================================
FILE: markdown/getstarted.md
================================================
# 起步
**Getting started**
**起步**
First, you'll want to check whether ruby is installed. From the shell prompt (denoted here by "%", so don't type the %), type
首先,如果你想检测**Ruby**是否已经安装,在**提示符**中输入:
`ruby -v`
(-v tells the interpreter to print the version of ruby), then press the Enter key. If ruby is installed, you will see a message something like the following:
(`-v`表示让**解释器**打印出当前**Ruby**的版本)
然后按下**回车键**。如果**Ruby**已经安装,你将会看到类似下面这样的信息:
```
ruby -v
ruby 2.1.0p0 (2013-12-25 revision 44422) [x86_64-linux]
```
If ruby is not installed, you can ask your administrator to install it, or you can do it yourself, since ruby is free software with no restrictions on its installation or use.
如果**Ruby**还没有安装,那么你可以选择自己动手安装,或者向计算机管理员寻求帮助。**Ruby**是一个**自由软件**,任何人都可以随意安装和使用。
Now, let's play with ruby. You can place a ruby program directly on the command line using the -e option:
现在,让我们来把玩一下**Ruby**。你可以在**命令行中**用`-e`选项来直接执行**Ruby**程序。
```
ruby -e 'puts "hello world"'
hello world
```
More conventionally, a ruby program can be stored in a file.
更传统一点,**Ruby**程序可以被保存在文件中。
```
echo "puts 'hello world'" > hello.rb
ruby hello.rb
hello world**
```
When writing more substantial code than this, you will want to use a real text editor!
你编写的代码量远超上面的示例时,你可能想到是时候使用一个**文本编辑器**了。
Some surprisingly complex and useful things can be done with miniature programs that fit in a command line.
命令行中的小程序可以用来完成一些非常复杂和有用的操作。
For example, this one replaces foo with bar in all C source and header files in the current working directory, backing up the original files with ".bak" appended:
举个例子,这个程序会将当前目录中的**C语言源文件**和**头文件**中的**foo**替换为**bar**。
`ruby -i.bak -pe 'sub "foo", "bar"' *.[ch]`
This program works like the UNIX cat command (but works slower than cat):
而这个程序的作用则有点像**UNIX**中的**cat**命令(但是处理过程比**cat**慢)。
`ruby -pe 0 file`
[上一章 Ruby是什么?](./index.md "Ruby是什么?")
[下一章 简单示例](./examples.md "简单示例")
================================================
FILE: markdown/globalvars.md
================================================
# 全局变量
**Global variables**
**全局变量**
A global variable has a name beginning with $.
**全局变量**的名字以`$`开头。
It can be referred to from anywhere in a program. Before initialization, a global variable has the special value nil.
你可以在程序的任何地方引用**全局变量**。在对其进行初始化之前,一个全局变量的值是特殊的`nil`值。
```
ruby> $foo
nil
ruby> $foo = 5
5
ruby> $foo
5
```
Global variables should be used sparingly.
应当谨慎使用**全局变量**。
They are dangerous because they can be written to from anywhere.
全局变量非常危险,因为它们可以在任何地方被改写。
Overuse of globals can make isolating bugs difficult; it also tends to indicate that the design of a program has not been carefully thought out.
过度使用**全局变量**会使隔离Bug变得很困难;它也倾向于表明一个程序的设计并没有经过仔细的考虑。
Whenever you do find it necessary to use a global variable, be sure to give it a descriptive name that is unlikely to be inadvertently used for something else later (calling it something like $foo as above is probably a bad idea).
无论何时,当你发现确实有必要使用**全局变量**时,一定要给它一个描述性的名称,这个名称不太可能在以后因为其他事情而无意中使用它(将其命名为`$foo`很可能是一个坏主意)。
One nice feature of a global variable is that it can be traced; you can specify a procedure which is invoked whenever the value of the variable is changed.
**全局变量**的一个很好的特性是它可以被跟踪;你可以指定一个**过程**,该**过程**在变量的值被更改时被调用。
```
ruby> trace_var :$x, proc{puts "$x is now #{$x}"}
nil
ruby> $x = 5
$x is now 5
5
```
When a global variable has been rigged to work as a trigger to invoke a procedure whenever changed, we sometimes call it an active variable.
当一个**全局变量**被操纵,作为触发器来调用一个过程时,我们有时会把它称为一个**活动变量**。
For instance, it might be useful for keeping a GUI display up to date.
例如,对于保持GUI展示最新内容,全局变量可能有用。
There is a collection of special variables whose names consist of a dollar sign ($) followed by a single character.
有一组特殊的变量,它们的名字由一个美元符号(`$`)组成,后面跟着一个字符。
For example, $$ contains the process id of the ruby interpreter, and is read-only. Here are the major system variables:
例如,`$$`包含**Ruby**解释器的进程id,并且是只读的。以下是主要的系统变量:
| 标识符 | 类型 |
| ---: | --------------------: |
| $! | 最新的错误消息 |
| $@ | 错误的位置 |
| $_ | 最后读取的字符串 |
| $. | 解释器读取的最后的行号 |
| $& | 最后匹配的正则表达式字符串 |
| $~ | 最后的正则表达式匹配,子表达式数组 |
| $n | 最后匹配的第N个子表达式 (同$~[n]) |
| $= | 不区分大小写的标记 |
| $/ | 输入记录分隔符 |
| $\ | 输出记录分隔符 |
| $0 | Ruby脚本文件的名字 |
| $* | 命令行参数 |
| $$ | 解释器进程ID |
| $? | 执行子进程的最后退出状态 |
In the above, $_ and $~ have local scope.
上面的`$_`和`$~`都有局部作用域。
Their names suggest they should be global, but they are much more useful this way, and there are historical reasons for using these names.
它们的名称表明它们应该是全局的,但是它们在这种方式中更有用,使用这些名字有一些历史原因。
[上一章 变量](./variables.md "Variables")
[下一章 实例变量](./instancevars.md "Instance variables")
================================================
FILE: markdown/index.md
================================================
# Ruby是什么?
**What is ruby?**
**Ruby是什么?**
Ruby is "an interpreted scripting language for quick and easy object-oriented programming" -- what does this mean?
**Ruby**是一门灵活简单的**面向对象**的**解释型脚本语言**。这些意味着什么?
**interpreted scripting language**:
**解释型脚本语言:**
ability to make operating system calls directly
- 直接执行操作系统调用的能力
powerful string operations and regular expressions
- 强大的字符操作和正则表达式
immediate feedback during development
- 开发过程中的即时反馈
**quick and easy**:
**灵活简单:**
variable declarations are unnecessary
- 变量无需声明
variables are not typed
- 变量不是类型化的
syntax is simple and consistent
- 语法简单一致
memory management is automatic
- 自动内存管理
**object oriented programming:**
**面向对象编程:**
everything is an object
- 一切皆为对象
classes, methods, inheritance, etc.
- 类,方法,继承等等
singleton methods
- 单例方法
"mixin" functionality by module
- 模块的混入功能
iterators and closures
- 迭代器和闭包
**also:**
**以及:**
multiple precision integers
- 多精度整数
convenient exception processing
- 方便的异常处理
dynamic loading
- 动态加载
threading support
- 支持线程
If you are unfamiliar with some of the concepts above, read on, and don't worry. The mantra of the ruby language is quick and easy.
如果你对上面的某些概念不熟悉,不必担心,继续往下看即可,因为**Ruby**的"**咒语**"灵活而简单。
[上一章 目录](../README.md "目录")
[下一章 起步](./getstarted.md "起步")
================================================
FILE: markdown/inheritance.md
================================================
# 继承
**Inheritance**
**继承**
Our classification of objects in everyday life is naturally hierarchical.
我们在日常生活中对物品的分类是自然分层的。
We know that all cats are mammals, and all mammals are animals. Smaller classes inherit characteristics from the larger classes to which they belong. If all mammals breathe, then all cats breathe.
我们知道,所有的**猫**(Cat)都是**哺乳动物**(Mammal),而所有的**哺乳动物**都是**动物**。较小的类继承了它们所属的较大类的特征。如果所有的**哺乳动物**都呼吸,那么所有的**猫**也都需要呼吸。
We can express this concept in ruby:
我们可以用**Ruby**来表达这个概念:
```
ruby> class Mammal
| def breathe
| puts "inhale and exhale"
| end
| end
nil
ruby> class Cat<Mammal
| def speak
| puts "Meow"
| end
| end
nil
```
Though we didn't specify how a `Cat` should breathe, every cat will inherit that behavior from the `Mammal` class since `Cat` was defined as a subclass of `Mammal`. (In OO terminology, the smaller class is a *subclass* and the larger class is a *superclass*.) Hence from a programmer's standpoint, cats get the ability to breathe for free; after we add a `speak` method, our cats can both breathe and speak.
尽管我们没有具体说明一只`Cat`应该如何呼吸,但每只`Cat`都会继承`Mammal`的行为,因为`Cat`被定义为`Mammal`的一个子类。(在**OO**的术语中,较小的类是`子类`,较大的类是`父类`。)因此,从程序员的角度来看,猫咪可以自由地呼吸。在我们添加了`speak`方法之后,我们的猫既可以呼吸也可以叫了。
```
ruby> tama = Cat.new
#<Cat:0xbd80e8>
ruby> tama.breathe
inhale and exhale
nil
ruby> tama.speak
Meow
nil
```
There will be situations where certain properties of the superclass should not be inherited by a particular subclass. Though birds generally know how to fly, penguins are a flightless subclass of birds.
在某些情况下,**父类**的某些属性不应该由特定的**子类**继承。尽管鸟类一般都知道如何飞行,但是企鹅是鸟类的一个不能飞行的子类。
```
ruby> class Bird
| def preen
| puts "I am cleaning my feathers."
| end
| def fly
| puts "I am flying."
| end
| end
nil
ruby> class Penguin<Bird
| def fly
| fail "Sorry. I'd rather swim."
| end
| end
nil
```
Rather than exhaustively define every characteristic of every new class, we need only to append or to redefine the differences between each subclass and its superclass.
相比详尽地定义每一个新类的每一个特征,我们仅仅需要**添加**或者**重定义**每个和它的父类之间的差异。
This use of inheritance is sometimes called *differential programming*. It is one of the benefits of object-oriented programming.
这种**继承**的使用有时被称为**微分编程**,这是面向对象编程的好处之一。
[上一章 类](./classes.md "Classes")
[下一章 重新定义方法](./redefinemethods.md "Redefinition of methods")
================================================
FILE: markdown/instancevars.md
================================================
# 实例变量
**Instance variables**
**实例变量**
An instance variable has a name beginning with @, and its scope is confined to whatever object self refers to.
一个**实例变量**的名称以`@`开头,而且它的作用域仅限于该对象自身。
Two different objects, even if they belong to the same class, are allowed to have different values for their instance variables.
2个不同的对象,尽管它们属于同一个类,允许对**实例变量**有不同的值。
From outside the object, instance variables cannot be altered or even observed (i.e., ruby's instance variables are never public) except by whatever methods are explicitly provided by the programmer.
对于外部对象,除了由程序员明确提供的方法之外,**实例变量**不可改变,甚至不可见(即,**Ruby**的实例变量从来不是公开的)。
As with globals, instance variables have the nil value until they are initialized.
与**全局变量**一样,**实例变量**在初始化之前的值为`nil`。
Instance variables do not need to be declared.
**实例变量**不需要声明。
This indicates a flexible object structure; in fact, each instance variable is dynamically appended to an object when it is first assigned.
这表明了一个灵活的对象结构,事实上,每个**实例变量**都是在第一次被赋值时被动态地追加到一个对象中。
```
ruby> class InstTest
| def set_foo(n)
| @foo = n
| end
| def set_bar(n)
| @bar = n
| end
| end
nil
ruby> i = InstTest.new
#<InstTest:0x83678>
ruby> i.set_foo(2)
2
ruby> i
#<InstTest:0x83678 @foo=2>
ruby> i.set_bar(4)
4
ruby> i
#<InstTest:0x83678 @foo=2, @bar=4>
```
Notice above that i does not report a value for @bar until after the set_bar method is invoked.
注意,上面的`i`在调用`set-bar`方法之前并没有返回@bar的值。
[上一章 全局变量](./globalvars.md "Global variables")
[下一章 局部变量](./localvars.md "Local variables")
================================================
FILE: markdown/iterators.md
================================================
# 迭代器
**Iterators**
**迭代器**
Iterators are not an original concept with ruby.
**迭代器**并不是**Ruby**的原创概念。
They are in common use in object-oriented languages.
它们在面向对象的语言中是通用的。
They are also used in Lisp, though there they are not called iterators. However the concept of iterator is an unfamiliar one for many so it should be explained in more detail.
它们也被用于**Lisp**中,尽管不被叫做迭代器。然而,**迭代器**的概念对于很多人来说都是陌生的,所以应该更详细地解释它。
The verb iterate means to do the same thing many times, you know, so an iterator is something that does the same thing many times.
动词**迭代**意味着多次执行相同的操作,所以**迭代器**就是多次执行相同操作的东西。
When we write code, we need loops in various situations. In C, we code them using for or while. For example,
当我们编写代码时,我们需要在不同的情况下循环。在**C**语言中,我们用`for`或者`while`来编写它们,举个例子:
```
char *str;
for (str = "abcdefg"; *str != '\0'; str++) {
/* process a character here */
}
```
C's for(...) syntax provides an abstraction to help with the creation of a loop, but the test of *str against a null character requires the programmer to know details about the internal structure of a string.
**C**的`for(…)`语法提供了一个抽象来帮助创建循环,但是,要测试`*str`是否为一个空的字符串,则要求程序员了解一个字符串内部结构的细节究竟是怎样的。
This makes C feel like a low-level language. Higher level languages are marked by their more flexible support for iteration. Consider the following sh shell script:
这让**C**感觉像是一种低级语言,更高级别的语言则通过对**迭代**的显式支持使其更加灵活。考虑下面的`shell`脚本:
```
#!/bin/sh
for i in *.[ch]; do
# ... 这里是对每个文件要执行的操作
done
```
All the C source and header files in the current directory are processed, and the command shell handles the details of picking up and substituting file names one by one. I think this is working at a higher level than C, don't you?
当前目录中的所有**C**源文件和头文件都被处理了,并且命令shell将处理获取和替换文件名的详细信息。相比**C**,我认为这是在更高的层次上工作,你觉得呢?
But there is more to consider: while it is fine for a language to provide iterators for built-in data types, it is a disappointment if we must go back to writing low level loops to iterate over our own data types. In OOP, users often define one data type after another, so this could be a serious problem.
但是这里仍有一些问题要考虑:对于一种语言来说,为内置数据类型提供迭代器是很好的,如果我们必须回到编写低级别循环来迭代我们自己的数据类型,这将是一个令人失望的事情。在**OOP**中,用户经常定义一个数据类型,因此这可能是一个严重的问题。
So every OOP language includes some facilities for iteration. Some languages provide a special class for this purpose; ruby allows us to define iterators directly.
所以每个**OOP**语言都包含了一些用于迭代的工具,有一些语言提供了用于迭代的类,**Ruby**则允许我们直接定义**迭代器**。
Ruby's String type has some useful iterators:
**Ruby**的**字符串**类型就有一些有用的迭代器:
```
ruby> "abc".each_byte{|c| printf "<%c>", c}; print "\n"
<a><b><c>
nil
```
each_byte is an iterator for each character in the string. Each character is substituted into the local variable c. This can be translated into something that looks a lot like C code ...
`each_byte`是字符串中的每个字符的**迭代器**。每个字符都被局部变量`c`替换,这可以被翻译成看起来很像**C**代码的东西。
```
ruby> s="abc";i=0
0
ruby> while i<s.length
| printf "<%c>", s[i]; i+=1
| end; print "\n"
<a><b><c>
nil
```
... however, the each_byte iterator is both conceptually simpler and more likely to continue to work even if the String class happens to be radically modified in the future.
然而,迭代器`each_byte`在概念上都更简单,即使字符串类在将来会被彻底修改,它仍可能会继续工作。
One benefit of iterators is that they tend to be robust in the face of such changes; indeed that is a characteristic of good code in general. (Yes, have patience, we're about to talk about what classes are, too.)
**迭代器**的一个优点是,面对这样的变化时,它们往往是健壮的,这确实是好代码所拥有的特点。(是的,要有耐心,我们也要谈谈课程的内容。)
Another iterator of String is each_line.
字符串的另一个**迭代器**是`each_line`。
```
ruby> "a\nb\nc\n".each_line{|l| print l}
a
b
c
nil
```
The tasks that would take most of the programming effort in C (finding line delimiters, generating substrings, etc.) are easily tackled using iterators.
使用**迭代器**可以很容易地完成**C**语言(查找行分隔符、生成子字符串等)的大多数编程工作。
The for statement appearing in the previous chapter does iteration by way of an each iterator. String's each works the same as each_line, so let's rewrite the above example with for:
在前一章节中出现的`for`语句通过**迭代器**的方法对每一个进行迭代,
```
ruby> for l in "a\nb\nc\n"
| print l
| end
a
b
c
nil
```
We can use a control structure retry in conjunction with an iterated loop, and it will retry the loop from the beginning.
我们可以将迭代器循环和控制结构`retry`结合使用,它会从头开始重新尝试循环。
```
ruby> c=0
0
ruby> for i in 0..4
| print i
| if i == 2 and c == 0
| c = 1
| print "\n"
| retry
| end
| end; print "\n"
012
01234
nil
```
Replacing retry in the above example with redo causes just the current iteration of the loop to be redone, with this output:
在上面的例子中,用`redo`来替换`retry`,只会导致循环的当前迭代被重新执行,会有如下输出:
**012**
**234**
yield occurs sometimes in a definition of an iterator.
`yield`有时出现于迭代器的定义中。
yield moves control to the block of code that is passed to the iterator (this will be explored in more detail in the chapter about procedure objects).
`yield`将控制权移交到传递给**迭代器**的代码块(这将在关于过程对象的章节中更详细地探讨)。
The following example defines an iterator repeat, which repeats a block of code the number of times specified in an argument.
下面的示例定义了一个重复执行的`迭代器`,它重复一个代码块,重复的次数由传递给它的参数指定。
```
ruby> def repeat(num)
| while num > 0
| yield
| num -= 1
| end
| end
nil
ruby> repeat(3) { puts "foo" }
foo
foo
foo
nil
```
With retry, one can define an iterator which works something like ruby's standard while.
通过`retry`,可以定义一个**迭代器**,它的工作方式类似于**Ruby**标准的`while`。
```
ruby> def WHILE(cond)
| return if not cond
| yield
| retry
| end
nil
ruby> i=0; WHILE(i<3) { print i; i+=1 }
012 nil
```
Do you understand what an iterator is? There are a few restrictions, but you can write your original iterators; and in fact, whenever you define a new data type, it is often convenient to define suitable iterators to go with it.
你明白**迭代器**是什么了么?这里有几个条件,但是你可以编写你自己的**迭代器**原型。事实上,无论在什么时候定义一个新的数据类型,定义合适的迭代器通常都是很方便的。
In this sense, the above examples are not terribly useful. We can talk about practical iterators after we have a better understanding of what classes are.
从这个意义上来说,上面的例子并不是很有用。在我们对课程有了更好的理解之后,我们可以讨论一些实际的迭代器。
[上一章 流程控制](./control.md "Control structures")
[下一章 面向对象的思考](./oothinking.md "Object-oriented thinking")
================================================
FILE: markdown/localvars.md
================================================
# 局部变量
**Local variables**
**局部变量**
A local variable has a name starting with a lower case letter or an underscore character (_).
一个**局部变量**的名称以小写字母或下划线`_`开头。
Local variables do not, like globals and instance variables, have the value nil before initialization:
不同于**全局变量**和**实例变量**,**局部变量**初始化之前并没有默认的`nil`值。
```
ruby> $foo
nil
ruby> @foo
nil
ruby> foo
ERR: (eval):1: undefined local variable or method `foo' for main(Object)
```
The first assignment you make to a local variable acts something like a declaration.
你对**局部变量**做的第一个赋值就像是一个声明。
If you refer to an uninitialized local variable, the ruby interpreter cannot be sure whether you are referencing a bogus variable; you might, for example, have misspelled a method name. Hence the rather nonspecific error message you see above.
如果你引用一个未初始化的**局部变量**,**Ruby**解释器无法确定你是否引用了一个伪变量。例如,你可能会拼错一个方法名。因此,您可以看到上面所看到的非特定的错误消息。
Generally, the scope of a local variable is one of
一般来说,**局部变量**的范围是
1. proc{ ... }
2. loop{ ... }
3. def ... end
4. class ... end
5. module ... end
6. 整个脚本 (除了上述情况之外)
In the next example, defined? is an operator which checks whether an identifier is defined.
接下来的示例中,`defined?`操作符用来检测标识符是否定义。
It returns a description of the identifier if it is defined, or nil otherwise.
如果标识符定义了,它将返回标识符,否则返回`nil`。
As you see, bar's scope is local to the loop; when the loop exits, bar is undefined.
如你所见,`bar`的作用域是`loop`,但`loop`退出,`bar`便成了未定义的。
```
ruby> foo = 44; puts foo; defined?(foo)
44
"local-variable"
ruby> loop{bar=45; puts bar; break}; defined?(bar)
45
nil
```
Procedure objects that live in the same scope share whatever local variables also belong to that scope. Here, the local variable bar is shared by main and the procedure objects p1 and p2:
在相同范围内的过程对象共享也属于该范围的任何局部变量。此处,局部变量`bar`被`main`以及过程对象`p1`、`p2`所共享。
```
ruby> bar=nil
nil
ruby> p1 = proc{|n| bar=n}
#<Proc:0x8deb0>
ruby> p2 = proc{bar}
#<Proc:0x8dce8>
ruby> p1.call(5)
5
ruby> bar
5
ruby> p2.call
5
```
Note that the "bar=nil" at the beginning cannot be omitted; it ensures that the scope of bar will encompass p1 and p2.
注意最开始的`bar=nil`不能省略,它确保了`bar`的范围将包括`p1`和`p2`。
Otherwise p1 and p2 would each end up with its own local variable bar, and calling p2 would have resulted in an "undefined local variable or method" error.
否则,`p1`和`p2`将各自使用其局部变量`bar`,而调用p2将导致"**undefined local variable or method**"错误。
We could have said bar=0 instead, but using nil is a courtesy to others who will read your code later.
我们也可以使用`bar=0`,但是使用`nil`显得对阅读你代码的人更友好。
It indicates fairly clearly that you are only establishing scope, because the value being assigned is not intended to be meaningful.
它很清楚地表明你只是在建立作用域,因为被分配的值并不是有意义的。
A powerful feature of procedure objects follows from their ability to be passed as arguments: shared local variables remain valid even when they are passed out of the original scope.
过程对象的一个强大功能来自它们可以作为参数被传递的能力:即使在最初的作用域之外,共享的局部变量仍然有效。
```
ruby> def box
contents = nil
get = proc{contents}
set = proc{|n| contents = n}
return get, set
end
nil
ruby> reader, writer = box
[#<Proc:0x40170fc0>, #<Proc:0x40170fac>]
ruby> reader.call
nil
ruby> writer.call(2)
2
ruby> reader.call
2
```
Ruby is particularly smart about scope. It is evident in our example that the contents variable is being shared between the reader and writer.
**Ruby**在作用域方面特别聪明。在我们的示例中很明显,变量`contents`是在**reader**和**writer**之间共享的。
But we can also manufacture multiple reader-writer pairs using box as defined above; each pair shares a contents variable, and the pairs do not interfere with each other.
但是,我们也可以使用如上所定义的**box**来制造多个**reader-writer**对。
```
ruby> reader_1, writer_1 = box
[#<Proc:0x40172820>, #<Proc:0x4017280c>]
ruby> reader_2, writer_2 = box
[#<Proc:0x40172668>, #<Proc:0x40172654>]
ruby> writer_1.call(99)
99
ruby> reader_1.call
99
ruby> reader_2.call # nothing is in this box yet
nil
```
This kind of programming could be considered a perverse little object-oriented framework.
这种编程可以被认为是一个不合理的面向对象的框架。
The box method acts something like a class, with get and set serving as methods (except those aren't really the method names, which could vary with each box instance) and contents being the lone instance variable.
**box**方法的作用类似于一个类,**get**和**set**作为方法(但是它们并不是真正的方法名,它们可能会随着每个box实例的不同而不同),而`contents`是唯一的实例变量。
Of course, using ruby's legitimate class framework leads to much more readable code.
当然,使用**Ruby**的合法类框架会得到可读性更强的代码。
[上一章 实例变量](./instancevars.md "Instance variables")
[下一章 类常量](./constants.md "Class constants")
================================================
FILE: markdown/methods.md
================================================
# 方法
**Methods**
**方法**
What is a method? In OO programming, we don't think of operating on data directly from outside an object; rather, objects have some understanding of how to operate on themselves (when asked nicely to do so).
方法是什么呢?在**OO编程**中,我们不考虑直接从对象外部操作数据。相反,对象知道该如何操作它自己(当被要求做得很好时)。
You might say we pass messages to an object, and those messages will generally elicit some kind of an action or meaningful reply.
你可能会说我们将消息传递给了一个对象,这些消息通常会引发某种行为或有意义的回应。
This ought to happen without our necessarily knowing or caring how the object really works inside. The tasks we are allowed to ask an object to perform (or equivalently, the messages it understands) are that object's methods.
这应该发生在我们不需要知道或关心对象如何在内部运作的情况下。我们允许请求对象执行的任务(或者是它所理解的消息)是对象的方法。
In ruby, we invoke a method of an object with dot notation (just as in C++ or Java). The object being talked to is named to the left of the dot.
在`Ruby`中,我们通过点号`.`来调用一个对象的方法(就像C++或Java)。讨论的对象在点号`.`左边有一个名字。
```
ruby> "abcdef".length
6
```
Intuitively, this string object is being asked how long it is. Technically, we are invoking the length method of the object "abcdef".
直观上看,我们正在询问这个字符串对象它的长度是多少。在技术上来说,我们正在调用对象"abcdef"的`length`方法。
Other objects may have a slightly different interpretation of length, or none at all.
其他对象对长度的解释,可能有稍微的不同,或者完全不相同。
Decisions about how to respond to a message are made on the fly, during program execution, and the action taken may change depending on what a variable refers to.
关于如何对消息作出响应的决定是在程序执行期间进行的,而在程序执行期间,程序所采取的操作可能会随着变量的引用而发生变化。
```
ruby> foo = "abc"
"abc"
ruby> foo.length
3
ruby> foo = ["abcde", "fghij"]
["abcde", "fghij"]
ruby> foo.length
2
```
What we mean by length can vary depending on what object we are talking about.
对我们所说的长度有何种不同的理解,取决于我们正在谈论的对象。
The first time we ask foo for its length in the above example, it refers to a simple string, and there can only be one sensible answer.
在上面的例子中,我们第1次询问foo的长度,它指向的是一个简单的字符串,而且只能有一个合理的答案。
The second time, foo refers to an array, and we might reasonably think of its length as either 2, 5, or 10; but the most generally applicable answer is of course 2 (the other kinds of length can be figured out if wished).
第2次foo指向来一个数组,我们可以合理地把它的长度看成是**2,5**或**10**。
```
ruby> foo[0].length
5
ruby> foo[0].length + foo[1].length
10
```
The thing to notice here is that an array knows something about what it means to be an array.
这里要值得注意的是,数组对象知道,对于一个数组而言,`length`的含义是什么。
Pieces of data in ruby carry such knowledge with them, so that the demands made on them can automatically be satisfied in the various appropriate ways.
**Ruby**中的数据块携带了这样的知识,因此,可以通过各种适当的方式自动满足他们的要求。
This relieves the programmer from the burden of memorizing a great many specific function names, because a relatively small number of method names, corresponding to concepts that we know how to express in natural language, can be applied to different kinds of data and the results will be what we expect.
这使程序员免除了记忆许多特定函数名的负担,因为相对较少的方法名,对应于我们知道如何用自然语言表达的概念,可以应用于不同类型的数据,而其结果也将是我们所期望的。
This feature of OO programming languages (which, IMHO, Java has done a poor job of exploiting) is called polymorphism.
**OO编程**语言的这一特性(即IMHO,Java在开发方面做得很差)被称为**多态**。
When an object receives a message that it does not understand, an error is "raised":
当一个对象接收到了一个它不能理解的消息,一个错误便出现了。
```
ruby> foo = 5
5
ruby> foo.length
ERR: (eval):1: undefined method `length' for 5(Fixnum)
```
So it is necessary to know what methods are acceptable to an object, though we need not know how the methods are processed.
所以尽管我们不需要知道一个对象是如何处理方法的,但知道它可以接收何种方法仍是很有必要的,
If arguments are given to a method, they are generally surrounded by parentheses,
如果参数被提供给一个方法,它们通常都被圆括号括起来`()`,
```
object.method(arg1, arg2)
```
but they can be omitted if doing so does not cause ambiguity.
但如果省略圆括号而不会造成歧义,就可以省略它们。
```
object.method arg1, arg2
```
There is a special variable self in ruby; it refers to whatever object calls a method. This happens so often that for convenience the "self." may be omitted from method calls from an object to itself:
**Ruby**中有一个特殊变量`self`,它指向的是调用方法的任何对象。这种情况经常发生,为了方便,对象的方法调用中可以忽略“**self**”。
```
self.method_name(args...)
```
is the same as
它等同于
```
method_name(args...)
```
What we would think of traditionally as a function call is just this abbreviated way of writing method invocations by self.
我们通常认为,函数调用是由self来编写方法调用的一种缩写形式。
This makes ruby what is called a pure object oriented language. Still, functional methods behave quite similarly to the functions in other programming languages for the benefit of those who do not grok how function calls are really object methods in ruby. We can speak of functions as if they were not really object methods if we want to.
这使得**Ruby**成为一种纯粹的面向对象语言。尽管如此,函数方法与其他编程语言中的函数非常相似,这对那些不知道**Ruby**中是对象方法是如何同函数方法一样被调用的人来说是有好处的。我们可以谈论函数,就好像它们不是真正的对象方法,如果我们想的话。
[上一章 面向对象的思考](./oothinking.md "Object-oriented thinking")
[下一章 类](./classes.md "Classes")
================================================
FILE: markdown/misc.md
================================================
# 其他
**Nuts and bolts**
**其他**
This chapter addresses a few practical issues.
这一章解决了一些实际问题。
**Statement delimiters**
**语句分隔符**
Some languages require some kind of punctuation, often a semicolon (;), to end each statement in a program.
有些语言需要某种标点符号,通常是分号(`;`),以结束程序中的每个语句。
Ruby instead follows the convention used in shells like sh and csh.
**Ruby**替换了了在像sh和csh这样的shell中使用的约定。
Multiple statements on one line must be separated by semicolons, but they are not required at the end of a line;
同一行的多条语句必须用分号分隔,但在一行的末尾不需要;
a linefeed is treated like a semicolon. If a line ends with a backslash (\\), the linefeed following it is ignored; this allows you to have a single logical line that spans several lines.
一个换行符被当作分号对待。如果一行以反斜线(`\`)结尾,下面的换行符将被忽略。这允许你有一个跨越多行代码的逻辑行。
**Comments**
**注释**
Why write comments?
为何要写注释?
Although well written code tends to be self-documenting, it is often helpful to scribble in the margins, and it can be a mistake to believe that others will be able to look at your code and immediately see it the way you do.
尽管好的代码能够自我说明,但在空白处乱涂乱画通常也是有帮助的,如果相信其他人能够看到你的代码,并能一下就理解你的代码,那就大错特错了。
Besides, for practical purposes, you yourself are a different person within a few days anyway; which of us hasn't gone back to fix or enhance a program after the passage of time and said, I know I wrote this, but what in blazes does it mean?
此外,出于实用的目的,你自己在几天之内就会将之前写的代码遗忘。我们中的哪一个人在经过了一段时间后没有回过头去修复或加强一个项目,我知道我写了这个代码,但这到底是什么意思呢?
Some experienced programmers will point out, quite correctly, that contradictory or outdated comments can be worse than none at all.
一些有经验的程序员会指出,毫无疑问的是,矛盾或过时的注释可能比没有任何东西更糟糕。
Certainly, comments shouldn't be a substitute for readable code;
没错,注释不应该是可读代码的替代品;
if your code is unclear, it's probably also buggy.
如果你的代码不清晰,那它可能也会有问题
You may find that you need to comment more while you are learning ruby, and then less as you become better at expressing your ideas in simple, elegant, readable code.
你可能会发现,在学习**Ruby**时,你需要更多地注释,而当你在简单、优雅、可读的代码中表达自己的想法时,注释就会变得更少。
Ruby follows a common scripting convention, which is to use a pound symbol (#) to denote the start of a comment.
**Ruby**遵循一种常见的脚本约定,即使用磅符号(`#`)来表示注释的开始。
Anything following an unquoted #, to the end of the line on which it appears, is ignored by the interpreter.
任何被`#`引用,到其出现的行尾的内容,都会被解释器忽略。
Also, to facilitate large comment blocks, the ruby interpreter also ignores anything between a line starting with "=begin" and another line starting with "=end".
此外,为了方便大型的注释块,**Ruby**解释器还忽略了从“`=begin`”开始的一行和从“`=end`”开始的另一行。
```
#!/usr/bin/env ruby
=begin
**********************************************************************
This is a comment block, something you write for the benefit of
human readers (including yourself). The interpreter ignores it.
There is no need for a '#' at the start of every line.
**********************************************************************
=end
```
**Organizing your code**
**组织你的代码**
Ruby's unusually high level of dynamism means that classes, modules, and methods exist only after their defining code runs.
**Ruby**异常高的动态级别意味着类、模块和方法只在它们定义的代码运行之后才存在。
If you're used to programming in a more static language, this can sometimes lead to surprises.
如果你习惯于用一种更静态的语言编程,这有时会导致意外。
```
# The below results in an "undefined method" error:
puts successor(3)
def successor(x)
x + 1
end
```
Although the interpreter checks over the entire script file for syntax before executing it, the def successor ... end code has to actually run in order to create the successor method. So the order in which you arrange a script can matter.
尽管解释器在执行脚本之前将检查整个脚本的语法,`def successor … end`为了创建后续的方法,终端代码必须实际运行。
This does not, as it might seem at first glance, force you to organize your code in a strictly bottom-up fashion.
这并不像乍看上去那样,强迫你以一种严格的自下而上的方式组织您的代码。
When the interpreter encounters a method definition, it can safely include undefined references, as long as you can be sure they will be defined by the time the method is actually invoked:
当解释器遇到方法定义时,它可以安全地包含未定义的引用,只要你确信它们将在方法实际被调用的时间被定义:
```
# Conversion of fahrenheit to celsius, broken
# down into two steps.
def f_to_c(f)
scale(f - 32.0) # This is a forward reference, but it's okay.
end
def scale(x)
x * 5.0 / 9.0
end
printf "%.1f is a comfortable temperature.\n", f_to_c(72.3)
```
So while this may seem less convenient than what you may be used to in Perl or Java, it is less restrictive than trying to write C without prototypes (which would require you to always maintain a partial ordering of what references what).
因此,虽然这看起来不像你在**Perl**或**Java**中所使用的那样方便,但它没有尝试编写没有原型的C(这将要求你始终保持对引用的部分顺序的部分排序)。
Putting top-level code at the bottom of a source file always works. And even this is less of an annoyance than it might at first seem.
在源文件的底部放置顶级代码总是有效的。即使这样,也不像乍看起来那样令人烦恼。
A sensible and painless way to enforce the behavior you want is to define a main function at the top of the file, and call it from the bottom.
执行你想要的行为的一种明智而无痛的方法是在文件的顶部定义一个主函数,并从底部调用它。
```
#!/usr/bin/env ruby
def main
# Express the top level logic here...
end
# ... put support code here, organized as you see fit ...
main # ... and start execution here.
```
It also helps that ruby provides tools for breaking complicated programs into readable, reusable, logically related chunks.
**Ruby**还提供了一些工具,可以将复杂的程序分解为可读的、可重用的、逻辑相关的块。
We have already seen the use of include for accessing modules.
我们已经看到了用于访问模块的`include`。
You will also find the load and require facilities useful.
您还会发现`load`和`require`的有用的工具。
load works as if the file it refers to were copied and pasted in (something like the #include preprocessor directive in C). require is somewhat more sophisticated, causing code to be loaded at most once and only when needed.
`load`工作的方式就像它所引用的文件被复制和粘贴到(类似于**C**中的预处理器指令)一样,`require`更复杂一些,只需要在需要时才加载代码。
**That's it...**
**就是这样**
This tutorial should be enough to get you started writing programs in Ruby.
本教程应该足以让你开始用**Ruby**编写程序。
As further questions arise, you can get more help from the user community, and from an always-growing body of printed and online resources.
其他的信息,你可以从用户社区获得更多的帮助,从不断增长的出版物和在线资源中获得更多的帮助。
Good luck, and happy coding!
祝你好运,编程快乐!
[上一章 对象初始化](./objinitialization.md "Object initialization")
[下一章 关于本指南](./about.md "About the guide")
================================================
FILE: markdown/modules.md
================================================
# 模块
**Modules**
**模块**
Modules in ruby are similar to classes, except:
**Ruby**中的**模块**同**类**非常相似,但有些许不同:
- A module can have no instances.
- 模块不能有实例。
- A module can have no subclasses.
- 模块不能有子类。
- A module is defined by module ... end.
- 模块是通过`module … end`定义的。
Actually... the Module class of module is the superclass of the Class class of class. Got that? No? Let's move on.
实际上,module的`Module`类是class的`Class`类的父类。明白了吗?没有?让我们继续。
There are two typical uses of modules. One is to collect related methods and constants in a central location. The Math module in ruby's standard library plays such a role:
模块有两种典型的用法。其一是在一个集中的位置收集相关的方法和常量。**Ruby**标准库中的数学模块发挥了这样的作用:
```
ruby> Math.sqrt(2)
1.41421
ruby> Math::PI
3.14159
```
The :: operator tells the ruby interpreter which module it should consult for the value of a constant (conceivably, some module besides Math might mean something else by PI).
这个`::`操作符告诉**Ruby**解释器,它应该咨询哪个模块来得到一个常量的值(可以想象,除了**Math**之外的某个模块还可能用**PI**表达其他内容)。
If we want to refer to the methods or constants of a module directly without using ::, we can include that module:
如果我们想不使用`::`而是直接引用某个**模块**的**方法**或**常量**,那么我们可以`include`那个模块:
```
ruby> include Math
Object
ruby> sqrt(2)
1.41421
ruby> PI
3.14159
```
Another use of modules is called mixin. Some OO programming languages, including C++, allow multiple inheritance, that is, inheritance from more than one superclass.
另外一种使用模块的方法被称为**mixin**。许多**OO**编程语言,包括**C++**,允许**多重继承**,也就是说,从多个**父类**继承。
A real-world example of multiple inheritance is an alarm clock; you can think of alarm clocks as belonging to the class of clocks and also the class of things with buzzers.
**多重继承**的一个现实生活中的例子是闹钟。你可以把闹钟看作属于**钟**类,也可以看作属于**蜂鸣器**类。
Ruby purposely does not implement true multiple inheritance, but the mixin technique is a good alternative.
**Ruby**故意不实现真正的多重继承,但是**mixin**技术是一个不错的替代品。
Remember that modules cannot be instantiated or subclassed; but if we include a module in a class definition, its methods are effectively appended, or "mixed in", to the class.
记住,**模块**不能被**实例化**或**子类化**,但是如果我们在一个类定义中包含了模块,它的方法便被有效地附加或“**混合**”到了类中。
Mixin can be thought of as a way of asking for whatever particular properties we want to have.
**Mixin**可以被认为是一种请求任何我们想要的特定属性的方式。
For example, if a class has a working each method, mixing in the standard library's Enumerable module gives us sort and find methods for free.
比如,如果一个类有一个可工作的`each`方法,那么混合标准库中的`Enumerable`模块可以免费为我们提供`sort`和`find`方法。
This use of modules gives us the basic functionality of multiple inheritance but allows us to represent class relationships with a simple tree structure, and so simplifies the language implementation considerably (a similar choice was made by the designers of Java).
模块的使用提供了多重继承的基本功能,但允许我们用简单的树结构来表示类关系,这样就大大简化了语言的实现(**Java**设计者也做出了类似的选择)。
[上一章 单例方法](./singletonmethods.md "Singleton methods")
[下一章 过程对象](./procobjects.md "Procedure objects")
================================================
FILE: markdown/objinitialization.md
================================================
# 对象初始化
**Object initialization**
**对象初始化**
Our Fruit class from the previous chapter had two instance variables, one to describe the kind of fruit and another to describe its condition.
我们上一章节中的`Fruit`类有2个实例变量,其中一个描述了水果的种类,另外一个描述了环境。
It was only after writing a custom inspect method for the class that we realized it didn't make sense for a piece of fruit to lack those characteristics.
只有在为类写了一种自定义的`inspect`方法之后,我们才意识到,一种水果缺乏这种特性是没有意义的。
Fortunately, ruby provides a way to ensure that instance variables always get initialized.
幸运的是,**Ruby**提供了一种方法来确保实例变量总是被初始化。
The initialize method
`initialize`方法
Whenever Ruby creates a new object, it looks for a method named initialize and executes it.
当**Ruby**创建一个新的对象时,它会查找并运行一个名为`initialize`的方法。
So one simple thing we can do is use an initialize method to put default values into all the instance variables, so the inspect method will have something to say.
因此,我们可以做的一件简单的事情是使用`initialize`方法将默认值放入所有的实例变量中,因此`inspect`方法将会有一些内容。
```
ruby> class Fruit
| def initialize
| @kind = "apple"
| @condition = "ripe"
| end
| end
nil
ruby> f4 = Fruit.new
"a ripe apple"
```
Changing assumptions to requirements
改变需求的假设
There will be times when a default value doesn't make a lot of sense.
在某些情况下,默认值没有什么意义。
Is there such a thing as a default kind of fruit? It may be preferable to require that each piece of fruit have its kind specified at the time of its creation.
有什么东西是一种默认的水果吗?最好是要求每一种水果都在其诞生之时指定种类。
To do this, we would add a formal argument to the initialize method.
为了做到这一点,我们将向`initialize`方法添加一个正式的参数。
For reasons we won't get into here, arguments you supply to new are actually delivered to initialize.
由于一些原因我们此处不作深入探讨,你提供给`new`方法的参数实际上被传递给了`initalize`方法。
```
ruby> class Fruit
| def initialize( k )
| @kind = k
| @condition = "ripe"
| end
| end
nil
ruby> f5 = Fruit.new "mango"
"a ripe mango"
ruby> f6 = Fruit.new
ERR: (eval):1:in `initialize': wrong # of arguments(0 for 1)
```
**Flexible initialization**
**灵活的初始化**
Above we see that once an argument is associated with the initialize method, it can't be left off without generating an error.
上面我们看到,一旦一个参数与`initialize`方法相关联,如果不产生错误,它就不能被关闭。
If we want to be more considerate, we can use the argument if it is given, or fall back to default values otherwise.
如果我们想要更加周到,我们可以只在提供了参数时才使用它,否则就使用默认值。
```
ruby> class Fruit
| def initialize( k="apple" )
| @kind = k
| @condition = "ripe"
| end
| end
nil
ruby> f5 = Fruit.new "mango"
"a ripe mango"
ruby> f6 = Fruit.new
"a ripe apple"
```
You can use default argument values for any method, not just initialize.
不仅仅是在`initialize`中,你可以给任何方法的参数指定默认值。
The argument list must be arranged so that those with default values come last.
必须对参数列表进行安排,以确保那些有默认值的出现在最后。
Sometimes it is useful to provide several ways to initialize an object.
有时,提供几个方法来初始化一个对象是很有用的。
Although it is outside the scope of this tutorial, ruby supports object reflection and variable-length argument lists, which together effectively allow method overloading.
虽然它超出了本教程的范围,但是**Ruby**支持**对象反射**和**变长参数列表**,这两者一起有效地允许方法重载。
[上一章 访问器](./accessors.md "Accessors")
[下一章 其他](./misc.md "misc")
================================================
FILE: markdown/oothinking.md
================================================
# 面向对象的思考
**Object-oriented thinking**
**面向对象的思考**
Object oriented is a catchy phrase. To call anything object oriented can make you sound pretty smart. Ruby claims to be an object oriented scripting language; but what exactly does "object oriented" mean?
**面向对象**是一个引人注目的措辞。调用任何面向对象的东西都让你听起来感觉相当时髦。**Ruby**声称是面向对象的脚本语言,但是“**面向对象**”的确切含义又是什么呢?
There have been a variety of answers to that question, all of which probably boil down to about the same thing. Rather than sum it too quickly, let's think for a moment about the traditional programming paradigm.
关于这个问题有各种各样的答案,但所有这些都可能归结为同一件事。让我们来思考一下传统的编程范例,而不是简单地总结一下。
Traditionally, a programming problem is attacked by coming up with some kinds of data representations, and procedures that operate on that data.
传统上,编程问题受到了一些数据表示形式,以及对这些数据进行操作的过程的攻击。
Under this model, data is inert, passive, and helpless; it sits at the complete mercy of a large procedural body, which is active, logical, and all-powerful.
在这个模型下,数据是惰性的,被动的,没有帮助的。它完全取决于一个庞大的程序主体,它是活跃的、合乎逻辑的,而且是全能的。
The problem with this approach is that programs are written by programmers, who are only human and can only keep so much detail clear in their heads at any one time.
这种方法的问题在于程序是由程序员编写的,他们是人类,在任何时候,都只能在头脑中清楚地知道这些细节。
As a project gets larger, its procedural core grows to the point where it is difficult to remember how the whole thing works.
随着项目规模的扩大,它的处理核心逐渐增长到难以记住整个过程是如何运作的地步。
Minor lapses of thinking and typographical errors become more likely to result in well-concealed bugs.
思维和排版错误的小错误更容易导致隐藏的bug。
Complex and unintended interactions begin to emerge within the procedural core, and maintaining it becomes like trying to carry around an angry squid without letting any tentacles touch your face.
复杂的和非预期的交互开始在过程核心中出现,维护它就像尝试让愤怒的鱿鱼不把任何触手碰到你脸上一样。
There are guidelines for programming that can help to minimize and localize bugs within this traditional paradigm, but there is a better solution that involves fundamentally changing the way we work.
有一些编程指南可以帮助最小化和局部化这个传统范例中的bug,但有一个能从根本上改变了我们的工作方式懂更好的解决方案。
What object-oriented programming does is to let us delegate most of the mundane and repetitive logical work to the data itself; it changes our concept of data from passive to active.
**面向对象编程**所做的是让我们将大多数普通的和重复的逻辑工作委托给数据本身,它改变了我们从被动到主动的数据概念。
Put another way,We stop treating each piece of data as a box with an open lid that lets us reach in and throw things around.
换句话说,我们不再把每个数据都当作一个盒子,盒子里有一个打开的盖子,可以让我们可以进去,并且把东西放在里面。
We start treating each piece of data as a working machine with a closed lid and a few well-marked switches and dials.
我们开始把每一个数据都当作一个工作的机器,它有一个封闭的盖子,还有一些很好的开关和刻度盘。
What is described above as a "machine" may be very simple or complex on the inside; we can't tell from the outside, and we don't allow ourselves to open the machine up (except when we are absolutely sure something is wrong with its design), so we are required to do things like flip the switches and read the dials to interact with the data. Once the machine is built, we don't want to have to think about how it operates.
上面所描述的“机器”可能非常简单,也可能非常复杂。我们不能从外部识别它,我们也不能允许我们自己把它打开(除非我们完全确定它的设计有问题)。所以我们需要做一些如翻转开关,读取刻度盘的事情来与数据进行交互。一旦构建好机器,我们便不需要考虑它是如何运作的。
You might think we are just making more work for ourselves, but this approach tends to do a nice job of preventing all kinds of things from going wrong.
你可能认为我们只是在为自己做更多的工作,但是这种方法能很好地防止所有的事情出错。
Let's start with a example that is too simple to be of practical value, but should illustrate at least part of the concept.
让我们从一个由简单到拥有实用价值的例子开始,但是应该至少说明这个概念的一部分。
Your car has a tripmeter. Its job is to keep track of the distance the car has travelled since the last time its reset button was pushed.
你的车有一个里程表。它的工作是追踪汽车行驶的距离,这是自上次按下了重置按钮情况。
How would we model this in a programming language?
我们如何在编程语言中对其进行建模呢?
In C, the tripmeter would just be a numeric variable, possibly of type float. The program would manipulate that variable by increasing its value in small increments, with occasional resets to zero when appropriate.
在**C**语言中,里程表可能只是一个数值变量,并且它的类型可能是`float`。程序将通过增加小增量的值来操作这个变量,在适当的时候会重新设置为0。
What's wrong with that? A bug in the program could assign a bogus value to the variable, for any number of unexpected reasons.
这样有什么问题呢?程序中的一个错误可以是为该变量分配了一个虚假的值,因为很多意想不到的原因。
Anyone who has programmed in C knows what it is like to spend hours or days tracking down such a bug whose cause seems absurdly simple once it has been found. (The moment of finding the bug is commonly indicated by the sound of a loud slap to the forehead.)
任何用**C**编程的人都知道,花上几个小时或几天时间来追踪这样的bug是什么感觉,因为一旦找到了它,它的起因似乎是荒谬的。(发现bug的那一刻,通常就像在你的脑门上拍上一记响亮的耳光)
The same problem would be attacked from a much different angle in an object-oriented context.
同样的问题在面向对象的环境中会受到不同的角度的攻击。
The first thing a programmer asks when designing the tripmeter is not "which of the familiar data types comes closest to resembling this thing?" but "how exactly is this thing supposed to act?"
程序员在设计里程表时要问的第一件事不是“哪个熟悉的数据类型最接近于这个东西”,而是“这件事该怎么做?”。
The difference winds up being a profound one. It is necessary to spend a little bit of time deciding exactly what an odometer is for, and how the outside world expects to interact with it. We decide to build a little machine with controls that allow us to increment it, reset it, read its value, and nothing else.
两者的区别是深刻的。有必要花时间来确定一个里程表是什么,以及它会外部世界是如何互动的。我们决定构建一个带有控制的小机器,我们可以对它进行增加,重置,读取,以及其他任何东西。
We don't provide a way for a tripmeter to be assigned arbitrary values; why? because we all know tripmeters don't work that way.
为什么我们不提供一种可以让里程表被赋予任意的值的方法呢?为什么呢?因为我们都知道里程表不工作。
There are only a few things you should be able to do with a tripmeter, and those are all we allow.
有几件事可以让里程表去做,并且这些是我们所允许的。
Thus, if something else in the program mistakenly tries to place some other value (say, the target temperature of the vehicle's climate control) into the tripmeter, there is an immediate indication of what went wrong.
因此,如果程序中的其他东西错误地尝试将其他值(比如车辆的气候控制的目标温度)放入里程表中,就会立即显示出哪里出了问题。
We are told when running the program (or possibly while compiling, depending on the nature of the language) that we are not allowed to assign arbitrary values to Tripmeter objects.
当运行程序时(或者可能在编译时,取决于语言的性质),我们被告知,我们不被允许将任意值赋给Tripmeter对象。
The message might not be exactly that clear, but it will be reasonably close to that.
这个信息可能不是很清楚,但是它会和那个很接近。
It doesn't prevent the error, does it? But it quickly points us in the direction of the cause. This is only one of several ways in which OO programming can save a lot of wasted time.
它并不能阻止错误,不是么?但是它很快就为我们指向了方向。
We commonly take one step of abstraction above this, because it turns out to be as easy to build a factory that makes machines as it is to make an individual machine.
我们通常在这上面做一个抽象的步骤,因为它很容易建造一个制造机器的工厂,就像制造一台机器一样。
We aren't likely to build a single tripmeter directly; rather, we arrange for any number of tripmeters to be built from a single pattern.
我们不太可能直接就创建一个里程表,相反,我们可以从一个单个模式来构建里程表的任何部分。
The pattern (or if you like, the tripmeter factory) corresponds to what we call a class, and an individual tripmeter generated from the pattern (or made by the factory) corresponds to an object. Most OO languages require a class to be defined before we can have a new kind of object, but ruby does not.
这个模式(如果你喜欢的话也可以叫它里程表工厂)对应的是我们所称的类,从模式中产生的一个单独的里程表(或由工厂制造)对应于一个对象。大多数**OO**语言都需要在我们能够拥有一种新的对象之前先定义一个类,但是**Ruby**不这样做。
It's worth noting here that the use of an OO language will not enforce proper OO design.
这里值得注意的是,使用**OO**语言并不会强制执行**OO**设计。
Indeed it is possible in any language to write code that is unclear, sloppy, ill-conceived, buggy, and wobbly all over.
实际上,任何语言都有可能编写不清楚、草率、构思错误、漏洞百出、到处都是不稳定的代码。
What ruby does for you (as opposed, especially, to C++) is to make the practice of OO programming feel natural enough that even when you are working on a small scale you don't feel a necessity to resort to ugly code to save effort.
**Ruby**为你所做的事情(而不是,特别的,对C++),是使面向对象编程的实践变得足够自然,即使你正在进行小规模的工作,你也没有必要求助于丑陋的代码来节省精力。
We will be discussing the ways in which ruby accomplishes that admirable goal as this guide progresses; the next topic will be the "switches and dials" (object methods) and from there we'll move on to the "factories" (classes). Are you still with us?
我们将在这个指南中讨论**Ruby**实现这个令人钦佩的目标的方式,下一个主题将是“开关和刻度盘”(对象方法),然后我们将进入“工厂”(类)。你要和我们一起探究下去么?
[上一章 迭代器](./iterators.md "Iterators")
[下一章 方法](./methods.md "Methods")
================================================
FILE: markdown/procobjects.md
================================================
# 过程对象
**Procedure objects**
**过程对象**
It is often desirable to be able to specify responses to unexpected events.
我们通常希望能够指定对意外事件的响应。
As it turns out, this is most easily done if we can pass blocks of code as arguments to other methods, which means we want to be able to treat code as if it were data.
事实证明,如果我们可以将代码块作为参数传递给其他方法,这是最容易做到的,这意味着我们希望能够将代码看作是数据。
A new procedure object is formed using proc:
一个新的过程对象是通过`proc`来形成的:
```
ruby> quux = proc {
| puts "QUUXQUUXQUUX!!!"
| }
#<Proc:0x4017357c>
```
Now what quux refers to is an object, and like most objects, it has behavior that can be invoked. Specifically, we can ask it to execute, via its call method:
现在quux指向了一个对象,并且如同大多数对象,它有行为可供调用。特别的,我们可以通过它的`call`方法来要求它执行。
```
ruby> quux.call
QUUXQUUXQUUX!!!
nil
```
So, after all that, can quux be used as a method argument? Sure.
那么,在这之后,可以使用quux作为一个方法参数吗?当然。
```
ruby> def run( p )
| puts "About to call a procedure..."
| p.call
| puts "There: finished."
| end
nil
ruby> run quux
About to call a procedure...
QUUXQUUXQUUX!!!
There: finished.
nil
```
The trap method lets us assign the response of our choice to any system signal.
`trap`方法允许我们将选择的响应分配给任何系统信号。
```
ruby> inthandler = proc{ puts "^C was pressed." }
#<Proc:0x401730a4>
ruby> trap "SIGINT", inthandler
#<Proc:0x401735e0>
```
Normally pressing ^C makes the interpreter quit.
通常情况下,`^C`会让解释器退出。
Now a message is printed and the interpreter continues running, so you don't lose the work you were doing. (You're not trapped in the interpreter forever; you can still exit by typing exit.)
现在已经打印了一条消息,解释器继续运行,所以你不会丢失你正在做的工作。(你不会被永远困在解释器中;你仍然可以通过输入`exit`来退出。)
A final note before we move on to other topics: it's not strictly necessary to give a procedure object a name before binding it to a signal. An equivalent anonymous procedure object would look like
在我们继续讨论其他话题之前最后要注意的是:在将其绑定到一个信号之前,不需要给一个过程对象一个名称。一个等价的匿名过程对象是
```
ruby> trap "SIGINT", proc{ puts "^C was pressed." }
nil
```
or more compactly still,
或者更加简洁,
```
ruby> trap "SIGINT", 'puts "^C was pressed."'
nil
```
This abbreviated form provides some convenience and readability when you write small anonymous procedures.
当您编写小型的匿名程序时,这个简短的表单提供了一些便利和可读性。
[上一章 模块](./modules.md "Modules")
[下一章 变量](./variables.md "Variables")
================================================
FILE: markdown/redefinemethods.md
================================================
# 重新定义方法
**Redefinition of methods**
**重新定义方法**
In a subclass, we can change the behavior of the instances by redefining superclass methods.
在**子类**中,我们可以通过重定义继承自**父类**的方法来改变实例的行为。
```
ruby> class Human
| def identify
| puts "I'm a person."
| end
| def train_toll(age)
| if age < 12
| puts "Reduced fare.";
| else
| puts "Normal fare.";
| end
| end
| end
nil
ruby> Human.new.identify
I'm a person.
nil
ruby> class Student1<Human
| def identify
| puts "I'm a student."
| end
| end
nil
ruby> Student1.new.identify
I'm a student.
nil
```
Suppose we would rather enhance the superclass's identify method than entirely replace it. For this we can use super.
假如我们想要增强父类的的**identify**方法,而不是完全替换它。为此我们可以使用`super`。
```
ruby> class Student2<Human
| def identify
| super
| puts "I'm a student too."
| end
| end
nil
ruby> Student2.new.identify
I'm a person.
I'm a student too.
nil
```
super lets us pass arguments to the original method. It is sometimes said that there are two kinds of people...
`super`让我们将传递参数给原始的方法。有时会说,有两种人...
```
ruby> class Dishonest<Human
| def train_toll(age)
| super(11) # 我们想要便宜的车票
| end
| end
nil
ruby> Dishonest.new.train_toll(25)
Reduced fare.
nil
ruby> class Honest<Human
| def train_toll(age)
| super(age) # 传递我们给的参数
| end
| end
nil
ruby> Honest.new.train_toll(25)
Normal fare.
nil
```
[上一章 继承](./inheritance.md "Inheritance")
[下一章 访问控制](./accesscontrol.md "Access control")
================================================
FILE: markdown/regexp.md
================================================
# 正则表达式
**Regular expressions**
**正则表达式**
Let's put together a more interesting program. This time we test whether a string fits a description, encoded into a concise pattern.
让我们把一个更有趣的程序放在一起。这次我们用简洁的模式来测试一个字符串是否符合描述。
There are some characters and character combinations that have special meaning in these patterns, including:
在这些模式中有一些特殊的字符和字符组合,包括:
[] range specificication (e.g., [a-z] means a letter in the range a to z)
**[]** **范围(比如[a-z]表示a到z范围内的字母)**
\w word character; same as [0-9A-Za-z_]
**\w** **word字符,等同于[0-9A-Za-z_]**
\W non-word character
**\W** **非word字符**
\s space character; same as [ \t\n\r\f]
**\s** **间隔符号,等同于[ \t\n\r\f]**
\S non-space character
**\S** **非间隔符号**
\d digit character; same as [0-9]
**\d** **数字字符,等同于[0-9]**
\D non-digit character
**\D** **非数字字符**
\b backspace (0x08) (only if in a range specification)
**\b** **退格(0x08) (只有在一个范围规范中)**
\b word boundary (if not in a range specification)
**\b** **word边界(如果不在范围规范中)**
\B non-word boundary
**\B** **非word边界**
\* zero or more repetitions of the preceding
**\*** **前述字符的0次或多次重复**
\+ one or more repetitions of the preceding
**\+** **前述字符的1次或多次重复**
{m,n} at least m and at most n repetitions of the preceding
**{m,n}** **前述字符的重复次数在m和n之间**
?at most one repetition of the preceding; same as {0,1}
**?** **前述字符的重复次数最多1次,等同于{0,1}**
|either preceding or next expression may match
**|** **匹配其前后2个表达式中的任意一个**
()grouping
**()** **分组**
The common term for patterns that use this strange vocabulary is regular expressions. In ruby, as in Perl, they are generally surrounded by forward slashes rather than double quotes.
使用这种奇怪词汇表的模式的常用术语是**正则表达式**。**Ruby**和**Perl**一样,**正则表达式**通常被**斜线**包围,而不是**双引号**。
If you have never worked with regular expressions before, they probably look anything but regular, but you would be wise to spend some time getting familiar with them.
如果你以前从未使用过**正则表达式**,那么它们可能看起可能来和其他字符串并没有什么不同,但是你最好花些时间熟悉它们。
They have an efficient expressive power that will save you headaches (and many lines of code) whenever you need to do pattern matching, searching, or other manipulations on text strings.
当你需要对文本字符串进行模式匹配、搜索或其他操作时,它们具有一种有效的表达能力,可以为你省去繁琐(以及许多行代码)。
For example, suppose we want to test whether a string fits this description: "Starts with lower case f, which is immediately followed by exactly one upper case letter, and optionally more junk after that, as long as there are no more lower case characters."
举个例子,假设我们想测试一个字符串是否符合如下的描述:*以小写字母f开头,紧随其后的是一个大写字母,之后还有其他除了小写字母的字符*。
If you're an experienced C programmer, you've probably already written about a dozen lines of code in your head, right? Admit it; you can hardly help yourself. But in ruby you need only request that your string be tested against the regular expression /^f[A-Z][^a-z]*$/.
如果你是一个有经验的C语言程序员,你可能已经在脑子里写了十几行代码了,是吧?承认吧,你几乎不能帮到自己。但是在**Ruby**中,你只需要使用**正则表达式**对你的字符串进行测试即可。
How about "Contains a hexadecimal number enclosed in angle brackets"? No problem.
又该如何测试“*包含一个用尖括号括起来的十六进制数字*”的字符串呢?很简单。
```
ruby> def chab(s) # "contains hex in angle brackets"
| (s =~ /<0(x|X)(\d|[a-f]|[A-F])+>/) != nil
| end
nil
ruby> chab "Not this one."
false
ruby> chab "Maybe this? {0x35}" # wrong kind of brackets
false
ruby> chab "Or this? <0x38z7e>" # bogus hex digit
false
ruby> chab "Okay, this: <0xfc0004>."
true
```
Though regular expressions can be puzzling at first glance, you will quickly gain satisfaction in being able to express yourself so economically.
尽管**正则表达式**会让初次见到它的人感到很疑惑,但你很快就会感到满意,因为它能让你更精简地表达自己。
Here is a little program to help you experiment with regular expressions. Store it as regx.rb and run it by typing "ruby regx.rb" at the command line.
这里有一个小程序可以帮助你尝试正则表达式。将它保存为regx.rb,然后在命令行中输入"ruby regx.rb"来运行它。
# Requires an ANSI terminal!
## 需要一个ANSI终端!
```
st = "\033[7m"
en = "\033[m"
puts "Enter an empty string at any time to exit."
while true
print "str> "; STDOUT.flush; str = gets.chop
break if str.empty?
print "pat> "; STDOUT.flush; pat = gets.chop
break if pat.empty?
re = Regexp.new(pat)
puts str.gsub(re,"#{st}\\&#{en}")
end
```
The program requires input twice, once for a string and once for a regular expression. The string is tested against the regular expression, then displayed with all the matching parts highlighted in reverse video. Don't mind details now; an analysis of this code will come soon.
这个程序要求你输入2次,一次是输入**字符串**,另一次是输入**正则表达式**。字符串是根据正则表达式进行测试的,然后在显示器中突出显示所有的匹配部分。现在不要在意细节,很快你就会看到对这段代码的分析。
```
str> foobar
pat> ^fo+
**foo**bar
~~~
```
What you see above as red text will appear as reverse video in the program output. The "~~~" lines are for the benefit of those using text-based browsers.
你在上面看到的`****`中的文本会在在程序输出中突出显示,“~~~”用于使用基于文本浏览器的用户。
Let's try several more inputs.
让我们再尝试几个输入。
```
str> abc012dbcd555
pat> \d
abc**012***dbcd**555**
~~~ ~~~
```
If that surprised you, refer to the table at the top of this page: \d has no relationship to the character d, but rather matches a single digit.
如果结果让你感到很意外,请回过头去看看参考页面顶部的表格:\d与字符d没有关系,它仅仅匹配一个数字。
What if there is more than one way to correctly match the pattern?
还有其他方法可以正确地匹配该模式吗?
```
str> foozboozer
pat> f.*z
**foozbooz**er
~~~~~~~~
```
foozbooz is matched instead of just fooz, since a regular expression matches the longest possible substring.
匹配到了foozbooz,而不是fooz,因为**正则表达式**匹配尽可能长的子字符串。
Here is a pattern to isolate a colon-delimited time field.
这里有一种模式,可以分离一个以冒号分隔的时间字段。
```
str> Wed Feb 7 08:58:04 JST 1996
pat> [0-9]+:[0-9]+(:[0-9]+)?
Wed Feb 7 **08:58:04** JST 1996
~~~~~~~~
```
"=~" is a matching operator with respect to regular expressions; it returns the position in a string where a match was found, or nil if the pattern did not match.
`=~`是**正则表达式**的匹配操作符。如果找到匹配的字符串,就返回字符串的位置,如果模式不匹配,则不返回。
```
ruby> "abcdef" =~ /d/
3
ruby> "aaaaaa" =~ /d/
nil
```
[上一章 字符串](./strings.md "Strings")
[下一章 数组](./arrays.md "Arrays")
================================================
FILE: markdown/rescue.md
================================================
# 异常处理:rescue
**Exception processing: rescue**
**异常处理:rescue**
An executing program can run into unexpected problems.
一个运行的程序可能会遇到意想不到的问题。
A file that it wants to read might not exist; the disk might be full when it wants to save some data; the user may provide it with some unsuitable kind of input.
一个想要读取的文件可能不存在;想要保存一些数据的时候磁盘却满了;用户可能会提供一些不合适的输入。
```
ruby> file = open("some_file")
ERR: (eval):1:in `open': No such file or directory - some_file
```
A robust program will handle these situations sensibly and gracefully.
一个健壮的程序将会明智而优雅地处理这些情况。
Meeting that expectation can be an exasperating task.
满足这种期望可能是一个令人恼火的任务。
C programmers are expected to check the result of every system call that could possibly fail, and immediately decide what is to be done:
**C**程序员期望检查每一个可能失败的系统调用的结果,并立即决定要做什么:
```
FILE *file = fopen("some_file", "r");
if (file == NULL) {
fprintf( stderr, "File doesn't exist.\n" );
exit(1);
}
bytes_read = fread( buf, 1, bytes_desired, file );
if (bytes_read != bytes_desired ) {
/* do more error handling here ... */
}
...
```
This is such a tiresome practice that programmers can tend to grow careless and neglect it, and the result is a program that doesn't handle exceptions well.
这是一种令人厌烦的做法,程序员可能会变得粗心大意,忽视它,结果是它成了一个不处理异常的程序。
On the other hand, doing the job right can make programs hard to read, because there is so much error handling cluttering up the meaningful code.
另一方面,做正确的工作可能会使程序难以阅读,因为有太多的错误处理会使有意义的代码变得混乱。
In ruby, as in many modern languages, we can handle exceptions for blocks of code in a compartmentalized way, thus dealing with surprises effectively but not unduly burdening either the programmer or anyone else trying to read the code later.
在**Ruby**中,就像在许多现代语言中一样,我们可以用一种划分的方式处理代码块的异常,这样就可以有效地处理意外事件,但不会给程序员或其他试图阅读代码的人造成太大的负担。
The block of code marked with begin executes until there is an exception, which causes control to be transferred to a block of error handling code, which is marked with rescue.
从有`begin`标记的代码块开始执行,直到有一个异常,这导致控制被转移到一个错误处理代码块,这个代码块被标记为`rescue`。
If no exception occurs, the rescue code is not used. The following method returns the first line of a text file, or nil if there is an exception:
如果没有异常发生,则不使用`rescue`代码。下面的方法返回文本文件的第一行,如果有异常,则返回`nil`:
```
def first_line( filename )
begin
file = open("some_file")
info = file.gets
file.close
info # Last thing evaluated is the return value
rescue
nil # Can't read the file? then don't return a string
end
end
```
There will be times when we would like to be able to creatively work around a problem. Here, if the file we want is unavailable, we try to use standard input instead:
有时候,我们希望能够创造性地解决一个问题。在这里,如果我们想要的文件不可用,我们尝试使用标准输入:
```
begin
file = open("some_file")
rescue
file = STDIN
end
begin
# ... process the input ...
rescue
# ... and deal with any other exceptions here.
end
```
retry can be used in the rescue code to start the begin code over again. It lets us rewrite the previous example a little more compactly:
可以在`rescue`代码中使用`retry`,以重新启动开始的代码。它让我们更简洁地重写上一个例子:
```
fname = "some_file"
begin
file = open(fname)
# ... process the input ...
rescue
fname = "STDIN"
retry
end
```
However, there is a flaw here. A nonexistent file will make this code retry in an infinite loop. You need to watch out for such pitfalls when using retry for exception processing.
然而,这里有一个缺陷。一个不存在的文件将使该代码在无限循环中重试。在使用重试进行异常处理时,需要注意这些缺陷。
Every ruby library raises an exception if any error occurs, and you can raise exceptions explicitly in your code too.
如果出现任何错误,每个**Ruby**库都会抛出异常,并且你也可以在代码中显式地抛出异常。
To raise an exception, use raise. It takes one argument, which should be a string that describes the exception.
使用`raise`来抛出一个异常。它可以接受一个描述异常的字符串作为参数。
The argument is optional but should not be omitted. It can be accessed later via the special global variable $!.
这个参数是可选的,但不应该省略。稍后可以通过特殊的全局变量`$!`来访问它。
```
ruby> raise "test error"
test error
ruby> begin
| raise "test2"
| rescue
| puts "An error occurred: #{$!}"
| end
An error occurred: test2
nil
```
[上一章 类常量](./constants.md "Class constants")
[下一章 异常处理:ensure](./ensure.md "Exception processing: ensure")
================================================
FILE: markdown/singletonmethods.md
================================================
# 单例方法
**Singleton methods**
**单例方法**
The behavior of an instance is determined by its class, but there may be times we know that a particular instance should have special behavior.
一个实例的行为是由它所属的类决定的,但是我们也有可能知道,特定的实例有自己特定的行为。
In most languages, we must go to the trouble of defining another class, which would then only be instantiated once.
在大多数语言中,我们必须去定义另一个类,这样就只会实例化一次。
In ruby we can give any object its own methods.
在**Ruby**中,我们可以给任何对象它自己的方法。
```
ruby> class SingletonTest
| def size
| 25
| end
| end
nil
ruby> test1 = SingletonTest.new
#<SingletonTest:0xbc468>
ruby> test2 = SingletonTest.new
#<SingletonTest:0xbae20>
ruby> def test2.size
| 10
| end
nil
ruby> test1.size
25
ruby> test2.size
10
```
In this example, test1 and test2 belong to same class, but test2 has been given a redefined size method and so they behave differently. A method given only to a single object is called a singleton method.
在这个示例中,test1和test2都属于同一个类,但是test2重定义了`size`方法,因此它们有不同的行为。只属于一个对象的**方法**被称为**单例方法**。
Singleton methods are often used for elements of a graphic user interface (GUI), where different actions need to be taken when different buttons are pressed.
**单例方法**经常用于图形用户界面(GUI)的元素,当不同的按钮被按下时,需要采取不同的行动。
Singleton methods are not unique to ruby, as they appear in CLOS, Dylan, etc. Also, some languages, for example, Self and NewtonScript, have singleton methods only. These are sometimes called prototype-based languages.
**单例方法**并不是**Ruby**独有的,它出现于**CLOS**、**Dylan**等,同样,也出现于许多语言中,例如,**Self**和**NewtonScript**只有**单例方法**。它们有时被称为**基于原型的语言**。
[上一章 访问控制](./accesscontrol.md "Access control")
[下一章 模块](./modules.md "Modules")
================================================
FILE: markdown/strings.md
================================================
# 字符串
**Strings**
**字符串**
Ruby deals with strings as well as numerical data. A string may be double-quoted ("...") or single-quoted ('...').
**Ruby**处理字符串就同处理数值数据一样优秀。定义字符串可以用**双引号**或者**单引号**。
```
ruby> "abc"
"abc"
ruby> 'abc'
"abc"
```
Double- and single-quoting have different effects in some cases. A double-quoted string allows character escapes by a leading backslash, and the evaluation of embedded expressions using #{}. A single-quoted string does not do this interpreting; what you see is what you get. Examples:
在某些场景中,**双引号**和**单引号**会产生不同的结果。**双引号**字符串允许通过**反斜线**对字符进行**转义**,以及对使用`#{}`嵌入的表达式进行求值。**单引号**字符串则不对这些进行解释,你所看到的便是其最终的结果。比如:
```
ruby> puts "a\nb\nc"
a
b
c
nil
```
```
ruby> puts 'a\nb\n'
a\nb\nc
nil
```
```
ruby> "\n"
"\n"
```
```
ruby> '\n'
"\\n"
```
```
ruby> "\001"
"\t"
```
```
ruby> '\001'
"\001"
```
```
ruby> "abcd #{5*3} efg"
"abcd 15 efg"
```
```
ruby> var = " abc "
" abc "
```
```
ruby> "1234#{var}5678"
"1234 abc 5678"
```
Ruby's string handling is smarter and more intuitive than C's. For instance, you can concatenate strings with +, and repeat a string many times with *:
**Ruby**的字符串处理比**C语言**更智能,更直观。举个例子,你可以使用`+`把字符串连接起来,或者使用`*`将字符串重复多次。
```
ruby> "foo" + "bar"
"foobar"
```
```
ruby> "foo" * 2
"foofoo"
```
Concatenating strings is much more awkward in C because of the need for explicit memory management:
在**C语言**中连接字符串要显得更笨拙,因为它需要显式地进行内存管理:
```
char *s = malloc(strlen(s1)+strlen(s2)+1);
strcpy(s, s1);
strcat(s, s2);
/* ... */
free(s);
```
But using ruby, we do not have to consider the space occupied by a string. We are free from all memory management.
但是如果使用的是**Ruby**,我们则不需要考虑字符串占用的空间,由此从所有的内存管理工作中解放出来。
Here are some things you can do with strings.
这里有一些你可以用字符串完成的事情。
Concatenation:
连接:
```
ruby> word = "fo" + "o"
"foo"
```
Repetition:
重复:
```
ruby> word = word * 2
"foofoo"
```
Extracting characters (note that characters are integers in ruby):
取出字符(注意在**Ruby**中字符是整数):
```
ruby> word[0]
102 # 102是`f'的ASCII码
ruby> word[-1]
111 # 111是`o'的ASCII码
```
(Negative indices mean offsets from the end of a string, rather than the beginning.)
(负数的**索引**则表示从字符串末尾开始计算的偏移量,而不是从头开始计算。)
Extracting substrings:
取出子字符串:
```
ruby> herb = "parsley"
"parsley"
ruby> herb[0,1]
"p"
ruby> herb[-2,2]
"ey"
ruby> herb[0..3]
"pars"
ruby> herb[-5..-2]
"rsle"
Testing for equality:
ruby> "foo" == "foo"
true
ruby> "foo" == "bar"
false
```
Now, let's put some of these features to use. This puzzle is "guess the word," but perhaps the word "puzzle" is too dignified for what is to follow ;-)
现在,让我们来使用一些这些特性。这个谜题是“猜单词”,但也许“谜”这个词太过凝重,不适合接下来的内容;-)
# save this as guess.rb
## 保存为guess.rb
```
words = ['foobar', 'baz', 'quux']
secret = words[rand(3)]
print "guess? "
while guess = STDIN.gets
guess.chop!
if guess == secret
puts "You win!"
break
else
puts "Sorry, you lose."
end
print "guess? "
end
puts "The word was ", secret, "."
```
For now, don't worry too much about the details of this code. Here is what a run of the puzzle program looks like.
现在,不要太担心这段代码的细节。下面是这个谜题程序的运行情况。
```
ruby guess.rb
guess? foobar
Sorry, you lose.
guess? quux
Sorry, you lose.
guess? ^D
The word was baz.
```
(I should have done a bit better, considering the 1/3 probability of success.)
(考虑到1/3的成功概率,我应该可以做得更好一些。)
[上一章 简单示例](./examples.md "Simple examples")
[下一章 正则表达式](./regexp.md "Regular expressions")
================================================
FILE: markdown/variables.md
================================================
# 变量
**Variables**
**变量**
Ruby has three kinds of variables, one kind of constant and exactly two pseudo-variables.
**Ruby**有3种类型的变量,一种是**常量**,另外两种是**伪变量**。
The variables and the constants have no type. While untyped variables have some drawbacks, they have many more advantages and fit well with ruby's quick and easy philosophy.
变量和常量都没有类型。尽管没有类型的变量有一些缺点,但是它们有远远更多的优点,并且与**Ruby**的快速和简单的哲学相适应。
Variables must be declared in most languages in order to specify their type, modifiability (i.e., whether they are constants), and scope; since type is not an issue, and the rest is evident from the variable name as you are about to see, we do not need variable declarations in ruby.
变量在大多数语言中必须声明,以指定它们的类型、可修改性(即:它们是否是常数)和作用域;因为类型不是问题,剩下的就是从变量名中可以看到的,正如你即将要看到的,在**Ruby**中使用变量不需要声明。
The first character of an identifier categorizes it at a glance:
标识符的第一个字符对它进行了分类:
| 标识符 | 类型 |
| --------- | :--: |
| $ | 全局变量 |
| @ | 实例变量 |
| [a-z] 或 _ | 局部变量 |
| [A-Z] | 常量 |
The only exceptions to the above are ruby's pseudo-variables: self, which always refers to the currently executing object, and nil, which is the meaningless value assigned to uninitialized variables.
上面的唯一例外是**Ruby**的伪变量:总是指向当前运行对象的`self`和被赋给未初始化变量的无意义的值`nil`。
Both are named as if they are local variables, but self is a global variable maintained by the interpreter, and nil is really a constant.
虽然两者都像是局部变量一样被命名,但是`self`是由解释器维持的一个全局变量,而`nil`实际上是一个常量。
As these are the only two exceptions, they don't confuse things too much.
因为这是仅有的2个例外,他们不会把事情搞得太混乱。
You may not assign values to self or nil. main, as a value of self, refers to the top-level object:
你不能给`self`或`nil`赋值。`main`,作为`self`的值,指的是顶级对象:
```
ruby> self
main
ruby> nil
nil
```
[上一章 过程对象](./procobjects.md "Procedure objects")
[下一章 全局变量](./globalvars.md "Global variables")
gitextract_mh9e3o7z/
├── License.txt
├── README.md
└── markdown/
├── about.md
├── accesscontrol.md
├── accessors.md
├── arrays.md
├── backtoexamples.md
├── classes.md
├── constants.md
├── contributor.md
├── control.md
├── copyright.md
├── ensure.md
├── examples.md
├── getstarted.md
├── globalvars.md
├── index.md
├── inheritance.md
├── instancevars.md
├── iterators.md
├── localvars.md
├── methods.md
├── misc.md
├── modules.md
├── objinitialization.md
├── oothinking.md
├── procobjects.md
├── redefinemethods.md
├── regexp.md
├── rescue.md
├── singletonmethods.md
├── strings.md
└── variables.md
Condensed preview — 33 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (183K chars).
[
{
"path": "License.txt",
"chars": 22962,
"preview": "\n GNU Free Documentation License\n Version 1.3, 3 November 2008\n\n\n Copyright (C) 2000, 200"
},
{
"path": "README.md",
"chars": 2283,
"preview": "# 简介\n\n**Ruby** : *A PROGRAMMER'S BEST FRIEND*\n\n这是 [Ruby User’s Guide]( ht"
},
{
"path": "markdown/about.md",
"chars": 903,
"preview": "# 关于本指南\n**About the guide**\n\n**关于本指南**\n\nThis introductory user's guide is mirrored in various places and is available in"
},
{
"path": "markdown/accesscontrol.md",
"chars": 4392,
"preview": "# 访问控制\n**Access control**\n\n**访问控制**\n\nEarlier, we said that ruby has no functions, only methods. \n\n之前我们曾说,**Ruby**没有**函数*"
},
{
"path": "markdown/accessors.md",
"chars": 5638,
"preview": "# 访问器\n**Accessors**\n\n**访问器**\n\nWhat is an accessor?\n\n**访问器**是什么?\n\nWe briefly discussed instance variables in an earlier c"
},
{
"path": "markdown/arrays.md",
"chars": 2093,
"preview": "# 数组\n\n**Arrays**\n\n**数组**\n\nYou can create an array by listing some items within square brackets ([]) and separating them "
},
{
"path": "markdown/backtoexamples.md",
"chars": 12295,
"preview": "# 再读“简单示例”\n**Back to the simple examples**\n\n**再读“简单示例”**\n\nNow let's take apart the code of some of our previous example "
},
{
"path": "markdown/classes.md",
"chars": 3359,
"preview": "# 类\n**Classes**\n\n**类**\n\nThe real world is filled by objects, and we can classify them. \n\n现实世界中充满了对象,并且我们还可以给它们分类。\n\nFor e"
},
{
"path": "markdown/constants.md",
"chars": 1703,
"preview": "# 类常量\n**Class constants**\n\n**类常量**\n\nA constant has a name starting with an uppercase character. \n\n常量的名称以大写字母开头。\n\nIt shou"
},
{
"path": "markdown/contributor.md",
"chars": 1098,
"preview": "# 贡献者名单\n\n>如果我比别人看得远,那是因为我站在巨人的肩膀上。——艾萨克·牛顿\n\n感谢以下人员为[《Ruby用户指南》](https://github.com/BadTudou/RubyUsersGuide-zh)做出的巨大贡献!(*"
},
{
"path": "markdown/control.md",
"chars": 5324,
"preview": "# 流程控制\n**Control structures**\n\n**流程控制**\n\nThis chapter explores more of ruby's control structures.\n\n本章节探究了更多的**Ruby**流程控制"
},
{
"path": "markdown/copyright.md",
"chars": 614,
"preview": "# 版权信息\n\n**Copyright (c) 2005-2014 Mark Slagell**\n\n**版权所有 (c) 2005-2014 Mark Slagell**\n\nPermission is granted to copy, d"
},
{
"path": "markdown/ensure.md",
"chars": 2110,
"preview": "# 异常处理:ensure\n**Exception processing: ensure**\n\n**异常处理:ensure**\n\nThere may be cleanup work that is necessary when a meth"
},
{
"path": "markdown/examples.md",
"chars": 5463,
"preview": "# 简单示例\n\n**Simple examples**\n\n**简单示例**\n\nLet's write a function to compute factorials. The mathematical definition of `n` "
},
{
"path": "markdown/getstarted.md",
"chars": 1906,
"preview": "# 起步\n**Getting started**\n\n**起步**\n\nFirst, you'll want to check whether ruby is installed. From the shell prompt (denoted "
},
{
"path": "markdown/globalvars.md",
"chars": 2820,
"preview": "# 全局变量\n**Global variables**\n\n**全局变量**\n\nA global variable has a name beginning with $. \n\n**全局变量**的名字以`$`开头。\n\nIt can be re"
},
{
"path": "markdown/index.md",
"chars": 1288,
"preview": "# Ruby是什么?\n\n**What is ruby?**\n\n**Ruby是什么?**\n\nRuby is \"an interpreted scripting language for quick and easy object-orient"
},
{
"path": "markdown/inheritance.md",
"chars": 2459,
"preview": "# 继承\n**Inheritance**\n\n**继承**\n\nOur classification of objects in everyday life is naturally hierarchical.\n\n我们在日常生活中对物品的分类是"
},
{
"path": "markdown/instancevars.md",
"chars": 1571,
"preview": "# 实例变量\n**Instance variables**\n\n**实例变量**\n\nAn instance variable has a name beginning with @, and its scope is confined to "
},
{
"path": "markdown/iterators.md",
"chars": 6247,
"preview": "# 迭代器\n**Iterators**\n\n**迭代器**\n\nIterators are not an original concept with ruby. \n\n**迭代器**并不是**Ruby**的原创概念。\n\nThey are in c"
},
{
"path": "markdown/localvars.md",
"chars": 4607,
"preview": "# 局部变量\n**Local variables**\n\n**局部变量**\n\nA local variable has a name starting with a lower case letter or an underscore cha"
},
{
"path": "markdown/methods.md",
"chars": 4970,
"preview": "# 方法\n**Methods**\n\n**方法**\n\nWhat is a method? In OO programming, we don't think of operating on data directly from outside"
},
{
"path": "markdown/misc.md",
"chars": 6323,
"preview": "# 其他\n**Nuts and bolts**\n\n**其他**\n\nThis chapter addresses a few practical issues.\n\n这一章解决了一些实际问题。\n\n**Statement delimiters**"
},
{
"path": "markdown/modules.md",
"chars": 2945,
"preview": "# 模块\n**Modules**\n\n**模块**\n\nModules in ruby are similar to classes, except:\n\n**Ruby**中的**模块**同**类**非常相似,但有些许不同:\n\n- A modul"
},
{
"path": "markdown/objinitialization.md",
"chars": 3264,
"preview": "# 对象初始化\n**Object initialization**\n\n**对象初始化**\n\nOur Fruit class from the previous chapter had two instance variables, one "
},
{
"path": "markdown/oothinking.md",
"chars": 8419,
"preview": "# 面向对象的思考\n**Object-oriented thinking**\n\n**面向对象的思考**\n\nObject oriented is a catchy phrase. To call anything object oriente"
},
{
"path": "markdown/procobjects.md",
"chars": 2330,
"preview": "# 过程对象\n**Procedure objects**\n\n**过程对象**\n\nIt is often desirable to be able to specify responses to unexpected events. \n\n我们"
},
{
"path": "markdown/redefinemethods.md",
"chars": 1623,
"preview": "# 重新定义方法\n**Redefinition of methods**\n\n**重新定义方法**\n\nIn a subclass, we can change the behavior of the instances by redefini"
},
{
"path": "markdown/regexp.md",
"chars": 5933,
"preview": "# 正则表达式\n**Regular expressions**\n\n**正则表达式**\n\nLet's put together a more interesting program. This time we test whether a s"
},
{
"path": "markdown/rescue.md",
"chars": 4190,
"preview": "# 异常处理:rescue\n**Exception processing: rescue**\n\n**异常处理:rescue**\n\nAn executing program can run into unexpected problems. "
},
{
"path": "markdown/singletonmethods.md",
"chars": 1691,
"preview": "# 单例方法\n**Singleton methods**\n\n **单例方法**\n\nThe behavior of an instance is determined by its class, but there may be times "
},
{
"path": "markdown/strings.md",
"chars": 3476,
"preview": "# 字符串\n**Strings**\n\n**字符串**\n\nRuby deals with strings as well as numerical data. A string may be double-quoted (\"...\") or "
},
{
"path": "markdown/variables.md",
"chars": 1851,
"preview": "# 变量\n**Variables**\n\n**变量**\n\nRuby has three kinds of variables, one kind of constant and exactly two pseudo-variables. \n\n"
}
]
About this extraction
This page contains the full source code of the BadTudou/RubyUsersGuide-zh GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 33 files (134.9 KB), approximately 44.1k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.