diff --git a/ext/v8/external.h b/ext/v8/external.h index 5a26e14..b9defb2 100644 --- a/ext/v8/external.h +++ b/ext/v8/external.h @@ -3,7 +3,7 @@ #define EXTERNAL_H namespace rr { - class External : Ref { + class External : public Ref { public: static void Init(); @@ -13,6 +13,8 @@ namespace rr { inline External(VALUE value) : Ref(value) {} inline External(v8::Isolate* isolate, v8::Handle handle) : Ref(isolate, handle) {} + inline External(v8::Isolate* isolate, v8::Handle value) : + External(isolate, v8::Handle::Cast(value)) {} struct Container { Container(VALUE v) : object(v) {} diff --git a/ext/v8/function.cc b/ext/v8/function.cc index 83cbe13..f9c570d 100644 --- a/ext/v8/function.cc +++ b/ext/v8/function.cc @@ -12,7 +12,9 @@ namespace rr { defineMethod("GetInferredName", &GetInferredName). defineMethod("GetScriptLineNumber", &GetScriptLineNumber). defineMethod("GetScriptColumnNumber", &GetScriptColumnNumber). - defineMethod("GetScriptId", &GetScriptId). + defineMethod("IsBuiltin", &IsBuiltin). + defineMethod("ScriptId", &ScriptId). + defineMethod("GetBoundFunction", &GetBoundFunction). defineMethod("GetScriptOrigin", &GetScriptOrigin). store(&Class); @@ -81,15 +83,32 @@ namespace rr { return INT2FIX(function->GetScriptColumnNumber()); } - VALUE Function::GetScriptId(VALUE self) { + VALUE Function::IsBuiltin(VALUE self) { + Function function(self); + Locker lock(function); + + return Bool(function->IsBuiltin()); + } + + VALUE Function::ScriptId(VALUE self) { Function function(self); Locker lock(function.getIsolate()); return INT2FIX(function->ScriptId()); } + VALUE Function::GetBoundFunction(VALUE self) { + Function function(self); + Locker lock(function); + + return Value(function.getIsolate(), function->GetBoundFunction()); + } + VALUE Function::GetScriptOrigin(VALUE self) { - return not_implemented("GetScriptOrigin"); + Function function(self); + Locker lock(function); + + return ScriptOrigin(function, function->GetScriptOrigin()); } } diff --git a/ext/v8/function.h b/ext/v8/function.h index 60c489b..0aa0a59 100644 --- a/ext/v8/function.h +++ b/ext/v8/function.h @@ -12,9 +12,12 @@ namespace rr { static VALUE SetName(VALUE self, VALUE name); static VALUE GetName(VALUE self); static VALUE GetInferredName(VALUE self); + static VALUE GetDisplayName(VALUE self); static VALUE GetScriptLineNumber(VALUE self); static VALUE GetScriptColumnNumber(VALUE self); - static VALUE GetScriptId(VALUE self); + static VALUE IsBuiltin(VALUE self); + static VALUE ScriptId(VALUE self); + static VALUE GetBoundFunction(VALUE self); static VALUE GetScriptOrigin(VALUE self); inline Function(VALUE value) : Ref(value) {} diff --git a/ext/v8/init.cc b/ext/v8/init.cc index 1d0a2f5..1dfaba3 100644 --- a/ext/v8/init.cc +++ b/ext/v8/init.cc @@ -19,6 +19,7 @@ extern "C" { String::Init(); Function::Init(); Script::Init(); + ScriptOrigin::Init(); Array::Init(); External::Init(); diff --git a/ext/v8/ref.h b/ext/v8/ref.h index d58dd8c..deaf008 100644 --- a/ext/v8/ref.h +++ b/ext/v8/ref.h @@ -97,7 +97,7 @@ namespace rr { isolate(isolate), cell(new v8::Persistent(isolate, handle)) {} virtual ~Holder() { - Isolate(isolate).scheduleDelete(cell); + Isolate(isolate).scheduleReleaseObject(cell); } v8::Isolate* isolate; diff --git a/ext/v8/rr.h b/ext/v8/rr.h index fb4f8df..d312862 100644 --- a/ext/v8/rr.h +++ b/ext/v8/rr.h @@ -41,7 +41,8 @@ inline VALUE not_implemented(const char* message) { // This one is named v8_string to avoid name collisions with C's string.h #include "rr_string.h" -#include "function.h" #include "script.h" +#include "script-origin.h" +#include "function.h" #endif diff --git a/ext/v8/script-origin.cc b/ext/v8/script-origin.cc new file mode 100644 index 0000000..a529979 --- /dev/null +++ b/ext/v8/script-origin.cc @@ -0,0 +1,51 @@ +#include "rr.h" + +namespace rr { + VALUE ScriptOrigin::Class; + void ScriptOrigin::Init() { + ClassBuilder("ScriptOrigin"). + defineSingletonMethod("new", &initialize). + + defineMethod("ResourceName", &ResourceName). + defineMethod("ResourceLineOffset", &ResourceLineOffset). + defineMethod("ResourceColumnOffset", &ResourceColumnOffset). + defineMethod("ScriptID", &ScriptID). + defineMethod("SourceMapUrl", &SourceMapUrl). + + store(&Class); + } + + VALUE ScriptOrigin::initialize(int argc, VALUE argv[], VALUE self) { + Container* container = new Container(); + rb_scan_args(argc, argv, "17", + &container->name, + &container->line_offset, + &container->column_offset, + &container->is_shared_cross_origin, + &container->script_id, + &container->is_embedder_debug_script, + &container->source_map_url, + &container->is_opaque); + return ScriptOrigin(container); + } + + VALUE ScriptOrigin::ResourceName(VALUE self) { + return ScriptOrigin(self).container->name; + } + + VALUE ScriptOrigin::ResourceLineOffset(VALUE self) { + return ScriptOrigin(self).container->line_offset; + } + + VALUE ScriptOrigin::ResourceColumnOffset(VALUE self) { + return ScriptOrigin(self).container->column_offset; + } + + VALUE ScriptOrigin::ScriptID(VALUE self) { + return ScriptOrigin(self).container->script_id; + } + + VALUE ScriptOrigin::SourceMapUrl(VALUE self) { + return ScriptOrigin(self).container->source_map_url; + } +} diff --git a/ext/v8/script-origin.h b/ext/v8/script-origin.h new file mode 100644 index 0000000..cbcafb5 --- /dev/null +++ b/ext/v8/script-origin.h @@ -0,0 +1,95 @@ +// -*- mode: c++ -*- +#ifndef SCRIPT_ORIGIN_H +#define SCRIPT_ORIGIN_H + +namespace rr { + class ScriptOrigin { + struct Container { + inline Container() {} + + Container(VALUE name_, + VALUE line_offset_, + VALUE column_offset_, + VALUE is_shared_cross_origin_, + VALUE script_id_, + VALUE is_embedder_debug_script_, + VALUE source_map_url_, + VALUE is_opaque_) : + name(name_), + line_offset(line_offset_), + column_offset(column_offset_), + is_shared_cross_origin(is_shared_cross_origin_), + script_id(script_id_), + is_embedder_debug_script(is_embedder_debug_script_), + source_map_url(source_map_url_), + is_opaque(is_opaque_) {} + + + VALUE name; + VALUE line_offset; + VALUE column_offset; + VALUE is_shared_cross_origin; //option + VALUE script_id; + VALUE is_embedder_debug_script; //option + VALUE source_map_url; + VALUE is_opaque; //option + + }; + struct Integer : public Equiv { + Integer(v8::Handle value) : + Equiv(INT2FIX(value->IntegerValue())) { + } + }; + public: + static void Init(); + + ScriptOrigin(VALUE value) { + Data_Get_Struct(value, struct Container, container); + } + ScriptOrigin(Container* container_) : + container(container_) { + } + ScriptOrigin(v8::Isolate* isolate, v8::ScriptOrigin origin) : + ScriptOrigin(new Container( + Value(isolate, origin.ResourceName()), + Integer(origin.ResourceLineOffset()), + Integer(origin.ResourceColumnOffset()), + Bool(origin.Options().IsSharedCrossOrigin()), + Integer(origin.ScriptID()), + Bool(origin.Options().IsEmbedderDebugScript()), + Value(isolate, origin.SourceMapUrl()), + Bool(origin.Options().IsOpaque()))) { + } + + static void mark(Container* container) { + rb_gc_mark(container->name); + rb_gc_mark(container->line_offset); + rb_gc_mark(container->column_offset); + rb_gc_mark(container->script_id); + rb_gc_mark(container->source_map_url); + rb_gc_mark(container->is_shared_cross_origin); + rb_gc_mark(container->is_embedder_debug_script); + rb_gc_mark(container->is_opaque); + } + + static VALUE initialize(int argc, VALUE argv[], VALUE self); + + static void deallocate(Container* container) { + delete container; + } + inline operator VALUE() { + return Data_Wrap_Struct(Class, &mark, &deallocate, container); + } + static VALUE ResourceName(VALUE self); + static VALUE ResourceLineOffset(VALUE self); + static VALUE ResourceColumnOffset(VALUE self); + static VALUE ScriptID(VALUE self); + static VALUE SourceMapUrl(VALUE self); + + static VALUE Class; + private: + Container* container; + }; +} + +#endif /* SCRIPT_ORIGIN_H */ diff --git a/ext/v8/script.cc b/ext/v8/script.cc index 75f2620..77477db 100644 --- a/ext/v8/script.cc +++ b/ext/v8/script.cc @@ -1,7 +1,6 @@ #include "rr.h" namespace rr { - void Script::Init() { ClassBuilder("Script"). defineSingletonMethod("Compile", &Compile). @@ -12,11 +11,6 @@ namespace rr { store(&Class); - // TODO - // ClassBuilder("ScriptOrigin"). - // defineSingletonMethod("new", &ScriptOrigin::initialize). - // store(&ScriptOrigin::Class); - // TODO // ClassBuilder("ScriptData"). // defineSingletonMethod("PreCompile", &ScriptData::PreCompile). @@ -27,6 +21,7 @@ namespace rr { // store(&ScriptData::Class); } + VALUE Script::Compile(int argc, VALUE argv[], VALUE self) { VALUE source, rb_context, origin; rb_scan_args(argc, argv, "21", &source, &rb_context, &origin); @@ -44,5 +39,4 @@ namespace rr { return Value::handleToRubyObject(context->GetIsolate(), Script(self)->Run()); } - } diff --git a/ext/v8/script.h b/ext/v8/script.h index 9ed9d3c..860214e 100644 --- a/ext/v8/script.h +++ b/ext/v8/script.h @@ -1,6 +1,9 @@ +// -*- mode: c++ -*- #ifndef RR_SCRIPT #define RR_SCRIPT +#include "rr.h" + namespace rr { class Script : public Ref { @@ -13,7 +16,5 @@ namespace rr { inline Script(VALUE value) : Ref(value) {} inline Script(v8::Isolate* isolate, v8::Handle script) : Ref(isolate, script) {} }; - } - #endif diff --git a/ext/v8/value.cc b/ext/v8/value.cc index 02b4119..aa2df9d 100644 --- a/ext/v8/value.cc +++ b/ext/v8/value.cc @@ -166,10 +166,9 @@ namespace rr { return Qfalse; } - // TODO - // if (handle->IsExternal()) { - // return External((v8::Handle)v8::External::Cast(*handle)); - // } + if (handle->IsExternal()) { + return External(isolate, handle); + } if (handle->IsUint32()) { return UInt32(handle->Uint32Value()); diff --git a/spec/c/function_spec.rb b/spec/c/function_spec.rb index 76ed15c..f0c3a88 100644 --- a/spec/c/function_spec.rb +++ b/spec/c/function_spec.rb @@ -3,6 +3,14 @@ require 'c_spec_helper' describe V8::C::Function do requires_v8_context + it "has a script origin" do + fn = run '(function() { return "foo" })' + origin = fn.GetScriptOrigin() + expect(origin.ResourceName().ToString().Utf8Value()).to eql 'undefined' + expect(origin.ResourceLineOffset()).to eql 0 + expect(origin.ResourceColumnOffset()).to eql 0 + end + it 'can be called' do fn = run '(function() { return "foo" })' expect(fn.Call(@ctx.Global, []).Utf8Value).to eq 'foo' @@ -26,12 +34,12 @@ describe V8::C::Function do expect(fn.NewInstance.Get(V8::C::String.NewFromUtf8(@isolate, 'foo')).Utf8Value).to eq 'foo' end - # it 'can be called as a constructor with arguments' do - # fn = run '(function(foo) {this.foo = foo})' - # object = fn.NewInstance([V8::C::String.NewFromUtf8(@isolate, 'bar')]) + it 'can be called as a constructor with arguments' do + fn = run '(function(foo) {this.foo = foo})' + object = fn.NewInstance([V8::C::String.NewFromUtf8(@isolate, 'bar')]) - # expect(object.Get(V8::C::String.NewFromUtf8(@isolate, 'foo')).Utf8Value).to eq 'bar' - # end + expect(object.Get(V8::C::String.NewFromUtf8(@isolate, 'foo')).Utf8Value).to eq 'bar' + end # TODO # it 'doesn\'t kill the world if invoking it throws a javascript exception' do diff --git a/spec/c/script_origin_spec.rb b/spec/c/script_origin_spec.rb new file mode 100644 index 0000000..0a85771 --- /dev/null +++ b/spec/c/script_origin_spec.rb @@ -0,0 +1,38 @@ +require 'c_spec_helper' + +describe V8::C::ScriptOrigin do + requires_v8_context + + describe "with only a name" do + let(:origin) { V8::C::ScriptOrigin.new V8::C::String::NewFromUtf8(@isolate, "bob.js") } + + it "it hase a resource name" do + expect(origin.ResourceName().Utf8Value).to eql "bob.js" + end + + it "has nil for all the other values" do + expect(origin.ResourceLineOffset()).to be_nil + expect(origin.ResourceColumnOffset()).to be_nil + expect(origin.ScriptID()).to be_nil + expect(origin.SourceMapUrl()).to be_nil + end + end + + describe "with all the other options" do + let(:origin) do + V8::C::ScriptOrigin.new( + V8::C::String::NewFromUtf8(@isolate, "bob.js"), 5, 25, + true, 100, true, + V8::C::String::NewFromUtf8(@isolate, "http://foo/bob.js.map"), + false + ) + end + it "maps the correct values" do + expect(origin.ResourceName().Utf8Value()).to eql 'bob.js' + expect(origin.ResourceLineOffset()).to eql 5 + expect(origin.ResourceColumnOffset()).to eql 25 + expect(origin.ScriptID()).to eql 100 + expect(origin.SourceMapUrl().Utf8Value()).to eql "http://foo/bob.js.map" + end + end +end