除去 Rails 元编程那章,已经《Ruby 元编程》读了两遍多了,伴隨着的也是自己由初级水平向中级水平的提升。 刚看此书时,自己基本上只处于刚好知道一点 Ruby 元编程。然后第看过第一遍后,接着便是在公司的实际项目中将所学的进行实践,接着看第二遍便是对之前所学知识、所写代码的进行一检阅。
下面是看书过程中的一些笔记。
String.ancestors # => [String, Comparable, Object, Kernel, BasicObject]
「向右一步,再向上」:
send # => 动态派发
defind_method # => 动态定义方法
method_missing # => 幽灵方法
当一个幽灵方法和一个真实方法发生命名冲突时,后者会胜出。
为了安全起见,你应该在代理类中删除绝大多数继承来的方法(可以使用 Module#undef_method
和 Module#remove_method
)。这就是所谓的白板 ( Blank State ) 类,它所拥有的方法比 Object 类还要少。
当代码运行时,它需要一个执行环境:局部变量、实例变量、self …… 这些东西是绑定在对象上的名字,可以把它们简称为绑定 ( binding )。
当定义一个块时,它会获取当时环境中的绑定。而且将这个块传给一个方法时,它会带着这些绑定一起进入该方法。
每个 Ruby 作用域包含一组绑定,并且不同的作用域之间被称为作用域门。
程序会在这三个地方关闭前一个作用域,同时打开一个新的作用域:
让绑定穿越作用域门:
Class.new() { } # 代替 class
Module.new() { } # 代替 module
Module#defind_method # 代替 def
Ruby 中绝大多数东西都是对象,但是 block 不是。
&
操作符的真正含义:在 Proc 和 block 之间转换。
block 使用 yield
语句来调用,Proc 使用 call
语句来调用。
在 lambda 中,return
仅仅表示从这个 lambda 中返回
在 Proc 中,return
则表示从定义 Proc 的作用域中返回
在 lambda 中,参数数量要对应
在 Proc 中,会忽略多余的参数,或者对未指定的参数赋值 nil
建议:将 lambda 作为第一选择。
注意:方法的对象必须属于同一个类
class MyClass
def initialize(value)
@x = value
end
def my_method
@x
end
end
obj = MyClass.new(1)
m = obj.method :my_methodm.call # => 1
unbound = m.unbindanother_obj = MyClass.new(2)
m = unbound.bind(another_obj)
m.call # => 2
当使用 class
关键字时,并非是在指定对象未来的行为方式,相反,实际上是在运行代码。
类只是增强的模块。
Ruby 解释器总是追踪当前类(或模块)的引用。在类的定义中,当前类就是 self ——正在定义的类。
instance_eval
方法仅仅会修改 self,而 class_eval
方法会同时修改 self 和当前类。
类的实例变量不同于类的对象的实例变量
class MyClass
@my_var = 1
def self.read() @my_var; end
def write() @my_var = 2; end
def read() @my_var; end
end
obj = MyClass.new
obj.write
obj.read # => 2
MyClass.read # => 1
绝大多数 Ruby 主义者都避免使用类变量,而尽量使用类实例变量。
obj = Object.new
eigenclass = class << obj
self
end
eigenclass.class # => Class
module MyModule
def my_method() 'hello'; end
end
obj = Object.new
obj.extend MyModule
obj.my_method # => 'hello'
class MyClass
extend MyModule
end
MyClass.my_method # => 'hello'
Object#extend
只是在接收者 eigenclass 中包含模块的快捷方式,你完全可以自己手动实现。
alias :new :old # Ruby 关键字,而非方法,所以两个方法之间没有逗号
alias_method :new, :old # Ruby 方法
可以通过以下三个步骤写一个环绕别名