Add #fetch Utility function
The #fetch utility acts in (roughly) the same way as Ruby's Hash#fetch function. This addition should hopefully make constructors more rigorous and help to prevent a few classes of errors.
This commit is contained in:
parent
af8cfbe333
commit
6f42b061b3
55
lib/utils.js
55
lib/utils.js
|
@ -183,6 +183,61 @@ var Utils = module.exports = {
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Public: Analogue to Ruby's Hash#fetch method for looking up object
|
||||||
|
// properties.
|
||||||
|
//
|
||||||
|
// obj - object to do property lookup on
|
||||||
|
// property - string property name to attempt to look up
|
||||||
|
// fallback - either:
|
||||||
|
// - a fallback value to return if `property` can't be found
|
||||||
|
// - a function to be executed if `property` can't be found. The function
|
||||||
|
// will be passed `property` as an argument.
|
||||||
|
//
|
||||||
|
// Examples
|
||||||
|
//
|
||||||
|
// var object = { property: "hello world" };
|
||||||
|
// fetch(object, "property");
|
||||||
|
// //=> "hello world"
|
||||||
|
//
|
||||||
|
// fetch(object, "notaproperty", "default value");
|
||||||
|
// //=> "default value"
|
||||||
|
//
|
||||||
|
// var notFound = function(prop) { return prop + " not found!" };
|
||||||
|
// fetch(object, "notaproperty", notFound)
|
||||||
|
// // "notaproperty not found!"
|
||||||
|
//
|
||||||
|
// var badFallback = function(prop) { prop + " not found!" };
|
||||||
|
// fetch(object, "notaproperty", badFallback)
|
||||||
|
// // Error: no return value from provided callback function
|
||||||
|
//
|
||||||
|
// fetch(object, "notaproperty");
|
||||||
|
// // Error: key not found: "notaproperty"
|
||||||
|
//
|
||||||
|
// Returns the value of obj[property], a fallback value, or the results of
|
||||||
|
// running 'fallback'. If the property isn't found, and 'fallback' hasn't been
|
||||||
|
// provided, will throw an error.
|
||||||
|
fetch: function(obj, property, fallback) {
|
||||||
|
if (obj.hasOwnProperty(property)) {
|
||||||
|
return obj[property];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fallback === void 0) {
|
||||||
|
throw new Error('key not found: "' + property + '"');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof(fallback) === 'function') {
|
||||||
|
var value = fallback(property);
|
||||||
|
|
||||||
|
if (value === void 0) {
|
||||||
|
throw new Error('no return value from provided fallback function');
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fallback;
|
||||||
|
},
|
||||||
|
|
||||||
// Public: Adds necessary utils to global namespace, along with base class
|
// Public: Adds necessary utils to global namespace, along with base class
|
||||||
// extensions.
|
// extensions.
|
||||||
//
|
//
|
||||||
|
|
|
@ -222,4 +222,52 @@ describe("Utils", function() {
|
||||||
expect(proxy.boundMethod("Hello", "World")).to.eql(["Hello", "World"]);
|
expect(proxy.boundMethod("Hello", "World")).to.eql(["Hello", "World"]);
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("#fetch", function() {
|
||||||
|
var fetch = utils.fetch,
|
||||||
|
obj = { property: 'hello world', 'false': false, 'null': null };
|
||||||
|
|
||||||
|
context("if the property exists on the object", function() {
|
||||||
|
it("returns the value", function() {
|
||||||
|
expect(fetch(obj, 'property')).to.be.eql('hello world');
|
||||||
|
expect(fetch(obj, 'false')).to.be.eql(false);
|
||||||
|
expect(fetch(obj, 'null')).to.be.eql(null);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
context("if the property doesn't exist on the object", function() {
|
||||||
|
context("and no fallback value has been provided", function() {
|
||||||
|
it("throws an Error", function() {
|
||||||
|
var fn = function() { return fetch(obj, "notaproperty"); };
|
||||||
|
expect(fn).to.throw(Error, 'key not found: "notaproperty"');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
context("and a fallback value has been provided", function() {
|
||||||
|
it('returns the fallback value', function() {
|
||||||
|
expect(fetch(obj, 'notakey', 'fallback')).to.be.eql('fallback');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
context("and a fallback function has been provided", function() {
|
||||||
|
context("if the function has no return value", function() {
|
||||||
|
it("throws an Error", function() {
|
||||||
|
var fn = function() { fetch(obj, 'notakey', function() {}); },
|
||||||
|
str = 'no return value from provided fallback function';
|
||||||
|
|
||||||
|
expect(fn).to.throw(Error, str);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
context("if the function returns a value", function() {
|
||||||
|
it("returns the value returned by the fallback function", function() {
|
||||||
|
var fn = function(key) { return "Couldn't find " + key },
|
||||||
|
value = "Couldn't find notakey";
|
||||||
|
|
||||||
|
expect(fetch(obj, 'notakey', fn)).to.be.eql(value);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue