-
Notifications
You must be signed in to change notification settings - Fork 3
/
index.js
86 lines (74 loc) · 2.7 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
// Function extends a base object with properties from term
var extend = function(base, term){
for (var property in term)
{
base[property] = term[property];
}
}
// Function remove properties in a base object if present in term
var contract = function(base, term){
for (var property in term)
{
if (base[property] === term[property])
delete base[property];
}
}
// Function returns properties in base object
var extract = function(base){
var result = {};
for (var property in base)
{
// console.log(property, ':', this[property])
result[property] = base[property];
}
return result;
}
// Crafts a lacing (series of function sets) using currying.
// initial is the first function in the lacing.
var craft = function(initial){
var lacing = []; // Contains a series of all of the function sets
// Helper is a local created for each lacing.
// It provides controls during the lacing invocation.
var helper = {
// Executes the first function in the next function set in the lacing.
next: (function makeNext(index){
return function(){
// Extract and cache the current lace
var oldLace = extract(lace);
// Set helper.next to a next function with an incremented index
helper.next = makeNext(index+1);
// Give lace the properties of the local helper
extend(lace, helper);
// Invoke the next function in the set
lacing[index][0].apply(this, arguments);
// Remove the properties of the local helper from lace
contract(lace, helper);
// Set helper.next back to previous index
helper.next = makeNext(index);
// Give lace it's previous properties
extend(lace, oldLace);
};
})(0),
// Reference the outer scope.
outer: extract(lace)
};
// Adds a set of functions to the lacing.
function add(){
// Push arguments (functions) into lacing as an array.
lacing.push(Array.prototype.slice.call(arguments));
// Return itself to continue currying recursivelly.
return add;
}
// setTimeout is used to let the outer scope finish execution before the initial function is invoked.
// This lets the other function sets curry into the lacing before the initial function is called.
// This is all possible because setTimeout is asynchronous and JS has only one thread of execution, thus can only process one function at a time.
setTimeout(helper.next, 0);
// Add the initial function as the first function set in the lacing.
add(initial);
// craft returns the add function for currying more function sets into the lacing.
return add;
}
// lace is the exported variable, initially set to the craft function.
// lace will be recursively set to a internal local within the craft function (lace) during the lacing execution.
var lace = craft;
module.exports = lace;