Comparing version 0.1.4 to 0.1.6
19
index.js
@@ -62,4 +62,9 @@ (function() { | ||
var exists = _.has(self.definitions, type); | ||
if (definition.extendIfFirst && (!exists)) { | ||
definition.extend = definition.extendIfFirst; | ||
} | ||
if ((!definition.extend) && (definition.extend !== false)) { | ||
if (_.has(self.definitions, type)) { | ||
if (exists) { | ||
// Double definitions result in implicit subclassing of | ||
@@ -128,3 +133,7 @@ // the original definition by the new one; anything else | ||
if (!next) { | ||
return callback(new Error('The type ' + type + ' is not defined.')); | ||
if (!callback) { | ||
throw 'The type ' + type + ' is not defined.'; | ||
} else { | ||
return callback(new Error('The type ' + type + ' is not defined.')); | ||
} | ||
} | ||
@@ -134,3 +143,7 @@ while (next) { | ||
if (_.has(seen, current.__meta.ordinal)) { | ||
return callback(new Error('The type ' + type + ' encounters an infinite loop, "extend" probably points back to itself or its subclass.')); | ||
var error = new Error('The type ' + type + ' encounters an infinite loop, "extend" probably points back to itself or its subclass.'); | ||
if (callback) { | ||
return callback(error); | ||
} | ||
throw error; | ||
} | ||
@@ -137,0 +150,0 @@ seen[current.__meta.ordinal] = true; |
{ | ||
"name": "moog", | ||
"version": "0.1.4", | ||
"version": "0.1.6", | ||
"description": "Moog provides powerful module subclassing.", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
@@ -5,3 +5,3 @@ # moog | ||
Moog is for creating objects that can be subclassed. | ||
Moog creates objects, with rich support for subclassing and "implicit subclassing" (like "categories" in Objective C). Moog implements the "self pattern," so you never have to worry about using `.call`, `.apply` or `.bind`. | ||
@@ -88,6 +88,16 @@ ```javascript | ||
#### Default base class | ||
**If you set the `defaultBaseClass` option of `moog`** and do not explicitly `extend` anything for a particular type, then that type will extend the `defaultBaseClass`. If you wish to override this behavior for a specific type, just set `extend` to `false`. | ||
**If you define the same class twice** without setting `extend` the second time, an *implicit subclass* is created. The new version subclasses the old one, effectively "patching" it with new options and behavior without having to redefine everything. All other types that subclass that name now subclass the new version. | ||
#### Implicit subclassing | ||
**If you define the same class twice** without setting `extend` the second time, an *implicit subclass* is created. | ||
The new version subclasses the old one, effectively "patching" it with new options and behavior without having to redefine everything. All other types that subclass that name now subclass the new version. | ||
### Fallback base classes | ||
If you are not sure if there is an existing definition for the type, you can use `extendIfFirst` to specify a fallback base class. This is helpful when encouraging third-party developers to optionally define a type themselves. | ||
#### Defining many types at once | ||
@@ -161,2 +171,4 @@ | ||
0.1.5: added support for `extendIfFirst`, useful when you don't know if there is an existing definition of the type. report certain errors synchronously when creating objects synchronously. | ||
0.1.4: allow setting `extend` to `false` to explicitly turn off `defaultBaseClass` for a particular type. Also corrected the unit test for `defaultBaseClass` (the feature worked, but the test was wrong). | ||
@@ -163,0 +175,0 @@ |
105
test/test.js
@@ -428,2 +428,61 @@ var assert = require('assert'); | ||
}); | ||
it('extendIfFirst property is honored if there is no existing definition for the type to implicitly subclass', function(done){ | ||
var moog = require('../index.js')({}); | ||
moog.define('fallback', { | ||
construct: function(self, options) { | ||
self._order = (self._order || []).concat('interloper'); | ||
} | ||
}); | ||
moog.define('myObject', { | ||
construct: function(self, options) { | ||
self._order = (self._order || []).concat('second'); | ||
}, | ||
extendIfFirst: 'fallback' | ||
}); | ||
moog.create('myObject', {}, function(err, myObject) { | ||
assert(!err); | ||
assert(myObject); | ||
assert(myObject._order.length === 2); | ||
assert(myObject._order[0] === 'interloper'); | ||
assert(myObject._order[1] === 'second'); | ||
return done(); | ||
}); | ||
}); | ||
it('extendIfFirst property is ignored if there is an existing definition for the type', function(done){ | ||
var moog = require('../index.js')({}); | ||
moog.define('fallback', { | ||
construct: function(self, options) { | ||
self._order = (self._order || []).concat('interloper'); | ||
} | ||
}); | ||
moog.define('myObject', { | ||
construct: function(self, options) { | ||
self._order = (self._order || []).concat('first'); | ||
} | ||
}); | ||
moog.define('myObject', { | ||
construct: function(self, options) { | ||
self._order = (self._order || []).concat('second'); | ||
}, | ||
extendIfFirst: 'fallback' | ||
}); | ||
moog.create('myObject', {}, function(err, myObject) { | ||
assert(!err); | ||
assert(myObject); | ||
assert(myObject._order.length === 2); | ||
assert(myObject._order[0] === 'first'); | ||
assert(myObject._order[1] === 'second'); | ||
return done(); | ||
}); | ||
}); | ||
}); | ||
@@ -789,2 +848,26 @@ | ||
// cyclical references | ||
it('should report an error synchronously on a cyclical reference (extend in a loop) when creating synchronously', function() { | ||
var moog = require('../index.js')({}); | ||
moog.define('classOne', { | ||
extend: 'classTwo' | ||
}); | ||
moog.define('classTwo', { | ||
extend: 'classOne' | ||
}); | ||
var e; | ||
var classOne; | ||
try { | ||
classOne = moog.create('classOne', {}); | ||
} catch (_e) { | ||
e = _e; | ||
} | ||
assert(e); | ||
assert(!classOne); | ||
}); | ||
it('should allow synchronous creation of a class with no asynchronous beforeConstruct or construct methods', function() { | ||
@@ -867,3 +950,25 @@ var moog = require('../index.js')({}); | ||
}); | ||
it('should report an error synchronously when creating a nonexistent type synchronously', function() { | ||
var moog = require('../index.js')({}); | ||
var e; | ||
var result; | ||
try { | ||
result = moog.create('nonesuch'); | ||
} catch (_e) { | ||
e = _e; | ||
} | ||
assert(e); | ||
assert(!result); | ||
}); | ||
it('should report an error asynchronously when creating a nonexistent type asynchronously', function(done) { | ||
var moog = require('../index.js')({}); | ||
moog.create('nonesuch', function(err, result) { | ||
assert(err); | ||
assert(!result); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
}); |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
48465
1154
180