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

Embed lambdas and procs into V8::Context

This adds the ability embed basic Ruby code blocks into a javascript
context and invoke it.

  cxt = V8::Context.new
  cxt['twice'] = lambda {|str| "#{str}#{str}"}
  cxt.eval('twice("hi")') #=> "hihi"

Note that error handling is not accounted for yet. If an exception
happens inside the called proc, it will cause terrible, awful things
to happen because portions of the C++ stack will not be unwound leaving
the Isolate in an indeterminate state.
This commit is contained in:
Charles Lowell 2015-08-12 21:02:39 +03:00
parent d4c68dfc62
commit 250b8e7d50
3 changed files with 67 additions and 31 deletions

View file

@ -140,3 +140,28 @@ class Symbol
V8::C::Symbol::For(context.isolate.native, V8::C::String::NewFromUtf8(isolate, to_s))
end
end
class Object
def to_v8(context)
V8::C::Object::New(context.isolate.native)
end
end
class Proc
def to_v8(context)
isolate = context.isolate.native
callback = lambda do |info|
args = []
arity = info.Length()
if self.arity > -1
arity = self.arity
end
arity.times do |i|
args << context.to_ruby(info[i])
end
result = context.to_v8 self.call(*args)
info.GetReturnValue().Set(result)
end
V8::C::Function::New(isolate, callback)
end
end

View file

@ -43,7 +43,18 @@ class V8::Conversion
# First it checks to see if there is an entry in the id map for
# this object. Otherwise, it will run the default conversion.
def to_v8(context, ruby_object)
rb_idmap[ruby_object.object_id] || ruby_object.to_v8(context)
if v8_object = rb_idmap[ruby_object.object_id]
v8_object
else
v8_object = ruby_object.to_v8(context)
if v8_object.kind_of? V8::C::Object
v8_object.tap do
equate ruby_object, v8_object
end
else
v8_object
end
end
end
##

View file

@ -93,12 +93,12 @@ describe "V8::Context" do
end
end
# xit "unwraps ruby objects returned by embedded ruby code to maintain referential integrity" do
# Object.new.tap do |o|
# @cxt['get'] = lambda {o}
# @cxt.eval('get()').should be(o)
# end
# end
it "unwraps ruby objects returned by embedded ruby code to maintain referential integrity" do
Object.new.tap do |o|
@cxt['get'] = lambda {o}
@cxt.eval('get()').should be(o)
end
end
it "always returns the same ruby object for a single javascript object" do
obj = @cxt.eval('obj = {}')
@ -133,25 +133,25 @@ describe "V8::Context" do
# end
end
# describe "Calling Ruby Code From Within Javascript", :compat => '0.1.0' do
describe "Calling Ruby Code From Within Javascript" do
# before(:each) do
before(:each) do
# @class = Class.new
# @instance = @class.new
# @cxt = V8::Context.new
@cxt = V8::Context.new
# @cxt['o'] = @instance
# end
end
# xit "can embed a closure into a context and call it" do
# @cxt["say"] = lambda { |*args| args[-2] * args[-1] }
# @cxt.eval("say('Hello', 2)").should == "HelloHello"
# end
it "can embed a closure into a context and call it" do
@cxt["say"] = lambda { |*args| args[-2] * args[-1] }
@cxt.eval("say('Hello', 2)").should == "HelloHello"
end
# xit "recognizes the same closure embedded into the same context as the same function object" do
# @cxt['say'] = @cxt['declare'] = lambda { |*args| args }
# @cxt.eval('say == declare').should be(true)
# @cxt.eval('say === declare').should be(true)
# end
it "recognizes the same closure embedded into the same context as the same function object" do
@cxt['say'] = @cxt['declare'] = lambda { |*args| args }
@cxt.eval('say == declare').should be(true)
@cxt.eval('say === declare').should be(true)
end
# xit "translates ruby Array to Javascript Array" do
# class_eval do
@ -275,17 +275,17 @@ describe "V8::Context" do
# @cxt.eval('typeof(RObject)').should == 'function'
# end
# xit "truncates lambda arguments passed in to match the arity of the function", :compat => '0.4.2' do
# @cxt['testing'] = lambda { |arg| arg }
# lambda {
# @cxt.eval('testing(1,2,3)')
# }.should_not raise_error
it "truncates lambda arguments passed in to match the arity of the function", :compat => '0.4.2' do
@cxt['testing'] = lambda { |arg| arg }
lambda {
@cxt.eval('testing(1,2,3)')
}.should_not raise_error
# @cxt['testing'] = lambda { }
# lambda {
# @cxt.eval('testing(1,2,3)')
# }.should_not raise_error
# end
@cxt['testing'] = lambda { }
lambda {
@cxt.eval('testing(1,2,3)')
}.should_not raise_error
end
# xit "truncates method arguments passed in to match the arity of the function", :compat => '0.4.3' do
# @instance.instance_eval do
@ -652,7 +652,7 @@ describe "V8::Context" do
# @class.class_eval &body
# end
# end
end
describe "Calling JavaScript Code From Within Ruby", :compat => '0.1.0' do