Learn Ruby Metaprogramming 备忘

原创文章,转载请注明来源并保留原文链接

又见元编程,元编程是拿语言本身当做操作的对象。
元编程是Ruby的一种自省能力。

1)继承族谱
顶层的是BasicObject(ruby1.9新增)

ruby-1.9.2-rc2 > BasicObject.superclass
 => nil

Object继承自BasicObject

ruby-1.9.2-rc2 > Object.superclass
 => BasicObject

Module继承了Object

ruby-1.9.2-rc2 > Module.superclass
 => Object

Class继承了Module

ruby-1.9.2-rc2 > 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中的一般的常量(大写开头):

irb(main):001:0> A = "1"
=> "1"
irb(main):002:0> self.class.const_get(:A)
=> "1"

我们定义一个类的时候,其实也无形中给class这个类增加了一个常量,例如:

irb(main):004:0> class Zires;end
=> nil
irb(main):005:0> Class.constants.grep("Zires")
=> ["Zires"]

irb(main):008:0> 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
 
# 这些方法看文档吧,比较全

Leave a Reply

Your email address will not be published. Required fields are marked *