serializable_proc icon indicating copy to clipboard operation
serializable_proc copied to clipboard

Proc that can be serialized

= serializable_proc

== IMPORTANT#1: SerializableProc was written in the days of ruby 1.9.x, it should be buggy for anything beyond that. == IMPORTANT#2: SerializableProc is no longer maintained, use it at your own risk, & expect no bug fixes.

As the name suggests, SerializableProc is a proc that can be serialized (marshalled). A proc is a closure, which consists of the code block defining it, and binding of local variables. SerializableProc's approach to serializability is to extract:

  1. the code from the proc (using sourcify), and
  2. the local, instance, class & global variables reference within the proc from the proc's binding, using deep copy via Marshal.load(Marshal.dump(var))

A SerializableProc differs from the vanilla Proc in the following 2 ways:

=== 1. Isolated variables

By default, upon initializing, all variables (local, instance, class & global) within its context are extracted from the proc's binding, and are isolated from changes outside the proc's scope, thus, achieving a snapshot effect.

require 'rubygems' require 'serializable_proc'

x, @x, @@x, $x = 'lx', 'ix', 'cx', 'gx'

s_proc = SerializableProc.new { [x, @x, @@x, $x].join(', ') } v_proc = Proc.new { [x, @x, @@x, $x].join(', ') }

x, @x, @@x, $x = 'ly', 'iy', 'cy', 'gy'

s_proc.call # >> "lx, ix, cx, gx" v_proc.call # >> "ly, iy, cy, gy"

Sometimes, we may want global variables to behave as truely global, meaning we don't want to isolate globals at all, this can be done by declaring @@_not_isolated_vars within the code block:

s_proc = SerializableProc.new do @@_not_isolated_vars = :global # globals won't be isolated $stdout << "WakeUp !!" # $stdout is the $stdout in the execution context end

Supported values are :global, :class, :instance, :local & :all, with :all overriding all others. The following declares all variables as not isolatable:

s_proc = SerializableProc.new do @@_not_isolated_vars = :all ... end

When invoking, Kernel.binding should be passed in to avoid unpleasant surprises:

s_proc.call(binding)

(take a look at SerializableProc's rdoc for more details)

=== 2. Marshallable

No throwing of TypeError when marshalling a SerializableProc:

Marshal.load(Marshal.dump(s_proc)).call # >> "lx, ix, cx, gx" Marshal.load(Marshal.dump(v_proc)).call # >> TypeError (cannot dump Proc)

== Installing It

The religiously standard way:

$ gem install serializable_proc

== Gotchas

Under the hood, SerializableProc relies on sourcify[http://github.com/ngty/sourcify] to do code extraction, thus it shares the same gotchas as sourcify.

== Supported Rubies

SerializableProc has been tested to work on the following rubies:

  1. MRI 1.8.6, 1.8.7 & 1.9.1
  2. REE 1.8.7
  3. JRuby 1.5.1+

== Note on Patches/Pull Requests

  • Fork the project.
  • Make your feature addition or bug fix.
  • Add tests for it. This is important so I don't break it in a future version unintentionally.
  • Commit, do not mess with rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
  • Send me a pull request. Bonus points for topic branches.

== Copyright

Copyright (c) 2010 NgTzeYang. See LICENSE for details.