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:
parent
d4c68dfc62
commit
250b8e7d50
3 changed files with 67 additions and 31 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
##
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue