From: dsc Date: Mon, 12 Mar 2012 18:30:25 +0000 (-0700) Subject: Updates Cascade X-Git-Url: http://git.less.ly:3516/?a=commitdiff_plain;h=c40e5084c1a9deb5b8260204a94806895be26585;p=kraken-ui.git Updates Cascade --- diff --git a/lib/underscore/object.co b/lib/underscore/object.co index 1416a49..d1f4b62 100644 --- a/lib/underscore/object.co +++ b/lib/underscore/object.co @@ -91,14 +91,16 @@ _obj = do * @param {Boolean} [ensure=false] If true, intermediate keys that are `null` or * `undefined` will be filled in with a new empty object `{}`, ensuring the get will * return valid metadata. - * @retruns {null|Object} If found, the object is of the form `{ key: Qualified key name, obj: Parent object of key, val: Value at obj[key] }`. Otherwise `null`. + * @retruns {undefined|Object} If found, the object is of the form + * `{ key: Qualified key name, obj: Parent object of key, val: Value at obj[key] }`. + * Otherwise `undefined`. */ getNestedMeta : (obj, chain, ensure=false) -> chain = chain.split('.') if typeof chain is 'string' _.reduce do chain (current, key, idx, chain) -> - return null unless current? + return undefined unless current? if idx is chain.length-1 return @@ -112,7 +114,7 @@ _obj = do else if ensure current[key] = {} else - null + undefined obj /** @@ -138,7 +140,7 @@ _obj = do * @param {Boolean} [ensure=false] If true, intermediate keys that are `null` or * `undefined` will be filled in with a new empty object `{}`, ensuring the set * will succeed. - * @retruns {null|Any} If found, returns the old value, and otherwise `null`. + * @retruns {undefined|Any} If found, returns the old value, and otherwise `undefined`. */ setNested : (obj, chain, value, ensure=false) -> meta = _obj.getNestedMeta obj, chain, ensure @@ -146,7 +148,25 @@ _obj = do meta.obj[meta.key] = value meta.val else - null + undefined + + /** + * Searches a heirarchical object for a given subkey specified in + * dotted-property syntax, removing it if found. + * @param {Object} obj The object to serve as the root of the property-chain. + * @param {Array|String} chain The property-chain to lookup. + * @param {Boolean} [ensure=false] If true, intermediate keys that are `null` or + * `undefined` will be filled in with a new empty object `{}`, ensuring the set + * will succeed. + * @retruns {undefined|Any} If found, returns the old value, and otherwise `undefined`. + */ + unsetNested : (obj, chain, ensure=false) -> + meta = _obj.getNestedMeta obj, chain, ensure + if meta + delete meta.obj[meta.key] + meta.val + else + undefined exports import _obj diff --git a/lib/util/cascade.co b/lib/util/cascade.co index 6258ade..6b3ade0 100644 --- a/lib/util/cascade.co +++ b/lib/util/cascade.co @@ -1,40 +1,62 @@ _ = require 'kraken/underscore' + /** * @class A mapping of key-value pairs supporting lookup fallback across multiple objects. */ class Cascade /** + * Map holding the object's KV-pairs. It is also the first element of the + * cascade lookup. + * @type Object + * @private + */ + _data : null + + /** * List of objects for lookups. * @type Array * @private */ - _dicts : null + _lookups : null + /** * @constructor */ - -> - @_dicts = [] - @extend ... + (data={}, lookups=[]) -> + @_data = {} import data + @_lookups = [@_data].concat lookups.slice() /** - * @returns {Number} Number of real keys in the Dict. + * @returns {Cascade} A copy of the lookup chain. */ - size : -> - _.keys @_dicts .length + clone: -> + new Cascade @_data, @_lookups + + + + ### Lookups ### /** - * @returns {Cascade} A copy of the dict, including fallbacks as well as data. + * Adds a new lookup dictionary to the chain. + * @returns {this} */ - clone: -> - d = new Cascade - _.each @_dicts, (v, k) -> - d.setAlias k, v.slice() - d + addLookup: (dict) -> + @_lookups.push dict + this + + /** + * Removes a lookup dictionary from the chain. + * @returns {this} + */ + removeLookup: (dict) -> + _.remove @_lookups, dict + this + @@ -44,85 +66,82 @@ class Cascade * @returns {Boolean} Whether there is a value at the given key. */ has : (key) -> - (@get key, null)? + (@get key, undefined) is not undefined + /** - * @returns {*} Ignores aliases, returning the value at key or `undefined`. + * @returns {*} First value for the given key found in the lookup chain, + * and the default otherwise. */ - getValue : (key) -> - prop = _.getNested @_dicts, key - prop.value if prop? - get : (key, def) -> - aliases = @_aliases[key] or [key] - val = aliases.reduce do - (val, alias) -> - return val if val? is not undefined - prop = _.getNested @_dicts, alias - prop.value if prop? - undefined - - if val is not undefined - val - else - def + for data of @_lookups + val = _.getNested data, key, undefined + return val if val is not undefined + def + /** + * @param {String} key Key to set. + * @param {*} val Non-`undefined` value to set. + * @returns {this} + */ set : (key, val) -> - _.setNested @_dicts, key, val, true - val + throw new Error("Value and key cannot be undefined!") unless key and val is not undefined + _.setNested @_data, key, val + this - del : (key) -> - prop = _.getNestedMeta key - if prop - delete prop.obj[prop.key] - prop.value + /** + * Delete the given key from this object's concrete data. If missing, + * does not cascade. + * @returns {undefined|*} If found, returns the old value, and otherwise `undefined`. + */ + del: (key) -> + _.unsetNested @_data, key, false ### Collection Methods ### + extend : (...args) -> + for o of args + for k,v in o then @set k, v + this + toObject: -> - _.extend {}, ...@_dicts + _.extend {}, ...@_lookups - # XXX: Merge keys from all objects? keys: -> - _.keys @_data + _.flatten _.map @_lookups, -> _.keys it values: -> - _.values @_data - - extend : (...args) -> - for o of args - for k,v in o then @set k, v - this + _.flatten _.map @_lookups, -> _.values it reduce : (fn, acc, context=this) -> - _.reduce @_data, fn, acc, context + _.reduce @_lookups, fn, acc, context map : (fn, context=this) -> - _.map @_data, fn, context + _.map @_lookups, fn, context filter: (fn, context=this) -> - _.filter @_data, fn, context + _.filter @_lookups, fn, context each : (fn, context=this) -> - _.each @_data, fn, context + _.each @_lookups, fn, context this invoke : (name, ...args) -> - _.invoke @_data, name, ...args + _.invoke @_lookups, name, ...args pluck : (attr) -> - _.pluck @_data, attr + _.pluck @_lookups, attr find: (fn, context=this) -> - _.find @_data, fn, context + _.find @_lookups, fn, context toString: -> - Cls = @.constructor + Cls = this.constructor "#{Cls.displayName or Cls.name}()"