UNPKG

boo

Version:

Core prototypical primitives for Object Orientation/Composition.

195 lines (156 loc) 5.78 kB
// # Module boo // // Base primitives for prototypical OO. // // // :licence: MIT // Copyright (c) 2011 Quildreen "Sorella" Motta <quildreen@gmail.com> // // 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. // -- Aliases ---------------------------------------------------------- var slice = Function.call.bind([].slice) var keys = Object.keys var inherit = Object.create var define = Object.defineProperty var descriptor = Object.getOwnPropertyDescriptor var hasGetter = function () { var getter = { get: function(){ return true } } try { return true === Object.create( {} , { x: getter }).x } catch(e){ return false }}() // -- Interfaces ------------------------------------------------------- // ### Type data-object // :: { toData: () -> object } // ### Type mixin // :: object | data-object // -- Helpers ---------------------------------------------------------- // ### Function copyProperty // :internal: // Copies a property from `source` to `target`. // // :: A, B, string -> B function copyProperty(source, target, property) { !hasGetter? target[property] = source[property] : /* otherwise */ define(target, property, descriptor(source, property)) return target } // ### Function isDataObject // :internal: // Checks if the given subject matches the `DataObject` interface // // :: A -> bool function isDataObject(subject) { return subject != null && typeof subject.toData == 'function' } // ### Function resolveMixins // :internal: // Returns the proper object for the given mixin. // // :: mixin -> object function resolveMixin(subject) { return isDataObject(subject)? subject.toData() : /* otherwise */ subject } // ### Function fastExtend // :internal: // Extends the target object with the provided mixins, using a // right-most precedence rule — when a there's a property conflict, the // property defined in the last object wins. // // `DataObject`s are properly handled by the `resolveMixin` // function. // // **warning:** low-level // // > This function is not meant to be called directly from end-user // > code, use the `extend` function instead. // // :: object, [mixin] -> object function fastExtend(object, mixins) { var i, j, len, mixin, props, key for (i = 0, len = mixins.length; i < len; ++i) { mixin = resolveMixin(mixins[i]) props = keys(mixin) for (j = props.length; j--;) { key = props[j] copyProperty(mixin, object, key) }} return object } // -- Basic primitives ------------------------------------------------- // ### Function extend // Extends the target object with the provided mixins, using a // right-most precedence rule. // // See also: // - `fastExtend` — lower level function. // - `merge` — pure version. // // :: object, mixin... -> object function extend(target) { return fastExtend(target, slice(arguments, 1)) } // ### Function merge // Creates a new object that merges the provided mixins, using a // right-most precedence rule. // // See also: // - `extend` — impure version. // // :: mixin... -> object function merge() { return fastExtend({}, arguments) } // ### Function derive // Creates a new object inheriting from the given prototype and extends // the new instance with the provided mixins. // // :: object, mixin... -> object function derive(proto) { return fastExtend(inherit(proto), slice(arguments, 1)) } // -- Root object ------------------------------------------------------ // ### Object Base // // Provides the previous primitive combinators in an easy and OOP-way. // // :: object <| Base var Base = { constructor: function(){ } // #### Function make // Constructs new instances of this object. // // :: @object => A... -> this <| object , make: function make() { var instance = new this.constructor if (this.init) this.init.apply(instance, arguments) return instance } // #### Function derive // Constructs a new object that inherits from the object this function // is being applied to, and extends it with the provided mixins. // // :: @object => mixin... -> this <| object , derive: function _derive() { var instance = fastExtend(inherit(this), arguments) instance.constructor = function(){ } instance.constructor.prototype = instance return instance }} Base.constructor.prototype = Base // -- Exports ---------------------------------------------------------- module.exports = { extend : extend , merge : merge , derive : derive , Base : Base }