/serializable_proc

Proc that can be serialized

Primary LanguageRubyMIT LicenseMIT

serializable_proc

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 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 © 2010 NgTzeYang. See LICENSE for details.