Last active
December 10, 2015 01:29
-
-
Save egonelbre/4358887 to your computer and use it in GitHub Desktop.
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
// allows easily making an Actor with a Role | |
// if it's already an actor the context will be attached. | |
Object.defineProperty(Object.prototype, "as", {enumerable: false, value : function(role){ | |
// this will add a role to the object | |
if(this.__isActor__) { | |
this.__addRole__(role); | |
return this; | |
} | |
// if this is not an actor - | |
// an object that can play a role, we must make a new actor | |
var actor = new Actor(this); | |
actor.__addRole__(role); | |
return actor; | |
}}); | |
function sameObject(a, b){ | |
if(a.__isActor__) | |
a = a.original; | |
if(b.__isActor__) | |
b = b.original; | |
return a === b; | |
} | |
// this defines a Context | |
function Context(fn) { | |
return function(){ | |
fn.__ctx__ = GUID(); | |
return fn.apply(null, arguments); | |
}; | |
} | |
// this is for creating a new Role | |
// also attaches the context of the methods | |
// should only be called in a Context | |
function Role(methods) { | |
var role = { | |
__ctx__: currentContext(), | |
__methods__: methods | |
}; | |
for(var e in methods) { | |
methods[e].__ctx__ = role.__ctx__; | |
} | |
return role; | |
} | |
// for using anonymous methods | |
// this will attach the correct context otherwise the function will be contextless | |
function Fn(fn) { | |
var ctx = currentContext(); | |
fn.__ctx__ = ctx; | |
return fn; | |
} | |
function Methods(obj){ | |
var ctx = currentContext(); | |
obj.__ctx__ = ctx; | |
for(var name in obj){ | |
if(typeof obj[name] ){ | |
obj[name].__ctx__ = ctx; | |
} | |
} | |
return obj; | |
} | |
// this defines an actor capable of dispatching to roles depending on context | |
// ! should not be used directly | |
function Actor(original) { | |
// actor specific things | |
this.__isActor__ = true; | |
this.__original__ = original; | |
var contexts = { /*context : [Role1, Role2, Role3]*/ }; | |
// this method makes a dispatcher that finds the correct method | |
// depending on the calling context | |
var mkDispatcher = function(name) { | |
var fx = function() { | |
var ctx = currentContext(), | |
roles = contexts[ctx], | |
fn = original[name]; | |
if(roles) { | |
for(var i = 0; i < roles.length; i += 1) { | |
var methods = roles[i].__methods__; | |
if(methods[name]) { | |
fn = methods[name]; | |
break; | |
} | |
} | |
} | |
if(!fn){ | |
throw new Error("undefined method '" + name + "'"); | |
} | |
return fn.apply(this, arguments); | |
}; | |
fx.__ctx__ = "Dispatcher[" + name + "]"; // for debugging | |
return fx; | |
}; | |
// for dispatching get/set to the original | |
var redirect = function(from, to, name){ | |
from.__defineGetter__(name, function(){ | |
return to[name]; | |
}); | |
from.__defineSetter__(name, function(v){ | |
to[name] = v; | |
}); | |
}; | |
// for dispatching calls to the original | |
this.constructor = original.constructor; | |
for(var name in original){ | |
if(typeof original[name] === "function"){ | |
this[name] = mkDispatcher(name); | |
} else { | |
redirect(this, original, name); | |
} | |
} | |
// this just adds a role to the actor table | |
// and makes additional dispatchers for role methods | |
this.__addRole__ = function(role) { | |
var ctx = role.__ctx__; | |
if(!contexts[ctx]) | |
contexts[ctx] = []; | |
contexts[ctx].unshift(role); | |
var methods = role.__methods__; | |
for(var name in methods) { | |
if(!methods.hasOwnProperty(name) || this.hasOwnProperty(name)) | |
continue; | |
this[name] = mkDispatcher(name); | |
} | |
}; | |
} | |
// this finds the current context | |
// undefined if, none found | |
// ! should not be used directly | |
function currentContext() { | |
return currentContext.caller.caller.__ctx__; | |
} | |
// used for uniquely identifyig contexts | |
function GUID() { | |
// http://www.ietf.org/rfc/rfc4122.txt | |
var s = []; | |
var hexDigits = "0123456789abcdef"; | |
for(var i = 0; i < 36; i++) { | |
s[i] = hexDigits[Math.random() * 0x10 | 0]; | |
} | |
s[14] = "4"; | |
s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1); | |
s[8] = s[13] = s[18] = s[23] = "-"; | |
var uuid = s.join(""); | |
return uuid; | |
} |
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
<!doctype html> | |
<title>DCI Test</title> | |
<pre id="log"></pre> | |
<script src="dci.js"></script> | |
<script> | |
write = function() { | |
var lg = document.getElementById("log"), | |
args = Array.prototype.slice.apply(arguments), | |
line = args.join(", ") + "<br>"; | |
lg.innerHTML += line; | |
}; | |
function makePlayerTalk(player) { | |
player.say(); | |
} | |
var Battle = Context(function(alpha, beta) { | |
var Bear = Role({ | |
say: function() { | |
write( "[" + this.name + "] " + "Grrrr....."); | |
}, | |
touch: function(other) { | |
this.say(); | |
other.say(); | |
} | |
}); | |
var Lion = Role({ | |
say: function() { | |
write( "[" + this.name + "] " + "Meow...."); | |
}, | |
touch: function(other) { | |
this.say(); | |
other.say(); | |
} | |
}); | |
return Methods({ | |
doit : function(){ | |
var lion = alpha.as(Lion), | |
alphaBear = alpha.as(Bear), | |
bear = beta.as(Bear); | |
write("# Conversing"); | |
lion.say(); | |
bear.say(); | |
alphaBear.say(); | |
write("# lion touching the bear"); | |
lion.touch(bear); | |
write("# making alpha talk"); | |
makePlayerTalk(lion); | |
write("# making beta talk"); | |
makePlayerTalk(bear); | |
} | |
}); | |
}); | |
var player = { | |
name: "Jack", | |
say: function() { | |
write( "[" + this.name + "] " + "says Hello!"); | |
} | |
}; | |
var cpu = { | |
name: "Cyborg", | |
say: function() { | |
write( "[" + this.name + "] " + "bleeps Hello!"); | |
} | |
}; | |
var battle = Battle(player, cpu); | |
battle.doit(); | |
/* output | |
# Conversing | |
[Jack] Meow.... | |
[Cyborg] Grrrr..... | |
[Jack] Grrrr..... | |
# lion touching the bear | |
[Jack] Meow.... | |
[Cyborg] Grrrr..... | |
# making alpha talk | |
[Jack] says Hello! | |
# making beta talk | |
[Cyborg] bleeps Hello! | |
*/ | |
</script> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment