Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit cc2cb14
Showing
4 changed files
with
177 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
.idea | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
A simple map from strings to values in JavaScript | ||
================================================= | ||
|
||
This implementation avoids the pitfalls of directly using objects for this purpose. | ||
|
||
Usage on Node.js (on browsers, you need an AMD-compatible script loader such as [RequireJS](http://requirejs.org/)): | ||
|
||
> var strmap = require("./strmap"); | ||
> var map = new strmap.StrMap({ foo: 1, bar: 2}); | ||
> map.get("foo") | ||
1 | ||
> map.set("foo", "abc") | ||
|
||
Tests | ||
----- | ||
|
||
- Run the tests via [Mocha](http://visionmedia.github.com/mocha/). | ||
- Assertion API: [expect.js](https://github.com/LearnBoost/expect.js). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
"use strict"; | ||
|
||
({ define: typeof define === "function" ? define : function(A,F) { module.exports = F.apply(null, A.map(require)) } }). | ||
define([], | ||
function () { | ||
var e = {}; | ||
var hasOwnProperty = Object.prototype.hasOwnProperty; | ||
|
||
function getOwnPropertyValue(obj, propName) { | ||
return hasOwnProperty.call(obj, propName) ? obj[propName] : undefined; | ||
} | ||
|
||
/* | ||
* Make sure that there never is a key "__proto__". | ||
* Exported for unit test. | ||
*/ | ||
e._escapeKey = function (key) { | ||
if (key.indexOf("__proto__") >= 0) { | ||
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong.
rauschma
Author
Owner
|
||
return "%"+key; | ||
} else { | ||
return key; | ||
} | ||
} | ||
|
||
e.StrMap = function (obj) { | ||
var that = this; | ||
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong. |
||
this._data = {}; | ||
if (obj instanceof Object) { | ||
copyOne(this._data, obj, true); | ||
} | ||
}; | ||
|
||
/** | ||
* Add an entry to the map. | ||
* | ||
* @param key The key of the entry | ||
* @param value The value of the entry | ||
*/ | ||
e.StrMap.prototype.set = function (key, value) { | ||
key = e._escapeKey(key); | ||
this._data[key] = value; | ||
}; | ||
|
||
/** | ||
* Retrieve the value of an entry from the map. | ||
* | ||
* @param key The key of the entry | ||
*/ | ||
e.StrMap.prototype.get = function (key) { | ||
key = e._escapeKey(key); | ||
return getOwnPropertyValue(this._data, key); | ||
}; | ||
e.StrMap.prototype.delete = function (key) { | ||
key = e._escapeKey(key); | ||
var value = getOwnPropertyValue(this._data, key); | ||
delete this._data[key]; | ||
return value; | ||
}; | ||
|
||
/** | ||
* Is there an entry with the given key in the map? | ||
*/ | ||
e.StrMap.prototype.hasKey = function (key) { | ||
key = e._escapeKey(key); | ||
return hasOwnProperty.call(key); | ||
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong. |
||
}; | ||
|
||
/** | ||
* Starting with the first argument, then the second, override | ||
* the entries in this map. Each argument can be either | ||
* a map or an object. Overriding means: copy each entry | ||
* to this map. If there already is an entry that has the same | ||
* key, remove it. | ||
*/ | ||
e.StrMap.prototype.overrideWith = function () { | ||
return this._copyProperties(arguments, true); | ||
}; | ||
|
||
/** | ||
* Similar to overrideWith(), but doesn’t override properties that | ||
* already exist in this map. | ||
*/ | ||
e.StrMap.prototype.supplementWith = function () { | ||
return this._copyProperties(arguments, false); | ||
}; | ||
|
||
/** | ||
* Convert this map to an object. | ||
*/ | ||
e.StrMap.prototype.toObject = function() { | ||
return copyOne({}, this._data, true); | ||
}; | ||
|
||
e.StrMap.prototype._copyProperties = function (args, override) { | ||
var target = this._data; | ||
for (var i=0; i<args.length; i++) { | ||
var source = args[i]; | ||
if (source instanceof e.StrMap) { | ||
source = source._data; | ||
} | ||
copyOne(target, source, override); | ||
} | ||
return this; | ||
} | ||
|
||
function copyOne(target, source, override) { | ||
Object.keys(source).forEach(function(propName) { | ||
if (override || !hasOwnProperty.call(target, propName)) { | ||
target[propName] = source[propName]; | ||
} | ||
}); | ||
return target; | ||
} | ||
|
||
return e; | ||
} | ||
|
||
|
||
|
||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
"use strict"; | ||
|
||
({ define: typeof define === "function" ? define : function(A,F) { module.exports = F.apply(null, A.map(require)) } }). | ||
define([ "expect.js", "../strmap" ], | ||
function (expect, strmap) { | ||
describe('StrMap', function(){ | ||
it('should handle __proto__', function () { | ||
var map = new strmap.StrMap(); | ||
map.set("__proto__", 123); | ||
expect(map.get("__proto__")).to.equal(123); | ||
|
||
// Escaping must avoid key clashes | ||
var escapedProto = strmap._escapeKey("__proto__"); | ||
map.set(escapedProto, "abc"); | ||
expect(map.get(escapedProto)).to.equal("abc"); | ||
|
||
}); | ||
it('should not inherit keys', function () { | ||
expect(new strmap.StrMap().hasKey("toString")).to.be.false; | ||
}); | ||
it("imports and exports own properties of objects", function () { | ||
var map = new strmap.StrMap({ foo: 1, bar: 2}); | ||
expect(map.toObject()).to.eql({ foo: 1, bar: 2 }); | ||
}); | ||
it("overrides", function () { | ||
var map1 = new strmap.StrMap({ foo: 1, bar: 1}); | ||
var map2 = new strmap.StrMap({ bar: 2, baz: 2}); | ||
expect(map1.overrideWith(map2).toObject()).to.eql({ foo: 1, bar: 2, baz: 2 }); | ||
}); | ||
it("supplements", function () { | ||
var map1 = new strmap.StrMap({ foo: 1, bar: 1}); | ||
var map2 = new strmap.StrMap({ bar: 2, baz: 2}); | ||
expect(map1.supplementWith(map2).toObject()).to.eql({ foo: 1, bar: 1, baz: 2 }); | ||
}); | ||
}); | ||
} | ||
); |
Shouldn't this check be
=== 0
? a key like"foo__proto__"
shouldn't cause a problem.