From a9eec635a73f050ebc4046f7e9609db5659b366e Mon Sep 17 00:00:00 2001 From: Charles Lowell Date: Mon, 18 Apr 2011 10:24:52 -0500 Subject: [PATCH] infrastructure for managing JavaScript proxies for Ruby object at the gc level. --- lib/v8/portal/proxies.rb | 27 ++++++++++++++++++++++----- spec/ext/ext_spec_helper.rb | 8 +++++--- spec/v8/portal/proxies_spec.rb | 33 ++++++++++++++++++++++----------- 3 files changed, 49 insertions(+), 19 deletions(-) diff --git a/lib/v8/portal/proxies.rb b/lib/v8/portal/proxies.rb index a0abab3..d9e7492 100644 --- a/lib/v8/portal/proxies.rb +++ b/lib/v8/portal/proxies.rb @@ -3,16 +3,33 @@ module V8 class Proxies def initialize - @js_proxies = {} - @rb_proxies = {} + @js_proxies_rb2js = {} + @js_proxies_js2rb = {} end def register_javascript_proxy(proxy, options = {}) target = options[:for] or fail ArgumentError, "must specify the object that you're proxying with the :for => param" fail ArgumentError, "javascript proxy must be a Handle to an actual V8 object" unless proxy.kind_of?(V8::C::Handle) - # handle = V8::C::Handle::New(proxy) - # handle.MakeWeak(&clear_jsproy) - @js_proxies[proxy.object_id] = target + + @js_proxies_js2rb[proxy] = target + @js_proxies_rb2js[target] = proxy + proxy.MakeWeak(&clear_js_proxy(proxy)) + end + + def rb_object_2_js_proxy(object) + @js_proxies_rb2js[object] + end + + def js_proxy_2_rb_object(proxy) + @js_proxies_js2rb[proxy] + end + + def clear_js_proxy(proxy) + lambda do + rb = @js_proxies_js2rb[proxy] + @js_proxies_js2rb.delete(proxy) + @js_proxies_rb2js.delete(rb) + end end end end diff --git a/spec/ext/ext_spec_helper.rb b/spec/ext/ext_spec_helper.rb index 962c641..959e4d2 100644 --- a/spec/ext/ext_spec_helper.rb +++ b/spec/ext/ext_spec_helper.rb @@ -10,12 +10,13 @@ module V8::ExtSpec end after do @cxt.Exit() + @cxt.Dispose() end end end - def v8_eval(script) - c::Script::New(c::String::New(script), c::String::New('')).Run() + def v8_eval(script, sourcename = "") + c::Script::New(c::String::New(script), c::String::New(sourcename)).Run() end def c @@ -31,7 +32,8 @@ module V8::ExtSpec end def v8_gc - c::Script::New(c::String::New("gc()"), c::String::New("gc.js")).Run() + while !c::V8::IdleNotification();end + v8_eval('gc()', 'gc.js') end end \ No newline at end of file diff --git a/spec/v8/portal/proxies_spec.rb b/spec/v8/portal/proxies_spec.rb index c0627fd..4b744c4 100644 --- a/spec/v8/portal/proxies_spec.rb +++ b/spec/v8/portal/proxies_spec.rb @@ -4,11 +4,19 @@ describe V8::Portal::Proxies do include V8::ExtSpec context "for Ruby objects which are embedded into javascript" do - + + it "allows you to resolve the Ruby object's JavaScript proxy" do + proxy = c::Object::New() + object = Object.new + subject.register_javascript_proxy proxy, :for => object + subject.rb_object_2_js_proxy(object).should be(proxy) + subject.js_proxy_2_rb_object(proxy).should be(object) + end + it "requires a Ruby object which is the actual object that is proxied" do expect {subject.register_javascript_proxy c::Object::New()}.should raise_error(ArgumentError) end - + it "can only register proxies which are low-level JavaScript objects" do expect {subject.register_javascript_proxy Object.new, :for => Object.new}.should raise_error(ArgumentError) end @@ -22,33 +30,36 @@ describe V8::Portal::Proxies do it "releases the hard reference if its corresponding javascript object has been garbage collected" do object = Object.new + proxy = c::Object::New() ObjectSpace.define_finalizer(object, method(:finalize)) - subject.register_javascript_proxy c::Object::New(), :for => object - object = nil - v8_gc - afterwards {@finalized.should be_true} + subject.register_javascript_proxy proxy, :for => object + ruby_gc do + object = nil + v8_gc() + afterwards {@finalized.should be_true} + end end end context "for a JavaScript objects which are embedded into Ruby" do it "holds a weak referece to any javascript object which is " end - + private - + def finalize(object_id) @finalized = true end - + def afterwards(&block) @after ||= [] @after << block if block_given? end - + after do ruby_gc do @after.each(&:call) if @after end end - + end