A
ara.t.howard
this was kind of fun
cfp: ~> cat a.rb
class Object
def let *a, &b
Let.evaluate *a, &b
end
def as local, kvs = {}, &block
kvs.update local => self
Let.evaluate kvs, &block
end
class Let
instance_methods.each{|m| undef_method m unless m[%r/^__/]}
Instance_eval = Object.instance_method :instance_eval
Instance_variable_set =
Object.instance_method :instance_variable_set
def self.evaluate kvs = {}, &block
current = {}
binding = block.binding
undefined = Object.new
begin
push_vars kvs, current, binding, undefined
let = new
singleton_class =
class << let
self
end
instance_eval = Instance_eval.bind let
instance_variable_set = Instance_variable_set.bind let
singleton_class.module_eval{ kvs.keys.each{|k| attr k} }
instance_eval.call{ kvs.each{|k,v|
instance_variable_set.call "@#{ k }", v} }
instance_eval.call &block
ensure
pop_vars current, binding, undefined
end
end
def self.push_vars kvs, current, binding, undefined
kvs.each do |k,v|
current[k] =
begin
eval "#{ k }", binding
rescue NameError
undefined
end
eval "#{ k } = ObjectSpace._id2ref #{ v.object_id }",
binding unless
current[k] == undefined
end
end
def self.pop_vars current, binding, undefined
current.each do |k,v|
next if v == undefined
eval "#{ k } = ObjectSpace._id2ref #{ v.object_id }", binding
end
end
end
end
a = 40
b = 2
c = 'forty-two'
p letx => a, :y => b){ x + y } #=> 42
p a.asb){ a + b } #=> 80
p a.asx, :y => b){ x + y } #=> 42
p letc => a, :d => b){ c + d } #=> 42
p a #=> 40
p b #=> 2
p c #=> "forty-two"
i know people have done 'let' before on ruby-talk but, iirc, not and
impl which allowed shadowing locals.
a @ http://codeforpeople.com/
cfp: ~> cat a.rb
class Object
def let *a, &b
Let.evaluate *a, &b
end
def as local, kvs = {}, &block
kvs.update local => self
Let.evaluate kvs, &block
end
class Let
instance_methods.each{|m| undef_method m unless m[%r/^__/]}
Instance_eval = Object.instance_method :instance_eval
Instance_variable_set =
Object.instance_method :instance_variable_set
def self.evaluate kvs = {}, &block
current = {}
binding = block.binding
undefined = Object.new
begin
push_vars kvs, current, binding, undefined
let = new
singleton_class =
class << let
self
end
instance_eval = Instance_eval.bind let
instance_variable_set = Instance_variable_set.bind let
singleton_class.module_eval{ kvs.keys.each{|k| attr k} }
instance_eval.call{ kvs.each{|k,v|
instance_variable_set.call "@#{ k }", v} }
instance_eval.call &block
ensure
pop_vars current, binding, undefined
end
end
def self.push_vars kvs, current, binding, undefined
kvs.each do |k,v|
current[k] =
begin
eval "#{ k }", binding
rescue NameError
undefined
end
eval "#{ k } = ObjectSpace._id2ref #{ v.object_id }",
binding unless
current[k] == undefined
end
end
def self.pop_vars current, binding, undefined
current.each do |k,v|
next if v == undefined
eval "#{ k } = ObjectSpace._id2ref #{ v.object_id }", binding
end
end
end
end
a = 40
b = 2
c = 'forty-two'
p letx => a, :y => b){ x + y } #=> 42
p a.asb){ a + b } #=> 80
p a.asx, :y => b){ x + y } #=> 42
p letc => a, :d => b){ c + d } #=> 42
p a #=> 40
p b #=> 2
p c #=> "forty-two"
i know people have done 'let' before on ruby-talk but, iirc, not and
impl which allowed shadowing locals.
a @ http://codeforpeople.com/