Permalink
Browse files

Added makefile with commands to build dev and minified versions of Cl…

…assic targeted to browser, node and AMD use. Additionally, the makefile will generate docs via docco and run tests via jasmine-node.
  • Loading branch information...
1 parent b9ebf13 commit 76c0d8d297416de04f90af19f09cef7fe681a867 @gordonbrander committed Apr 7, 2012
Showing with 273 additions and 139 deletions.
  1. +28 −0 Makefile
  2. +4 −0 lib/amd.footer.js
  3. +2 −0 lib/amd.header.js
  4. +3 −0 lib/node.exports.js
  5. +4 −0 lib/std.footer.js
  6. +2 −0 lib/std.header.js
  7. +0 −1 min/classic.amd.min.js
  8. +18 −0 package.json
  9. +78 −0 spec/classic.spec.js
  10. +0 −138 src/classic.amd.js
  11. +134 −0 src/classic.js
View
28 Makefile
@@ -0,0 +1,28 @@
+NODE_PATH ?= ./node_modules
+JS_COMPILER = $(NODE_PATH)/uglify-js/bin/uglifyjs
+DOCCO = $(NODE_PATH)/docco/bin/docco
+TEST = $(NODE_PATH)/jasmine-node/bin/jasmine-node
+
+all: classic.min.js classic.amd.min.js classic.node.js docs
+
+install:
+ mkdir -p node_modules
+ npm install
+
+docs:
+ $(DOCCO) src/classic.js
+
+test:
+ $(TEST) ./spec/
+
+classic.js: lib/std.header.js src/classic.js lib/std.footer.js
+ cat > $@ $^
+
+classic.amd.js: lib/amd.header.js src/classic.js lib/amd.footer.js
+ cat > $@ $^
+
+classic.node.js: src/classic.js lib/node.exports.js
+ cat > $@ $^
+
+%.min.js: %.js Makefile
+ $(JS_COMPILER) < $< > $@
View
4 lib/amd.footer.js
@@ -0,0 +1,4 @@
+
+
+return classic;
+});
View
2 lib/amd.header.js
@@ -0,0 +1,2 @@
+define(function () {
+
View
3 lib/node.exports.js
@@ -0,0 +1,3 @@
+
+
+exports.classic = classic;
View
4 lib/std.footer.js
@@ -0,0 +1,4 @@
+
+
+return classic;
+});
View
2 lib/std.header.js
@@ -0,0 +1,2 @@
+var classic = (function () {
+
View
1 min/classic.amd.min.js
@@ -1 +0,0 @@
-define(function(){var a=Array.prototype.slice,b=function(b){var c=a.call(arguments,1),d,e,f,g,h;for(e=0,f=c.length;e<f;e++){g=c[e];for(d in g)b[d]=g[d]}return b},c=function(a){function c(){}var b=Object.create;return b?b(a):(c.prototype=a,new c)},d=function(d){var e="function"==typeof d,f=a.call(arguments,e?1:0),g=e?c(d.prototype):{},h;return b.apply(null,[g].concat(f)),h=g.hasOwnProperty("constructor")?g.constructor:e?function(){return d.apply(this,arguments)}:function(){},(h.prototype=g).constructor=h,h};return d.create=c,d.merge=b,d});
View
18 package.json
@@ -0,0 +1,18 @@
+{
+ "name": "Classic",
+ "version": "0.1.0",
+ "description": "Obvious inheritance for JavaScript",
+ "author": {
+ "name": "Gordon Brander",
+ "url": "http://gordonbrander.com"
+ },
+ "repository": {
+ "type": "git",
+ "url": "https://gordonbrander@github.com/gordonbrander/Classic.git"
+ },
+ "devDependencies": {
+ "docco": ">= 0.3.0",
+ "uglify-js": ">= 1.2.6",
+ "jasmine-node": ">= 1.0.23"
+ }
+}
View
78 spec/classic.spec.js
@@ -0,0 +1,78 @@
+var classic = require('../classic.node.js').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('will not obscure constructor if one is 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 () {
+ 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
+ });
+});
View
138 src/classic.amd.js
@@ -1,138 +0,0 @@
-define(function () {
- // Fast slice lookup.
- var slice = Array.prototype.slice;
-
- // Merge any number of objects together, using shallow copy for efficiency.
- // The first object is modified in place (doesn't return a new object).
- // The last mentioned object property wins.
- //
- // Serves the same purpose as jQuery.extend or _.extend.
- var merge = function (obj) {
- var objects = slice.call(arguments, 1),
- key, i, l, objN, val;
-
- for (i=0, l=objects.length; i < l; i++) {
- objN = objects[i];
- for (key in objN) {
- obj[key] = objN[key];
- }
- }
-
- return obj;
- };
-
- // Create a new object, using the provided object as its prototype
- // (prototypal inheritance). Delegates to native Object.create,
- // if supported.
- var create = function (obj) {
- var nativeCreate = Object.create;
- if (nativeCreate) return nativeCreate(obj);
- function Ctor() {}
- Ctor.prototype = obj;
- return new Ctor();
- };
-
- // Minimal classical inheritance from object literals.
- // Inspired by jashkenas' Proposal: <https://gist.github.com/1329619>.
- //
- // Properties of passed objects will be attached to the prototype of your
- // new function.
- //
- // **Classical inheritance**: if the first argument is another constructor
- // function, a prototype chain will be created between it and the resulting
- // child function. This gives you classical inheritance via efficient
- // prototype chaining, without emulating `super` or `static`.
- //
- // Check it out -- define a base class:
- //
- // var Bunny = classic({
- // hop: function (length) { ... }
- // });
- //
- // ...and inherit from it:
- //
- // var JackRabbit = classic(Bunny, {
- // constructor: function (type) {
- // this.type = type;
- // },
- // skip: function (length) { ... }
- // });
- //
- // All prototype properties of Bunny are available to JackRabbit:
- //
- // var myJackRabbit = new Jackrabbit('grey');
- // myJackRabbit.hop();
- // myJackRabbit.skip();
- //
- // Multiple inheritance is also supported. Pass in any number of
- // objects to be mixed in with the prototype:
- //
- // var artist = { ... };
- // var musician = { ... };
- // var writer = { ... };
- // var Composer = classic(artist, musician, writer);
- //
- // var myComposer = new Composer();
- //
- // Mix in objects are merged. and the last mentioned property wins,
- // as you might expect.
- //
- // Want to do both? Go for it. The first property may optionally be a
- // function, followed by any number of objects.
- //
- // var BrownBear = classic(Animal, bear, best);
- var classic = function (Parent) {
- var // If the first param is a function, consider it the parent function.
- // Cache this test, since we use it more than once.
- hasParent = ('function' === typeof Parent),
- // Get the "rest" of the arguments as an array of objects.
- // If the first parameter is a parent function, exclude it from
- // the array -- we treat parent funcs differently.
- rest = slice.call(arguments, (hasParent ? 1 : 0)),
- // Create a new object for our prototype.
- // If a parent function has been provided, construct an object
- // using it's prototype as the proototype for our new object.
- // Otherwise, use an ordinary object.
- proto = hasParent ? create(Parent.prototype) : {},
- Child;
-
- // Merge all "rest" objects into our newly created object.
- merge.apply(null, [proto].concat(rest));
-
- // Get constructor function from:
- //
- // * `constructor` property of merged proto object, if present.
- // (Limitation: must be an "own" property, since all objects
- // have "Object" as a constructor property on their prototype).
- // * OR patch in the parent constructor if a parent has been provided
- // * OR use an empty function if no parent is assigned.
- Child = (
- proto.hasOwnProperty('constructor') ?
- proto.constructor :
- (
- hasParent ?
- function () {
- return Parent.apply(this, arguments);
- } :
- function () {}
- )
- );
-
- // Now that we have a constructor function, assign our prototype object
- // to it.
- //
- // After assignment, 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**).
- (Child.prototype = proto).constructor = Child;
- return Child;
- };
-
- // Expose these handy helper methods.
- classic.create = create;
- classic.merge = merge;
-
- return classic;
-});
View
134 src/classic.js
@@ -0,0 +1,134 @@
+// Fast slice lookup.
+var slice = Array.prototype.slice;
+
+// Merge any number of objects together, using shallow copy for efficiency.
+// The first object is modified in place (doesn't return a new object).
+// The last mentioned object property wins.
+//
+// Serves the same purpose as jQuery.extend or _.extend.
+var merge = function (obj) {
+ var objects = slice.call(arguments, 1),
+ key, i, l, objN, val;
+
+ for (i=0, l=objects.length; i < l; i++) {
+ objN = objects[i];
+ for (key in objN) {
+ obj[key] = objN[key];
+ }
+ }
+
+ return obj;
+};
+
+// Create a new object, using the provided object as its prototype
+// (prototypal inheritance). Delegates to native Object.create
+// if supported.
+var create = function (obj) {
+ var nativeCreate = Object.create;
+ if (nativeCreate) return nativeCreate(obj);
+ function Ctor() {}
+ Ctor.prototype = obj;
+ return new Ctor();
+};
+
+// Minimal classical inheritance from object literals.
+// Inspired by jashkenas' Proposal: <https://gist.github.com/1329619>.
+//
+// Properties of passed objects will be attached to the prototype of your
+// new function.
+//
+// **Classical inheritance**: if the first argument is another constructor
+// function, a prototype chain will be created between it and the resulting
+// child function. This gives you classical inheritance via efficient
+// prototype chaining, without emulating `super` or `static`.
+//
+// Check it out -- define a base class:
+//
+// var Bunny = classic({
+// hop: function (length) { ... }
+// });
+//
+// ...and inherit from it:
+//
+// var JackRabbit = classic(Bunny, {
+// constructor: function (type) {
+// this.type = type;
+// },
+// skip: function (length) { ... }
+// });
+//
+// All prototype properties of Bunny are available to JackRabbit:
+//
+// var myJackRabbit = new Jackrabbit('grey');
+// myJackRabbit.hop();
+// myJackRabbit.skip();
+//
+// Multiple inheritance is also supported. Pass in any number of
+// objects to be mixed in with the prototype:
+//
+// var artist = { ... };
+// var musician = { ... };
+// var writer = { ... };
+// var Composer = classic(artist, musician, writer);
+//
+// var myComposer = new Composer();
+//
+// Mix in objects are merged. and the last mentioned property wins,
+// as you might expect.
+//
+// Want to do both? Go for it. The first property may optionally be a
+// function, followed by any number of objects.
+//
+// var BrownBear = classic(Animal, bear, best);
+var classic = function (Parent) {
+ var // If the first param is a function, consider it the parent function.
+ // Cache this test, since we use it more than once.
+ hasParent = ('function' === typeof Parent),
+ // Get the "rest" of the arguments as an array of objects.
+ // If the first parameter is a parent function, exclude it from
+ // the array -- we treat parent funcs differently.
+ rest = slice.call(arguments, (hasParent ? 1 : 0)),
+ // Create a new object for our prototype.
+ // If a parent function has been provided, construct an object
+ // using it's prototype as the proototype for our new object.
+ // Otherwise, use an ordinary object.
+ proto = hasParent ? create(Parent.prototype) : {},
+ Child;
+
+ // Merge all "rest" objects into our newly created object.
+ merge.apply(null, [proto].concat(rest));
+
+ // Get constructor function from:
+ //
+ // * `constructor` property of merged proto object, if present.
+ // (Limitation: must be an "own" property, since all objects
+ // have "Object" as a constructor property on their prototype).
+ // * OR patch in the parent constructor if a parent has been provided
+ // * OR use an empty function if no parent is assigned.
+ Child = (
+ proto.hasOwnProperty('constructor') ?
+ proto.constructor :
+ (
+ hasParent ?
+ function () {
+ return Parent.apply(this, arguments);
+ } :
+ function () {}
+ )
+ );
+
+ // Now that we have a constructor function, assign our prototype object
+ // to it.
+ //
+ // After assignment, 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**).
+ (Child.prototype = proto).constructor = Child;
+ return Child;
+};
+
+// Expose these handy helper methods.
+classic.create = create;
+classic.merge = merge;

0 comments on commit 76c0d8d

Please sign in to comment.