《Ruby元编程》 之后
《Ruby元编程》
这本书用两个字总结:法术。用一个句话总结:根本没有什么元编程,只有编程而已。
对于 Ruby 来说
我接触到 Ruby 这个语言源于 Rails,但我不希望自己学习 Ruby 只是终于 Rails,终于 Web。
所以我想要熟悉 Ruby,精通 Ruby,想要知道他是什么,他能干些什么,为什么 Rails 能用 Ruby 写出来。
Ruby的元
我对元的理解是,事物对自己的抽象。一个编程语言想要应用到现实世界中,非常需要中间层来一层层地将想要描述的事物抽象出来。
Ruby 的语言设计和元能力有两个优点。
非常符合这种现实世界对于编程语言的需求。
Ruby 语言的写法精简,抽象程度高,语法对程序员友好。
但是 Ruby 语言的性能问题和对应用高并发情况出现的处理能力一直被人诟病。
不过好像2.0++的版本出来后,性能得到了质的飞跃,再也没有什么人说 Ruby 性能的坏话了。
法术
《Ruby元编程》附录中的法术手册就是 Ruby 元编程的一个总结。我认为,假如你把附录中的法术都掌握之后都不用看这本书了。这本书就是
详解剖析这些东西而已。下面的例子在 Ruby 2.1.2版本下测试。
假若你已经对这些字眼非常了解,就不必往下看了。当然我没有非常详细的解析,只是一个括览:
Around Alias 环绕别名
Blank Slate 白板
Class Extyension 类扩展
Class Extension 类扩展混入
Context Probe 上下文探针
Dynamic Method 动态方法
Deferred Evaluation 延迟执行
Dynamic Proxy 动态代理
Flat Scpoe 扁平作用域
Kernel Method 内核方法
Monkeypatch 猴子补丁
Object Extension 对象扩展
Shared Scope 共享作用域
Around Alias 环绕别名
class String
alias old_reverse reverse
def reverse
"x#{old_reverse}x"
end
end
"abc".reverse # => "xcbax"
"abc".old_reverse # => "cba"
old_reverse 和 reverse互 用,但是重新定义 reverse,old_reverse 指向原来的 reverse。
Blank Slate 白板
class C
def method_missing(name, *args)
"a Ghost Method"
end
end
obj = C.new
obj.to_s # => "#<C:XXXX>"
class C
instance_methods.each do |m|
undef_method(m) unless m.to_s =~ /method_missing|resopnd_to?/
end
end
obj.to_s # => "a Ghost Method"
书里面有个 BUG,用来匹配的正则是“/method_missing|resopnd_to?|^/”,这样把所有方法都匹配到了。
而且 Ruby 这里比较有意思的是“=~”匹配的时候,真返回0,假返回 nil。Ruby 里面的判断有值就为真,而 C 和 C++ 都会将0设为 false,1设为 true。
定义了一个类的 method_missing 方法时候,对象调用了一个不知名方法,就会直接调用 method_missing。method_missing 也是很多 Ruby 魔法的根源。
Class Extyension 类扩展
class C ; end
module M
def my_method
"a class method"
end
end
class << C
include M
end
C.my_method # => "a class method"
a = C.new
a.my_method # => "NoMethodError: undefined method `my_method' for #<C:0x000000029d5c68>"
这里对类进行方法扩展,但是对于创建类的对象是没有这个方法的。
Class Extension 类扩展混入
module M
def self.included(base)
base.extend(ClassMethods)
end
module ClassMethods
def my_method
"a class method"
end
end
end
class C
include M
end
C.my_method # => "a class method"
这里的 self.included(base) 使用了类的钩子功能,Ruby 还有其他的钩子方法。
当类C include M的时候,触发了模块M的钩子方法 included,所以 base 就是C,然后C再扩展了M模块的 ClassMethods 的所有方法。
Context Probe 上下文探针
class C
def initialize
@x = "some thing"
end
end
obj = C.new
obj.instance_eval{@x}
instance_eval 可以打开对象自己,操作自己内部。
Dynamic Method 动态方法
class C ; end
C.class_eval do
define_method :my_method do
"a dynamic method"
end
end
obj = C.new
obj.my_method # => "a dynamic method"
class_eval 可以打开一个类,对类进行操作。
Deferred Evaluation 延迟执行
class C
def store(&block)
@my_code_capsule = block
end
def execute
@my_code_capsule.call
end
end
obj = C.new
obj.store{$X = 1}
$X = 0
obj.execute
$X # => 1
可以动态地将一个块存到对象的一个变量中。
Dynamic Proxy 动态代理
class MyDynamicProxy
def initialize(target)
@target = target
end
def method_missing(name, *args, &block)
"result: #{@target.send(name, *args, &block)}"
end
end
obj = MyDynamicProxy.new("a String")
obj.reverse # => "result: gnirtS a"
使用到了 method_missing 和 send。Duang。另外一个魔法诞生了。
Flat Scpoe 扁平作用域
class C
def an_attribute
@attr
end
end
obj = C.new
a_variable = 100
obj.instance_eval do
@attr = a_variable
end
obj.an_attribute # =>100
就是使用了 instance_eval 和闭包嘛。
Kernel Method 内核方法
module Kernel
def a_method
"a kernel method"
end
end
a_method # => "a kernel method"
在 kernel 模块中定义方法,所有对象可见。
Monkeypatch 猴子补丁
class String
def reverse
"override"
end
end
"abc".reverse # => "override"
著名的猴子补丁,在 runtime 中改变类和对象的属性和方法。guerrilla patch 拟音 gorilla patch ,然后变成了 monkey patch。
Object Extension 对象扩展
obj = Object.new
module M
def my_method
"a singleton method"
end
end
class << obj
include M
end
obj.my_thod # => "a singleton method"
对 obj 的元类进行扩展,混入模块 M 的方法。
Shared Scope 共享作用域
lambda {
shared = 10
self.class # => Object
self.class.class_eval do
define_method :counter do
shared
end
define_method :down do
shared -= 1
end
end
}.call
counter # => 10
3.times {down}
counter # => 7
lambda 对 Object 对象进行操作,并且共享变量。
总结
其实这些东西熟悉了这些东西之后,还是那句话:根本没有什么元编程,只有编程而已。