Source: lib/class/index.js

/*jshint node:true, laxcomma:true, smarttabs: true, forin:false, unused: false */
'use strict';
/**
 * Prototypal inheritance made easy - A slight modification on the prime libs
 * @module tastypie/lib/class
 * @author Eric Satterwhite
 * @requires mout/object/hasOwn
 * @requires mout/object/mixIn
 * @requires mout/lang/createObject
 * @requires mout/lang/kindOf
 * @requires mout/lang/clone
 * @requires mout/object/merge
 **/
var hasOwn = require("mout/object/hasOwn")
  , mixIn  = require("mout/object/mixIn")
  , create = require("mout/lang/createObject")
  , clone = require('mout/lang/clone')
  , kindOf = require("mout/lang/kindOf")
  , isObject = require('mout/lang/isObject')
  , merge  = require('mout/object/merge')
  , mutators = {

    };

var hasDescriptors = true;

try {
    Object.defineProperty({}, "~", {});
    Object.getOwnPropertyDescriptor({}, "~");
} catch (e){
    hasDescriptors = false;
}

// we only need to be able to implement "toString" and "valueOf" in IE < 9
var hasEnumBug = !({valueOf: 0}).propertyIsEnumerable("valueOf"),
    buggy      = ["toString", "valueOf"];

var verbs = /^constructor|inherits|mixin$/;

var implement = function(proto){
    var mutator
      , value
      , descriptor
      , prototype
      ;

    prototype = this.prototype;

    for (var key in proto){
        if (key.match(verbs)){
            continue;
        }

        if( mutators.hasOwnProperty( key ) ){
            mutator = mutators[ key ];
            value = proto[ key ];
            value = mutator.call( this, value );
            
            if( !value ){
               continue;
            }
            this[ key ] = value;
        }

        if (hasDescriptors){
            descriptor = Object.getOwnPropertyDescriptor(proto, key);
            if (descriptor){
                Object.defineProperty(prototype, key, descriptor);
                continue;
            }
        }
        prototype[key] = proto[key];
    }

    if (hasEnumBug){
        for (var i = 0; (key = buggy[i]); i++){
            value = proto[key];
            if (value !== Object.prototype[key]){
                prototype[key] = value;
            }
        }
    }

    return this;
};

var prime = function(proto){

    if (kindOf(proto) === "Function"){
        proto = {constructor: proto};
    }

    var superprime = proto.inherits;

    // if our nice proto object has no own constructor property
    // then we proceed using a ghosting constructor that all it does is
    // call the parent's constructor if it has a superprime, else an empty constructor
    // proto.constructor becomes the effective constructor
    var constructor = (hasOwn(proto, "constructor")) ? proto.constructor : (superprime) ? function(){
        return superprime.apply(this, arguments);
    } : function(){};

    if (superprime){

        mixIn(constructor, superprime);

        var superproto = superprime.prototype;
        // inherit from superprime
        var cproto = constructor.prototype = create(superproto);

        // setting constructor.parent to superprime.prototype
        // because it's the shortest possible absolute reference
        constructor.parent = superproto;
        cproto.constructor = constructor;
        cproto.$class = constructor;
        isObject(proto.options) && isObject(superproto.options) && (proto.options = merge(clone(superproto.options), proto.options));

    }

    if (!constructor.implement){
        constructor.implement = implement;
    }

    var mixins = proto.mixin;
    if (mixins){
        if (kindOf(mixins) !== "Array"){
            mixins = [mixins];
        }

        for (var i = 0; i < mixins.length; i++){
            constructor.implement(create(mixins[i].prototype));
        }
    }

    // implement proto and return constructor
    return constructor.implement(proto);
};

prime.defineMutator = function(name ,fn ){
    Object.defineProperty( mutators, name, {
        enumerable: true
        ,configurable: false
        ,get: function( ){
            return fn;
        }
    });
};

/**
 * @constructor
 * @alias module:tastypie/lib/class
 * @param {Object} prototype an object to serve as the instance prototype
 * @param {Function} [prototype.constructor]
 * @param {Class|Class[]|Function|Function[]} [prototype.mixin]
 * @param {Function|Class} [prototype.extends] A function or class definintion to server as the prototype to inherit from ( parent class )
 * @example 
var EventEmitter = require('events').EventEmitter
var Options = require('tastypie/lib/class/options');

MyClass = new Class({
    extends: require('fs').Stream
    ,mixin:[ EventEmitter, Options ]
    ,options:{
        isActive: false
    }
    ,constructor: function( options ){
        this.setOptions( options ) // from options mixin
        console.log("im the constructor");
        EventEmitter.call( this );
    }
    ,work: function(){
        console.log('I'm doing work)
        this.emit('work', this.options.isActive )
    }
 });
 */

module.exports = prime;