programming ruby

p12

方法是通过向对象发送消息来唤起调用的,消息包含方法名称以及方法需要的参数。

p13

方法调用是 . 之前的东西称为接受者,后面的名字是被调用的方法

这个例子用来介绍很不错,可以引申出很多

def say_goodnight(name)
  result = "Good night, " + name
  return result
end
# Time for bed...
puts say_goodnight("Jhon-Boy")
puts say_goodnight("Mary-Eleen")

从基础有语法,注释,方法,字符串内插,变量来扩展开来

p26

inspect 方法(可以发送给任何对象)默认将对象的 ID 和实例变量格式化。所以我们可以 通过重写某个类的 inspect 方法来控制它的格式化显示(比如 new 的时候)

p27

TODO 字符串内插也可以用 "#@name" 这样的么,内插的格式究竟应该具体是怎样的?

p28

关于调用 super 方法和代码解耦的,让每个类处理其自身的实现细节。我以为,要是本来 的意愿就是微调一下,日如增加点输出什么的那么可以使用 super,否则到时修改要改两处 也是麻烦,但是本意就是自定义不同的行为,就要自己重写方法了。

p32

虚拟属性。对外部世界来说,它们就像其他属性一样,但是内部它没有对应的实例变量。

当你设计一个类的时候,你决定其具有什么样的内部状态,并决定这内部状态对外界的表现 形式。内部状态保存在实例变量中。通过方法暴露出来的外部状态,我们称之为属性。你的 类可以执行的其他动作,就是一般方法。这并非是一个非常重要的区别,但是通过把一个 对象的外部状态称为属性,可以帮助人们了解你所编写的类。

p37

访问控制

p40

变量只是对象的引用,保存的是对象引用而非对象本身。

p44

Array#, 所以 a[0, -1] 返回的是 nil,正确用法是 a[0..-1]

p45

如果 []= 的下标是两个数字或者是 range,那么原数组中的那些元素都将被赋值语句中 右边的东西所替换。如果长度是 0,赋值语句右边的东西将被插入到数组的起点位置之前, 且不会删除任何元素。如果右边本身是一个数组,那么其元素将替换掉原数组对应位置上 的东西。如果索引下标选择的元素个数和赋值语句右边的元素个数不一致,那么数组会自动 调整其大小。

a = [1, 2, 3, 5, 7, 9]
a[2, 3] = 'cat'  => [1, 3, 'cat', 9]
a[2, 0] = 'dog'  => [1, 3, 'dog', 'cat', 9]
a[1, 1] = [9, 8, 7]  => [1, 9, 8, 7, 'dog', 'cat', 9]
a[0..3] = []  => ['dog', 'cat', 9]
a[5..6] = 99, 98  => ['dog', 'cat', 9, nil, nil, 99, 98]

p66

ruby 使用区间去实现 3 种不同的特性,序列(sequences),条件(conditionals)和 间隔(intervals)。

p67

当然,就像一个面向对象语言所期望的那样,ruby 可以根据你定义个对象来创建区间。唯一 的限制是这些对象要有 succ 和 <=> 方法。

What's the difference between equal?, eql?, ===, and ==? http://stackoverflow.com/questions/7156955/whats-the-difference-between-equal-eql-and

p69

匹配操作符 =~,匹配操作符对 String 和 Regexp 对象均有定义,匹配操作符至少有一个 操作数必须为正则表达式。$& 得到于模式匹配的那部分字符串,$` 得到匹配之前,$' 得到匹配之后的。这个匹配也设置了局部变量(thread-local variables),$~ 与 $1 直到 $9,$~ 变量是 MatchData 对象,持有你想知道的有关匹配的所有信息。$1 等 持有匹配的各个部分的值。

p73

正则中的未转义的竖线优先级很低,比如说 /red ball|angry sky/ 会匹配 red ball 或者 angry sky 而不是 red ball sky 或者 red angry sky,必要时使用编组来重载默认的优先级。

p75

在基于模式的替换中(gsub,sub),\1, \2 表示的是第 n 个已匹配的组,\&(最后的匹配—), +(最后匹配的组), `(匹配之前的字符串),\'(匹配之后的字符串), \(字面量\) 而且你还可以使用块呦。

p81

我们在调用 self.class 是必须要指定一个接受对象,这是因为 class 在 ruby 中是一个 关键字,单独使用它会产生语法错误。

p89

运行命令 `cmad` %x“cmd”, 命令退出状态保存在 $? 中。

p90

ruby 中的赋值语句有两种,第一种是将一个对象引用赋值给变量或者常量。这种形式的赋值 在 ruby 语言中是值直接执行的

instruments = 'piano'
MIDDLE_A = 440

第二种形式等号左边是对象属性或者元素的额引用,它是通过调用左值的方法来实现的,这 意味这你可以重载它们

song.duration = 234
instruments["ano"] = "ccolo"

p92

可写属性有个隐藏的陷阱。通常,类中的方法是可以通过函数形式(即带一个隐式 self 作 为接受者)调用同一个类的其他方法和它父类的方法。然而这并不适用与属性赋值函数: ruby 看到赋值语句时,会认为左边的名字的局部变量而不是为属性赋值的一个方法调用。

class One
  attr_accessor :left, :right
  def vol=(value)
    left = right = value
  end
end

one = One.new
one.left = 1
one.right = 2
one => #<One:0x00000004548860 @left=1, @right=2>
one.vol = 100
one => #<One:0x00000004548860 @left=1, @right=2>
# 没有什么用,因为赋值给局部变量了。所以记得要用 self

使用 ruby 的并行赋值操作,你可以叠起和展开数组。如果最后一个左值有一个 * 前缀, 那么所有的多余的右值将被集合在一起,并作为一个数组赋给左值。同样地,如果最后一个 右值是一个数组,前面的 * 会使它被自动展开成其元素的值(如果右边只有一个值,那么 这就没有必要了,数组会自动展开的)

a = [1, 2, 3, 4]
b, c = a         => b = 1, c = 2
b, *c = a        => b = 1, c = [2, 3, 4]
b, c = 99, a     => b = 99, c = [1, 2, 3, 4]
b, *c = 99, a    => b = 99, c= [[1, 2, 3, 4]]
b, c = 99, *a    => b = 99, c = 1
b, *c = 99, *a   => b = 99, c = [1, 2, 3, 4]

p93

ruby 中对真值的定义很简单,任何不是 nil 或者常量 false 的值都为真。

p94

优先级 ! > && > || > not > and = or

p95

== === eql? equal? difference http://stackoverflow.com/questions/7156955/whats-the-difference-between-equal-eql-and

p99

ruby 的所有类都是类 Class 的实例,它定义了 === 以测试参数是否为该类或者其父类 的一个实例。

p106

中间的第二个例子已经失效的,结果是 x 仍旧是 nil

注意在外部作用域中变量不必有值:ruby 解释器只需要看到它即可

if false
  a = 1
end
a  => nil

p107

异常允许把错误信息打包到一个对象中,然后该异常对象自动传播回调用栈,直到运行系统 找到明确声明知道如何处理这类异常的代码为止。

p108

当异常被引发时,ruby 将相关 Exception 对象的引用放在全局变量 $! 中,这与任何随后 的异常处理不相关。

ruby 异常层次结构要记一下

p111

else 子句是一个类似 ensure 子句的构造。如果存在的话,会出现在 rescue 子句之后和 任何一个 ensure 子句之前。只有当代码体没有引发任何异常才会被执行。

p112

引发异常

raise 只是简单的重新引发当前的异常(如果没有当前异常的话,引发 RuntimeError)。 这种形式用于首先截获异常然后再将其继续传递的异常处理方法中。

raise 'bad mp3 encoidng' 创建新的 RuntimeError 异常,把它的消息设置为指定的 字符串,然后异常随着调用栈向上引发。

raise IndexError, 'blabla'

raise ArgumentError, 'keyboard failure', caller 使用第一个参数创建异常,然后把 相关联的消息设置给第二个参数,同时把栈信息设置给第三个参数。通常使用 Kernel.caller 方法产生栈信息。

p119

你 inlcude Comparable 模块,然后再定义一个方法 <=>,你就有有 5 个新方法了 (< <= == => >)

p120

你 inlcude Enumerable 模块,编写一个 each 的迭代器,然后你的类就可以支持 map, include?,find_all 等操作,如果你还实现了使用 <=> 实现了有意义的排序语义,你 还会得到诸如 min, max 和 sort 等方法。

p167 建议运行脚本时开启警告 -w 选项

p168

注意 {} 和 do end 的优先级问题.

p171

可以使用 -r profile 命令行选项来进行代码剖析。

p180

ARGV 保存所有的命令行参数,注意 ARGV[0] 是第一个参数而不是程序名字

p181

ENV 保存了预定义的变量,相应与 Hash 相同的方法,但实际上不是 Hash

p183

ruby 变量 $: 是一个目录数组,用来查找翼装入的文件。这个变量被初始化为标准 目录表,加上 RUBYLIB 和 -I 选项指定的所有附加目录。

p187

irb 的一个重要用途在于,体验你刚刚写的代码,使用 load。没有使用 require 的原因 是: load 允许我们多次加载同一个文件,如果这样我们发现了一个 bug 然后编辑文件, 可以将它重新加载到 irb 会话中。

p318

ruby 每个源代码文件都已声明当自己被装载时要执行的代码 block(BEGIN block)和程序 运行后要执行的 block(END block), 两者在一个文件中可以有多个。

BEGIN {
  开始代码
}
...
EN {
  结束代码
}

p319

常规分隔输入

p323

散列表必须能够相应 hash 中消息并返回一个散列码(hash code),且某个键对应的散列 码不能改变。散列表中能使用的键也必须能够 eql? 来比较。如果 eal? 在比较连个键时 返回真,那么这两个键必定具有相同的散列码。这意味着某些类(例如数组和散列表) 不适用做键,因为它们的 hash 值可能会随着内容而发生改变。因为字符串是最常用的键, 且字符串内容会经常变化,所以 ruby 会对字符串键进行特别处理。如果你使用 String 对象作为 hash 键,则 hash 将在内部复制该字符串,并使用该拷贝作为键。此拷贝将被 冻结,对原字符串的任意改变都不会影响 hash。如果你实现了自定义的类,并使用该类 的对象实例作为 hash 键,那么你需要确保(a)一旦对象被创建,它的散列码就不再改变 或者(b)每当键的散列码发生变化时都调用 Hash#rehash 方法重新对散列表进行索引。

p329

变量和方法的二意性

在表达式中,当 ruby 看到像 a 这样的名字时,它需要判断 a 是一个局部变量引用还是 对没有参数方法 a 的调用。ruby 使用一种启发式的方法来判断这种情况。当 ruby 解析 源代码文件时,它会记录所以已经被赋值的符号。它认为这些符号是变量。以后当遇到一个 既可以是变量又可以是方法调用的符号时,ruby 会检查是否已经对该符号进行了赋值。如果 是,那么把该符号当作变量,否则当作方法调用。

例子有问题啊,2.2.1 下跪 Orz

p330

注意赋值语句并不一定被执行————只要 ruby 看到它了就可以,下面的程序不会导致错误。

> a if 1 if false; a
=> nil

p347

方法定义可能不包含类或模块定义。他们可以含有嵌套的实例或者单例方法定义。当执行 外部的方法时,内部的方法被定义。在被嵌套方法的上下文中,内部方法不是一个闭包,它 是自包含的。

def toggle
  def toggle
    "subsequent times"
  end
  "first time"
end

toggle => "first time"
toggle => "subsequent time"
toggle => "subsequent time"

p354

类属性声明不是 ruby 语法的一部分,而是定义在类 module 中的方法。

p355

方法 module#module_function 通过拷贝一个或多个模块实例方法的定义来创建相应的 模块方法来解决“实例方法定义的功能不能通过模块方法来实现”这个问题。

module Math
  def sin(x)
    ...
  end
end

# the onlyw way to access Math.sin is...
include Math
sin(1)

with module#module_function

module Math
  def sin(x)
    ...
  end
  module_function :sin
end

Math.sin(1)
include Math
sin(1)