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:
-
the code from the proc (using sourcify), and
-
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:
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)
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)
The religiously standard way:
$ gem install serializable_proc
Under the hood, SerializableProc relies on sourcify to do code extraction, thus it shares the same gotchas as sourcify.
SerializableProc has been tested to work on the following rubies:
-
MRI 1.8.6, 1.8.7 & 1.9.1
-
REE 1.8.7
-
JRuby 1.5.1+
-
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.