Adds generic non-Backbone base class.
authorDavid Schoonover <dsc@wikimedia.org>
Mon, 18 Jun 2012 19:54:13 +0000 (12:54 -0700)
committerDavid Schoonover <dsc@wikimedia.org>
Mon, 18 Jun 2012 19:54:13 +0000 (12:54 -0700)
lib/base/base.co [new file with mode: 0644]
lib/base/index.co
lib/util/event/ready-emitter.co
lib/util/event/waiting-emitter.co
lib/util/underscore/_functions.co [moved from lib/util/underscore/functions.co with 100% similarity]
lib/util/underscore/class.co [new file with mode: 0644]
lib/util/underscore/function.co [new file with mode: 0644]
lib/util/underscore/index.co

diff --git a/lib/base/base.co b/lib/base/base.co
new file mode 100644 (file)
index 0000000..c35ed5d
--- /dev/null
@@ -0,0 +1,73 @@
+{EventEmitter} = require 'events'
+EventEmitter::trigger = EventEmitter::emit
+
+{ _, op
+} = require 'kraken/util'
+
+
+
+/**
+ * @class Eventful base class.
+ * @extends EventEmitter
+ */
+class Base extends EventEmitter
+    
+    /**
+     * After the super chain has exhausted (but not necessarily at the end
+     * of init -- it depends on when you super()), Base will publish a 'new'
+     * event on the instance's class, allowing anyone to subscribe to
+     * notifications about new objects.
+     * @constructor
+     */
+    ->
+        @__class__      = @..
+        @__superclass__ = @..superclass
+        @__apply_bind__()
+        super()
+        @__class__.emit 'new', this
+    
+    
+    ### Auto-Bound methods
+    
+    /**
+     * A list of method-names to bind on `initialize`; set this on a subclass to override.
+     * @type Array<String>
+     */
+    __bind__ : []
+    
+    /**
+     * Applies the contents of `__bind__`.
+     */
+    __apply_bind__: ->
+        names = _ @pluckSuperAndSelf '__bind__' .chain().flatten().compact().unique().value()
+        _.bindAll this, ...names if names.length
+    
+    
+    
+    getClassName: ->
+        "#{@..name or @..displayName}"
+    
+    toString: ->
+        "#{@getClassName()}()"
+    
+    
+    
+    ### Class Methods
+    
+    @extended = (Subclass) ->
+        # copy over all class methods, including this
+        for own k, v in this
+            Subclass[k] = v if typeof v is 'function'
+        Subclass.__super__ = @::
+        Subclass
+    
+    
+
+
+for k of <[ getSuperClasses pluckSuper pluckSuperAndSelf ]>
+    Base[k] = Base::[k] = _.methodize _[k]
+
+Base import EventEmitter::
+
+
+module.exports = Base
index 9a31587..17b6726 100644 (file)
@@ -1,7 +1,9 @@
+exports.Base = require 'kraken/base/base'
 mixins       = require 'kraken/base/base-mixin'
 models       = require 'kraken/base/base-model'
 views        = require 'kraken/base/base-view'
 cache        = require 'kraken/base/model-cache'
 cascading    = require 'kraken/base/cascading-model'
 data_binding = require 'kraken/base/data-binding'
-exports import mixins import models import views import cache import cascading import data_binding
+exports import mixins   import models       import views \
+        import cache    import cascading    import data_binding
index a247026..049ad1c 100644 (file)
@@ -1,11 +1,10 @@
-{EventEmitter} = require 'events'
-EventEmitter::trigger = EventEmitter::emit
+Base = require 'kraken/base/base'
 
 
 /**
  * @class An EventEmitter that auto-triggers new handlers once "ready".
  */
-class ReadyEmitter extends EventEmitter
+class ReadyEmitter extends Base
     readyEventName : 'ready'
     ready : false
     
index 3cc2733..3f29ddf 100644 (file)
@@ -1,12 +1,11 @@
-{EventEmitter} = require 'events'
-EventEmitter::trigger = EventEmitter::emit
-
+Base = require 'kraken/base/base'
 
 
 /**
  * @class An EventEmitter with a ratchet-up waiting counter.
+ * @extends Base
  */
-class WaitingEmitter extends EventEmitter
+class WaitingEmitter extends Base
     
     /**
      * Count of outstanding tasks.
diff --git a/lib/util/underscore/class.co b/lib/util/underscore/class.co
new file mode 100644 (file)
index 0000000..1381cb4
--- /dev/null
@@ -0,0 +1,53 @@
+_ = require 'underscore'
+
+
+_cls =
+    
+    /**
+     * @returns {Array<Class>} The list of all superclasses for this class
+     *  or object. Typically does not include Object or Function due to
+     *  the prototype's constructor being set by the subclass.
+     */
+    getSuperClasses : function getSuperClasses(Cls)
+        return [] unless Cls
+        
+        if Cls.__superclass__ or Cls.superclass or Cls.__super__?.constructor
+            superclass = that unless that is Cls
+        unless superclass
+            Cls = Cls.constructor if typeof Cls is not 'function'
+            if Cls.__superclass__ or Cls.superclass or Cls.__super__?.constructor
+                superclass = that unless that is Cls
+        unless superclass then []
+        else [superclass].concat getSuperClasses superclass
+    
+    /**
+     * Looks up an attribute on the prototype of each class in the class
+     * hierarchy. Values from Object or Function are not typically included --
+     * see the note at `getSuperClasses()`.
+     * 
+     * @param {Object} obj Object on which to reflect.
+     * @param {String} prop Property to nab.
+     * @returns {Array} List of the values, from closest parent to furthest.
+     */
+    pluckSuper : (obj, prop) ->
+        return [] unless obj
+        _ _cls.getSuperClasses(obj) .chain()
+            .pluck 'prototype'
+            .pluck prop 
+            .value()
+    
+    /**
+     * As `.pluckSuper()` but includes value of `prop` on passed `obj`. Values
+     *  from Object or Function are not typically included -- see the note
+     *  at `getSuperClasses()`.
+     * 
+     * @returns {Array} List of the values, starting with the object's own
+     *  value, and then moving from closest parent to furthest.
+     */
+    pluckSuperAndSelf : (obj, prop) ->
+        return [] unless obj
+        [ obj[prop] ].concat _cls.pluckSuper(obj, prop)
+    
+
+
+exports import _cls
diff --git a/lib/util/underscore/function.co b/lib/util/underscore/function.co
new file mode 100644 (file)
index 0000000..a6e50b7
--- /dev/null
@@ -0,0 +1,27 @@
+_ = require 'underscore'
+
+_fn =
+    
+    /**
+     * Decorates a function so that its receiver (`this`) is always added as the
+     * first argument, followed by the call arguments.
+     * @returns {Function}
+     */
+    methodize : (fn) ->
+        m = fn.__methodized__
+        return m if m
+        
+        g = fn.__genericized__
+        return that if g?.__wraps__
+        
+        m = fn.__methodized__ = (...args) ->
+            args.unshift this
+            fn.apply this, args
+        
+        m.__wraps__ = fn
+        m
+    
+    
+
+exports import _fn
+
index d24ced1..f59c17f 100644 (file)
@@ -2,8 +2,10 @@ _     = require 'underscore'
 _.str = require 'underscore.string'
 _.mixin _.str.exports()
 
+_.mixin require 'kraken/util/underscore/function'
 _.mixin require 'kraken/util/underscore/array'
 _.mixin require 'kraken/util/underscore/object'
+_.mixin require 'kraken/util/underscore/class'
 _.mixin require 'kraken/util/underscore/kv'
 _.mixin require 'kraken/util/underscore/string'