Skip to content

Commit 230d16a

Browse files
author
Krzysztof Chrapka
committed
feature: add support for named constructors
1 parent d52b6c5 commit 230d16a

File tree

4 files changed

+129
-5
lines changed

4 files changed

+129
-5
lines changed

.travis.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
language: node_js
22
node_js:
33
- "0.10"
4+
- "0.12"
5+
- "4.4"
6+
- "5.10"
47
branches:
58
only:
69
- master
7-
- dev
10+
- dev

docs/components.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,9 @@ myComponent: {
166166
// and shave off some cpu cycles (No guessing will be done)
167167
// at the cost of being more verbose.
168168
isConstructor: true, // or false
169+
// Optional: If object is instantiated using a named constructor,
170+
// you can specify its name here, so that it will be called.
171+
namedConstructor: "create",
169172
}
170173
}
171174
```

lib/plugin/basePlugin.js

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ define(function(require) {
219219
* @param {function} wire
220220
*/
221221
function instanceFactory(resolver, componentDef, wire) {
222-
var create, args, isConstructor, module, instance;
222+
var create, args, isConstructor, module, instance, constructorName;
223223

224224
create = componentDef.options;
225225

@@ -228,12 +228,14 @@ define(function(require) {
228228
} else if(wire.resolver.isRef(create)) {
229229
module = wire(create);
230230
args = getArgs(create, wire);
231+
constructorName = create.constructorName;
231232
} else if(object.isObject(create) && create.module) {
232233
module = wire.resolver.isRef(create.module)
233234
? wire(create.module)
234235
: wire.loadModule(create.module);
235236
args = getArgs(create, wire);
236237
isConstructor = create.isConstructor;
238+
constructorName = create.constructorName;
237239
} else {
238240
module = create;
239241
}
@@ -246,9 +248,11 @@ define(function(require) {
246248
function createInstance(module, args) {
247249
// We'll either use the module directly, or we need
248250
// to instantiate/invoke it.
249-
return typeof module == 'function'
250-
? instantiate(module, args, isConstructor)
251-
: Object.create(module);
251+
return constructorName
252+
? module[constructorName].apply(module, args)
253+
: typeof module == 'function'
254+
? instantiate(module, args, isConstructor)
255+
: Object.create(module);
252256
}
253257
}
254258

test/node/lib/plugin/basePlugin-test.js

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,35 @@ function factory1(v1) {
5656
};
5757
}
5858

59+
function ClassWithNamedConstructor() {
60+
61+
}
62+
63+
ClassWithNamedConstructor.createInstance = function(){
64+
var instance = new ClassWithNamedConstructor();
65+
instance.createInstanceCalled = true;
66+
instance.createInstanceArgs = Array.prototype.slice.call(arguments);
67+
instance.thisSetInCreateInstance = this;
68+
69+
return instance;
70+
};
71+
72+
ClassWithNamedConstructor.createInstancePromise = function(){
73+
return {
74+
then: function(f) {
75+
f(ClassWithNamedConstructor.createInstance());
76+
}
77+
};
78+
};
79+
80+
ClassWithNamedConstructor.createInstanceReject = function(){
81+
return {
82+
then: function(f, reject) {
83+
reject(new Error('test error'));
84+
}
85+
};
86+
};
87+
5988
buster.testCase('lib/plugin/basePlugin', {
6089
'module factory': {
6190
'should use module exports value as component': function() {
@@ -506,6 +535,91 @@ buster.testCase('lib/plugin/basePlugin', {
506535
},
507536
fail
508537
);
538+
},
539+
'constructorName': {
540+
'should use static named constructor if constructorName is set': function() {
541+
return createContext({
542+
test: {
543+
create: {
544+
module: ClassWithNamedConstructor,
545+
constructorName: 'createInstance'
546+
}
547+
}
548+
}).then(function(wired){
549+
assert('test' in wired);
550+
assert(wired.test.createInstanceCalled);
551+
});
552+
},
553+
'should pass arguments to named constructor': function() {
554+
return createContext({
555+
test: {
556+
create: {
557+
module: ClassWithNamedConstructor,
558+
constructorName: 'createInstance',
559+
args: ['foo', 'bar', 1, 1.2]
560+
}
561+
}
562+
}).then(function(wired){
563+
assert('test' in wired);
564+
assert.equals(wired.test.createInstanceArgs, ['foo', 'bar', 1, 1.2]);
565+
});
566+
},
567+
'should work with module loaded by reference': function() {
568+
return createContext({
569+
reference: {
570+
module: ClassWithNamedConstructor,
571+
},
572+
test: {
573+
create: {
574+
module: {$ref: 'reference'},
575+
constructorName: 'createInstance'
576+
}
577+
}
578+
}).then(function(wired){
579+
assert('test' in wired);
580+
assert(wired.test.createInstanceCalled);
581+
});
582+
},
583+
'this in named constructor should be the constructor on which it is called': function() {
584+
return createContext({
585+
test: {
586+
create: {
587+
module: ClassWithNamedConstructor,
588+
constructorName: 'createInstance',
589+
}
590+
}
591+
}).then(function(wired){
592+
assert('test' in wired);
593+
assert.equals(wired.test.thisSetInCreateInstance, ClassWithNamedConstructor);
594+
});
595+
},
596+
'should support constructors returning promises or promise-like objects': function() {
597+
return createContext({
598+
test: {
599+
create: {
600+
module: ClassWithNamedConstructor,
601+
constructorName: 'createInstancePromise',
602+
}
603+
}
604+
}).then(function(wired){
605+
assert('test' in wired);
606+
assert(wired.test instanceof ClassWithNamedConstructor);
607+
});
608+
},
609+
'should reject if named constructor rejects': function() {
610+
return createContext({
611+
test: {
612+
create: {
613+
module: ClassWithNamedConstructor,
614+
constructorName: 'createInstanceReject',
615+
}
616+
}
617+
}).then(function(){
618+
throw new Error('Unexpected success');
619+
}, function(err){
620+
assert.equals(err.message, 'test error');
621+
});
622+
}
509623
}
510624
},
511625

0 commit comments

Comments
 (0)