Skip to content

Commit

Permalink
Add data to SetMethod and SetPrototypeMethod (#876)
Browse files Browse the repository at this point in the history
  • Loading branch information
drorgl authored and kkoopa committed Nov 20, 2019
1 parent c98d7aa commit 60e86a9
Show file tree
Hide file tree
Showing 5 changed files with 249 additions and 7 deletions.
9 changes: 6 additions & 3 deletions doc/methods.md
Original file line number Diff line number Diff line change
Expand Up @@ -478,10 +478,12 @@ Signature:
```c++
void Nan::SetMethod(v8::Local<v8::Object> recv,
const char *name,
Nan::FunctionCallback callback)
Nan::FunctionCallback callback,
v8::Local<v8::Value> data = v8::Local<v8::Value>())
void Nan::SetMethod(v8::Local<v8::Template> templ,
const char *name,
Nan::FunctionCallback callback)
Nan::FunctionCallback callback,
v8::Local<v8::Value> data = v8::Local<v8::Value>())
```
<a name="api_nan_set_prototype_method"></a>
Expand All @@ -494,7 +496,8 @@ Signature:
```c++
void Nan::SetPrototypeMethod(v8::Local<v8::FunctionTemplate> recv,
const char* name,
Nan::FunctionCallback callback)
Nan::FunctionCallback callback,
v8::Local<v8::Value> data = v8::Local<v8::Value>())
```

<a name="api_nan_set_accessor"></a>
Expand Down
11 changes: 7 additions & 4 deletions nan.h
Original file line number Diff line number Diff line change
Expand Up @@ -2469,9 +2469,10 @@ template <typename T, template <typename> class HandleType>
inline void SetMethod(
HandleType<T> recv
, const char *name
, FunctionCallback callback) {
, FunctionCallback callback
, v8::Local<v8::Value> data = v8::Local<v8::Value>()) {
HandleScope scope;
v8::Local<v8::FunctionTemplate> t = New<v8::FunctionTemplate>(callback);
v8::Local<v8::FunctionTemplate> t = New<v8::FunctionTemplate>(callback, data);
v8::Local<v8::String> fn_name = New(name).ToLocalChecked();
t->SetClassName(fn_name);
// Note(@agnat): Pass an empty T* as discriminator. See note on
Expand All @@ -2481,11 +2482,13 @@ inline void SetMethod(

inline void SetPrototypeMethod(
v8::Local<v8::FunctionTemplate> recv
, const char* name, FunctionCallback callback) {
, const char* name
, FunctionCallback callback
, v8::Local<v8::Value> data = v8::Local<v8::Value>()) {
HandleScope scope;
v8::Local<v8::FunctionTemplate> t = New<v8::FunctionTemplate>(
callback
, v8::Local<v8::Value>()
, data
, New<v8::Signature>(recv));
v8::Local<v8::String> fn_name = New(name).ToLocalChecked();
recv->PrototypeTemplate()->Set(fn_name, t);
Expand Down
4 changes: 4 additions & 0 deletions test/binding.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -185,4 +185,8 @@
"target_name" : "stringify"
, "sources" : [ "cpp/json-stringify.cpp" ]
}
, {
"target_name":"methodswithdata"
, "sources" :["cpp/methodswithdata.cpp"]
}
]}
194 changes: 194 additions & 0 deletions test/cpp/methodswithdata.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
/*********************************************************************
* NAN - Native Abstractions for Node.js
*
* Copyright (c) 2019 NAN contributors
*
* MIT License <https://github.com/nodejs/nan/blob/master/LICENSE.md>
********************************************************************/

#include <nan.h>

using namespace Nan; // NOLINT(build/namespaces)

NAN_METHOD(TestWithData) {
info.GetReturnValue().Set(false);
{
std::string datavalue = *Nan::Utf8String(info.Data());
if (datavalue != "test-value")return;
}
info.GetReturnValue().Set(true);
}

class SetterGetter : public ObjectWrap {
public:
static NAN_MODULE_INIT(Init);
static v8::Local<v8::Value> NewInstance ();
static NAN_METHOD(New);
static NAN_METHOD(Log);
static NAN_GETTER(GetProp1);
static NAN_GETTER(GetProp2);
static NAN_SETTER(SetProp2);

SetterGetter();

char log[1024];
char prop1[256];
char prop2[256];
};

static Persistent<v8::FunctionTemplate> settergetter_constructor;

SetterGetter::SetterGetter() {
log[0] = '\0';
strncpy(prop1, "this is property 1", sizeof (prop1) - 1);
prop1[sizeof (prop1) - 1] = '\0';
prop2[0] = '\0';
}

v8::Local<v8::Value> SetterGetter::NewInstance () {
EscapableHandleScope scope;
v8::Local<v8::FunctionTemplate> constructorHandle =
Nan::New(settergetter_constructor);
v8::Local<v8::Object> instance =
Nan::NewInstance(
Nan::GetFunction(constructorHandle).ToLocalChecked()).ToLocalChecked();
return scope.Escape(instance);
}

NAN_METHOD(SetterGetter::New) {
std::string datavalue = *Nan::Utf8String(info.Data());
assert(datavalue == "new-data");

SetterGetter* settergetter = new SetterGetter();
assert(strlen(settergetter->log) < sizeof (settergetter->log));
strncat(
settergetter->log
, "New()\n"
, sizeof (settergetter->log) - 1 - strlen(settergetter->log));
settergetter->Wrap(info.This());

info.GetReturnValue().Set(info.This());
}

NAN_GETTER(SetterGetter::GetProp1) {
std::string datavalue = *Nan::Utf8String(info.Data());
assert(datavalue == "prop1-data");
SetterGetter* settergetter =
ObjectWrap::Unwrap<SetterGetter>(info.Holder());
assert(strlen(settergetter->log) < sizeof (settergetter->log));
strncat(
settergetter->log
, "Prop1:GETTER("
, sizeof (settergetter->log) - 1 - strlen(settergetter->log));
assert(strlen(settergetter->log) < sizeof (settergetter->log));
strncat(
settergetter->log
, settergetter->prop1
, sizeof (settergetter->log) - 1 - strlen(settergetter->log));
assert(strlen(settergetter->log) < sizeof (settergetter->log));
strncat(
settergetter->log
, ")\n"
, sizeof (settergetter->log) - 1 - strlen(settergetter->log));

info.GetReturnValue().Set(Nan::New(settergetter->prop1).ToLocalChecked());
}

NAN_GETTER(SetterGetter::GetProp2) {
std::string datavalue = *Nan::Utf8String(info.Data());
assert(datavalue == "prop2-data");

SetterGetter* settergetter =
ObjectWrap::Unwrap<SetterGetter>(info.Holder());
assert(strlen(settergetter->log) < sizeof (settergetter->log));
strncat(
settergetter->log
, "Prop2:GETTER("
, sizeof (settergetter->log) - 1 - strlen(settergetter->log));
assert(strlen(settergetter->log) < sizeof (settergetter->log));
strncat(
settergetter->log
, settergetter->prop2
, sizeof (settergetter->log) - 1 - strlen(settergetter->log));
assert(strlen(settergetter->log) < sizeof (settergetter->log));
strncat(
settergetter->log
, ")\n"
, sizeof (settergetter->log) - 1 - strlen(settergetter->log));

info.GetReturnValue().Set(Nan::New(settergetter->prop2).ToLocalChecked());
}

NAN_SETTER(SetterGetter::SetProp2) {
std::string datavalue = *Nan::Utf8String(info.Data());
assert(datavalue == "prop2-data");

SetterGetter* settergetter =
ObjectWrap::Unwrap<SetterGetter>(info.Holder());
strncpy(
settergetter->prop2
, *Utf8String(value)
, sizeof (settergetter->prop2));
settergetter->prop2[sizeof (settergetter->prop2) - 1] = '\0';
assert(strlen(settergetter->log) < sizeof (settergetter->log));
strncat(
settergetter->log
, "Prop2:SETTER("
, sizeof (settergetter->log) - 1 - strlen(settergetter->log));
assert(strlen(settergetter->log) < sizeof (settergetter->log));
strncat(
settergetter->log
, settergetter->prop2
, sizeof (settergetter->log) - 1 - strlen(settergetter->log));
assert(strlen(settergetter->log) < sizeof (settergetter->log));
strncat(
settergetter->log
, ")\n"
, sizeof (settergetter->log) - 1 - strlen(settergetter->log));
}

NAN_METHOD(SetterGetter::Log) {
SetterGetter* settergetter =
ObjectWrap::Unwrap<SetterGetter>(info.Holder());

info.GetReturnValue().Set(Nan::New(settergetter->log).ToLocalChecked());
}

NAN_METHOD(CreateNew) {
std::string datavalue = *Nan::Utf8String(info.Data());
assert(datavalue == "create-data");

info.GetReturnValue().Set(SetterGetter::NewInstance());
}

NAN_MODULE_INIT(Init) {
SetMethod(target, "testWithData", TestWithData, New("test-value").ToLocalChecked());

v8::Local<v8::FunctionTemplate> tpl =
Nan::New<v8::FunctionTemplate>(SetterGetter::New, New("new-data").ToLocalChecked());
settergetter_constructor.Reset(tpl);
tpl->SetClassName(Nan::New<v8::String>("SetterGetter").ToLocalChecked());
tpl->InstanceTemplate()->SetInternalFieldCount(1);
SetPrototypeMethod(tpl, "log", SetterGetter::Log,Nan::New("log-data").ToLocalChecked());
v8::Local<v8::ObjectTemplate> itpl = tpl->InstanceTemplate();
SetAccessor(
itpl
, Nan::New("prop1").ToLocalChecked()
, SetterGetter::GetProp1
, 0
, Nan::New("prop1-data").ToLocalChecked());
SetAccessor(
itpl
, Nan::New<v8::String>("prop2").ToLocalChecked()
, SetterGetter::GetProp2
, SetterGetter::SetProp2
, Nan::New("prop2-data").ToLocalChecked()
);

v8::Local<v8::Function> createnew =
Nan::GetFunction(
Nan::New<v8::FunctionTemplate>(CreateNew, Nan::New("create-data").ToLocalChecked())).ToLocalChecked();
Set(target, Nan::New<v8::String>("create").ToLocalChecked(), createnew);
}

NODE_MODULE(methodswithdata, Init)
38 changes: 38 additions & 0 deletions test/js/methodswithdata-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*********************************************************************
* NAN - Native Abstractions for Node.js
*
* Copyright (c) 2019 NAN contributors
*
* MIT License <https://github.com/nodejs/nan/blob/master/LICENSE.md>
********************************************************************/

const test = require('tap').test
, testRoot = require('path').resolve(__dirname, '..')
, bindings = require('bindings')({ module_root: testRoot, bindings: 'methodswithdata' })

test('SetMethod with data', function (t) {
t.plan(1);
t.ok(bindings.testWithData());
});

test('accessors with data', function (t) {
t.plan(7)
var settergetter = bindings.create()
t.equal(settergetter.prop1, 'this is property 1')
t.ok(settergetter.prop2 === '')
settergetter.prop2 = 'setting a value'
t.equal(settergetter.prop2, 'setting a value')
t.equal(settergetter.log(),
'New()\n' +
'Prop1:GETTER(this is property 1)\n' +
'Prop2:GETTER()\n' +
'Prop2:SETTER(setting a value)\n' +
'Prop2:GETTER(setting a value)\n'
)
var derived = Object.create(settergetter)
t.equal(derived.prop1, 'this is property 1')
derived.prop2 = 'setting a new value'
t.equal(derived.prop2, 'setting a new value')
t.equal(settergetter.prop2, 'setting a new value')
})

0 comments on commit 60e86a9

Please sign in to comment.