1. 面向对象


1.1 对象

Ruby是面向对象语言,所操作的每件东西都是对象,操作结果本身也是对象。在Ruby里,需要定义类来表示实体。类是状态和使用这些状态的方法的组合。一旦建立了类,通常要为每个类创建若干个实例。

在Ruby中,通过调用构造函数来创建对象,标准的构造函数被称为new,例如:

obj = MyClass.new()

每个对象都有一个唯一的对象标识符,可以定义一些实例变量,这些变量的值对于每个实例来说是独一的,这些实例变量都持有对象的状态。可以为每个类定义实例方法,每个方法是一组功能,它们可能会在类的内部或从类的外部被调用。

Ruby与大多数语言之间有一个很大的区别就是内建的能力,例如:

number = number.abs


1.2 基本语法

Ruby中每个语句放在单独的行上,不需要在语句结束处加上分号。Ruby中的注释以一个"#"字符开始,在行尾结束,例如:

# this is a demo
def test(name)
  puts name
end

方法用关键字def来定义,后面跟着方法名称和在括号中的方法参数,Ruby没有使用花括号来界定复杂的语句和定义的程序体,可以用关键字end结束这个程序体。调用方法的程序很简单,例如:

def say_name(name) 
  return'my name is : ' + name
end
puts say_name('John')


1.3 字符串

创建字符串对象有多种途径,最常用的可能是使用字符串字面量,即一组单引号或双引号之间的字符序列。这两种形式的区别在于,当构造字面量时,Ruby对单引号串处理得很少,而对双引号字符串有更多的处理。

首先,它寻找以反斜线开始的序列,并用二进制值替换它们,常见的比如"\n",它会被回车换行符替换掉,例如:

puts "Hello World!\nRuby"

其次Ruby对双引号字符串所做的第二件事情是字符串内的表达式内插,"#{表达式}"序列会被表达式的值替换,例如:

def say_name(name)  
  return "my name is : #{name}"
end
puts say_name('John')

如果表达式只是一个全局实例或类变量,则不需要提供花括号,例如:

$global
@instance
puts "#$global,#@instance"

Ruby方法所返回的值,是最后一个被求值的表达式的值,所在有时候可以把return去掉,例如:

def say_name(name)   
  "my name is : #{name}"
end
puts say_name('John')


1.4 命名

Ruby使用一种命令惯例来区分名称的用途:名称的第一个字符显示这个名称如何被使用。局部变量、方法参数、方法名称都必须以小写字母或下划线开始。全局变量都有美元符号"$"为前缀,而实例变量都以"@"符号开始,类变量以两个"@@"符号开始。最后,类名称、模块名称和常量都必须以一个大写字母开始。

从上述规定的初始字符之后开始,名称可以是字母、数字和下划线的组合。方法名称可以"?"、"!"和"="字符结束。


2. 基本结构


2.1  数组和散列表

Ruby的数组和散列表都是存储对象的集合,通过键来访问。数组的键是整数,而散列表支持以任何对象作为它的键。数组和散列表会按需调整大小来保存新的元素。任何具体的数组或散列表可以保存不同类型的对象。

使用数组字面量可以创建和初始化新的数组对象,例如:

myarray = [1,'a',0.1]

可以在方括号之间提供索引以便可以访问单个元素,例如:

puts a[0]

在Ruby中,nil代表一个对象,它用来表示没有任何东西的对象。

Ruby有一种快捷方式来创建一组单词的数组,使用"%w"即能完成,例如:

myarray = %w{hello ok bye}

Ruby的散列表与数组相似,散列表字面量使用花括号而不是方括号,字面量必须为每一项提供两个对象:一个键和一个值,例如:

myhash = {
  'str1' => 'string1',
  'str2' => 'string2',
  'str3' => 'string3',
}

散列表使用与数组相同的方括号表示法来进行索引,例如:

puts myhash['str1']


2.2 控制结构

Ruby具有所有常见的控制结构,如if语句和while循环,Ruby是使用end关键字来表明程序体的结束,例如:

if var > 10
  puts 'done'
elsif var > 5
  puts 'again'
else
  puts 'try'
end
while var > 10
  var -= 1
end

大多数Ruby语句会返回值,意味着可以把它们当条件使用,例如:

while line = gets
  puts line.downcase
end

Ruby有一种快捷方式:语句修饰符,例如:

puts 'done' if var > 10
var -= 1 while var > 10


2.3 正则表达式

在Ruby中,通常在斜线之间编写模式来创建正则表达式,同时正则表达式是对象并且可以当作对象来操作,例如:

/Perl|Python/

创建了模式以后,"=~"匹配操作符可以用正则表达式来匹配字符串,如果在字符串中发现了模式,"=~"返回模式的开始位置,否则它返回nil。这意味着可以在if和while语句中把正则表达式当作条件使用,例如:

if line =~ /Perl|Python/
  puts 'Scripting language'
end

正则表达式匹配到的字符串部分,可以使用Ruby的其中一种替换方法,替换为其他文本,sub方法可以替换第一个匹配到的子串,gsub方法可以替换所有匹配到的字串,例如:

line.sub(/Perl/, 'Ruby')
line.gsub(/Python/, 'Ruby')


2.4 Block和迭代器

Block是一种可以和方法调用相关联的代码块,可以用block实现回调,传递一组代码,以及实现迭代器,Block只是在花括号或者do...end之间的一组代码,例如:

{
  puts 'Hello World'
}
do
  puts 'Hello World'
end

花括号的优先级比do...end要高。

一旦创建了block,就可以与方法的调用相关联,把block的开始放在含有方法调用的源码行的结尾处,就可以实现关联,例如:

method {
  puts 'Hello World'
}

如果方法有参数,它们出现在block之前,例如:

method('param1', 'param2') {
  puts 'Hello World'
}

使用Ruby的yield语句,方法可以一次或多次地调用相关联的block,例如:

def call_block
  puts 'Start'
  yield
  yield
  puts 'end'
end
call_block {
  puts 'Hello World'
}

在block中,竖线之间给出参数名来接受来自yield的参数,例如:

def call_block 
  puts 'Start'
  yield('John', 'addr1') 
  yield('Marry', 'addr2') 
  puts 'end'
end
call_block {|name, address|
  puts "Hello #{name} from #{address}"
}

在Ruby库中大量使用了block来实现迭代器,迭代器是从某种收集如数组中连续返回元素的方法,例如:

myarray = %w{str1 str2 str3}
myarray.each{|string| puts string}


2.5 读写文件

Ruby有两个常用的用来输出的方法,puts输出它的参数,并在每个参数后面添加回车换行符,print也输出它的参数,但没有添加回车换行符。它们都可以用来向任何I/O对象进行输出,但在默认情况下,它们输出到标准输出。

另一个输出方法是printf,它在一个格式化字符串的控制下打印出它的参数,例如:

printf("Number: %5.2f,\nString: %s\n", 1.23, 'hello')

有许多方式可以把输入读到程序中,最传统的方式是使用gets函数,它从程序的标准输入流中读取下一行,例如:

line = gets
print line