On Sun, 10 Jul 2005 21:25:36 +0200, Robin Stocker  
<robin-lists-ruby-talk / nibor.org> wrote:

>    def to_proc
>      # Raises exception if block isn't valid, e.g. SyntaxError.
>      eval "Proc.new{ #{@block} }"
>    end
>
>    def method_missing( *args )
>      to_proc.send( *args )
>    end

Nice idea, to avoid storing the Proc object in an instance variable and so  
being able to just use the default serializing. But I guess this is quite  
slow ;-)

So, here is my solution. It should be almost as fast as normal procs, but  
I had to implement custom serializing methods. I also implemented a custom  
==, because that doesn't really work with method_missing/delegate.


require "delegate"
require "yaml"

class SProc < DelegateClass(Proc)

     attr_reader :proc_src

     def initialize(proc_src)
         super(eval("Proc.new { #{proc_src} }"))
         @proc_src = proc_src
     end

     def ==(other)
         @proc_src == other.proc_src rescue false
     end

     def inspect
         "#<SProc: #{@proc_src.inspect}>"
     end
     alias :to_s :inspect

     def marshal_dump
         @proc_src
     end

     def marshal_load(proc_src)
         initialize(proc_src)
     end

     def to_yaml(opts = {})
         YAML::quick_emit(self.object_id, opts) { |out|
             out.map("!rubyquiz.com,2005/SProc" ) { |map|
                 map.add("proc_src", @proc_src)
             }
         }
     end

end

YAML.add_domain_type("rubyquiz.com,2005", "SProc") { |type, val|
     SProc.new(val["proc_src"])
}

if $0 == __FILE__
     require "pstore"

     code = SProc.new %q{ |*args|
         puts "Hello world"
         print "Args: "
         p args
     }

     orig = code

     code.call(1)

     File.open("proc.marshalled", "w") { |file| Marshal.dump(code, file) }
     code = File.open("proc.marshalled") { |file| Marshal.load(file) }

     code.call(2)

     store = PStore.new("proc.pstore")
     store.transaction do
         store["proc"] = code
     end
     store.transaction do
         code = store["proc"]
     end

     code.call(3)

     File.open("proc.yaml", "w") { |file| YAML.dump(code, file) }
     code = File.open("proc.yaml") { |file| YAML.load(file) }

     code.call(4)

     p orig == code
end