MetaProgramming Chapter 2
Ruby 元编程 第二章
该文档包含Ruby对象模型的基本概述。
阅读文档,你将学到:
- 语言构件:类class,模块module,实例变量variable,方法method的定义与关系
- 祖先链ancestor,超类superclass与所属类class
- 打开类和细化Refinement
打开类
猴子补丁(Monkeypatch)
class Array
def replace(original, replacement)
self.map {|e| e == original ? replacement : e }
end
end
def test_replace
original = ['one', 'two', 'one', 'three']
replaced = original.replace('one', 'zero')
assert_equal ['zero', 'two', 'zero', 'three'], replaced
end
[].methods.grep /^re/
# => [:reverse_each, :reverse, ..., :replace, ...]
INFO: 细化Refinement比猴子补丁安全
类的真相
NOTE: 类就是一个对象(Class 类的一个实例)外加一组实例方法和一个对其超类的引用
对象
NOTE: 对象就是一组实例变量外加一个指向其类的引用
INFO:一切皆对象
对象中包含实例变量,方法
实例变量放在对象中,方法放在类中
String.instance_methods == "abc".methods
# => true
String.methods == "abc".methods
# => false
类与对象,实例变量关系图
常量
NOTE: 任何以大写字母开头的引用(包括类名和模块名)都是常量
- 常量与变量的区别
INFO: 作用域不同
module MyModule
MyConstant = 'Outer constant'
class MyClass
MyConstant = 'Inner constant'
end
end
- 常量的路径
module M
class C
X = 'a constant'
end
C::X # => "a constant"
end
M::C::X # => "a constant"
Y = 'a root-level constant'
module M
Y = 'a constant in M'
Y # => "a constant in M"
::Y # => "a root-level constant"
end
当前代码路径查询:
module M
class C
module M2
Module.nesting
end
end
end
方法
- 模块与方法查找
- prepend 把模块插入祖先链中包含它的该类下方
- include 把模块插入祖先链中包含它的该类上方
module M1
def my_method
'M1#my_method()'
end
end
class C
include M1
end
class D < C; end
D.ancestors # => [D, C, M1, Object, Kernel, BasicObject]
class C2
prepend M2
end
class D2 < C2; end
D2.ancestors # => [D2, M2, C2, Object, Kernel, BasicObject]
- Kernel模块
NOTE: Object类包含了Kernel模块
Kernel.private_instance_methods.grep(/^pr/) # => [:printf, :print, :proc]
- 执行方法
- self 当前对象
- private
——-我是不懂分割线——-
Quesetion:
NOTE:
1.如果调用方法的接受者不是自己,必须明确指明接受者。
2.不能明确指定接收者来调用私有方法,私有方法只能通过隐性的接受者self调用
3.如果x,y都是同一个类的对象,x不能调用y的私有方法。因为需要指明接受者来调用另一个对象的方法。但可以调用从超类继承的私用方法,因为调用继承来的方法不用明确指明接受者
举个栗子:
class C
def public_method
self.private_method
end
private
def private_method; end
end
C.new.public_method
< NoMethodError: private method ‘private_method’ called [...]
——-不懂分割线结束—–
细化(Refinement)
打开类与细化区别
- 细化只在两种场合有效:
1) refine代码快内部
2) 从using语句的位置开始到模块结束,或是文件结束
INFO: 细化在有限范围内与猴子补丁一样,既可以定义新方法,也可以重新定义已有方法,还可以include或prepend某个模块。只作用在希望生效的地方,可以避免无意中破坏有用的代码
class String
def to_alphanumeric
gsub(/[^\w\s]/, '')
end
end
module StringExtensions
refine String do
def to_alphanumeric
gsub(/[^\w\s]/, '')
end
end
end
using StringExtension
"my *1st* refinement!".to_alphanumeric # => "my 1st refinement"
细化的问题
class MyClass
def my_method
"original my_method()"
end
def another_method
my_method
end
end
module MyClassRefinement
refine MyClass do
def my_method
"refined my_method()"
end
end
end
using MyClassRefinement
MyClass.new.my_method # => "refined my_method()"
MyClass.new.another_method # => "original my_method()"
WARNING: Refinements are experimental, and the behavior may change in future versions of Ruby!
细化是试验性的,在未来版本中可能发生变化