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:
parent
fb4ac37c69
commit
bbef262f17
13 changed files with 129 additions and 51 deletions
|
@ -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));
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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)));
|
||||
}
|
||||
|
||||
}
|
31
ext/v8/rr.h
31
ext/v8/rr.h
|
@ -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);
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
|
@ -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'
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
25
lib/v8/function.rb
Normal 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
|
|
@ -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
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in a new issue