From d8c935c6dff249168d9b9d990ba39880809fad0c Mon Sep 17 00:00:00 2001 From: Brian Gray Date: Mon, 27 Oct 2014 16:27:12 -0400 Subject: [PATCH 1/5] Add package.json for use with other node projects --- .gitignore | 3 +++ package.json | 12 ++++++++++++ spec/support/jasmine.json | 6 ++++++ 3 files changed, 21 insertions(+) create mode 100644 .gitignore create mode 100644 package.json create mode 100644 spec/support/jasmine.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..718cfca --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.idea/ +node_modules/ + diff --git a/package.json b/package.json new file mode 100644 index 0000000..b11088b --- /dev/null +++ b/package.json @@ -0,0 +1,12 @@ +{ + "name": "enums", + "version": "0.0.1", + "description": "Enums for JavaScript", + "main": "enums.js", + "devDependencies": { + "jasmine": "^2.0.1" + }, + "scripts": { + "test": "./node_modules/.bin/jasmine" + } +} diff --git a/spec/support/jasmine.json b/spec/support/jasmine.json new file mode 100644 index 0000000..f8a7214 --- /dev/null +++ b/spec/support/jasmine.json @@ -0,0 +1,6 @@ +{ + "spec_dir": "./", + "spec_files": [ + "enums.spec.js" + ] +} \ No newline at end of file From 9c90f3563e217a2be51f842b8bbb8a70ae318830 Mon Sep 17 00:00:00 2001 From: Brian Gray Date: Mon, 27 Oct 2014 16:59:43 -0400 Subject: [PATCH 2/5] Add fromName function --- enums.js | 15 ++++++++++----- enums.spec.js | 23 +++++++++++++++++++++++ 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/enums.js b/enums.js index 560ae4b..5ce253a 100644 --- a/enums.js +++ b/enums.js @@ -26,7 +26,7 @@ }; Object.freeze(Symbol.prototype); - Enum = function (obj) { + var Enum = function (obj) { if (arguments.length === 1 && obj !== null && typeof obj === "object") { Object.keys(obj).forEach(function (name) { this[name] = new Symbol(name, obj[name]); @@ -37,18 +37,23 @@ }, this); } Object.freeze(this); - } + }; Enum.prototype.symbols = function() { return Object.keys(this).map( function(key) { return this[key]; }, this ); - } + }; Enum.prototype.contains = function(sym) { - if (! sym instanceof Symbol) return false; + if (!sym instanceof Symbol) return false; return this[sym.name] === sym; - } + }; + Enum.prototype.fromName = function (name) { + if (!name instanceof String) return undefined; + return this[name]; + }; + exports.Enum = Enum; exports.Symbol = Symbol; }(typeof exports === "undefined" ? this.enums = {} : exports)); diff --git a/enums.spec.js b/enums.spec.js index 57d7ba8..4e94ac2 100644 --- a/enums.spec.js +++ b/enums.spec.js @@ -1,6 +1,12 @@ var enums = require("./enums.js"); describe("Enum", function() { + it("can create enums", function() { + var color = new enums.Enum("red", "green", "blue"); + expect(color.red).toBeDefined(); + expect(color.red.name).toEqual("red"); + }); + it("can have symbols with custom properties", function() { var color = new enums.Enum({ red: { de: "rot" }, @@ -11,12 +17,29 @@ describe("Enum", function() { return c.de; } expect(translate(color.green)).toEqual("grün"); + expect(translate(color.green)).toEqual("grün"); }); + it("can check for symbol membership", function() { var color = new enums.Enum("red", "green", "blue"); var fruit = new enums.Enum("apple", "banana"); expect(color.contains(color.red)).toBeTruthy(); expect(color.contains(fruit.apple)).toBeFalsy(); }); + + describe("fromName", function() { + it("can create values from enum names", function() { + var color = new enums.Enum("red", "green", "blue"); + var red = color.fromName("red"); + expect(red).toBeDefined(); + expect(red.name).toEqual("red"); + }); + it("is undefined for unknown names", function() { + var color = new enums.Enum("red", "green", "blue"); + var foo = color.fromName("foo"); + expect(foo).toBeUndefined(); + }); + }); + }); From 0663562fb12a27a4ab617838ab80abee60b40aef Mon Sep 17 00:00:00 2001 From: Brian Gray Date: Mon, 27 Oct 2014 17:25:46 -0400 Subject: [PATCH 3/5] Add fromValue function --- enums.js | 20 ++++++++++++++++++++ enums.spec.js | 42 ++++++++++++++++++++++++++++++++++++++---- 2 files changed, 58 insertions(+), 4 deletions(-) diff --git a/enums.js b/enums.js index 5ce253a..467414f 100644 --- a/enums.js +++ b/enums.js @@ -54,6 +54,26 @@ return this[name]; }; + /** + * Get the enum based on a matching value + * @param valueMatcher an object literal with any subset of the properties passed into the original constructor + * @returns an array of matching enums or, if only one matches the enum or, if none match, undefined + */ + Enum.prototype.fromValue = function (valueMatcher) { + if (!valueMatcher) return undefined; + var matches = this.symbols().filter(function(symbol) { + for (var key in valueMatcher) { return valueMatcher[key] === symbol[key]; }; + }) + switch (matches.length) { + case 0: + return undefined; + case 1: + return matches[0]; + default: + return matches; + } + }; + exports.Enum = Enum; exports.Symbol = Symbol; }(typeof exports === "undefined" ? this.enums = {} : exports)); diff --git a/enums.spec.js b/enums.spec.js index 4e94ac2..1f9f732 100644 --- a/enums.spec.js +++ b/enums.spec.js @@ -11,7 +11,7 @@ describe("Enum", function() { var color = new enums.Enum({ red: { de: "rot" }, green: { de: "grün" }, - blue: { de: "blau" }, + blue: { de: "blau" } }); function translate(c) { return c.de; @@ -28,17 +28,51 @@ describe("Enum", function() { }); describe("fromName", function() { - it("can create values from enum names", function() { - var color = new enums.Enum("red", "green", "blue"); + var color = new enums.Enum("red", "green", "blue"); + it("can find enums via their names", function() { var red = color.fromName("red"); expect(red).toBeDefined(); expect(red.name).toEqual("red"); }); it("is undefined for unknown names", function() { - var color = new enums.Enum("red", "green", "blue"); var foo = color.fromName("foo"); expect(foo).toBeUndefined(); }); + it("is undefined for a bogus parameter", function() { + var foo = color.fromName({}); + expect(foo).toBeUndefined(); + }); + }); + + describe("fromValue", function() { + var color = new enums.Enum({ + red: { r: 255, g: 2, b: 0 }, + green: { r: 0, g: 255, b: 0 }, + blue: { r: 0, g: 0, b: 255 } + }); + it("can find enums via a single matching values", function() { + var red = color.fromValue({ r: 255 }); + expect(red).toBeDefined(); + expect(red.name).toEqual("red"); + }); + it("can find enums via a pair of matching values", function() { + var red = color.fromValue({ r: 255, g: 2 }); + expect(red).toBeDefined(); + expect(red.name).toEqual("red"); + }); + it("can find a list of enums", function() { + var noReds = color.fromValue({ r: 0 }); + expect(noReds).toBeDefined(); + expect(noReds.length).toEqual(2); + }); + it("is undefined with no input", function() { + var value = color.fromValue(); + expect(value).toBeUndefined(); + }); + it("is undefined with input that does not match our enum values", function() { + var value = color.fromValue({ foo: "bar" }); + expect(value).toBeUndefined(); + }); }); }); From b94fb73b2642b5c455e9a95333203acbf720f312 Mon Sep 17 00:00:00 2001 From: Brian Gray Date: Fri, 31 Oct 2014 12:07:20 -0400 Subject: [PATCH 4/5] Add repository field --- package.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/package.json b/package.json index b11088b..0aa7c9d 100644 --- a/package.json +++ b/package.json @@ -8,5 +8,9 @@ }, "scripts": { "test": "./node_modules/.bin/jasmine" + }, + "repository": { + "type": "git", + "url": "git@github.com:rauschma/enums.git" } } From 41597c61c43e365fa41277a717f841e9d5d1c1a4 Mon Sep 17 00:00:00 2001 From: Brian Gray Date: Mon, 3 Nov 2014 13:46:25 -0500 Subject: [PATCH 5/5] Add Object.prototype to the prototpe chain --- enums.js | 10 ++++++---- enums.spec.js | 18 ++++++++++++++++++ 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/enums.js b/enums.js index 467414f..987eed8 100644 --- a/enums.js +++ b/enums.js @@ -12,10 +12,12 @@ if (props) { copyOwnFrom(this, props); } - Object.freeze(this); + Object.seal(this); } /** We don’t want the mutable Object.prototype in the prototype chain */ - Symbol.prototype = Object.create(null); + // BG adding Object.prototype back to allow iteration, otherwise objects with + // symbols attached cannot be deep copied + Symbol.prototype = Object.create(Object.prototype); Symbol.prototype.constructor = Symbol; /** * Without Object.prototype in the prototype chain, we need toString() @@ -24,7 +26,7 @@ Symbol.prototype.toString = function () { return "|"+this.name+"|"; }; - Object.freeze(Symbol.prototype); + Object.seal(Symbol.prototype); var Enum = function (obj) { if (arguments.length === 1 && obj !== null && typeof obj === "object") { @@ -36,7 +38,7 @@ this[name] = new Symbol(name); }, this); } - Object.freeze(this); + Object.seal(this); }; Enum.prototype.symbols = function() { return Object.keys(this).map( diff --git a/enums.spec.js b/enums.spec.js index 1f9f732..b61c892 100644 --- a/enums.spec.js +++ b/enums.spec.js @@ -7,6 +7,24 @@ describe("Enum", function() { expect(color.red.name).toEqual("red"); }); + it("can iterate over its properties", function() { + var color = new enums.Enum({ + red: { r: 255, g: 2, b: 0 }, + green: { r: 0, g: 255, b: 0 }, + blue: { r: 0, g: 0, b: 255 } + }); + var red = color.red; + var rValue; + for (var property in red) { + if (red.hasOwnProperty(property) && property === "r") { + rValue = red[property]; + } + } + + expect(rValue).toBeDefined(); + expect(rValue).toEqual(255); + }); + it("can have symbols with custom properties", function() { var color = new enums.Enum({ red: { de: "rot" },