Ruby元编程2011-03-24
又见元编程,元编程是拿语言本身当做操作的对象,元编程是Ruby的一种自省能力。
1)继承族谱
顶层的是BasicObject(ruby1.9新增)
BasicObject.superclass
=> nil
Object继承自BasicObject
Object.superclass
=> BasicObject
Module继承了Object
Module.superclass
=> Object
Class继承了Module
Class.superclass
=> Module
注意观察:
Class.new.ancestors => [#class:0x000000022ef638, Object, Kernel, BasicObject]
Class.ancestors => [Class, Module, Object, Kernel, BasicObject]
BasicObject.class => Class
2)main入口
不管是java还是c,都有个main函数作为程序的入口,ruby的在哪呢?其实我们一直在用:
ruby-1.9.2-rc2 > self
=> main
ruby-1.9.2-rc2 > self.class
=> Object
我们写的代码其实都是在这个top-level对象main中发生的,一切都是对象,看吧,一点也不奇怪。
3)constants
Module#const_get
Module#const_set
Module#remove_const
来看看ruby中的一般的常量(大写开头):
A = "1"
=> "1"
self.class.const_get(:A)
=> "1"
我们定义一个类的时候,其实也无形中给class这个类增加了一个常量,例如:
class Zires;end
=> nil
Class.constants.grep("Zires")
=> ["Zires"]
Class.constants - Object.constants
=> []
另外,constants在ruby中还扮演着类似文件路径的作用,例如:
module C
File = "in C"
class Doc
File = "in c/doc"
def root
p File
p ::C::File # 类似绝对路径,absolute path
end
end
end
irb(main):018:0> C::File
=> "in C"
irb(main):019:0> Doc::File
NameError: uninitialized constant Doc
from (irb):19
from :0
irb(main):020:0> C::Doc::File
=> "in c/doc"
irb(main):021:0> C::Doc.new.root
"in c/doc"
"in C"
=> nil
4) dynamic define code
Class#new
Module#define_method
Module#remove_method
Module#method_defined?
看下面的例子:
oop = "Oops!"
class Oops
def say
p "I say #{oop}"
end
end
Oops.new.say #=>undefined local variable or method `oop'
oops = Class.new do
define_method :say do
p "I say #{oop}"
end
end
oops.new.say # => "I say Oops!"
5) dynamic run code
Object#send
Object#instance_eval
Module#module_eval
Module#class_eval
Kernel#eval
block
Proc
proc
lambda
method
send:
ruby-1.9.2-p180 > 1.send(:+, 2)
=> 3
eval&binding:
ruby-1.9.2-p180 > eval("1+2")
=> 3
ruby-1.9.2-p180 > x = 1
=> 1
ruby-1.9.2-p180 > eval("x + 2")
=> 3
def bind_x(x)
x = x
binding
end
ruby-1.9.2-p180 > eval("x + 2", bind_x(2))
=> 4
instance_eval:
ruby-1.9.2-p180 > 1.instance_eval { self + 2}
=> 3
class_eval:
1.class.class_eval do
def add_2
self + 2
end
end
ruby-1.9.2-p180 > 1.add_2
=> 3
ruby中有好几个’家伙’能响应call方法,与eval家族的区别是,他们具有延迟性:
*#Proc Objects* z = Proc.new { |x| p "#{x}"} z.call("a") # call的时候才执行 #=> "a"
l = lambda { |x| p "#{x}"} l.call("b") #=> "b"
p = proc { |x| p "#{x}"} p.call("c") #=> "c"
def myself(x) p "#{x}" end
m = method(:myself).class #=> Method m.call("d") # => "d"
Proc vs proc vs lambda vs method 相同点:
#1)都响应call方法 #2)method可以转化为proc,其余都是Proc的对象 ruby-1.9.2-p180 > Proc.new{}.class => Proc ruby-1.9.2-p180 > lambda{}.class => Proc ruby-1.9.2-p180 > proc{}.class => Proc
ruby-1.9.2-p180 > method(:myself).to_proc.class #=> Proc ***block其实也是Proc***
Proc vs proc vs lambda vs method 不同点:
#1)lambda 是Kernel方法,proc 也是Kernel方法,Proc是类,method是obj方法 #2)关于return,看例子比较 def check(callable) callable.call return "I AM Here!" end
check lambda { return 10 } # => "I AM Here!"
check Proc.new { return 10 } # => LocalJumpError: unexpected return
check proc { return 10 # ruby1.8可能输出"I AM Here!",ruby1.9把proc和Proc统一了 # proc其实就是Proc.new # => LocalJumpError: unexpected return
def myself ; return 10 ; end check method(:myself) # => "I AM Here!"
#3)关于参数 l = lambda { |x| p "#{x}"} p = Proc.new { |x| p "#{x}"} ruby-1.9.2-p180 > p.arity # => 1 ruby-1.9.2-p180 > l.arity # => 1
ruby-1.9.2-p180 > p.call # => ""
ruby-1.9.2-p180 > l.call # => ArgumentError: wrong number of arguments (0 for 1)
#4)lambda? 方法
ruby-1.9.2-p180 > lambda {}.lambda? => true ruby-1.9.2-p180 > proc{}.lambda? => false #5)简便写法 # lamda1.9新增 ruby-1.9.2-p180 > ->(x){ p "#{x}"}.class # => Proc
#6)method可以 unbind # 看 UnboundMethod
6) callbacks
method_missing
const_missing
included and extended
method_added and singleton_method_added
method_removed and method_undefined
singleton_method_removed and singleton_method_undefined
inherited
# 这些方法看文档吧,比较全