Skip to content

Instantly share code, notes, and snippets.

@timruffles
Created April 1, 2014 15:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save timruffles/9916046 to your computer and use it in GitHub Desktop.
Save timruffles/9916046 to your computer and use it in GitHub Desktop.
deps.js
function Container() {
this.call = exports.call.bind(null,this);
this._deps = {};
}
Container.prototype = {
get: function(dep) {
return this._deps[dep];
},
put: function(name,thing) {
if(typeof name === "object") {
var deps = name;
for(var prop in deps) {
var dep = deps[prop];
this.put(prop,dep)
}
return this;
}
this._deps[name] = thing;
return this;
},
with: function(extras) {
var newContainer = new Container;
if(extras._deps) extras = extras._deps;
for(var prop in this._deps) {
newContainer[prop] = this._deps[prop];
}
for(var prop in extras) {
newContainer[prop] = extras[prop];
}
return newContainer;
}
}
function fulfil(from,dep) {
return typeof from.get === "function" ? from.get(dep) : from[dep];
}
exports._fulfil = fulfil;
exports.container = function(deps) {
var cont = new Container;
return deps ? cont.put(deps) : cont;
};
var argsRe = /^function[^\(]*\(([^\)]*)/;
exports.call = function(container,fun) {
var fs = fun + "";
var match = argsRe.exec(fs);
var argNames = match[1].split(",").map("".trim.call.bind("".trim));
if(argNames.length === 0 && argNames[0] === "") {
return fun();
}
var positional = [].slice.call(arguments,2);
var positionalArgsUsed = false;
var args = argNames.map(function(name,index) {
var dep = fulfil(container,name);
if(dep) {
if(positionalArgsUsed) {
throw new Error(
"Conflict: named argument '" + name + "' used after positional arguments - design APIs to take dependenices first, then function arguments"
);
}
} else {
if(positional.length === 0) {
throw new Error("Missing dependencies: " + argNames.slice(index).join(", "));
}
positionalArgsUsed = true;
dep = positional.shift();
}
return dep;
});
return fun.apply(null,args);
}
var deps = require("./deps.js");
var _ = require("lodash");
function databaseAdd(database,id,number,cb) {
database.get(id,function(err,row) {
if(err) throw new Error(err);
cb(null,row.value + number);
})
}
describe("call",function() {
var container = {};
container.database = {
get: function(id,cb) {
cb(null,{value: 10});
}
};
it("allows a function to be run with deps from a container",function() {
deps.call(container,databaseAdd,"a4gf",50,function(err,answer) {
assert.equals(answer,60);
});
});
it("doesn't allow a named argument to come before a positional one",function() {
var withNumber = _.extend({number: 50},container);
var exception = false;
try {
deps.call(withNumber,databaseAdd,"a4gf",function(err,answer) { })
} catch(e) {
exception = e;
}
assert(exception,"no exception");
assert.match(exception.message,/named argument 'number' used after positional/);
});
})
describe("container",function() {
var container;
var otherDb = {
database: {
get: function(id,cb) {
cb(null,{value: 15});
}
}
};
beforeEach(function() {
container = deps.container({
database: {
get: function(id,cb) {
cb(null,{value: 10});
}
}
});
})
it("can use call to run a fn",function() {
container.call(databaseAdd,"a4gf",50,function(err,answer) {
assert.equals(answer,60);
});
})
});
@moutainmama
Copy link

what is this

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment