Skip to content
This repository has been archived by the owner on Dec 15, 2020. It is now read-only.

Commit

Permalink
version 0.2.0
Browse files Browse the repository at this point in the history
  • Loading branch information
kbjr committed Jun 3, 2012
1 parent 0a0be09 commit 6337dcf
Show file tree
Hide file tree
Showing 4 changed files with 123 additions and 27 deletions.
24 changes: 24 additions & 0 deletions class.html
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,30 @@

});

/**
* @mixin CanFoo
*/
Class.mixin('CanFoo', {

foo: function() {
console.log('Foo!');
}

});

/**
* @class Fooer
*/
Class('Fooer').uses(['CanFoo'], {

bar: function() {
console.log('Bar!');
}

});



</script>

</body>
Expand Down
84 changes: 58 additions & 26 deletions classes.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,22 @@
*/
(function() {
var _global = this;
var namespace = _global;

// The class constructor
var createClass = function(name, parent, constructor) {
var createClass = function(name, parent, mixins, constructor) {

// If an array was given for a name, we only want the
// actual name value
if (typeof name === 'object') {
if (typeof name === 'object' && name) {
name = name[1] || false;
if (! name) {
throw new TypeError('Invalid class name value');
}
}

// If only one parameter is given, it is a constructor,
// not a parent class
if (constructor === void(0)) {
constructor = parent;
// Default the parent to the global Object
if (! parent) {
parent = Object;
}

Expand All @@ -47,11 +46,11 @@

// Fetch the parent if a string is given
if (typeof parent === 'string') {
parent = _global[parent];
parent = namespace[parent];
}

// Inherit from the parent if one was given (inheritence model
// based on CoffeeScript classes)
// based roughly on CoffeeScript classes)
var _super = parent.prototype;
for (var i in parent) {
if (parent.hasOwnProperty(i)) {
Expand All @@ -64,9 +63,20 @@
ctor.prototype = parent.prototype;
self.prototype = new ctor();

// Inherit from mixins
if (mixins) {
for (var i = 0, c = mixins.length; i < c; i++) {
if (typeof mixins[i] === 'string') {
mixins[i] = namespace[mixins[i]];
}
mixins[i].mixinTo(self);
}
}

// The class/parent name
self.prototype.__class__ = self.__class__ = name;
self.prototype.__parent__ = self.__parent__ = parent.__class__ || getNativeClassName(parent);
self.prototype.__mixins__ = self.__mixins__ = mixins;

// Expose the parent
self.prototype.parent = self.parent = _super;
Expand Down Expand Up @@ -113,7 +123,7 @@
* @return void
*/
self.extend = function(name, constructor) {
_global.Class(name, self, constructor);
Class(name, self, constructor);
};

/**
Expand All @@ -137,15 +147,15 @@
};

// ----------------------------------------------------------------------------
// Used for the Class(...).extends(...) syntax
// Used for the extends() and uses() syntax

var TempClass = function(name) {
this.parent = null;
this.mixins = [ ];
this.uses = function(mixins, constructor) {
this.mixins.push.apply(this.mixins, mixins);
if (constructor) {
return assignClass(name,
return assignTo(name,
createClass(name, this.parent, this.mixins, constructor)
);
}
Expand All @@ -154,7 +164,7 @@
this.extends = function(parent, constructor) {
this.parent = parent;
if (constructor) {
return assignClass(name,
return assignTo(name,
createClass(name, this.parent, this.mixins, constructor)
);
}
Expand All @@ -163,21 +173,44 @@
};

// ----------------------------------------------------------------------------
// Expose
// Main Functions

function Class(name, parent, constructor) {
if (arguments.length <= 1) {
if (name && (typeof name === 'object' || typeof name === 'function')) {
if (name && (typeof name === 'object' || isFunc(name))) {
return createClass(null, null, name);
}
return new TempClass(name);
} else {
return assignClass(name, createClass(name, parent, constructor));
} else if (arguments.length === 2) {
return assignTo(name,
createClass(name, null, [ ], parent)
);
}
return assignTo(name,
createClass(name, parent, [ ], constructor)
);
}

Class.mixin = function(name, constructor) {
if (arguments.length === 1) {
constructor = name;
name = null;
}
return assignTo(name, new Mixin(constructor));
};

function Mixin(name, constructor) {

Class.namespace = function(ns) {
namespace = ns ? ns : _global;
};

function Mixin(constructor) {
this.mixinTo = function(func) {
for (var i in constructor) {
if (constructor.hasOwnProperty(i)) {
func.prototype[i] = constructor[i];
}
}
};
}

// ----------------------------------------------------------------------------
Expand All @@ -187,24 +220,23 @@

function isFunc(value) {
return (toString.call(value) === '[object Function]');
};
}

function assignClass(name, constructor) {
function assignTo(name, constructor) {
if (! name) {
return constructor;
} else if (typeof name === 'object' && name.length === 2) {
name[0][name[1]] = constructor;
} else if (typeof name === 'string') {
_global[name] = constructor;
namespace[name] = constructor;
} else {
throw new TypeError('Invalid class name value');
throw new TypeError('Invalid class/mixin name value');
}
};
}

function getNativeClassName(constructor) {
var str = toString.call(new constructor()).split(' ')[1];
return str.substr(0, str.length - 1);
};
return toString.call(new constructor()).slice(8, -1);
}

// ------------------------------------------------------------------
// Expose
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"author": "James Brumond <james@jbrumond.me> (http://jbrumond.me)",
"name": "classes",
"description": "A classical inheritence model",
"description": "A classical inheritence model with support for mixins",
"version": "0.2.0",
"repository": {
"type": "git",
Expand Down
40 changes: 40 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -162,4 +162,44 @@ thing.foo();
```

Mixins are different from inheritence in the sense that they do no add to the inheritence chain, they simply extend the current class with certain functionality. You cannot use `instanceof` do determine mixin inheritence because classes are not instances of mixins; In fact, there is no such thing as an _instance_ of a mixin, they are just objects.

## Using Namespaces

Before version 0.2.0, all new classes and mixins were defined, by default, on the global object, and if you wanted to define one elsewhere, you would have to use either anonymous classes or the array syntax (eg. `Class([exports, 'Foo'], ...)`). There is now a new way of defining namespaced classes that should prove useful, especially in the case of Node.js.

```javascript
var Class = require('classes').Class;
Class.namespace(exports);

Class('Foo', {

// ...

});

var foo = new exports.Foo();
```

The `Class.namespace()` function sets the default namespace, allowing shorter, more readable class declarations. Simply call `Class.namespace(exports)` at the top of your modules and your classes will automatically be defined in the correct space.






















0 comments on commit 6337dcf

Please sign in to comment.