它们各自来源于:Kernel#eval,BasicObject#instance_eval,BasicObject#instance_exec,Module#class_eval(module_eval是其别名)

即是,任何东西都可instance_eval/instance_exec ,而class_eval只能在Module/Class的new方法所产生的东西上调用,eval只能在Object以下的东西上调用

eval的参数如下:eval( string ‹ , binding ‹ , file ‹ , line ››› ),可传一个binding给它,以改变执行环境,而其它_eval只能作用于方法的接收者

当用于定义方法时,if you want to point out that "I am dealing with a class" or "I want to add methods on all instances of that class", use class_eval . otherwise, use instance_eval.

instance_eval与instance_exec区别在于,_eval不接收实参,而_exec可以(甚至可以传别的对象)

这使得instance_exec就像是在某对象上调用一个可接受参数的方法一样

instance_eval其实会yield自身给block,因proc对参数不敏感而lambda却敏感,所以lambda需写明形参

因此,以下都是能正常运行的

(若想确定instance_exec 时该传多少/什么参数给block,可检查arity)

irb:01:0> require 'ostruct'
irb:02:0> a, b, c = %w{a b c}.map do |name|
irb:03:1*       OpenStruct.new(name: name)
irb:04:1>   end
irb:05:0> a.instance_eval {puts name; puts c.name}
a
c
irb:06:0> a.instance_eval &Proc.new{puts name; puts c.name}
a
c
irb:07:0> a.instance_eval &-> o {puts name; puts o.name; puts c.name}
a
a
c
irb:08:0> a.instance_exec {puts name; puts c.name}
a
c
irb:09:0> a.instance_exec &Proc.new{puts name; puts c.name}
a
c
irb:10:0> a.instance_exec(b){|c| puts name; puts c.name}
a
b
irb:11:0> a.instance_exec b, &-> o {puts name; puts c.name }
a
c
irb:12:0>