From 7fee981c94aff2711d68361831daba65c12a296d Mon Sep 17 00:00:00 2001 From: Charles Lowell Date: Fri, 10 Jul 2015 19:17:06 -0500 Subject: [PATCH] add support for Symbols --- ext/v8/init.cc | 2 ++ ext/v8/name.cc | 16 ++++++++++ ext/v8/name.h | 15 +++++++++ ext/v8/rr.h | 2 ++ ext/v8/rr_string.cc | 2 +- ext/v8/symbol.cc | 74 +++++++++++++++++++++++++++++++++++++++++++ ext/v8/symbol.h | 26 +++++++++++++++ spec/c/symbol_spec.rb | 53 +++++++++++++++++++++++++++++++ 8 files changed, 189 insertions(+), 1 deletion(-) create mode 100644 ext/v8/name.cc create mode 100644 ext/v8/name.h create mode 100644 ext/v8/symbol.cc create mode 100644 ext/v8/symbol.h create mode 100644 spec/c/symbol_spec.rb diff --git a/ext/v8/init.cc b/ext/v8/init.cc index 1dfaba3..aede0c9 100644 --- a/ext/v8/init.cc +++ b/ext/v8/init.cc @@ -16,7 +16,9 @@ extern "C" { Value::Init(); Object::Init(); Primitive::Init(); + Name::Init(); String::Init(); + Symbol::Init(); Function::Init(); Script::Init(); ScriptOrigin::Init(); diff --git a/ext/v8/name.cc b/ext/v8/name.cc new file mode 100644 index 0000000..55c341b --- /dev/null +++ b/ext/v8/name.cc @@ -0,0 +1,16 @@ +#include "rr.h" + +namespace rr { + void Name::Init() { + ClassBuilder("Name", Primitive::Class). + defineMethod("GetIdentityHash", &GetIdentityHash). + + store(&Class); + } + VALUE Name::GetIdentityHash(VALUE self) { + Name name(self); + Locker lock(name.getIsolate()); + + return INT2FIX(name->GetIdentityHash()); + } +} diff --git a/ext/v8/name.h b/ext/v8/name.h new file mode 100644 index 0000000..334d8d3 --- /dev/null +++ b/ext/v8/name.h @@ -0,0 +1,15 @@ +//mode -*- c++ -*- +#ifndef NAME_H +#define NAME_H + +namespace rr { + class Name : public Ref { + public: + static void Init(); + static VALUE GetIdentityHash(VALUE self); + + Name(VALUE self) : Ref(self) {} + }; +} + +#endif /* NAME_H */ diff --git a/ext/v8/rr.h b/ext/v8/rr.h index d312862..f22e505 100644 --- a/ext/v8/rr.h +++ b/ext/v8/rr.h @@ -39,7 +39,9 @@ inline VALUE not_implemented(const char* message) { #include "primitive.h" #include "external.h" // This one is named v8_string to avoid name collisions with C's string.h +#include "name.h" #include "rr_string.h" +#include "symbol.h" #include "script.h" #include "script-origin.h" diff --git a/ext/v8/rr_string.cc b/ext/v8/rr_string.cc index fe87b5c..48ebf94 100644 --- a/ext/v8/rr_string.cc +++ b/ext/v8/rr_string.cc @@ -3,7 +3,7 @@ namespace rr { void String::Init() { - ClassBuilder("String", Primitive::Class). + ClassBuilder("String", Name::Class). defineSingletonMethod("NewFromUtf8", &NewFromUtf8). defineSingletonMethod("Concat", &Concat). diff --git a/ext/v8/symbol.cc b/ext/v8/symbol.cc new file mode 100644 index 0000000..a18b1c2 --- /dev/null +++ b/ext/v8/symbol.cc @@ -0,0 +1,74 @@ +#include "rr.h" + +namespace rr { + void Symbol::Init() { + ClassBuilder("Symbol", Name::Class). + defineSingletonMethod("New", &New). + defineSingletonMethod("For", &For). + defineSingletonMethod("ForApi", &ForApi). + defineSingletonMethod("GetIterator", &GetIterator). + defineSingletonMethod("GetUnscopables", &GetUnscopables). + defineSingletonMethod("GetToStringTag", &GetToStringTag). + defineMethod("Name", &Name). + + store(&Class); + } + + VALUE Symbol::New(int argc, VALUE argv[], VALUE self) { + VALUE rb_isolate, rb_name; + rb_scan_args(argc, argv, "11", &rb_isolate, &rb_name); + + Isolate isolate(rb_isolate); + Locker lock(isolate); + v8::HandleScope handle_scope(isolate); + + if (RTEST(rb_name)) { + return Symbol(isolate, v8::Symbol::New(isolate, String(rb_name))); + } else { + return Symbol(isolate, v8::Symbol::New(isolate)); + } + } + + VALUE Symbol::For(VALUE self, VALUE rb_isolate, VALUE name) { + Isolate isolate(rb_isolate); + Locker lock(isolate); + + return Symbol(isolate, v8::Symbol::For(isolate, String(name))); + } + + VALUE Symbol::ForApi(VALUE self, VALUE rb_isolate, VALUE name) { + Isolate isolate(rb_isolate); + Locker lock(isolate); + + return Symbol(isolate, v8::Symbol::ForApi(isolate, String(name))); + } + + VALUE Symbol::GetIterator(VALUE self, VALUE rb_isolate) { + Isolate isolate(rb_isolate); + Locker lock(isolate); + + return Symbol(isolate, v8::Symbol::GetIterator(isolate)); + } + + VALUE Symbol::GetUnscopables(VALUE self, VALUE rb_isolate) { + Isolate isolate(rb_isolate); + Locker lock(isolate); + + return Symbol(isolate, v8::Symbol::GetUnscopables(isolate)); + } + + VALUE Symbol::GetToStringTag(VALUE self, VALUE rb_isolate) { + Isolate isolate(rb_isolate); + Locker lock(isolate); + + return Symbol(isolate, v8::Symbol::GetToStringTag(isolate)); + } + + VALUE Symbol::Name(VALUE self) { + Symbol symbol(self); + Isolate isolate(symbol.getIsolate()); + Locker lock(isolate); + + return Value::handleToRubyObject(isolate, symbol->Name()); + } +} diff --git a/ext/v8/symbol.h b/ext/v8/symbol.h new file mode 100644 index 0000000..7501661 --- /dev/null +++ b/ext/v8/symbol.h @@ -0,0 +1,26 @@ +// -*- mode: c++ -*- +#ifndef SYMBOL_H +#define SYMBOL_H + +#include "rr.h" + +namespace rr { + class Symbol : public Ref { + public: + static void Init(); + + static VALUE Name(VALUE self); + static VALUE New(int argc, VALUE argv[], VALUE self); + static VALUE For(VALUE self, VALUE isolate, VALUE name); + static VALUE ForApi(VALUE self, VALUE isolate, VALUE name); + static VALUE GetIterator(VALUE self, VALUE isolate); + static VALUE GetUnscopables(VALUE self, VALUE isolate); + static VALUE GetToStringTag(VALUE self, VALUE isolate); + + Symbol(VALUE self) : Ref(self) {} + Symbol(v8::Isolate* isolate, v8::Local symbol) : + Ref(isolate, symbol) {} + }; +} + +#endif /* SYMBOL_H */ diff --git a/spec/c/symbol_spec.rb b/spec/c/symbol_spec.rb new file mode 100644 index 0000000..11bf0b1 --- /dev/null +++ b/spec/c/symbol_spec.rb @@ -0,0 +1,53 @@ +require 'c_spec_helper' + +describe V8::C::Symbol do + requires_v8_context + + describe "without a description" do + let(:symbol) { V8::C::Symbol::New(@isolate)} + + it "exists" do + expect(symbol).to be + end + + it "has an identity hash" do + expect(symbol.GetIdentityHash()).to be + end + end + + describe "with a description" do + let(:description) { V8::C::String::NewFromUtf8(@isolate, "bob") } + let(:symbol) { V8::C::Symbol::New(@isolate, description) } + + it "has a name" do + expect(symbol.Name().Utf8Value()).to eql "bob" + end + end + + describe "from symbol registries" do + let(:key) { V8::C::String::NewFromUtf8(@isolate, "mysym") } + let(:global) { V8::C::Symbol::For(@isolate, key) } + let(:api) { V8::C::Symbol::ForApi(@isolate, key) } + + it "always retrieves the same value for a given key" do + expect(V8::C::Symbol::For(@isolate, key).StrictEquals(global)).to be true + expect(V8::C::Symbol::ForApi(@isolate, key).StrictEquals(api)).to be true + end + + it "returns different symbols for different registries" do + expect(global.StrictEquals(api)).to be false + end + end + + describe "well-known symbols" do + it "GetIterator" do + expect(V8::C::Symbol::GetIterator(@isolate)).to be_kind_of V8::C::Symbol + end + it "GetUnscopables" do + expect(V8::C::Symbol::GetUnscopables(@isolate)).to be_kind_of V8::C::Symbol + end + it "GetToStringTag" do + expect(V8::C::Symbol::GetToStringTag(@isolate)).to be_kind_of V8::C::Symbol + end + end +end