This repository has been archived by the owner on Dec 5, 2019. It is now read-only.
/
functions.js
212 lines (153 loc) · 5.28 KB
/
functions.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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
var objects = require('./objects')
exports.id = function (i) {
return i
}
/*
often you want to do something like: map(array, JSON.stringify)
but map calls the iterator with (value, key, object)
which confuses JSON.stringify because it expects a replacer function as the second arg
previously one would do something like this:
map(array, function (x) {return JSON.stringify(x)})
TOO LONG, I can't be bothered!
now use:
map(array, curry(JSON.stringify, 0))
the `0` that thu first arg is in the first position.
non numbers are literal, also, negative numbers count from the end of the array
(handy for ensuring that callbacks are in the right place)
curry(func, 0) // function (a) { return func(a) }
curry(func, 0, 'whatever') // function (a) { return func(a, 'whatever') }
curry(func, 0, 'whatever', -1) // function (a, b) { return func(a, 'whatever', b) }
of course, you cannot use this function to stick in numbers, but what are you, an accountant?
it's really handy though, when you can simplify this:
ctrl.toAsync(function (ls) {
return d.map(ls, function (e) { return path.join(dir, e) } )
}) ]) (dir, cb)
to this:
ctrl.toAsync(d.curry(d.map, 0, d.curry(path.join, dir, 0) ))
*/
exports.curry = function (/*funx, args...*/) {
var args = [].slice.call(arguments)
, funx = args.shift()
return function (){
var _args = [].slice.call(arguments)
return funx.apply(this, objects.map(args, function (i) {
return 'number' !== typeof i ? i : _args[i < 0 ? _args.length + i : i]
}))
}
}
exports.deepCurry = function () {
var args = [].slice.call(arguments)
, funx = args.shift()
return function () {
var _args = [].slice.call(arguments)
return funx.apply(this, objects.deepMerge(args, _args))
}
}
/*
before: modify the args to a function before it is called.
I think this is called aspect oriented programming.
the 'before' function returns a function that calls a shim function before a given function,
the 'shim' function is passed the args of the returned function, and may alter them before
the given function is called.
hmm, thats about twice as much english than javascript.
use it like this:
function (x,p,z) {return whatever(z, p, x)}
before(whatever, function (args) { return args.reverse() })
hmm, thats more verbose than the straight forward way...
maybe that function is not such a great idea.
what about beforeCallback?
function (opts, callback) { request (opts, function (err, res, body) { callback(err, body) } }
beforeCallback(request, function (args) { return [args[0], args[2]] })
ah, that is better.
*/
var fName = function (f) {
return '"' + (f.name || f.toString().slice(0,100)) + '"'
}
var before = exports.before = function (given, shim) {
return function wrapped () {
return given.apply(this, shim([].slice.call(arguments)))
}
}
//before(whatever, function (a) { return a.reverse() })
var beforeCallback =
exports.beforeCallback = function (async, shim) {
return before(async, function (args) {
args.push(before(args.pop(), shim)); return args
})
}
/*
prevent a function from being called intil some thing important has happened.
(useful for delaying something until a connection is made.)
use like this:
dbSave = defer(dbSave)
bdSave(doc1) //these calls will be buffered
bdSave(doc2)
db.connect()
db.on('connection', dbSave.flush)
db.on('disconnection', function () {dbSave.buffer(); db.reconnect() })
*/
var defer =
exports.defer = function (deferred) {
var buffer = []
, buffering = true
function deferrer () {
var args = [].slice.call(arguments)
if(buffering)
buffer.push(args)
else deferred.apply(null, args)
}
deferrer.flush = function () {
buffering = false
while(!buffering && buffer.length) {
deferred.apply(null, buffer.shift())
}
}
deferrer.buffer = function () {
buffering = true
}
return deferrer
}
/*
curryHead(func, tail...)
-> function (head) { return func(head, tail...) }
given a function and tail args,
return a function that takes a head arg,
and applys head.concat(tail) to the given function
*/
var curryTail =
exports.curryTail = function (func) {
var args = [].slice.call(arguments, 1)
if(!args.length) return func
return function (a) {
return func.apply(this, [a].concat(args))
}
}
/*
curryHead(func, head)
-> function (tail...) { return func(head, tail...) }
given a function and head arg,
return a function that takes tail args,
and calls the given function with head.concat(tail)
*/
var curryHead =
exports.curryHead = function (func, a) {
return function () {
var args = [].slice.call(arguments)
return func.apply(this, [a].concat(args))
}
}
/*
curryTailHead
take a given function and return a function that takes tail args,
and returns a function that takes a head arg,
and that calls the given function with head.concat(tail)
you are certainly deep down the rabit hole when you are using functional composition on curry functions
this is actually gonna be useful for making spec assertions -- with higer order assertions.
so that you can say
equal(x, X)
with:
_equal(X)(x)
*/
var curryTailHead = exports.curryTailHead = function (funx) {
return curryHead (curryTail, funx)
}