Add basic Javascript Dict implementation

(imported from commit 9f2fb089eb6e269549de26b37bd588355757d22c)
This commit is contained in:
Zev Benjamin 2013-08-07 16:28:45 -04:00
parent e0eddabeb1
commit 0cfc8fae9f
4 changed files with 145 additions and 1 deletions

77
static/js/dict.js Normal file
View File

@ -0,0 +1,77 @@
/* Constructs a new Dict object.
*
* Dict() -> the new Dict will be empty
* Dict(otherdict) -> create a shallow copy of otherdict
* Dict(jsobj) -> create a Dict with keys corresponding to the properties of
* jsobj and values corresponding to the value of the appropriate
* property
*/
function Dict(obj) {
var self = this;
this._items = {};
if (typeof obj === "object" && obj !== null) {
if (obj instanceof Dict) {
_.each(obj.items(), function (kv) {
self.set(kv[0], kv[1]);
});
} else {
_.each(obj, function (val, key) {
self.set(key, val);
});
}
}
}
(function () {
function munge(k) {
return ':' + k;
}
function unmunge(k) {
return k.substr(1);
}
Dict.prototype = {
get: function Dict_get(key) {
return this._items[munge(key)];
},
set: function Dict_set(key, value) {
return (this._items[munge(key)] = value);
},
has: function Dict_has(key) {
return _.has(this._items, munge(key));
},
del: function Dict_del(key) {
return delete this._items[munge(key)];
},
keys: function Dict_keys() {
return _.map(_.keys(this._items), unmunge);
},
values: function Dict_values() {
return _.values(this._items);
},
items: function Dict_items() {
return _.map(_.pairs(this._items), function (pair) {
return [unmunge(pair[0]), pair[1]];
});
}
};
Dict.prototype = _.object(_.map(Dict.prototype,
function (value, key) {
return [key, util.enforce_arity(value)];
}));
}());
if (typeof module !== 'undefined') {
module.exports = Dict;
}

View File

@ -25,7 +25,7 @@ var globals =
+ ' composebox_typeahead typeahead_helper notifications hashchange'
+ ' invite ui util activity timerender MessageList blueslip unread stream_list'
+ ' onboarding message_edit tab_bar emoji popovers navigate message_tour'
+ ' avatar feature_flags search_suggestion referral stream_color'
+ ' avatar feature_flags search_suggestion referral stream_color Dict'
// colorspace.js
+ ' colorspace'

View File

@ -0,0 +1,66 @@
global._ = require('third/underscore/underscore.js');
global.util = require('js/util.js');
var Dict = require('js/dict.js');
var assert = require('assert');
(function test_basic() {
var d = new Dict();
assert.deepEqual(d.keys(), []);
d.set('foo', 'bar');
assert.equal(d.get('foo'), 'bar');
d.set('foo', 'baz');
assert.equal(d.get('foo'), 'baz');
d.set('bar', 'qux');
assert.equal(d.get('foo'), 'baz');
assert.equal(d.get('bar'), 'qux');
assert.equal(d.has('bar'), true);
assert.equal(d.has('baz'), false);
assert.deepEqual(d.keys(), ['foo', 'bar']);
assert.deepEqual(d.values(), ['baz', 'qux']);
assert.deepEqual(d.items(), [['foo', 'baz'], ['bar', 'qux']]);
d.del('bar');
assert.equal(d.has('bar'), false);
assert.strictEqual(d.get('bar'), undefined);
assert.deepEqual(d.keys(), ['foo']);
}());
(function test_restricted_keys() {
var d = new Dict();
assert.equal(d.has('__proto__'), false);
assert.equal(d.has('hasOwnProperty'), false);
assert.equal(d.has('toString'), false);
assert.strictEqual(d.get('__proto__'), undefined);
assert.strictEqual(d.get('hasOwnProperty'), undefined);
assert.strictEqual(d.get('toString'), undefined);
d.set('hasOwnProperty', function () {return true;});
assert.equal(d.has('blah'), false);
d.set('__proto__', 'foo');
d.set('foo', 'bar');
assert.equal(d.get('foo'), 'bar');
}());
(function test_construction() {
var d1 = new Dict();
assert.deepEqual(d1.items(), []);
var d2 = new Dict({foo: 'bar', baz: 'qux'});
assert.deepEqual(d2.items(), [['foo', 'bar'], ['baz', 'qux']]);
var d3 = new Dict(d2);
d3.del('foo');
assert.deepEqual(d2.items(), [['foo', 'bar'], ['baz', 'qux']]);
assert.deepEqual(d3.items(), [['baz', 'qux']]);
}());

View File

@ -363,6 +363,7 @@ JS_SPECS = {
'js/feature_flags.js',
'js/util.js',
'js/dict.js',
'js/setup.js',
'js/viewport.js',
'js/rows.js',