Skip to content

Instantly share code, notes, and snippets.

@egonelbre
Last active August 29, 2015 14:21
Show Gist options
  • Save egonelbre/d04f8002465b7f07dc06 to your computer and use it in GitHub Desktop.
Save egonelbre/d04f8002465b7f07dc06 to your computer and use it in GitHub Desktop.
function Account(code, balance) {
return {
get code(){ return code; },
get balance(){ return balance; },
increase: function(by){ balance += by; },
decrease: function(by){ balance -= by; }
};
}
function Bank(){
var accounts = {};
return {
openAccount: function(code, initialBalance){
accounts[code] = Account(code, initialBalance);
},
accountByCode: function(code){ return accounts[code]; }
}
}
Transfer = Context(
function(bank, from, to, amount) {
Source = bank.accountByCode(from);
Destination = bank.accountByCode(to);
Amount = amount;
Source.give();
}, {
Amount: {},
Source: {
give: function() {
if(Source.balance < Amount){
throw new Error("Insufficient funds.");
}
Source.decrease(Amount);
Destination.receive();
}
},
Destination: {
receive: function() {
Destination.increase(Amount);
}
}
});
var bank = Bank();
bank.openAccount("alice", 132);
bank.openAccount("bob", 23);
console.log("Before:");
console.log("alice ", bank.accountByCode("alice").balance);
console.log("bob ", bank.accountByCode("bob").balance);
Transfer(bank, "alice", "bob", 100);
console.log("After:");
console.log("alice", bank.accountByCode("alice").balance);
console.log("bob", bank.accountByCode("bob").balance);
// DCI implementation
function Context(init, roles, debug){
// scoped role players
var sfn = " var " + Object.keys(roles).join(",") + ";\n";
// creates the function
var mkName = function(role, fn){ return role + "$" + fn; };
// redirects all role method calls
var fixMethod = function(fn){
fn = fn.toString();
for(var roleName in roles){
var role = roles[roleName];
for(var fnName in role){
// replaces Role.method(arg1,arg2,arg3) with
// with Role$method.call(Role, arg1, arg2, arg3)
var rx = new RegExp( "(?!\\.)" + roleName + "\\s*\\.\\s*" + fnName + "\\s*\\(", "g");
fn = fn.replace(rx, mkName(roleName, fnName) + ".call(" + roleName + ",");
}
}
// hack-fix Role$method.call(Arg,)
fn = fn.replace(/,\)/g, ")");
return fn;
};
// define role methods in to the context
var methods = [];
for(var roleName in roles){
var role = roles[roleName];
for(var fnName in role){
methods.push(" var " + mkName(roleName, fnName) + " = " + fixMethod(role[fnName]));
}
}
sfn += methods.join(";\n") + ";\n";
// return the init
sfn += " return (" + fixMethod(init) + ").apply(null, arguments);";
if(debug){
console.log(sfn);
}
return (new Function(sfn));
}
@egonelbre
Copy link
Author

Transfer = (function(){
  var Amount,Source,Destination;
  var Source$give = function () {
      if(Source.balance < Amount){
        throw new Error("Insufficient funds.");
      }
      Source.decrease(Amount);
      Destination$receive.call(Destination);
    };
  var Destination$receive = function () {
      Destination.increase(Amount);
    };
  return (function (bank, from, to, amount) {
  Source = bank.accountByCode(from);
  Destination = bank.accountByCode(to);
  Amount = amount;

  Source$give.call(Source);
}).apply(null, arguments);
});

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