diff --git a/ext/v8/template.cc b/ext/v8/template.cc index b5e08a7..e82642d 100644 --- a/ext/v8/template.cc +++ b/ext/v8/template.cc @@ -2,11 +2,18 @@ namespace rr { void Template::Init() { - ClassBuilder("Template"); + ClassBuilder("Template"). + defineMethod("Set", &Set); ObjectTemplate::Init(); FunctionTemplate::Init(); } + VALUE Template::Set(int argc, VALUE argv[], VALUE self) { + VALUE name; VALUE value; VALUE attributes; + rb_scan_args(argc, argv, "21", &name, &value, &attributes); + Void(Template(self)->Set(*String(name), *Value(value), PropertyAttribute(attributes))); + } + void ObjectTemplate::Init() { ClassBuilder("ObjectTemplate", "Template"). defineSingletonMethod("New", &New). diff --git a/lib/v8/context.rb b/lib/v8/context.rb index 0abea21..eb82680 100644 --- a/lib/v8/context.rb +++ b/lib/v8/context.rb @@ -1,6 +1,6 @@ module V8 class Context - attr_reader :native + attr_reader :native, :conversion def initialize @native = V8::C::Context::New() @@ -15,6 +15,14 @@ module V8 @conversion.to_v8(ruby_object) end + def link(ruby_object, v8_object) + @conversion.equate ruby_object, v8_object + end + + def self.link(*args) + current.link *args + end + def enter(&block) if !entered? lock_scope_and_enter(&block) diff --git a/lib/v8/conversion/indentity.rb b/lib/v8/conversion/indentity.rb index 7c74aa5..2d41f66 100644 --- a/lib/v8/conversion/indentity.rb +++ b/lib/v8/conversion/indentity.rb @@ -1,30 +1,57 @@ class V8::Conversion module Identity def to_ruby(v8_object) - v8_idmap.lookup(v8_object) {super} + v8_idmap[v8_object] || super + end + + def to_v8(ruby_object) + rb_idmap[ruby_object] || super + end + + def equate(ruby_object, v8_object) + v8_idmap.equate(v8_object, ruby_object) + rb_idmap.equate(ruby_object, v8_object) end def v8_idmap @v8_idmap ||= V8IDMap.new end - class V8IDMap + def rb_idmap + @ruby_idmap ||= RubyIDMap.new + end + + class IDMap def initialize - @storage = {} + @map = {} end - def lookup(v8_object) - if v8_object.is_a?(V8::C::Object) - weakref = @storage[v8_object.GetIdentityHash()] - if weakref && weakref.weakref_alive? - weakref.__getobj__ - else - @storage[v8_object.GetIdentityHash()] = WeakRef.new(yield) - end - else - yield + def [](object) + weakref = @map[to_key(object)] + if weakref && weakref.weakref_alive? + weakref.__getobj__ end end + + def equate(key_object, value_object) + @map[to_key(key_object)] = WeakRef.new(value_object) + end + end + + class RubyIDMap < IDMap + def to_key(object) + object.object_id + end + end + + class V8IDMap < IDMap + def to_key(object) + object.GetIdentityHash() + end + + def [](v8_object) + super if v8_object.is_a?(V8::C::Object) + end end end end \ No newline at end of file diff --git a/lib/v8/conversion/object.rb b/lib/v8/conversion/object.rb index 4651326..e08fc1c 100644 --- a/lib/v8/conversion/object.rb +++ b/lib/v8/conversion/object.rb @@ -1,12 +1,31 @@ class V8::Conversion module Object def to_v8 - V8::C::Object::New() + template = V8::C::ObjectTemplate::New() + template.SetNamedPropertyHandler(Get, nil, nil, nil, nil, V8::C::External::New(self)) + instance = template.NewInstance() + V8::Context.link self, instance + return instance end def to_ruby self end + + class Get + def self.call(property, info) + context = V8::Context.current + object = info.Data().Value() + name = property.Utf8Value() + if object.respond_to?(name) && object.method(name).arity <= 0 + context.to_v8 object.send(name) + else + V8::C::Value::Empty + end + rescue Exception => e + warn "uncaught exception: #{e.class}: #{e.message} while accessing object property: #{e.backtrace.join('\n')}" + end + end end module NativeObject diff --git a/lib/v8/object.rb b/lib/v8/object.rb index fc475c4..400549e 100644 --- a/lib/v8/object.rb +++ b/lib/v8/object.rb @@ -6,6 +6,7 @@ class V8::Object def initialize(native = nil) @context = V8::Context.current or fail "tried to initialize a #{self.class} without being in an entered V8::Context" @native = native || V8::C::Object::New() + @context.link self, @native end def [](key)