Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added tests and vendor dir. Added new version of Classic, which repla…
…ces bridge function with an Object.create polyfill, which is much more useful.
- Loading branch information
1 parent
febe67b
commit a583854
Showing
11 changed files
with
3,121 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
define(function () { | ||
// Fast slice lookup. | ||
var slice = Array.prototype.slice; | ||
|
||
// Merge any number of objects together. | ||
// The first object has it's reference modified | ||
// (doesn't return a new object). | ||
// The last object property wins. | ||
// | ||
// Serves the same purpose as jQuery.extend and _.extend. | ||
var merge = function (obj) { | ||
var objects = slice.call(arguments, 1), | ||
key, i, l, objN; | ||
|
||
for (i=0, l=objects.length; i < l; i++) { | ||
objN = objects[i]; | ||
for (key in objN) { | ||
// Don't copy built-in or inherited object properties. | ||
if (!objN.hasOwnProperty(key)) continue; | ||
obj[key] = objN[key]; | ||
} | ||
} | ||
|
||
return obj; | ||
}; | ||
|
||
// Use a provided object as the prototype for | ||
// another object. | ||
// Delegates to Object.create, if supported. | ||
var create = Object.create || function (obj) { | ||
function Ctor() {} | ||
Ctor.prototype = obj; | ||
return new Ctor(); | ||
}; | ||
|
||
// Minimal classical inheritance via object literals. | ||
// Inspired by jashkenas' Proposal: <https://gist.github.com/1329619>. | ||
// | ||
// Creates constructor functions from objects. | ||
// All "own" properties of the passed objects will be copied to the | ||
// prototype. If the first argument is another constructor function, a | ||
// prototype bridge will be created between the constructor function | ||
// provided and the resulting child constructor function. | ||
// This gives you classical inheritance via efficient prototype chaining, | ||
// without emulating `super` or `static`. | ||
// | ||
// Check it out: | ||
// | ||
// var Bunny = classic({ | ||
// hop: function (length) { ... } | ||
// }); | ||
// | ||
// var JackRabbit = classic(Bunny, { | ||
// constructor: function (type) { | ||
// this.type = type; | ||
// }, | ||
// skip: function (length) { ... } | ||
// }); | ||
// | ||
// var myJackRabbit = new Jackrabbit('grey'); | ||
// myJackRabbit.hop(); | ||
// myJackRabbit.skip(); | ||
// | ||
// Also supported: multiple inheritance via any number of object mixins: | ||
// | ||
// var person = { ... }; | ||
// var musician = { ... }; | ||
// var writer = { ... }; | ||
// var Composer = classic(person, musician, writer); | ||
// | ||
// var myComposer = new Composer(); | ||
// | ||
// When more than one object is passed in, the objects are merged | ||
// The last mentioned property wins, as you might expect. | ||
// | ||
// Want to do both? Go for it. The first property can be a constructor | ||
// function, with any number of objects passed in after. | ||
// | ||
// var BrownBear = classic(Animal, bear, best); | ||
var classic = function (Parent) { | ||
// If the first param is a function, consider it the parent "class". | ||
// Cache this test, since we use it more than once. | ||
var hasParent = ('function' === typeof Parent), | ||
// Determine where to slice the arguments. If the first | ||
// argument is a constructor function, | ||
// we want to slice at `1`, so it is not included in the object merge. | ||
// If the first argument is not a function, assume it is an object | ||
// and include it in the object merge. | ||
at = (hasParent ? 1 : 0), | ||
rest = slice.call(arguments, at), | ||
obj, Child, __Child; | ||
|
||
// If we've got more than one object, merge all "rest" objects into a | ||
// single object, creating a shallow copy so we don't accidentally modify | ||
// objects passed in. | ||
obj = (rest.length > 1) ? merge.apply(null, [{}].concat(rest)) : rest[0]; | ||
|
||
// Create constructor using: | ||
// | ||
// * `constructor` property of object, if set | ||
// * OR patch in parent constructor if a parent has been passed in | ||
// * OR use an empty function if no parent is assigned. | ||
Child = ( | ||
obj.hasOwnProperty('constructor') ? | ||
obj.constructor : | ||
( | ||
hasParent ? | ||
function () { | ||
return Parent.apply(this, arguments); | ||
} : | ||
function () {} | ||
) | ||
); | ||
|
||
// Make a prototype bridge between child and parent. | ||
if (hasParent) Child.prototype = create(Parent.prototype); | ||
|
||
// Merge properties from our object literal into the prototype of our | ||
// constructor. Properties in our object will obscure properties inherited | ||
// from the `Parent` prototype. | ||
// | ||
// After merging, set the fully finished constructor function (with | ||
// prototype) as the constructor property of the prototype. | ||
// Putting a constructor property on the prototype will | ||
// guaranteed you have one, even if the browser does not set it during | ||
// construction (**cough, IE, cough**). | ||
merge(Child.prototype, obj).constructor = Child; | ||
return Child; | ||
}; | ||
|
||
// Expose these handy helper methods. | ||
classic.create = create; | ||
classic.merge = merge; | ||
|
||
return classic; | ||
}); |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
<!DOCTYPE HTML> | ||
<html> | ||
<head> | ||
<title>Jasmine Spec Runner</title> | ||
<link rel="stylesheet" href="vendor/jasmine.css"> | ||
<script src="../vendor/require.min.js"></script> | ||
<script src="vendor/jasmine.js"></script> | ||
<script src="vendor/jasmine-html.js"></script> | ||
<script> | ||
require.config({ | ||
// configure our AMD loader | ||
baseUrl: '../' | ||
}); | ||
|
||
require([ | ||
'test/spec/classic.spec' | ||
], | ||
function(){ | ||
jasmine.getEnv().addReporter(new jasmine.TrivialReporter()); | ||
jasmine.getEnv().execute(); | ||
}); | ||
</script> | ||
</head> | ||
|
||
<body> | ||
</body> | ||
</html> |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
define(['classic.amd'], function (classic) { | ||
describe('classic', function () { | ||
var Animal, Bunny, Jackrabbit, | ||
animal, bunny, jackrabbit; | ||
|
||
Animal = classic({ | ||
run: function () { } | ||
}); | ||
|
||
Bunny = classic(Animal, { | ||
constructor: function (color) { | ||
this.color = color; | ||
}, | ||
hop: function () { } | ||
}); | ||
|
||
Jackrabbit = classic(Bunny, { | ||
skip: function () { } | ||
}); | ||
|
||
beforeEach(function () { | ||
animal = new Animal(); | ||
bunny = new Bunny(); | ||
jackrabbit = new Jackrabbit(); | ||
}); | ||
|
||
it('is a function', function () { | ||
expect(typeof classic).toBe('function'); | ||
}); | ||
|
||
it('returns a constructor function', function () { | ||
expect(typeof Animal).toBe('function'); | ||
expect(animal instanceof Animal).toBeTruthy(); | ||
}); | ||
|
||
it('will create an empty constructor if one is not provided', | ||
function() { | ||
expect(typeof Animal.prototype.constructor).toBe('function'); | ||
}); | ||
|
||
it('constructed objects have the fully-formed constructor function assigned to the constructor property of their prototype', | ||
function () { | ||
expect(typeof bunny.constructor).toBe('function'); | ||
expect(bunny.constructor.prototype).toBe(Bunny.prototype); | ||
}); | ||
|
||
it('constructs objects that inherit properties from ancestors', | ||
function () { | ||
console.log(bunny, jackrabbit); | ||
|
||
expect(typeof bunny.run).toBe('function'); | ||
expect(typeof jackrabbit.hop).toBe('function'); | ||
expect(typeof jackrabbit.run).toBe('function'); | ||
}); | ||
|
||
it('properties inherited from a constructor function do so by prototype bridge rather than object copy.', | ||
function () { | ||
expect(Jackrabbit.prototype instanceof Bunny).toBeTruthy(); | ||
expect(jackrabbit.hasOwnProperty('run')).toBeFalsy(); | ||
expect(jackrabbit.hasOwnProperty('hop')).toBeFalsy(); | ||
}); | ||
|
||
it('constructor functions can be created by mixing multiple objects', function () { | ||
var musician = { play: function () {} }; | ||
var person = { think: function () {} }; | ||
|
||
var Composer = classic(person, musician); | ||
}); | ||
|
||
it('will call the parent\'s constructor if one is not supplied', | ||
function() { | ||
// TODO | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
Copyright (c) 2008-2011 Pivotal Labs | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining | ||
a copy of this software and associated documentation files (the | ||
"Software"), to deal in the Software without restriction, including | ||
without limitation the rights to use, copy, modify, merge, publish, | ||
distribute, sublicense, and/or sell copies of the Software, and to | ||
permit persons to whom the Software is furnished to do so, subject to | ||
the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be | ||
included in all copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE | ||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION | ||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | ||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
Oops, something went wrong.