[转]eval, class_eval, instance_eval和binding

http://www.cnblogs.com/rubylouvre/archive/2011/08/28/2112321.html
前些天写html生成器的时候用到了erb,在生成html的时候是这么一句:
html=tpl.result(binding)
binding这个变量(Kernel的一个方法 T_T)有点古怪,就搜了下。它表示了ruby的当前作用域,没有任何对外可见的成员函数,唯一的用途就是传递给eval作第二个参数。因而可以这样:
def test_binding
magic='brother Chun is PURE MAN'
return binding
end
eval "puts magic", test_binding

这样就穿越了一个作用域。
有时可以见到这样的构造函数:
a=Baby.new {
name "Makr"
father "Mike"
age 0.2
}
a.cry

好处就是好看。实现起来其实也很容易,用instance_eval:
class Baby
def initialize(&blc)
instance_eval(&blc) #here
end

def name(str=nil)
@name=str if str
@name
end
def age(num=nil)
@age=num if num
@age
end
def father(str=nil)
@father=str if str
@father
end
def cry
puts "#{name} is only #{age.to_s} year old, he wanna milk! Brother Chun is PURE MAN!"
end
end
#有重复代码?用class_eval缩短之,有点像宏了:
class Baby
def initialize(&blc)
instance_eval(&blc)
end

def Baby.my_attr(*names)
names.each{|n|
class_eval %{
def #{n}(x=nil)
@#{n}=x if x
@#{n}
end
}
}
end

my_attr :name, :father, :age

def cry
puts "#{name} is only #{age.to_s} year old, he wanna milk! Brother Chun is PURE MAN!"
end
end

a=Baby.new {
name "Makr"
father "Mike"
age 0.2
}
a.cry

这里class_eval穿越到了类的作用域,实现了动态添加函数。instance_eval也是,穿越到了实例的作用域,实现修改其内部数据。明白了它们的穿越关系,我们可以实现自己的class_eval和instance_eval——从合适的地方搞到binding就行了。
class Baby
def my_instance_eval(code)
eval code, binding
end
def Baby.my_class_eval(code='')
eval code, binding
end
end
#就这么简单。调用的时候就像这样:
class Baby
def initialize(code)
my_instance_eval(code)
end
my_attr :name, :father, :age
end
a=Baby.new %{
name "Test"
father "Orz"
age 0.2
}

刚才省略了一点,那就是class_eval和instance_eval可以接受block代替字符串。搜了下,貌似没找到eval接受block的方法,所以这顶多算是只能eval字符串的山寨class_eval。
update: 想起来ruby中lambda和proc在作用域上的小区别,也就是binding的不同了。proc直接使用原先的binding,lambda继承原先作用域创建一个新的binding。

def add_method(c, m, &b)
c.instance_eval { #在此使用class_eval是一样的效果
define_method(m, &b)
}
end
add_method(String, :greet) { "Hello, " + self }
p "world".greet # => "Hello, world"
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值