Last active
December 20, 2015 18:09
-
-
Save nakamura-to/6173630 to your computer and use it in GitHub Desktop.
ECMA Script 6のgeneratorを使ってIoC (Inversion of Control)。node v0.11.4で--harmony-generatorsオプションをつけて実行。
This file contains hidden or 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
/* | |
* IoC (Inversion o Control) Computation Expression | |
*/ | |
function ioc(fn) { | |
assert(isGeneratorFunction(fn), 'The argument `fn` must be a GeneratorFunction.'); | |
run.mflow_generatorFunction = fn; | |
return run; | |
function run(container) { | |
return function () { | |
var gen = fn.apply(this, arguments); | |
var ret = gen.next(); | |
var component; | |
while (!ret.done) { | |
if (typeof ret.value === 'string') { | |
component = container[ret.value]; | |
if (component != null) { | |
component = normalize(component, container); | |
ret = gen.next(component); | |
} else { | |
get.throw(new Error('The component is not found. key = "') + ret.value + '"'); | |
} | |
} else { | |
get.throw(new Error('The yieldable value must be a string')); | |
} | |
} | |
return ret.value; | |
}; | |
} | |
function normalize(obj, container) { | |
if (obj && obj.mflow_generatorFunction) obj = obj.mflow_generatorFunction; | |
if (isGeneratorFunction(obj)) { | |
obj = ioc(obj); | |
obj = obj(container); | |
} else if (isFunction(obj)) { | |
obj = obj(); | |
} | |
return obj; | |
} | |
function assert(prerequisite, message) { | |
if (prerequisite) return; | |
throw new Error(message); | |
} | |
function isFunction(obj) { | |
return typeof obj === 'function'; | |
} | |
function isGeneratorFunction(obj) { | |
return obj && obj.constructor && 'GeneratorFunction' === obj.constructor.name; | |
} | |
} | |
/* | |
* MAIN | |
*/ | |
var flow1 = ioc(function * () { | |
var p = yield 'person'; | |
return JSON.stringify(p); | |
}); | |
var flow2 = ioc(function * (prefix, suffix) { | |
var m = yield 'message'; | |
return prefix + m.content + suffix; | |
}); | |
var container = { | |
// mutable state | |
count: 0, | |
// singleton | |
person: { | |
name: 'foo', | |
age: 20 | |
}, | |
// singleton | |
flow1: flow1, | |
// singleton | |
flow2: flow2, | |
// prototype | |
message : function () { | |
var count = container.count++; | |
return { | |
content: 'hello ' + count | |
}; | |
}, | |
}; | |
var main= ioc(function * () { | |
var a = yield 'flow1'; | |
var b = yield 'flow2'; | |
var c = yield 'flow2'; | |
console.log(a()); // {"name":"foo","age":20} | |
console.log(b('[', ']')); // [hello 0] | |
console.log(c('<', '>')); // <hello 1> | |
}); | |
main(container)(); | |
/* | |
* Test using mock | |
*/ | |
var result = flow1({person: {name: 'test', age: 99}})(); | |
console.log(result); // {"name":"test","age":99} | |
result = flow2({message: { content: 'dummy'}})('(', ')'); | |
console.log(result); // (dummy) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
いくつか改善案
yieldにコンポーネントの名前だけでなくパスを指定できるようにする
コンポーネントが関数の場合にはそいつが属しているコンテナを引数で渡す