Here's some code I wrote to delay object instantiation until an
object's methods are needed.  If there's anything fooey about it, or
if there's a better version out there, please let me know :-)



--begin--
#########################################################################
#########################################################################
#### delayed.rb:  Thunks for Object Insantiation                    
####
#### Author:  Matthew Maycock                                       
####
#### Email:   _mr_bill_98 / yahoo.com                                 
####
#### Date:    June 16th, 2004 AD!                                   
####
####                                                                
####
#### Purpose:                                                       
####
####    Delay instantiation of objects until needed.                
####
####    Overhead given by an extra indirection of dispatch          
####
####    Use at your own risk!                                       
####
####                                                                
####
#### License:                                                       
####
####    The least restrictive license applicable to this software   
####
####    given that it was written in ruby and uses the ruby library.
####
####    I don't really know that much about such things, so if there
####
####    isn't anything in the way, consider this released under the 
####
####    public domain, free for all!                                
####
#########################################################################
#########################################################################



# Delay creation of an object until some method tries to use it.
class DelayedInstance < Object
  def initialize(klass, *args)
    @object  = Object.new
    ivars = Object.instance_method(:instance_variables)
    ieval = Object.instance_method(:instance_eval)
    iclss = Object.instance_method(:class)
    inspt = Object.instance_method(:inspect)

    switched = @delayed_switched = false


    switch = @delayed_switch     = Proc.new {
      raise "Already switched!" if switched
      switched = @delayed_switched = true
      @object  = klass.send(:new, *args)
    }

    delayed_self = self
    @object.instance_eval {
      @delayed_parent = delayed_self
      @delayed_switch = switch
      @delayed_added  = false
      @delayed_eval   = ieval
    }

    [:==, :===, :=~, :__id__, :__send__, :class, :clone, :display,
:dup, :eql?, :equal?, :extend, :freeze, :frozen?, :hash, :id,
     :inspect, :instance_eval, :instance_of, :instance_variable_get,
:instance_variable_set, :instance_variables, :is_a?, :kind_of?,
     :method, :methods, :new, :nil?, :object_id, :private_methods,
:protected_methods, :public_methods, :remove_instance_variable,
     :respond_to?, :send, :singleton_method_added,
:singleton_method_removed, :singleton_method_undefined,
:singleton_methods, :taint,
     :tainted?, :to_a, :to_s, :type, :untaint].each {|sym|
      eval <<-END_EVAL
        def @object.#{sym.to_s}(*args, &block)
          return super(*args, &block) unless @delayed_added
          parent = @delayed_parent
          @delayed_switch[]
          obj    = @delayed_eval.bind(parent).call { @object }
          obj.send(#{sym.inspect}, *args, &block)
        end
      END_EVAL
    }

    Object.instance_method(:instance_eval).bind(@object).call
{@delayed_added = true}
  end

  def method_missing(sym, *args, &block)
    @delayed_switch[] unless @delayed_switched
    @object.send(sym, *args, &block)
  end
end

[:==, :===, :=~, :__id__, :__send__, :class, :clone, :display, :dup,
:eql?, :equal?, :extend, :freeze, :frozen?, :hash, :id,
 :inspect, :instance_eval, :instance_of, :instance_variable_get,
:instance_variable_set, :instance_variables, :is_a?, :kind_of?,
 :method, :methods, :new, :nil?, :object_id, :private_methods,
:protected_methods, :public_methods, :remove_instance_variable,
 :respond_to?, :send, :singleton_method_added,
:singleton_method_removed, :singleton_method_undefined,
:singleton_methods, :taint,
 :tainted?, :to_a, :to_s, :type, :untaint].each {|sym|
  DelayedInstance.module_eval <<-END_EVAL
    def #{sym.to_s}(*args, &block)
      @object.send(#{sym.inspect}, *args, &block)
    end
  END_EVAL
}



if __FILE__ == $0 then

  class Test
    def initialize(index)
      $stdout.puts "Something that takes a thousand hours..."
      @index = index
    end

    def display
      $stdout.puts @index
    end
  end

  data = (1..10).map {|i| DelayedInstance.new(Test, i)}
  data.each {|d| d.display}

  $stdout.puts
  foo = DelayedInstance.new(Test, 1000)
  foo.instance_eval {
    $stdout.puts "Instance Eval!"
    @santa = 100
  }

  $stdout.puts foo.instance_variables.inspect
  $stdout.puts foo.instance_eval {@santa}
end

=begin
### ruby -v:  ruby 1.8.1 (2003-12-25) [i386-mswin32]
# OUTPUT
Something that takes a thousand hours...
1
Something that takes a thousand hours...
2
Something that takes a thousand hours...
3
Something that takes a thousand hours...
4
Something that takes a thousand hours...
5
Something that takes a thousand hours...
6
Something that takes a thousand hours...
7
Something that takes a thousand hours...
8
Something that takes a thousand hours...
9
Something that takes a thousand hours...
10

Something that takes a thousand hours...
Instance Eval!
["@index", "@santa"]
100
=end