Ruby 元法术
《Ruby元编程》 之后
《Ruby元编程》 (opens in a new tab) 这本书用两个字总结:法术。用一个句话总结:根本没有什么元编程,只有编程而已。
对于 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 对象进行操作,并且共享变量。
总结
其实这些东西熟悉了这些东西之后,还是那句话:根本没有什么元编程,只有编程而已。
© FTAndy.RSS