1
0
Fork 0
mirror of https://github.com/rubyjs/therubyracer synced 2023-03-27 23:21:42 -04:00

call JavaScript functions from Ruby.

This commit is contained in:
Charles Lowell 2012-06-12 07:06:25 -05:00
parent fb4ac37c69
commit bbef262f17
13 changed files with 129 additions and 51 deletions

View file

@ -89,7 +89,7 @@ VALUE Context::IsCodeGenerationFromStringsAllowed(VALUE self) {
}
VALUE ExtensionConfiguration::initialize(VALUE self, VALUE names) {
int length = (int)RARRAY_LEN(names);
int length = RARRAY_LENINT(names);
const char* array[length];
for (int i = 0; i < length; i++) {
array[i] = RSTRING_PTR(rb_ary_entry(names, i));

View file

@ -15,19 +15,17 @@ namespace rr {
store(&Class);
}
VALUE Function::NewInstance(int i, VALUE v[], VALUE self) {
if (i == 0) {
return Object(Function(self)->NewInstance());
VALUE Function::NewInstance(int argc, VALUE argv[], VALUE self) {
VALUE args;
rb_scan_args(argc,argv,"01", &args);
if (RTEST(args)) {
return Object(Function(self)->NewInstance(RARRAY_LENINT(args), Value::array<Value>(args)));
} else {
VALUE argc; VALUE argv;
rb_scan_args(i,v,"2", &argc, &argv);
std::vector< v8::Handle<v8::Value> > arguments(NUM2INT(argc));
return Object(Function(self)->NewInstance(NUM2INT(argc), Value::array(argv, arguments)));
return Object(Function(self)->NewInstance());
}
}
VALUE Function::Call(VALUE self, VALUE receiver, VALUE argc, VALUE argv) {
std::vector< v8::Handle<v8::Value> > arguments(NUM2INT(argc));
return Value(Function(self)->Call(Object(receiver), NUM2INT(argc), Value::array(argv, arguments)));
VALUE Function::Call(VALUE self, VALUE receiver, VALUE argv) {
return Value(Function(self)->Call(Object(receiver), RARRAY_LENINT(argv), Value::array<Value>(argv)));
}
VALUE Function::SetName(VALUE self, VALUE name) {

View file

@ -321,14 +321,12 @@ VALUE Object::IsCallable(VALUE self) {
return Bool(Object(self)->IsCallable());
}
VALUE Object::CallAsFunction(VALUE self, VALUE recv, VALUE argc, VALUE argv) {
std::vector< v8::Handle<v8::Value> > v(NUM2INT(argc));
return Value(Object(self)->CallAsFunction(Object(recv), NUM2INT(argc), Value::array(argv, v)));
VALUE Object::CallAsFunction(VALUE self, VALUE recv, VALUE argv) {
return Value(Object(self)->CallAsFunction(Object(recv), RARRAY_LENINT(argv), Value::array<Value>(argv)));
}
VALUE Object::CallAsConstructor(VALUE self, VALUE argc, VALUE argv) {
std::vector< v8::Handle<v8::Value> > v(NUM2INT(argc));
return Value(Object(self)->CallAsConstructor(NUM2INT(argc), Value::array(argv, v)));
VALUE Object::CallAsConstructor(VALUE self, VALUE argv) {
return Value(Object(self)->CallAsConstructor(RARRAY_LENINT(argv), Value::array<Value>(argv)));
}
}

View file

@ -8,6 +8,11 @@
#include "ruby/encoding.h"
#endif
#if !defined(RARRAY_LENINT)
# define RARRAY_LENINT(v) (int)RARRAY_LEN(v)
#endif /* ! defined(RARRAY_LENINT) */
namespace rr {
#define Void(expr) expr; return Qnil;
@ -127,15 +132,23 @@ public:
return v8::Handle<T>();
}
}
inline v8::Handle<T> operator->() const { return *this;}
inline v8::Handle<T> operator*() const {return *this;}
static v8::Handle<T> * array(VALUE argv, std::vector< v8::Handle<T> >& v) {
for (uint32_t i = 0; i < v.size(); i++) {
v[i] = Ref<T>(rb_ary_entry(argv, i));
template <class C> class array {
public:
inline array(VALUE ary) : argv(ary), vector(RARRAY_LENINT(argv)) {}
inline operator v8::Handle<T>*() {
for (uint32_t i = 0; i < vector.size(); i++) {
vector[i] = C(rb_ary_entry(argv, i));
}
return &vector[0];
}
return &v[0];
}
private:
VALUE argv;
std::vector< v8::Handle<T> > vector;
};
class Holder {
friend class Ref;
@ -525,8 +538,8 @@ public:
static VALUE GetIndexedPropertiesExternalArrayDataType(VALUE self);
static VALUE GetIndexedPropertiesExternalArrayDataLength(VALUE self);
static VALUE IsCallable(VALUE self);
static VALUE CallAsFunction(VALUE self, VALUE recv, VALUE argc, VALUE argv);
static VALUE CallAsConstructor(VALUE self, VALUE argc, VALUE argv);
static VALUE CallAsFunction(VALUE self, VALUE recv, VALUE argv);
static VALUE CallAsConstructor(VALUE self, VALUE argv);
inline Object(VALUE value) : Ref<v8::Object>(value) {}
inline Object(v8::Handle<v8::Object> object) : Ref<v8::Object>(object) {}
@ -550,8 +563,8 @@ public:
class Function : public Ref<v8::Function> {
public:
static void Init();
static VALUE NewInstance(int i, VALUE v[], VALUE self);
static VALUE Call(VALUE self, VALUE receiver, VALUE argc, VALUE argv);
static VALUE NewInstance(int argc, VALUE argv[], VALUE self);
static VALUE Call(VALUE self, VALUE receiver, VALUE argv);
static VALUE SetName(VALUE self, VALUE name);
static VALUE GetName(VALUE self);
static VALUE GetInferredName(VALUE self);

View file

@ -7,10 +7,12 @@ namespace rr {
store(&Class);
}
VALUE Signature::New(int length, VALUE args[], VALUE self) {
VALUE receiver; VALUE argc; VALUE argv;
rb_scan_args(length, args, "03", &receiver, &argc, &argv);
std::vector< v8::Handle<v8::FunctionTemplate> > parameters(NUM2INT(argc));
return Signature(v8::Signature::New(FunctionTemplate(receiver), NUM2INT(argc), FunctionTemplate::array(argv, parameters)));
VALUE Signature::New(int argc, VALUE args[], VALUE self) {
VALUE receiver; VALUE argv;
rb_scan_args(argc, args, "02", &receiver, &argv);
FunctionTemplate recv(receiver);
int length = RARRAY_LENINT(argv);
FunctionTemplate::array<FunctionTemplate> types(argv);
return Signature(v8::Signature::New(recv, length, types));
}
}

View file

@ -20,4 +20,5 @@ require 'v8/access/indices'
require 'v8/access'
require 'v8/context'
require 'v8/object'
require 'v8/array'
require 'v8/array'
require 'v8/function'

View file

@ -1,14 +1,15 @@
class V8::Array < V8::Object
def initialize(native_or_length = nil)
native = if native_or_length.is_a?(Numeric)
V8::C::Array::New(native_or_length)
elsif native_or_length.is_a?(V8::C::Array)
native_or_length
else
V8::C::Array::New()
super do
if native_or_length.is_a?(Numeric)
V8::C::Array::New(native_or_length)
elsif native_or_length.is_a?(V8::C::Array)
native_or_length
else
V8::C::Array::New()
end
end
super native
end
def each

View file

@ -24,7 +24,7 @@ for type in [Class, Object, Array, Hash, String, Symbol, Time, Proc, Method] do
end
end
for type in [:Object, :Array, :String, :Date] do
for type in [:Object, :String, :Date] do
V8::C::const_get(type).class_eval do
include V8::Conversion::const_get("Native#{type}")
end

View file

@ -8,10 +8,4 @@ class V8::Conversion
return array.to_v8
end
end
module NativeArray
def to_ruby
V8::Array.new(self)
end
end
end

View file

@ -83,7 +83,18 @@ class V8::Conversion
module NativeObject
def to_ruby
::V8::Object.new(self)
wrap = if IsArray()
::V8::Array
elsif IsFunction()
::V8::Function
else
::V8::Object
end
wrap.new(self)
end
def to_v8
self
end
end
end

25
lib/v8/function.rb Normal file
View file

@ -0,0 +1,25 @@
class V8::Function < V8::Object
def initialize(native = nil)
super do
native || V8::C::Function::New()
end
end
def methodcall(this, *args)
@context.enter do
@context.to_ruby native.Call(@context.to_v8(this), args.map {|a| @context.to_v8 a})
end
end
def call(*args)
@context.enter do
methodcall @context.native.Global(), *args
end
end
def new(*args)
@context.enter do
@context.to_ruby native.NewInstance(args.map {|a| @context.to_v8 a})
end
end
end

View file

@ -5,7 +5,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()
@native = block_given? ? yield : native || V8::C::Object::New()
@context.link self, @native
end
@ -34,7 +34,32 @@ class V8::Object
def to_s
@context.enter do
"#{self.class}#{@native.ToString().Utf8Value()}"
@context.to_ruby @native.ToString()
end
end
def respond_to?(method)
super or self[method] != nil
end
def method_missing(name, *args, &block)
if name.to_s =~ /(.*)=$/
if args.length > 1
self[$1] = args
return args
else
self[$1] = args.first
return args
end
end
return super(name, *args, &block) unless self.respond_to?(name)
property = self[name]
if property.kind_of?(V8::Function)
property.methodcall(self, *args)
elsif args.empty?
property
else
raise ArgumentError, "wrong number of arguments (#{args.length} for 0)" unless args.empty?
end
end
end

View file

@ -3,7 +3,17 @@ require 'spec_helper'
describe V8::C::Function do
it "can be called" do
fn = run '(function() {return "foo"})'
fn.Call(@cxt.Global(), 0, []).Utf8Value().should eql "foo"
fn.Call(@cxt.Global(), []).Utf8Value().should eql "foo"
end
it "can be called with arguments and context" do
fn = run '(function(one, two, three) {this.one = one; this.two = two; this.three = three})'
one = V8::C::Object::New()
two = V8::C::Object::New()
fn.Call(@cxt.Global(), [one, two, 3])
@cxt.Global().Get("one").should eql one
@cxt.Global().Get("two").should eql two
@cxt.Global().Get("three").should eql 3
end
it "can be called as a constructor" do
@ -13,7 +23,7 @@ describe V8::C::Function do
it "can be called as a constructor with arguments" do
fn = run '(function(foo) {this.foo = foo})'
object = fn.NewInstance(1, [V8::C::String::New("bar")])
object = fn.NewInstance([V8::C::String::New("bar")])
object.Get(V8::C::String::New('foo')).Utf8Value().should eql "bar"
end