Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Use named property for better ux.

Squashed commit of the following:

commit 758e614
Author: tokuhirom <tokuhirom@gmail.com>
Date:   Tue Aug 28 11:08:34 2012 +0900

    blessed.

commit 27258f3
Author: tokuhirom <tokuhirom@gmail.com>
Date:   Tue Aug 28 11:04:39 2012 +0900

    added 'blessed' method

commit 2310726
Author: tokuhirom <tokuhirom@gmail.com>
Date:   Tue Aug 28 10:52:29 2012 +0900

    you can pass a perl object to the perl world

commit 517ab31
Author: tokuhirom <tokuhirom@gmail.com>
Date:   Tue Aug 28 10:29:50 2012 +0900

    named property support for class method

commit 4eb4dd1
Author: tokuhirom <tokuhirom@gmail.com>
Date:   Tue Aug 28 10:15:17 2012 +0900

    named property support for instance method
  • Loading branch information...
commit 63c67f272e22103b5a40cd5a1257e61b2bc880fe 1 parent 4a1ed65
@tokuhirom authored
View
36 README.mkdn
@@ -32,44 +32,38 @@ evaluate the perl code and get a return value.
Get a class object(Instance of PerlClass) from perl.
-#### var val = perl.call(Str funcname, ...args)
+#### var klass = Perl.blessed(obj)
-Call perl5 function and get a return value in scalar context.
-You get a exception when Perl5 throws exception.
+Same as Scalar::Util::blessed.
-#### var val = perl.callList(str funcname, ...args)
+#### var val = perl[funcname]
-Same as call, but callList calls function in list context.
+Get a PerlMethod object.
### require('perl-simple').PerlObject
-#### `var name = perl_object.getClassName();`
-
-Get a class name from object.
-
-#### `var val = perl_object.call(...)`
-
-same as Perl#call, but call with an object.
+#### var val = obj[funcname]
-#### `var val = perl_object.callList(...)`
-
-same as Perl#callList, but call with an object.
+Get a PerlMethod object.
### require('perl-simple').PerlClass
You can get a instance of this class by Perl#getClass.
-#### `var val = perl_class.getClassName()`
+#### var val = klass[funcname]
+
+Get a PerlMethod object.
-Get a class name from class.
+### require('perl-simple').PerlMethod
-#### `var val = perl_class.call()`
+#### var val = method()
-same as Perl#call, but call with a class name.
+Call perl5 function and get a return value in scalar context.
+You get a exception when Perl5 throws exception.
-#### `var val = perl_class.callList()`
+#### var val = method.callList()
-same as Perl#callList, but call with a class name.
+Same as above, but callList calls function in list context.
Notes
-----
View
296 src/perl_bindings.cc
@@ -21,12 +21,27 @@ using namespace v8;
using namespace node;
#define INTERPRETER_NAME "node-perl-simple"
-
+#define THR_TYPE_ERROR(str) \
+ ThrowException(Exception::TypeError(String::New(str)))
#define REQ_EXT_ARG(I, VAR) \
if (args.Length() <= (I) || !args[I]->IsExternal()) \
return ThrowException(Exception::TypeError( \
String::New("Argument " #I " must be an external"))); \
Local<External> VAR = Local<External>::Cast(args[I]);
+#define REQ_STR_ARG(I, VAR) \
+if (args.Length() <= (I) || !args[I]->IsString()) \
+return ThrowException(Exception::TypeError( \
+String::New("Argument " #I " must be a string"))); \
+String::Utf8Value VAR(args[I]->ToString());
+
+#define REQ_OBJ_ARG(I, VAR) \
+if (args.Length() <= (I) || !args[I]->IsObject()) \
+return ThrowException(Exception::TypeError( \
+String::New("Argument " #I " must be a object"))); \
+Local<Object> VAR = Local<Object>::Cast(args[I]);
+
+// TODO: pass the NodePerlObject to perl5 world.
+// TODO: blessed() function
class PerlFoo {
protected:
@@ -63,53 +78,14 @@ class PerlFoo {
// TODO: return callback function for perl code.
}
- SV* js2perl(Handle<Value> val) const {
- if (val->IsTrue()) {
- return &PL_sv_yes;
- } else if (val->IsFalse()) {
- return &PL_sv_no;
- } else if (val->IsString()) {
- v8::String::Utf8Value method(val);
- return sv_2mortal(newSVpv(*method, method.length()));
- } else if (val->IsArray()) {
- Handle<Array> jsav = Handle<Array>::Cast(val);
- AV * av = newAV();
- av_extend(av, jsav->Length());
- for (int i=0; i<jsav->Length(); ++i) {
- SV * elem = this->js2perl(jsav->Get(i));
- av_push(av, SvREFCNT_inc(elem));
- }
- return sv_2mortal(newRV_noinc((SV*)av));
- } else if (val->IsObject()) {
- Handle<Object> jsobj = Handle<Object>::Cast(val);
- Handle<Array> keys = jsobj->GetOwnPropertyNames();
- HV * hv = newHV();
- hv_ksplit(hv, keys->Length());
- for (int i=0; i<keys->Length(); ++i) {
- SV * k = this->js2perl(keys->Get(i));
- SV * v = this->js2perl(keys->Get(i));
- hv_store_ent(hv, k, v, 0);
- // SvREFCNT_dec(k);
- }
- return sv_2mortal(newRV_inc((SV*)hv));
- } else if (val->IsInt32()) {
- return sv_2mortal(newSViv(val->Int32Value()));
- } else if (val->IsUint32()) {
- return sv_2mortal(newSVuv(val->Uint32Value()));
- } else if (val->IsNumber()) {
- return sv_2mortal(newSVnv(val->NumberValue()));
- } else {
- // RegExp, Date, External
- return NULL;
- }
- }
+ SV* js2perl(Handle<Value> val) const;
- Handle<Value> CallMethod(SV * self, const Arguments& args, bool in_list_context) {
+ Handle<Value> CallMethod2(const Arguments& args, bool in_list_context) {
+ REQ_STR_ARG(0, method);
+ return this->CallMethod2(NULL, *method, 1, args, in_list_context);
+ }
+ Handle<Value> CallMethod2(SV * self, const char *method, int offset, const Arguments& args, bool in_list_context) {
HandleScope scope;
- if (!args[0]->IsString()) {
- return ThrowException(Exception::Error(String::New("First argument must be string")));
- }
- v8::String::Utf8Value method(args[0]);
dSP;
ENTER;
@@ -118,7 +94,7 @@ class PerlFoo {
if (self) {
XPUSHs(self);
}
- for (int i=self?1:0; i<args.Length(); i++) {
+ for (int i=offset; i<args.Length(); i++) {
SV * arg = this->js2perl(args[i]);
if (!arg) {
PUTBACK;
@@ -132,7 +108,7 @@ class PerlFoo {
}
PUTBACK;
if (in_list_context) {
- int n = self ? call_method(*method, G_ARRAY|G_EVAL) : call_pv(*method, G_ARRAY|G_EVAL);
+ int n = self ? call_method(method, G_ARRAY|G_EVAL) : call_pv(method, G_ARRAY|G_EVAL);
SPAGAIN;
if (SvTRUE(ERRSV)) {
POPs;
@@ -153,9 +129,9 @@ class PerlFoo {
}
} else {
if (self) {
- call_method(*method, G_SCALAR|G_EVAL);
+ call_method(method, G_SCALAR|G_EVAL);
} else {
- call_pv(*method, G_SCALAR|G_EVAL);
+ call_pv(method, G_SCALAR|G_EVAL);
}
SPAGAIN;
if (SvTRUE(ERRSV)) {
@@ -178,38 +154,123 @@ class PerlFoo {
Handle<Value> perl2js_rv(SV * rv);
};
-class PerlObject: ObjectWrap, PerlFoo {
-private:
+class NodePerlMethod: ObjectWrap, PerlFoo {
+public:
+ SV * sv_;
+ std::string name_;
+
+ NodePerlMethod(SV *sv, const char * name, PerlInterpreter *myp): sv_(sv), name_(name), PerlFoo(myp) {
+ SvREFCNT_inc(sv);
+ }
+ ~NodePerlMethod() {
+ SvREFCNT_dec(sv_);
+ }
+
+ static Persistent<FunctionTemplate> constructor_template;
+
+ static void Init(Handle<Object> target) {
+ Local<FunctionTemplate> t = FunctionTemplate::New(NodePerlMethod::New);
+ constructor_template = Persistent<FunctionTemplate>::New(t);
+ constructor_template->SetClassName(String::NewSymbol("NodePerlMethod"));
+
+ /*
+ NODE_SET_PROTOTYPE_METHOD(t, "call", NodePerlMethod::call);
+ */
+ NODE_SET_PROTOTYPE_METHOD(t, "callList", NodePerlMethod::callList);
+
+ Local<ObjectTemplate> instance_template = constructor_template->InstanceTemplate();
+ instance_template->SetInternalFieldCount(1);
+ instance_template->SetCallAsFunctionHandler(NodePerlMethod::call, Undefined());
+
+ // NODE_SET_PROTOTYPE_METHOD(t, "eval", NodePerl::eval);
+ target->Set(String::NewSymbol("NodePerlMethod"), constructor_template->GetFunction());
+ }
+ static Handle<Value> New(const Arguments& args) {
+ HandleScope scope;
+
+ if (!args.IsConstructCall())
+ return args.Callee()->NewInstance();
+
+ REQ_EXT_ARG(0, jssv);
+ REQ_EXT_ARG(1, jsmyp);
+ REQ_STR_ARG(2, jsname);
+ SV* sv = static_cast<SV*>(jssv->Value());
+ PerlInterpreter* myp = static_cast<PerlInterpreter*>(jsmyp->Value());
+ try {
+ (new NodePerlMethod(sv, *jsname, myp))->Wrap(args.Holder());
+ } catch (const char *msg) {
+ return ThrowException(Exception::Error(String::New(msg)));
+ }
+ return scope.Close(args.Holder());
+ }
+ static Handle<Value> call(const Arguments& args) {
+ HandleScope scope;
+ return scope.Close(Unwrap<NodePerlMethod>(args.This())->Call(args, false));
+ }
+ static Handle<Value> callList(const Arguments& args) {
+ HandleScope scope;
+ return scope.Close(Unwrap<NodePerlMethod>(args.This())->Call(args, true));
+ }
+ Handle<Value> Call(const Arguments& args, bool in_list_context) {
+ return this->CallMethod2(this->sv_, name_.c_str(), 0, args, in_list_context);
+ }
+};
+
+class NodePerlObject: protected ObjectWrap, protected PerlFoo {
+protected:
SV * sv_;
public:
static Persistent<FunctionTemplate> constructor_template;
static void Init(Handle<Object> target) {
- Local<FunctionTemplate> t = FunctionTemplate::New(PerlObject::New);
+ Local<FunctionTemplate> t = FunctionTemplate::New(NodePerlObject::New);
constructor_template = Persistent<FunctionTemplate>::New(t);
- constructor_template->SetClassName(String::NewSymbol("PerlObject"));
+ constructor_template->SetClassName(String::NewSymbol("NodePerlObject"));
- NODE_SET_PROTOTYPE_METHOD(t, "getClassName", PerlObject::getClassName);
- NODE_SET_PROTOTYPE_METHOD(t, "call", PerlObject::call);
- NODE_SET_PROTOTYPE_METHOD(t, "callList", PerlObject::callList);
+ NODE_SET_PROTOTYPE_METHOD(t, "getClassName", NodePerlObject::getClassName);
Local<ObjectTemplate> instance_template = constructor_template->InstanceTemplate();
instance_template->SetInternalFieldCount(1);
+ instance_template->SetNamedPropertyHandler(NodePerlObject::GetNamedProperty);
// NODE_SET_PROTOTYPE_METHOD(t, "eval", NodePerl::eval);
- target->Set(String::NewSymbol("PerlObject"), constructor_template->GetFunction());
+ target->Set(String::NewSymbol("NodePerlObject"), constructor_template->GetFunction());
}
- PerlObject(SV *sv, PerlInterpreter *myp): sv_(sv), PerlFoo(myp) {
+ static Handle<Value> GetNamedProperty(Local<String> name,
+ const AccessorInfo &info) {
+ HandleScope scope;
+
+ if (info.This()->InternalFieldCount() < 1 || info.Data().IsEmpty()) {
+ return THR_TYPE_ERROR("SetNamedProperty intercepted "
+ "by non-Proxy object");
+ }
+
+ return scope.Close(Unwrap<NodePerlObject>(info.This())->getNamedProperty(name));
+ }
+ Handle<Value> getNamedProperty(Local<String> name) {
+ HandleScope scope;
+ v8::String::Utf8Value stmt(name);
+ Local<Value> arg0 = External::New(sv_);
+ Local<Value> arg1 = External::New(my_perl);
+ Local<Value> arg2 = name;
+ Local<Value> args[] = {arg0, arg1, arg2};
+ v8::Handle<v8::Object> retval(
+ NodePerlMethod::constructor_template->GetFunction()->NewInstance(3, args)
+ );
+ return scope.Close(retval);
+ }
+
+ NodePerlObject(SV *sv, PerlInterpreter *myp): sv_(sv), PerlFoo(myp) {
SvREFCNT_inc(sv);
}
- ~PerlObject() {
+ ~NodePerlObject() {
SvREFCNT_dec(sv_);
}
static Handle<Value> getClassName(const Arguments& args) {
HandleScope scope;
- return scope.Close(Unwrap<PerlObject>(args.This())->getClassName());
+ return scope.Close(Unwrap<NodePerlObject>(args.This())->getClassName());
}
Handle<Value> getClassName() {
HandleScope scope;
@@ -221,16 +282,18 @@ class PerlObject: ObjectWrap, PerlFoo {
return scope.Close(String::New(sv_reftype(SvRV(sv_),TRUE)));
}
}
- static Handle<Value> call(const Arguments& args) {
- HandleScope scope;
- return scope.Close(Unwrap<PerlObject>(args.This())->Call(args, false));
+ static SV* getSV(Handle<Object> val) {
+ return Unwrap<NodePerlObject>(val)->sv_;
}
- static Handle<Value> callList(const Arguments& args) {
- HandleScope scope;
- return scope.Close(Unwrap<PerlObject>(args.This())->Call(args, true));
+ static Handle<Value> blessed(Handle<Object> val) {
+ return Unwrap<NodePerlObject>(val)->blessed();
}
- Handle<Value> Call(const Arguments& args, bool in_list_context) {
- return this->CallMethod(this->sv_, args, in_list_context);
+ Handle<Value> blessed() {
+ HandleScope scope;
+ if(!(SvROK(sv_) && SvOBJECT(SvRV(sv_)))) {
+ return scope.Close(Undefined());
+ }
+ return scope.Close(String::New(sv_reftype(SvRV(sv_),TRUE)));
}
static Handle<Value> New(const Arguments& args) {
@@ -244,7 +307,7 @@ class PerlObject: ObjectWrap, PerlFoo {
SV* sv = static_cast<SV*>(jssv->Value());
PerlInterpreter* myp = static_cast<PerlInterpreter*>(jsmyp->Value());
try {
- (new PerlObject(sv, myp))->Wrap(args.Holder());
+ (new NodePerlObject(sv, myp))->Wrap(args.Holder());
} catch (const char *msg) {
return ThrowException(Exception::Error(String::New(msg)));
}
@@ -252,24 +315,20 @@ class PerlObject: ObjectWrap, PerlFoo {
}
};
-class PerlClass: PerlObject {
+class NodePerlClass: NodePerlObject {
public:
static Persistent<FunctionTemplate> constructor_template;
static void Init(Handle<Object> target) {
- Local<FunctionTemplate> t = FunctionTemplate::New(PerlClass::New);
+ Local<FunctionTemplate> t = FunctionTemplate::New(NodePerlClass::New);
constructor_template = Persistent<FunctionTemplate>::New(t);
- constructor_template->SetClassName(String::NewSymbol("PerlClass"));
-
- NODE_SET_PROTOTYPE_METHOD(t, "getClassName", PerlClass::getClassName);
- NODE_SET_PROTOTYPE_METHOD(t, "call", PerlClass::call);
- NODE_SET_PROTOTYPE_METHOD(t, "callList", PerlClass::callList);
+ constructor_template->SetClassName(String::NewSymbol("NodePerlClass"));
Local<ObjectTemplate> instance_template = constructor_template->InstanceTemplate();
instance_template->SetInternalFieldCount(1);
+ instance_template->SetNamedPropertyHandler(NodePerlObject::GetNamedProperty);
- // NODE_SET_PROTOTYPE_METHOD(t, "eval", NodePerl::eval);
- target->Set(String::NewSymbol("PerlClass"), constructor_template->GetFunction());
+ target->Set(String::NewSymbol("NodePerlClass"), constructor_template->GetFunction());
}
};
@@ -283,6 +342,7 @@ class NodePerl: ObjectWrap, PerlFoo {
NODE_SET_PROTOTYPE_METHOD(t, "call", NodePerl::call);
NODE_SET_PROTOTYPE_METHOD(t, "callList", NodePerl::callList);
t->InstanceTemplate()->SetInternalFieldCount(1);
+ NODE_SET_METHOD(t, "blessed", NodePerl::blessed);
target->Set(String::New("Perl"), t->GetFunction());
}
@@ -323,6 +383,17 @@ class NodePerl: ObjectWrap, PerlFoo {
return scope.Close(args.Holder());
}
+ static Handle<Value> blessed(const Arguments& args) {
+ HandleScope scope;
+ REQ_OBJ_ARG(0, jsobj);
+
+ if (NodePerlObject::constructor_template->HasInstance(jsobj)) {
+ return scope.Close(NodePerlObject::blessed(jsobj));
+ } else {
+ return scope.Close(Undefined());
+ }
+ }
+
static Handle<Value> evaluate(const Arguments& args) {
HandleScope scope;
if (!args[0]->IsString()) {
@@ -347,11 +418,11 @@ class NodePerl: ObjectWrap, PerlFoo {
static Handle<Value> call(const Arguments& args) {
HandleScope scope;
- return scope.Close(Unwrap<NodePerl>(args.This())->CallMethod(NULL, args, false));
+ return scope.Close(Unwrap<NodePerl>(args.This())->CallMethod2(args, false));
}
static Handle<Value> callList(const Arguments& args) {
HandleScope scope;
- return scope.Close(Unwrap<NodePerl>(args.This())->CallMethod(NULL, args, true));
+ return scope.Close(Unwrap<NodePerl>(args.This())->CallMethod2(args, true));
}
private:
@@ -361,7 +432,7 @@ class NodePerl: ObjectWrap, PerlFoo {
Local<Value> arg1 = External::New(my_perl);
Local<Value> args[] = {arg0, arg1};
v8::Handle<v8::Object> retval(
- PerlClass::constructor_template->GetFunction()->NewInstance(2, args)
+ NodePerlClass::constructor_template->GetFunction()->NewInstance(2, args)
);
return scope.Close(retval);
}
@@ -372,6 +443,55 @@ class NodePerl: ObjectWrap, PerlFoo {
public:
};
+SV* PerlFoo::js2perl(Handle<Value> val) const {
+ if (val->IsTrue()) {
+ return &PL_sv_yes;
+ } else if (val->IsFalse()) {
+ return &PL_sv_no;
+ } else if (val->IsString()) {
+ v8::String::Utf8Value method(val);
+ return sv_2mortal(newSVpv(*method, method.length()));
+ } else if (val->IsArray()) {
+ Handle<Array> jsav = Handle<Array>::Cast(val);
+ AV * av = newAV();
+ av_extend(av, jsav->Length());
+ for (int i=0; i<jsav->Length(); ++i) {
+ SV * elem = this->js2perl(jsav->Get(i));
+ av_push(av, SvREFCNT_inc(elem));
+ }
+ return sv_2mortal(newRV_noinc((SV*)av));
+ } else if (val->IsObject()) {
+ Handle<Object> jsobj = Handle<Object>::Cast(val);
+ if (NodePerlObject::constructor_template->HasInstance(jsobj)) {
+ SV * ret = NodePerlObject::getSV(jsobj);
+ return ret;
+ } else if (NodePerlClass::constructor_template->HasInstance(jsobj)) {
+ SV * ret = NodePerlObject::getSV(jsobj);
+ return ret;
+ } else {
+ Handle<Array> keys = jsobj->GetOwnPropertyNames();
+ HV * hv = newHV();
+ hv_ksplit(hv, keys->Length());
+ for (int i=0; i<keys->Length(); ++i) {
+ SV * k = this->js2perl(keys->Get(i));
+ SV * v = this->js2perl(keys->Get(i));
+ hv_store_ent(hv, k, v, 0);
+ // SvREFCNT_dec(k);
+ }
+ return sv_2mortal(newRV_inc((SV*)hv));
+ }
+ } else if (val->IsInt32()) {
+ return sv_2mortal(newSViv(val->Int32Value()));
+ } else if (val->IsUint32()) {
+ return sv_2mortal(newSVuv(val->Uint32Value()));
+ } else if (val->IsNumber()) {
+ return sv_2mortal(newSVnv(val->NumberValue()));
+ } else {
+ // RegExp, Date, External
+ return NULL;
+ }
+}
+
Handle<Value> PerlFoo::perl2js_rv(SV * rv) {
HandleScope scope;
@@ -384,7 +504,7 @@ Handle<Value> PerlFoo::perl2js_rv(SV * rv) {
Local<Value> arg1 = External::New(my_perl);
Local<Value> args[] = {arg0, arg1};
v8::Handle<v8::Object> retval(
- PerlObject::constructor_template->GetFunction()->NewInstance(2, args)
+ NodePerlObject::constructor_template->GetFunction()->NewInstance(2, args)
);
return scope.Close(retval);
} else if (svt == SVt_PVHV) {
@@ -419,8 +539,9 @@ Handle<Value> PerlFoo::perl2js_rv(SV * rv) {
}
}
-Persistent<FunctionTemplate> PerlObject::constructor_template;
-Persistent<FunctionTemplate> PerlClass::constructor_template;
+Persistent<FunctionTemplate> NodePerlObject::constructor_template;
+Persistent<FunctionTemplate> NodePerlMethod::constructor_template;
+Persistent<FunctionTemplate> NodePerlClass::constructor_template;
/**
* Load lazily libperl for dynamic loaded xs.
@@ -451,7 +572,8 @@ extern "C" void init(Handle<Object> target) {
}
NodePerl::Init(target);
- PerlObject::Init(target);
- PerlClass::Init(target);
+ NodePerlObject::Init(target);
+ NodePerlClass::Init(target);
+ NodePerlMethod::Init(target);
}
View
40 test/01_simple.js
@@ -13,40 +13,17 @@ test("", function (t) {
t.end();
});
-test("bless", function (t) {
- var perl = new Perl();
- var obj = perl.evaluate("package hoge; sub yo { warn q{yo!}; 5963 } sub f2 { warn join(q{...}, @_); } sub fun2 { shift; return shift()**2 } sub fun3 { (1,2,3,4) } sub fun4 { die } bless [], 'hoge'");
- t.equivalent(obj.call('yo'), 5963);
- t.equivalent(obj.call('fun2', 3), 9);
- t.equivalent(obj.call('fun2', 3), 9);
- t.equivalent(obj.call('fun3'), 4);
- t.equivalent(obj.callList('fun3'), [1,2,3,4]);
- try {
- obj.call('fun4');
- } catch (e) {
- t.ok(e.match(/Died/), 'died');
- }
- try {
- obj.callList('fun4');
- } catch (e) {
- t.ok(e.match(/Died/), 'died');
- }
- t.equivalent(obj.getClassName(), 'hoge');
- console.log(perl);
- t.end();
-});
-
test("eval", function (t) {
t.plan(2);
var perl = new Perl();
var obj = perl.evaluate("package hoge; sub yo { warn q{yo!}; 5963 } sub f2 { warn join(q{...}, @_); } sub fun2 { shift; return shift()**2 } sub fun3 { (1,2,3,4) } sub fun4 { die } bless [], 'hoge'");
try {
- obj.call('fun4');
+ obj.fun4();
} catch (e) {
t.ok(e.match(/Died/), 'died');
}
try {
- obj.callList('fun4');
+ obj.fun4.callList();
} catch (e) {
t.ok(e.match(/Died/), 'died');
}
@@ -68,10 +45,9 @@ test("class", function (t) {
perl.evaluate("package Foo; sub foo { 4**2 }");
perl.evaluate("package Foo; sub bar { $_[0]x3 }");
perl.evaluate("package Foo; sub baz { $_[1]*2 }");
- t.equivalent(perl.getClass('Foo').call('foo'), 16);
- t.equivalent(perl.getClass('Foo').call('bar'), "FooFooFoo");
- t.equivalent(perl.getClass('Foo').call('baz', 5), 10);
- t.equivalent(perl.getClass('Foo').getClassName(), 'Foo');
+ t.equivalent(perl.getClass('Foo').foo(), 16);
+ t.equivalent(perl.getClass('Foo').bar(), "FooFooFoo", 'bar');
+ t.equivalent(perl.getClass('Foo').baz(5), 10);
t.end();
});
@@ -84,9 +60,9 @@ test("gc", function (t) {
var perl = new Perl();
perl.evaluate("sub foo { 4**2 }");
perl.evaluate("sub bar { return (5,9,6,3) }");
- t.equivalent(perl.call('foo'), 16);
- t.equivalent(perl.call('bar'), 3);
- t.equivalent(perl.callList('bar'), [5,9,6,3]);
+ t.equivalent(perl.foo(), 16);
+ t.equivalent(perl.bar(), 3);
+ t.equivalent(perl.bar.callList(), [5,9,6,3]);
gc();
}
t.end();
View
46 test/03_instance_method.js
@@ -0,0 +1,46 @@
+var test = require('tap').test;
+var Perl = require('../index.js').Perl;
+
+test("bless", function (t) {
+ var perl = new Perl();
+ var obj = perl.evaluate("package hoge; sub yo { warn q{yo!}; 5963 } sub f2 { warn join(q{...}, @_); } sub fun2 { shift; return shift()**2 } sub fun3 { (1,2,3,4) } sub fun4 { die } bless [], 'hoge'");
+ perl.evaluate("sub p { print @_; \@_ }");
+ t.equivalent(obj.yo(), 5963);
+ t.equivalent(obj.fun2(3), 9);
+ t.equivalent(obj.fun3(), 4);
+ t.equivalent(obj.fun3.callList(), [1,2,3,4]);
+ try {
+ obj.fun4();
+ } catch (e) {
+ t.ok(e.match(/Died/), 'died');
+ }
+ try {
+ obj.fun4.callList();
+ } catch (e) {
+ t.ok(e.match(/Died/), 'died');
+ }
+ console.log(typeof(obj));
+ t.equivalent(Perl.blessed(obj), 'hoge');
+ console.log(perl);
+ t.end();
+});
+
+test("bless", function (t) {
+ var perl = new Perl();
+ var obj = perl.evaluate("bless [4,6,4,9], 'hoge'");
+ perl.evaluate("use Scalar::Util qw/blessed/; sub p { blessed(shift) }");
+ perl.evaluate("sub nop { shift }");
+ t.equivalent(perl.call('p', obj), 'hoge');
+ t.equivalent(perl.call('nop', perl.getClass("YO")), 'YO');
+ console.log(perl);
+ t.end();
+});
+
+test("blessed", function (t) {
+ var perl = new Perl();
+ var obj = perl.evaluate("bless [4,6,4,9], 'hoge'");
+ t.equivalent(Perl.blessed(obj), 'hoge');
+ t.equivalent(Perl.blessed(perl.getClass("YO")), undefined);
+ console.log(perl);
+ t.end();
+});
Please sign in to comment.
Something went wrong with that request. Please try again.