From 0f691539e885b9851fe66964ad21f2e30a4398e1 Mon Sep 17 00:00:00 2001 From: Charles Lowell Date: Sat, 16 Jun 2012 07:39:11 -0500 Subject: [PATCH] delegate invocation to callables via the context --- lib/v8.rb | 1 + lib/v8/access.rb | 1 + lib/v8/access/invocation.rb | 47 +++++++++++++++++++++++++++++++++++++ lib/v8/access/names.rb | 2 +- lib/v8/conversion.rb | 3 +++ lib/v8/conversion/code.rb | 9 +++---- 6 files changed, 58 insertions(+), 5 deletions(-) create mode 100644 lib/v8/access/invocation.rb diff --git a/lib/v8.rb b/lib/v8.rb index 35b914c..58b0f4f 100644 --- a/lib/v8.rb +++ b/lib/v8.rb @@ -21,6 +21,7 @@ require 'v8/conversion/string' require 'v8/conversion' require 'v8/access/names' require 'v8/access/indices' +require 'v8/access/invocation' require 'v8/access' require 'v8/context' require 'v8/object' diff --git a/lib/v8/access.rb b/lib/v8/access.rb index dcf470b..21b74f5 100644 --- a/lib/v8/access.rb +++ b/lib/v8/access.rb @@ -1,4 +1,5 @@ class V8::Access include Names include Indices + include Invocation end \ No newline at end of file diff --git a/lib/v8/access/invocation.rb b/lib/v8/access/invocation.rb new file mode 100644 index 0000000..210bf14 --- /dev/null +++ b/lib/v8/access/invocation.rb @@ -0,0 +1,47 @@ +class V8::Access + module Invocation + def methodcall(code, this, args) + code.methodcall this, args + end + + module Aritize + def aritize(args) + arity < 0 ? args : Array.new(arity).to_enum(:each_with_index).map {|item, i| args[i]} + end + end + + module Proc + include Aritize + def methodcall(this, args) + call *aritize([this].concat(args)) + end + ::Proc.send :include, self + end + + module Method + include Aritize + def methodcall(this, args) + context = V8::Context.current + access = context.access + if this.equal? self.receiver + call *aritize(args) + elsif this.class <= self.receiver.class + access.methodcall(unbind, this, args) + elsif this.equal? context.scope + call *aritize(args) + else + fail TypeError, "cannot invoke #{self} on #{this}" + end + end + ::Method.send :include, self + end + + module UnboundMethod + def methodcall(this, args) + access = V8::Context.current.access + access.methodcall bind(this), this, args + end + ::UnboundMethod.send :include, self + end + end +end diff --git a/lib/v8/access/names.rb b/lib/v8/access/names.rb index add6f5b..e2b8e41 100644 --- a/lib/v8/access/names.rb +++ b/lib/v8/access/names.rb @@ -9,7 +9,7 @@ class V8::Access methods = accessible_names(obj) if methods.include?(name) method = obj.method(name) - method.arity == 0 ? method.call : method + method.arity == 0 ? method.call : method.unbind elsif obj.respond_to?(:[]) && !special?(name) obj.send(:[], name, &dontintercept) else diff --git a/lib/v8/conversion.rb b/lib/v8/conversion.rb index 3d6962f..b993dad 100644 --- a/lib/v8/conversion.rb +++ b/lib/v8/conversion.rb @@ -23,6 +23,9 @@ for type in [Class, Object, Array, Hash, String, Symbol, Time, Proc, Method] do include V8::Conversion.const_get(name) end end +class UnboundMethod + include V8::Conversion::Method +end for type in [:Object, :String, :Date] do V8::C::const_get(type).class_eval do diff --git a/lib/v8/conversion/code.rb b/lib/v8/conversion/code.rb index 60606e4..e9beed5 100644 --- a/lib/v8/conversion/code.rb +++ b/lib/v8/conversion/code.rb @@ -22,14 +22,15 @@ class V8::Conversion def call(arguments) protect do context = V8::Context.current - length_of_given_args = arguments.Length() - args = ::Array.new(@code.arity < 0 ? length_of_given_args : @code.arity) + access = context.access + args = ::Array.new(arguments.Length()) 0.upto(args.length - 1) do |i| - if i < length_of_given_args + if i < args.length args[i] = context.to_ruby arguments[i] end end - context.to_v8 @code.call(*args) + this = context.to_ruby arguments.This() + context.to_v8 access.methodcall(@code, this, args) end end end