Robin Stocker <robin-lists-ruby-talk / nibor.org> writes:

> Hi,
>
> This is the second solution that I could finish in time. Well, it was
> pretty easy.
>
> I imagine my solution is not very fast, as each time a method on the
> SerializableProc is called, a new Proc object is created.
> The object could be saved in an instance variable @proc so that speed
> is only low on the first execution. But that would require the
> definition of custom dump methods for each Dumper so that it would not
> attempt to dump @proc.
>
> Here's my solution...

My code is very similar, but only eval()s once:


require 'delegate'

class SerializableProc < DelegateClass(Proc)
  attr_reader :__code

  def initialize(code)
    @__code = code.lstrip
    super eval("lambda { #@__code }")
  end

  def marshal_dump; @__code; end
  def marshal_load(code); initialize code; end

  def to_yaml
    Object.instance_method(:to_yaml).bind(self).call
  end

  def to_yaml_properties; ["@__code"]; end
  def to_yaml_type; "!ruby/serializableproc"; end
end

# .oO(Is there no easier way to do this?)
YAML.add_ruby_type( /^serializableproc/ ) { |type, val|
  type, obj_class = YAML.read_type_class( type, SerializableProc )
  o = YAML.object_maker( obj_class, val )
  o.marshal_load o.__code
}


Usage:

code = SerializableProc.new %{
  puts "this is serialized!"
  p binding; p caller
}


Obvious problems of this approach are the lack of closures and editor
support (depending on the inverse quality of your editor :P), better
results can be reached with flgr's hack to look for the source on disk
or by using nodewrap to serialize the AST.  See
http://rubystuff.org/nodewrap/ for details.

That was a nice quiz.

-- 
Christian Neukirchen <chneukirchen / gmail.com> http://chneukirchen.org