addons: build and test examples
authorFedor Indutny <fedor.indutny@gmail.com>
Sat, 18 Jan 2014 22:49:18 +0000 (22:49 +0000)
committerFedor Indutny <fedor.indutny@gmail.com>
Tue, 21 Jan 2014 20:39:13 +0000 (00:39 +0400)
fix #6910

.gitignore
Makefile
doc/api/addons.markdown
test/addons/async-hello-world/binding.cc
test/addons/at-exit/binding.cc
test/addons/hello-world-function-export/binding.cc
test/addons/hello-world/binding.cc
test/addons/testcfg.py [new file with mode: 0644]
test/testpy/__init__.py
tools/doc/addon-verify.js [new file with mode: 0644]

index e0f5151..a86377c 100644 (file)
@@ -42,6 +42,7 @@ ipch/
 /dist-osx
 /npm.wxs
 /tools/msvs/npm.wixobj
+/test/addons/doc-*/
 email.md
 deps/v8-*
 ./node_modules
index 0406b1d..cb27a33 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -100,26 +100,38 @@ test/gc/node_modules/weak/build/Release/weakref.node:
                --directory="$(shell pwd)/test/gc/node_modules/weak" \
                --nodedir="$(shell pwd)"
 
+build-addons:
+       @if [ ! -f node ]; then make all; fi
+       rm -rf test/addons/doc-*/
+       ./node tools/doc/addon-verify.js
+       $(foreach dir, \
+                       $(sort $(dir $(wildcard test/addons/*/*.gyp))), \
+                       ./node deps/npm/node_modules/node-gyp/bin/node-gyp rebuild \
+                                       --directory="$(shell pwd)/$(dir)" \
+                                       --nodedir="$(shell pwd)" && ) echo "build done"
+
 test-gc: all test/gc/node_modules/weak/build/Release/weakref.node
        $(PYTHON) tools/test.py --mode=release gc
 
-test-all: all test/gc/node_modules/weak/build/Release/weakref.node
+test-build: all build-addons
+
+test-all: test-build test/gc/node_modules/weak/build/Release/weakref.node
        $(PYTHON) tools/test.py --mode=debug,release
        make test-npm
 
-test-all-http1: all
+test-all-http1: test-build
        $(PYTHON) tools/test.py --mode=debug,release --use-http1
 
-test-all-valgrind: all
+test-all-valgrind: test-build
        $(PYTHON) tools/test.py --mode=debug,release --valgrind
 
-test-release: all
+test-release: test-build
        $(PYTHON) tools/test.py --mode=release
 
-test-debug: all
+test-debug: test-build
        $(PYTHON) tools/test.py --mode=debug
 
-test-message: all
+test-message: test-build
        $(PYTHON) tools/test.py message
 
 test-simple: all
@@ -140,6 +152,9 @@ test-npm: node
 test-npm-publish: node
        npm_package_config_publishtest=true ./node deps/npm/test/run.js
 
+test-addons: test-build
+       $(PYTHON) tools/test.py --mode=release addons
+
 apidoc_sources = $(wildcard doc/api/*.markdown)
 apidocs = $(addprefix out/,$(apidoc_sources:.markdown=.html)) \
           $(addprefix out/,$(apidoc_sources:.markdown=.json))
@@ -418,4 +433,4 @@ cpplint:
 
 lint: jslint cpplint
 
-.PHONY: lint cpplint jslint bench clean docopen docclean doc dist distclean check uninstall install install-includes install-bin all staticlib dynamiclib test test-all website-upload pkg blog blogclean tar binary release-only bench-http-simple bench-idle bench-all bench bench-misc bench-array bench-buffer bench-net bench-http bench-fs bench-tls
+.PHONY: lint cpplint jslint bench clean docopen docclean doc dist distclean check uninstall install install-includes install-bin all staticlib dynamiclib test test-all test-addons build-addons website-upload pkg blog blogclean tar binary release-only bench-http-simple bench-idle bench-all bench bench-misc bench-array bench-buffer bench-net bench-http bench-fs bench-tls
index ff97326..b6f3fd4 100644 (file)
@@ -38,22 +38,22 @@ the following JavaScript code:
 
 First we create a file `hello.cc`:
 
+    // hello.cc
     #include <node.h>
 
     using namespace v8;
 
-    Handle<Value> Method(const Arguments& args) {
+    void Method(const FunctionCallbackInfo<Value>& args) {
       Isolate* isolate = Isolate::GetCurrent();
       HandleScope scope(isolate);
-      return scope.Close(String::New("world"));
+      args.GetReturnValue().Set(String::NewFromUtf8(isolate, "world"));
     }
 
     void init(Handle<Object> exports) {
-      exports->Set(String::NewSymbol("hello"),
-          FunctionTemplate::New(Method)->GetFunction());
+      NODE_SET_METHOD(exports, "hello", Method);
     }
 
-    NODE_MODULE(hello, init)
+    NODE_MODULE(addon, init)
 
 Note that all Node addons must export an initialization function:
 
@@ -66,7 +66,7 @@ There is no semi-colon after `NODE_MODULE` as it's not a function (see
 The `module_name` needs to match the filename of the final binary (minus the
 .node suffix).
 
-The source code needs to be built into `hello.node`, the binary Addon. To
+The source code needs to be built into `addon.node`, the binary Addon. To
 do this we create a file called `binding.gyp` which describes the configuration
 to build your module in a JSON-like format. This file gets compiled by
 [node-gyp](https://github.com/TooTallNate/node-gyp).
@@ -74,7 +74,7 @@ to build your module in a JSON-like format. This file gets compiled by
     {
       "targets": [
         {
-          "target_name": "hello",
+          "target_name": "addon",
           "sources": [ "hello.cc" ]
         }
       ]
@@ -93,7 +93,8 @@ in `build/Release/`.
 You can now use the binary addon in a Node project `hello.js` by pointing
 `require` to the recently built `hello.node` module:
 
-    var addon = require('./build/Release/hello');
+    // hello.js
+    var addon = require('./build/Release/addon');
 
     console.log(addon.hello()); // 'world'
 
@@ -138,39 +139,42 @@ The following pattern illustrates how to read arguments from JavaScript
 function calls and return a result. This is the main and only needed source
 `addon.cc`:
 
+    // addon.cc
     #include <node.h>
 
     using namespace v8;
 
-    Handle<Value> Add(const Arguments& args) {
+    void Add(const FunctionCallbackInfo<Value>& args) {
       Isolate* isolate = Isolate::GetCurrent();
       HandleScope scope(isolate);
 
       if (args.Length() < 2) {
-        ThrowException(Exception::TypeError(
-            String::New("Wrong number of arguments")));
-        return scope.Close(Undefined(isolate));
+        isolate->ThrowException(Exception::TypeError(
+            String::NewFromUtf8(isolate, "Wrong number of arguments")));
+        return;
       }
 
       if (!args[0]->IsNumber() || !args[1]->IsNumber()) {
-        ThrowException(Exception::TypeError(String::New("Wrong arguments")));
-        return scope.Close(Undefined(isolate));
+        isolate->ThrowException(Exception::TypeError(
+            String::NewFromUtf8(isolate, "Wrong arguments")));
+        return;
       }
 
       Local<Number> num = Number::New(args[0]->NumberValue() +
           args[1]->NumberValue());
-      return scope.Close(num);
+
+      args.GetReturnValue().Set(num);
     }
 
     void Init(Handle<Object> exports) {
-      exports->Set(String::NewSymbol("add"),
-          FunctionTemplate::New(Add)->GetFunction());
+      NODE_SET_METHOD(exports, "add", Add);
     }
 
     NODE_MODULE(addon, Init)
 
 You can test it with the following JavaScript snippet:
 
+    // test.js
     var addon = require('./build/Release/addon');
 
     console.log( 'This should be eight:', addon.add(3,5) );
@@ -181,25 +185,23 @@ You can test it with the following JavaScript snippet:
 You can pass JavaScript functions to a C++ function and execute them from
 there. Here's `addon.cc`:
 
+    // addon.cc
     #include <node.h>
 
     using namespace v8;
 
-    Handle<Value> RunCallback(const Arguments& args) {
+    void RunCallback(const FunctionCallbackInfo<Value>& args) {
       Isolate* isolate = Isolate::GetCurrent();
       HandleScope scope(isolate);
 
       Local<Function> cb = Local<Function>::Cast(args[0]);
       const unsigned argc = 1;
-      Local<Value> argv[argc] = { String::New("hello world") };
+      Local<Value> argv[argc] = { String::NewFromUtf8(isolate, "hello world") };
       cb->Call(Context::GetCurrent()->Global(), argc, argv);
-
-      return scope.Close(Undefined(isolate));
     }
 
     void Init(Handle<Object> exports, Handle<Object> module) {
-      module->Set(String::NewSymbol("exports"),
-          FunctionTemplate::New(RunCallback)->GetFunction());
+      NODE_SET_METHOD(module, "exports", RunCallback);
     }
 
     NODE_MODULE(addon, Init)
@@ -211,6 +213,7 @@ adding the function as a property of `exports`.
 
 To test it run the following JavaScript snippet:
 
+    // test.js
     var addon = require('./build/Release/addon');
 
     addon(function(msg){
@@ -224,29 +227,30 @@ You can create and return new objects from within a C++ function with this
 `addon.cc` pattern, which returns an object with property `msg` that echoes
 the string passed to `createObject()`:
 
+    // addon.cc
     #include <node.h>
 
     using namespace v8;
 
-    Handle<Value> CreateObject(const Arguments& args) {
+    void CreateObject(const FunctionCallbackInfo<Value>& args) {
       Isolate* isolate = Isolate::GetCurrent();
       HandleScope scope(isolate);
 
       Local<Object> obj = Object::New();
-      obj->Set(String::NewSymbol("msg"), args[0]->ToString());
+      obj->Set(String::NewFromUtf8(isolate, "msg"), args[0]->ToString());
 
-      return scope.Close(obj);
+      args.GetReturnValue().Set(obj);
     }
 
     void Init(Handle<Object> exports, Handle<Object> module) {
-      module->Set(String::NewSymbol("exports"),
-          FunctionTemplate::New(CreateObject)->GetFunction());
+      NODE_SET_METHOD(module, "exports", CreateObject);
     }
 
     NODE_MODULE(addon, Init)
 
 To test it in JavaScript:
 
+    // test.js
     var addon = require('./build/Release/addon');
 
     var obj1 = addon('hello');
@@ -259,17 +263,18 @@ To test it in JavaScript:
 This pattern illustrates how to create and return a JavaScript function that
 wraps a C++ function:
 
+    // addon.cc
     #include <node.h>
 
     using namespace v8;
 
-    Handle<Value> MyFunction(const Arguments& args) {
+    void MyFunction(const FunctionCallbackInfo<Value>& args) {
       Isolate* isolate = Isolate::GetCurrent();
       HandleScope scope(isolate);
-      return scope.Close(String::New("hello world"));
+      args.GetReturnValue().Set(String::NewFromUtf8(isolate, "hello world"));
     }
 
-    Handle<Value> CreateFunction(const Arguments& args) {
+    void CreateFunction(const FunctionCallbackInfo<Value>& args) {
       Isolate* isolate = Isolate::GetCurrent();
       HandleScope scope(isolate);
 
@@ -277,20 +282,20 @@ wraps a C++ function:
       Local<Function> fn = tpl->GetFunction();
 
       // omit this to make it anonymous
-      fn->SetName(String::NewSymbol("theFunction"));
+      fn->SetName(String::NewFromUtf8(isolate, "theFunction"));
 
-      return scope.Close(fn);
+      args.GetReturnValue().Set(fn);
     }
 
     void Init(Handle<Object> exports, Handle<Object> module) {
-      module->Set(String::NewSymbol("exports"),
-          FunctionTemplate::New(CreateFunction)->GetFunction());
+      NODE_SET_METHOD(module, "exports", CreateFunction);
     }
 
     NODE_MODULE(addon, Init)
 
 To test:
 
+    // test.js
     var addon = require('./build/Release/addon');
 
     var fn = addon();
@@ -303,6 +308,7 @@ Here we will create a wrapper for a C++ object/class `MyObject` that can be
 instantiated in JavaScript through the `new` operator. First prepare the main
 module `addon.cc`:
 
+    // addon.cc
     #include <node.h>
     #include "myobject.h"
 
@@ -316,10 +322,12 @@ module `addon.cc`:
 
 Then in `myobject.h` make your wrapper inherit from `node::ObjectWrap`:
 
+    // myobject.h
     #ifndef MYOBJECT_H
     #define MYOBJECT_H
 
     #include <node.h>
+    #include <node_object_wrap.h>
 
     class MyObject : public node::ObjectWrap {
      public:
@@ -329,8 +337,8 @@ Then in `myobject.h` make your wrapper inherit from `node::ObjectWrap`:
       explicit MyObject(double value = 0);
       ~MyObject();
 
-      static v8::Handle<v8::Value> New(const v8::Arguments& args);
-      static v8::Handle<v8::Value> PlusOne(const v8::Arguments& args);
+      static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
+      static void PlusOne(const v8::FunctionCallbackInfo<v8::Value>& args);
       static v8::Persistent<v8::Function> constructor;
       double value_;
     };
@@ -341,8 +349,7 @@ And in `myobject.cc` implement the various methods that you want to expose.
 Here we expose the method `plusOne` by adding it to the constructor's
 prototype:
 
-    #include <node.h>
-    #include <node_object_wrap.h>
+    // myobject.cc
     #include "myobject.h"
 
     using namespace v8;
@@ -360,20 +367,18 @@ prototype:
 
       // Prepare constructor template
       Local<FunctionTemplate> tpl = FunctionTemplate::New(New);
-      tpl->SetClassName(String::NewSymbol("MyObject"));
+      tpl->SetClassName(String::NewFromUtf8(isolate, "MyObject"));
       tpl->InstanceTemplate()->SetInternalFieldCount(1);
 
       // Prototype
-      tpl->PrototypeTemplate()->Set(String::NewSymbol("plusOne"),
-          FunctionTemplate::New(PlusOne)->GetFunction());
-
-      Persistent<Function> constructor
-          = Persistent<Function>::New(isolate, tpl->GetFunction());
+      NODE_SET_PROTOTYPE_METHOD(tpl, "plusOne", PlusOne);
 
-      exports->Set(String::NewSymbol("MyObject"), constructor);
+      constructor.Reset(isolate, tpl->GetFunction());
+      exports->Set(String::NewFromUtf8(isolate, "MyObject"),
+                   tpl->GetFunction());
     }
 
-    Handle<Value> MyObject::New(const Arguments& args) {
+    void MyObject::New(const FunctionCallbackInfo<Value>& args) {
       Isolate* isolate = Isolate::GetCurrent();
       HandleScope scope(isolate);
 
@@ -382,27 +387,29 @@ prototype:
         double value = args[0]->IsUndefined() ? 0 : args[0]->NumberValue();
         MyObject* obj = new MyObject(value);
         obj->Wrap(args.This());
-        return args.This();
+        args.GetReturnValue().Set(args.This());
       } else {
         // Invoked as plain function `MyObject(...)`, turn into construct call.
         const int argc = 1;
         Local<Value> argv[argc] = { args[0] };
-        return scope.Close(constructor->NewInstance(argc, argv));
+        Local<Function> cons = Local<Function>::New(isolate, constructor);
+        args.GetReturnValue().Set(cons->NewInstance(argc, argv));
       }
     }
 
-    Handle<Value> MyObject::PlusOne(const Arguments& args) {
+    void MyObject::PlusOne(const FunctionCallbackInfo<Value>& args) {
       Isolate* isolate = Isolate::GetCurrent();
       HandleScope scope(isolate);
 
       MyObject* obj = ObjectWrap::Unwrap<MyObject>(args.This());
       obj->value_ += 1;
 
-      return scope.Close(Number::New(obj->value_));
+      args.GetReturnValue().Set(Number::New(obj->value_));
     }
 
 Test it with:
 
+    // test.js
     var addon = require('./build/Release/addon');
 
     var obj = new addon.MyObject(10);
@@ -421,22 +428,22 @@ explicitly instantiating them with the `new` operator in JavaScript, e.g.
 
 Let's register our `createObject` method in `addon.cc`:
 
+    // addon.cc
     #include <node.h>
     #include "myobject.h"
 
     using namespace v8;
 
-    Handle<Value> CreateObject(const Arguments& args) {
+    void CreateObject(const FunctionCallbackInfo<Value>& args) {
       Isolate* isolate = Isolate::GetCurrent();
       HandleScope scope(isolate);
-      return scope.Close(MyObject::NewInstance(args));
+      MyObject::NewInstance(args);
     }
 
     void InitAll(Handle<Object> exports, Handle<Object> module) {
       MyObject::Init();
 
-      module->Set(String::NewSymbol("exports"),
-          FunctionTemplate::New(CreateObject)->GetFunction());
+      NODE_SET_METHOD(module, "exports", CreateObject);
     }
 
     NODE_MODULE(addon, InitAll)
@@ -444,22 +451,24 @@ Let's register our `createObject` method in `addon.cc`:
 In `myobject.h` we now introduce the static method `NewInstance` that takes
 care of instantiating the object (i.e. it does the job of `new` in JavaScript):
 
+    // myobject.h
     #ifndef MYOBJECT_H
     #define MYOBJECT_H
 
     #include <node.h>
+    #include <node_object_wrap.h>
 
     class MyObject : public node::ObjectWrap {
      public:
       static void Init();
-      static v8::Handle<v8::Value> NewInstance(const v8::Arguments& args);
+      static void NewInstance(const v8::FunctionCallbackInfo<v8::Value>& args);
 
      private:
       explicit MyObject(double value = 0);
       ~MyObject();
 
-      static v8::Handle<v8::Value> New(const v8::Arguments& args);
-      static v8::Handle<v8::Value> PlusOne(const v8::Arguments& args);
+      static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
+      static void PlusOne(const v8::FunctionCallbackInfo<v8::Value>& args);
       static v8::Persistent<v8::Function> constructor;
       double value_;
     };
@@ -468,6 +477,7 @@ care of instantiating the object (i.e. it does the job of `new` in JavaScript):
 
 The implementation is similar to the above in `myobject.cc`:
 
+    // myobject.cc
     #include <node.h>
     #include "myobject.h"
 
@@ -485,17 +495,16 @@ The implementation is similar to the above in `myobject.cc`:
       Isolate* isolate = Isolate::GetCurrent();
       // Prepare constructor template
       Local<FunctionTemplate> tpl = FunctionTemplate::New(New);
-      tpl->SetClassName(String::NewSymbol("MyObject"));
+      tpl->SetClassName(String::NewFromUtf8(isolate, "MyObject"));
       tpl->InstanceTemplate()->SetInternalFieldCount(1);
 
       // Prototype
-      tpl->PrototypeTemplate()->Set(String::NewSymbol("plusOne"),
-          FunctionTemplate::New(PlusOne)->GetFunction());
+      NODE_SET_PROTOTYPE_METHOD(tpl, "plusOne", PlusOne);
 
-      constructor = Persistent<Function>::New(isolate, tpl->GetFunction());
+      constructor.Reset(isolate, tpl->GetFunction());
     }
 
-    Handle<Value> MyObject::New(const Arguments& args) {
+    void MyObject::New(const FunctionCallbackInfo<Value>& args) {
       Isolate* isolate = Isolate::GetCurrent();
       HandleScope scope(isolate);
 
@@ -504,38 +513,41 @@ The implementation is similar to the above in `myobject.cc`:
         double value = args[0]->IsUndefined() ? 0 : args[0]->NumberValue();
         MyObject* obj = new MyObject(value);
         obj->Wrap(args.This());
-        return args.This();
+        args.GetReturnValue().Set(args.This());
       } else {
         // Invoked as plain function `MyObject(...)`, turn into construct call.
         const int argc = 1;
         Local<Value> argv[argc] = { args[0] };
-        return scope.Close(constructor->NewInstance(argc, argv));
+        Local<Function> cons = Local<Function>::New(isolate, constructor);
+        args.GetReturnValue().Set(cons->NewInstance(argc, argv));
       }
     }
 
-    Handle<Value> MyObject::NewInstance(const Arguments& args) {
+    void MyObject::NewInstance(const FunctionCallbackInfo<Value>& args) {
       Isolate* isolate = Isolate::GetCurrent();
       HandleScope scope(isolate);
 
       const unsigned argc = 1;
       Handle<Value> argv[argc] = { args[0] };
-      Local<Object> instance = constructor->NewInstance(argc, argv);
+      Local<Function> cons = Local<Function>::New(isolate, constructor);
+      Local<Object> instance = cons->NewInstance(argc, argv);
 
-      return scope.Close(instance);
+      args.GetReturnValue().Set(instance);
     }
 
-    Handle<Value> MyObject::PlusOne(const Arguments& args) {
+    void MyObject::PlusOne(const FunctionCallbackInfo<Value>& args) {
       Isolate* isolate = Isolate::GetCurrent();
       HandleScope scope(isolate);
 
       MyObject* obj = ObjectWrap::Unwrap<MyObject>(args.This());
       obj->value_ += 1;
 
-      return scope.Close(Number::New(obj->value_));
+      args.GetReturnValue().Set(Number::New(obj->value_));
     }
 
 Test it with:
 
+    // test.js
     var createObject = require('./build/Release/addon');
 
     var obj = createObject(10);
@@ -556,19 +568,20 @@ by unwrapping them with Node's `node::ObjectWrap::Unwrap` helper function.
 In the following `addon.cc` we introduce a function `add()` that can take on two
 `MyObject` objects:
 
+    // addon.cc
     #include <node.h>
     #include <node_object_wrap.h>
     #include "myobject.h"
 
     using namespace v8;
 
-    Handle<Value> CreateObject(const Arguments& args) {
+    void CreateObject(const FunctionCallbackInfo<Value>& args) {
       Isolate* isolate = Isolate::GetCurrent();
       HandleScope scope(isolate);
-      return scope.Close(MyObject::NewInstance(args));
+      MyObject::NewInstance(args);
     }
 
-    Handle<Value> Add(const Arguments& args) {
+    void Add(const FunctionCallbackInfo<Value>& args) {
       Isolate* isolate = Isolate::GetCurrent();
       HandleScope scope(isolate);
 
@@ -577,18 +590,15 @@ In the following `addon.cc` we introduce a function `add()` that can take on two
       MyObject* obj2 = node::ObjectWrap::Unwrap<MyObject>(
           args[1]->ToObject());
 
-      double sum = obj1->Value() + obj2->Value();
-      return scope.Close(Number::New(sum));
+      double sum = obj1->value() + obj2->value();
+      args.GetReturnValue().Set(Number::New(sum));
     }
 
     void InitAll(Handle<Object> exports) {
       MyObject::Init();
 
-      exports->Set(String::NewSymbol("createObject"),
-          FunctionTemplate::New(CreateObject)->GetFunction());
-
-      exports->Set(String::NewSymbol("add"),
-          FunctionTemplate::New(Add)->GetFunction());
+      NODE_SET_METHOD(exports, "createObject", CreateObject);
+      NODE_SET_METHOD(exports, "add", Add);
     }
 
     NODE_MODULE(addon, InitAll)
@@ -596,6 +606,7 @@ In the following `addon.cc` we introduce a function `add()` that can take on two
 To make things interesting we introduce a public method in `myobject.h` so we
 can probe private values after unwrapping the object:
 
+    // myobject.h
     #ifndef MYOBJECT_H
     #define MYOBJECT_H
 
@@ -605,14 +616,14 @@ can probe private values after unwrapping the object:
     class MyObject : public node::ObjectWrap {
      public:
       static void Init();
-      static v8::Handle<v8::Value> NewInstance(const v8::Arguments& args);
-      double Value() const { return value_; }
+      static void NewInstance(const v8::FunctionCallbackInfo<v8::Value>& args);
+      inline double value() const { return value_; }
 
      private:
       explicit MyObject(double value = 0);
       ~MyObject();
 
-      static v8::Handle<v8::Value> New(const v8::Arguments& args);
+      static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
       static v8::Persistent<v8::Function> constructor;
       double value_;
     };
@@ -621,6 +632,7 @@ can probe private values after unwrapping the object:
 
 The implementation of `myobject.cc` is similar as before:
 
+    // myobject.cc
     #include <node.h>
     #include "myobject.h"
 
@@ -639,13 +651,13 @@ The implementation of `myobject.cc` is similar as before:
 
       // Prepare constructor template
       Local<FunctionTemplate> tpl = FunctionTemplate::New(New);
-      tpl->SetClassName(String::NewSymbol("MyObject"));
+      tpl->SetClassName(String::NewFromUtf8(isolate, "MyObject"));
       tpl->InstanceTemplate()->SetInternalFieldCount(1);
 
-      constructor = Persistent<Function>::New(isolate, tpl->GetFunction());
+      constructor.Reset(isolate, tpl->GetFunction());
     }
 
-    Handle<Value> MyObject::New(const Arguments& args) {
+    void MyObject::New(const FunctionCallbackInfo<Value>& args) {
       Isolate* isolate = Isolate::GetCurrent();
       HandleScope scope(isolate);
 
@@ -654,28 +666,31 @@ The implementation of `myobject.cc` is similar as before:
         double value = args[0]->IsUndefined() ? 0 : args[0]->NumberValue();
         MyObject* obj = new MyObject(value);
         obj->Wrap(args.This());
-        return args.This();
+        args.GetReturnValue().Set(args.This());
       } else {
         // Invoked as plain function `MyObject(...)`, turn into construct call.
         const int argc = 1;
         Local<Value> argv[argc] = { args[0] };
-        return scope.Close(constructor->NewInstance(argc, argv));
+        Local<Function> cons = Local<Function>::New(isolate, constructor);
+        args.GetReturnValue().Set(cons->NewInstance(argc, argv));
       }
     }
 
-    Handle<Value> MyObject::NewInstance(const Arguments& args) {
+    void MyObject::NewInstance(const FunctionCallbackInfo<Value>& args) {
       Isolate* isolate = Isolate::GetCurrent();
       HandleScope scope(isolate);
 
       const unsigned argc = 1;
       Handle<Value> argv[argc] = { args[0] };
-      Local<Object> instance = constructor->NewInstance(argc, argv);
+      Local<Function> cons = Local<Function>::New(isolate, constructor);
+      Local<Object> instance = cons->NewInstance(argc, argv);
 
-      return scope.Close(instance);
+      args.GetReturnValue().Set(instance);
     }
 
 Test it with:
 
+    // test.js
     var addon = require('./build/Release/addon');
 
     var obj1 = addon.createObject(10);
index d0303f7..02584c1 100644 (file)
@@ -13,21 +13,23 @@ struct async_req {
   Persistent<Function> callback;
 };
 
-void DoAsync (uv_work_t *r) {
-  async_req *req = reinterpret_cast<async_req *>(r->data);
+void DoAsync(uv_work_t* r) {
+  async_req* req = reinterpret_cast<async_req*>(r->data);
   sleep(1); // simulate CPU intensive process...
   req->output = req->input * 2;
 }
 
-void AfterAsync (uv_work_t *r) {
-  HandleScope scope;
-  async_req *req = reinterpret_cast<async_req *>(r->data);
+void AfterAsync(uv_work_t* r) {
+  Isolate* isolate = Isolate::GetCurrent();
+  HandleScope scope(isolate);
+  async_req* req = reinterpret_cast<async_req*>(r->data);
 
   Handle<Value> argv[2] = { Null(), Integer::New(req->output) };
 
   TryCatch try_catch;
 
-  req->callback->Call(Context::GetCurrent()->Global(), 2, argv);
+  Local<Function> callback = Local<Function>::New(isolate, req->callback);
+  callback->Call(Context::GetCurrent()->Global(), 2, argv);
 
   // cleanup
   req->callback.Dispose();
@@ -38,24 +40,23 @@ void AfterAsync (uv_work_t *r) {
   }
 }
 
-Handle<Value> Method(const Arguments& args) {
-  HandleScope scope;
+void Method(const FunctionCallbackInfo<Value>& args) {
+  Isolate* isolate = Isolate::GetCurrent();
+  HandleScope scope(isolate);
 
-  async_req *req = new async_req;
+  async_reqreq = new async_req;
   req->req.data = req;
 
   req->input = args[0]->IntegerValue();
   req->output = 0;
 
   Local<Function> callback = Local<Function>::Cast(args[1]);
-  req->callback = Persistent<Function>::New(callback);
+  req->callback.Reset(isolate, callback);
 
   uv_queue_work(uv_default_loop(),
                 &req->req,
                 DoAsync,
                 (uv_after_work_cb)AfterAsync);
-
-  return Undefined();
 }
 
 void init(Handle<Object> exports, Handle<Object> module) {
index 6558a08..3609e4d 100644 (file)
@@ -7,6 +7,7 @@
 using node::AtExit;
 using v8::Handle;
 using v8::HandleScope;
+using v8::Isolate;
 using v8::Local;
 using v8::Object;
 
@@ -15,7 +16,7 @@ static int at_exit_cb1_called = 0;
 static int at_exit_cb2_called = 0;
 
 static void at_exit_cb1(void* arg) {
-  HandleScope scope;
+  HandleScope scope(Isolate::GetCurrent());
   assert(arg == 0);
   Local<Object> obj = Object::New();
   assert(!obj.IsEmpty()); // assert VM is still alive
index dcdb6b8..91fc26c 100644 (file)
@@ -3,9 +3,10 @@
 
 using namespace v8;
 
-Handle<Value> Method(const Arguments& args) {
-  HandleScope scope;
-  return scope.Close(String::New("world"));
+void Method(const FunctionCallbackInfo<Value>& args) {
+  Isolate* isolate = Isolate::GetCurrent();
+  HandleScope scope(isolate);
+  args.GetReturnValue().Set(String::NewFromUtf8(isolate, "world"));
 }
 
 void init(Handle<Object> exports, Handle<Object> module) {
index 424fad8..1a6d179 100644 (file)
@@ -3,9 +3,10 @@
 
 using namespace v8;
 
-Handle<Value> Method(const Arguments& args) {
-  HandleScope scope;
-  return scope.Close(String::New("world"));
+void Method(const FunctionCallbackInfo<Value>& args) {
+  Isolate* isolate = Isolate::GetCurrent();
+  HandleScope scope(isolate);
+  args.GetReturnValue().Set(String::NewFromUtf8(isolate, "world"));
 }
 
 void init(Handle<Object> target) {
diff --git a/test/addons/testcfg.py b/test/addons/testcfg.py
new file mode 100644 (file)
index 0000000..908fd6a
--- /dev/null
@@ -0,0 +1,6 @@
+import sys, os
+sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
+import testpy
+
+def GetConfiguration(context, root):
+  return testpy.AddonTestConfiguration(context, root, 'addon')
index 54b0f19..9593a1f 100644 (file)
@@ -134,3 +134,28 @@ class SimpleTestConfiguration(test.TestConfiguration):
     status_file = join(self.root, '%s.status' % (self.section))
     if exists(status_file):
       test.ReadConfigurationInto(status_file, sections, defs)
+
+class AddonTestConfiguration(SimpleTestConfiguration):
+  def __init__(self, context, root, section, additional=[]):
+    super(AddonTestConfiguration, self).__init__(context, root, section)
+
+  def Ls(self, path):
+    def SelectTest(name):
+      return name.endswith('.js')
+
+    result = []
+    for subpath in os.listdir(path):
+      if os.path.isdir(join(path, subpath)):
+        for f in os.listdir(join(path, subpath)):
+          if SelectTest(f):
+            result.append([subpath, f[:-3]])
+    return result
+
+  def ListTests(self, current_path, path, mode):
+    all_tests = [current_path + t for t in self.Ls(join(self.root))]
+    result = []
+    for test in all_tests:
+      if self.Contains(path, test):
+        file_path = join(self.root, reduce(join, test[1:], "") + ".js")
+        result.append(SimpleTestCase(test, file_path, mode, self.context, self))
+    return result
diff --git a/tools/doc/addon-verify.js b/tools/doc/addon-verify.js
new file mode 100644 (file)
index 0000000..f87cfec
--- /dev/null
@@ -0,0 +1,94 @@
+var fs = require('fs');
+var path = require('path');
+var marked = require('marked');
+
+var doc = path.resolve(__dirname, '..', '..', 'doc', 'api', 'addons.markdown');
+var verifyDir = path.resolve(__dirname, '..', '..', 'test', 'addons');
+
+var contents = fs.readFileSync(doc).toString();
+
+var tokens = marked.lexer(contents, {});
+var files = null;
+var id = 0;
+
+// Just to make sure that all examples will be processed
+tokens.push({ type: 'heading' });
+
+var oldDirs = fs.readdirSync(verifyDir);
+oldDirs = oldDirs.filter(function(dir) {
+  return /^doc-/.test(dir);
+}).map(function(dir) {
+  return path.resolve(verifyDir, dir);
+});
+
+for (var i = 0; i < tokens.length; i++) {
+  var token = tokens[i];
+  if (token.type === 'heading') {
+    if (files && Object.keys(files).length !== 0) {
+      verifyFiles(files, function(err) {
+        if (err)
+          console.log(err);
+        else
+          console.log('done');
+      });
+    }
+    files = {};
+  } else if (token.type === 'code') {
+    var match = token.text.match(/^\/\/\s+(.*\.(?:cc|h|js))[\r\n]/);
+    if (match === null)
+      continue;
+    files[match[1]] = token.text;
+  }
+}
+
+function once(fn) {
+  var once = false;
+  return function() {
+    if (once)
+      return;
+    once = true;
+    fn.apply(this, arguments);
+  };
+}
+
+function verifyFiles(files, callback) {
+  var dir = path.resolve(verifyDir, 'doc-' + id++);
+
+  files = Object.keys(files).map(function(name) {
+    return {
+      path: path.resolve(dir, name),
+      name: name,
+      content: files[name]
+    };
+  });
+  files.push({
+    path: path.resolve(dir, 'binding.gyp'),
+    content: JSON.stringify({
+      targets: [
+        {
+          target_name: 'addon',
+          sources: files.map(function(file) {
+            return file.name;
+          })
+        }
+      ]
+    })
+  });
+
+  fs.mkdir(dir, function() {
+    // Ignore errors
+
+    var waiting = files.length;
+    for (var i = 0; i < files.length; i++)
+      fs.writeFile(files[i].path, files[i].content, next);
+
+    var done = once(callback);
+    function next(err) {
+      if (err)
+        return done(err);
+
+      if (--waiting === 0)
+        done();
+    }
+  });
+}