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 let(:x => a, :y => b){ x + y } #=> 42
p a.as(:b){ a + b }              #=> 80
p a.as(:x, :y => b){ x + y }     #=> 42
p let(:c => 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/
--
share your knowledge.  it's a way to achieve immortality.
h.h. the 14th dalai lama