From 32028f31fca5139fc51e5fa549e8003467ab03c4 Mon Sep 17 00:00:00 2001 From: Charles Lowell Date: Mon, 11 Jun 2012 01:58:12 -0500 Subject: [PATCH] factor out v8 conversions into separate modules --- lib/v8.rb | 10 +++ lib/v8/array.rb | 9 +- lib/v8/context.rb | 32 +++++-- lib/v8/conversion.rb | 141 +++++++++++-------------------- lib/v8/conversion/array.rb | 17 ++++ lib/v8/conversion/fundamental.rb | 11 +++ lib/v8/conversion/hash.rb | 11 +++ lib/v8/conversion/indentity.rb | 30 +++++++ lib/v8/conversion/numeric.rb | 7 ++ lib/v8/conversion/object.rb | 17 ++++ lib/v8/conversion/proc.rb | 7 ++ lib/v8/conversion/string.rb | 12 +++ lib/v8/conversion/symbol.rb | 7 ++ lib/v8/conversion/time.rb | 13 +++ lib/v8/object.rb | 9 +- 15 files changed, 231 insertions(+), 102 deletions(-) create mode 100644 lib/v8/conversion/array.rb create mode 100644 lib/v8/conversion/fundamental.rb create mode 100644 lib/v8/conversion/hash.rb create mode 100644 lib/v8/conversion/indentity.rb create mode 100644 lib/v8/conversion/numeric.rb create mode 100644 lib/v8/conversion/object.rb create mode 100644 lib/v8/conversion/proc.rb create mode 100644 lib/v8/conversion/string.rb create mode 100644 lib/v8/conversion/symbol.rb create mode 100644 lib/v8/conversion/time.rb diff --git a/lib/v8.rb b/lib/v8.rb index 2c5b65e..a700698 100644 --- a/lib/v8.rb +++ b/lib/v8.rb @@ -1,6 +1,16 @@ require "v8/version" require 'v8/init' +require 'v8/conversion/fundamental' +require 'v8/conversion/indentity' +require 'v8/conversion/numeric' +require 'v8/conversion/object' +require 'v8/conversion/time' +require 'v8/conversion/hash' +require 'v8/conversion/array' +require 'v8/conversion/proc' +require 'v8/conversion/symbol' +require 'v8/conversion/string' require 'v8/conversion' require 'v8/context' require 'v8/object' diff --git a/lib/v8/array.rb b/lib/v8/array.rb index dd445ec..c79b3a4 100644 --- a/lib/v8/array.rb +++ b/lib/v8/array.rb @@ -1,13 +1,14 @@ class V8::Array < V8::Object def initialize(native_or_length = nil) - if native_or_length.is_a?(Numeric) - super V8::C::Array::New(native.to_i) + native = if native_or_length.is_a?(Numeric) + V8::C::Array::New(native_or_length) elsif native_or_length.is_a?(V8::C::Array) - super native_or_length + native_or_length else - super V8::C::Array::New() + V8::C::Array::New() end + super native end def each diff --git a/lib/v8/context.rb b/lib/v8/context.rb index ce726fc..0abea21 100644 --- a/lib/v8/context.rb +++ b/lib/v8/context.rb @@ -1,10 +1,18 @@ module V8 class Context - include Conversion - attr_reader :native + def initialize @native = V8::C::Context::New() + @conversion = Conversion.new + end + + def to_ruby(v8_object) + @conversion.to_ruby(v8_object) + end + + def to_v8(ruby_object) + @conversion.to_v8(ruby_object) end def enter(&block) @@ -46,10 +54,22 @@ module V8 def eval(source, filename = '', line = 1) enter do - source = V8::C::String::New(source.to_s) - filename = V8::C::String::New(filename.to_s) - script = V8::C::Script::New(source, filename) - to_ruby script.Run() + V8::C::TryCatch() do |trycatch| + source = V8::C::String::New(source.to_s) + filename = V8::C::String::New(filename.to_s) + script = V8::C::Script::New(source, filename) + result = script.Run() + if trycatch.HasCaught() + exception = trycatch.Exception() + if exception.IsNativeError() + raise to_ruby exception.Get("message") + else + raise to_ruby exception.ToString() + end + else + to_ruby result + end + end end end diff --git a/lib/v8/conversion.rb b/lib/v8/conversion.rb index 89be39b..d338791 100644 --- a/lib/v8/conversion.rb +++ b/lib/v8/conversion.rb @@ -1,109 +1,68 @@ -module V8::Conversion + +class V8::Conversion + include Fundamental + include Identity + def to_ruby(v8_object) - v8_cache.get(v8_object) do - v8_object.respond_to?(:to_ruby) ? v8_object.to_ruby : v8_object - end + super v8_object end def to_v8(ruby_object) - ruby_object.respond_to?(:to_v8) ? ruby_object.to_v8 : V8::C::Object::New() + super ruby_object end +end - def v8_cache - @v8_cache ||= Cache.new - end - - - class Cache - def initialize - @storage = {} - end - - def get(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 - end - end +for type in [Numeric, Object, Array, Hash, String, Symbol, Time, Proc] do + type.class_eval do + include V8::Conversion.const_get(name) end end class Numeric - def to_v8 - self - end + include V8::Conversion::Numeric end -class V8::C::String - def to_ruby - self.Utf8Value() - end -end - -class String - def to_v8 - V8::C::String::New(self) - end -end - -class Symbol - def to_v8 - V8::C::String::NewSymbol(to_s) - end -end - -class V8::C::Date - def to_ruby - Time.at(self.NumberValue() / 1000) - end -end - -class Time - def to_v8 - V8::C::Date::New(to_f * 1000) - end -end - -class V8::C::Object - def to_ruby - V8::Object.new(self) - end -end - -class V8::Object - def to_v8 - self.native - end -end - -class V8::C::Array - def to_ruby - V8::Array.new(self) - end +class Object + include V8::Conversion::Object end class Array - def to_v8 - array = V8::Array.new(length) - each_with_index do |item, i| - array[i] = item - end - return array.to_v8 - end + include V8::Conversion::Array end class Hash - def to_v8 - object = V8::Object.new - each do |key, value| - object[key] = value - end - return object.to_v8 - end -end \ No newline at end of file + include V8::Conversion::Hash +end + +class String + include V8::Conversion::String +end + +class Symbol + include V8::Conversion::Symbol +end + +class Time + include V8::Conversion::Time +end + +class Proc + include V8::Conversion::Proc +end + +class V8::C::Object + include V8::Conversion::NativeObject +end + +class V8::C::Array + include V8::Conversion::NativeArray +end + +class V8::C::String + include V8::Conversion::NativeString +end + +class V8::C::Date + include V8::Conversion::NativeDate +end + diff --git a/lib/v8/conversion/array.rb b/lib/v8/conversion/array.rb new file mode 100644 index 0000000..4b243a2 --- /dev/null +++ b/lib/v8/conversion/array.rb @@ -0,0 +1,17 @@ +class V8::Conversion + module Array + def to_v8 + array = V8::Array.new(length) + each_with_index do |item, i| + array[i] = item + end + return array.to_v8 + end + end + + module NativeArray + def to_ruby + V8::Array.new(self) + end + end +end \ No newline at end of file diff --git a/lib/v8/conversion/fundamental.rb b/lib/v8/conversion/fundamental.rb new file mode 100644 index 0000000..a1ec5da --- /dev/null +++ b/lib/v8/conversion/fundamental.rb @@ -0,0 +1,11 @@ +class V8::Conversion + module Fundamental + def to_ruby(v8_object) + v8_object.to_ruby + end + + def to_v8(ruby_object) + ruby_object.to_v8 + end + end +end \ No newline at end of file diff --git a/lib/v8/conversion/hash.rb b/lib/v8/conversion/hash.rb new file mode 100644 index 0000000..a77be68 --- /dev/null +++ b/lib/v8/conversion/hash.rb @@ -0,0 +1,11 @@ +class V8::Conversion + module Hash + def to_v8 + object = V8::Object.new + each do |key, value| + object[key] = value + end + return object.to_v8 + end + end +end \ No newline at end of file diff --git a/lib/v8/conversion/indentity.rb b/lib/v8/conversion/indentity.rb new file mode 100644 index 0000000..7c74aa5 --- /dev/null +++ b/lib/v8/conversion/indentity.rb @@ -0,0 +1,30 @@ +class V8::Conversion + module Identity + def to_ruby(v8_object) + v8_idmap.lookup(v8_object) {super} + end + + def v8_idmap + @v8_idmap ||= V8IDMap.new + end + + class V8IDMap + def initialize + @storage = {} + 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 + end + end + end + end +end \ No newline at end of file diff --git a/lib/v8/conversion/numeric.rb b/lib/v8/conversion/numeric.rb new file mode 100644 index 0000000..fc3caf3 --- /dev/null +++ b/lib/v8/conversion/numeric.rb @@ -0,0 +1,7 @@ +class V8::Conversion + module Numeric + def to_v8 + self + end + end +end \ No newline at end of file diff --git a/lib/v8/conversion/object.rb b/lib/v8/conversion/object.rb new file mode 100644 index 0000000..4651326 --- /dev/null +++ b/lib/v8/conversion/object.rb @@ -0,0 +1,17 @@ +class V8::Conversion + module Object + def to_v8 + V8::C::Object::New() + end + + def to_ruby + self + end + end + + module NativeObject + def to_ruby + ::V8::Object.new(self) + end + end +end \ No newline at end of file diff --git a/lib/v8/conversion/proc.rb b/lib/v8/conversion/proc.rb new file mode 100644 index 0000000..8bff14b --- /dev/null +++ b/lib/v8/conversion/proc.rb @@ -0,0 +1,7 @@ +class V8::Conversion + module Proc + def to_v8 + + end + end +end \ No newline at end of file diff --git a/lib/v8/conversion/string.rb b/lib/v8/conversion/string.rb new file mode 100644 index 0000000..aef9ceb --- /dev/null +++ b/lib/v8/conversion/string.rb @@ -0,0 +1,12 @@ +class V8::Conversion + module String + def to_v8 + V8::C::String::New(self) + end + end + module NativeString + def to_ruby + self.Utf8Value() + end + end +end \ No newline at end of file diff --git a/lib/v8/conversion/symbol.rb b/lib/v8/conversion/symbol.rb new file mode 100644 index 0000000..702997e --- /dev/null +++ b/lib/v8/conversion/symbol.rb @@ -0,0 +1,7 @@ +class V8::Conversion + module Symbol + def to_v8 + V8::C::String::NewSymbol(to_s) + end + end +end \ No newline at end of file diff --git a/lib/v8/conversion/time.rb b/lib/v8/conversion/time.rb new file mode 100644 index 0000000..eac28f1 --- /dev/null +++ b/lib/v8/conversion/time.rb @@ -0,0 +1,13 @@ +class V8::Conversion + module Time + def to_v8 + V8::C::Date::New(to_f * 1000) + end + end + + module NativeDate + def to_ruby + ::Time.at(self.NumberValue() / 1000) + end + end +end \ No newline at end of file diff --git a/lib/v8/object.rb b/lib/v8/object.rb index 9f72aed..fc475c4 100644 --- a/lib/v8/object.rb +++ b/lib/v8/object.rb @@ -1,6 +1,7 @@ class V8::Object include Enumerable attr_reader :native + alias_method :to_v8, :native def initialize(native = nil) @context = V8::Context.current or fail "tried to initialize a #{self.class} without being in an entered V8::Context" @@ -23,10 +24,16 @@ class V8::Object def each @context.enter do names = @native.GetPropertyNames() - 0.upto(@native.Length() - 1) do |i| + 0.upto(names.Length() - 1) do |i| name = names.Get(i) yield @context.to_ruby(name), @context.to_ruby(@native.Get(name)) end end end + + def to_s + @context.enter do + "#{self.class}#{@native.ToString().Utf8Value()}" + end + end end \ No newline at end of file