1
2
3
4
5
6
7
8
9
10
11
12
13
14 root: this
15
16
17
18 previousUnderscore: root._
19
20
21
22
23
24 wrapper: (obj) ->
25 this._wrapped: obj
26 this
27
28
29
30 breaker: if typeof(StopIteration) is 'undefined' then '__break__' else StopIteration
31
32
33
34 _: root._: (obj) -> new wrapper(obj)
35
36
37
38 if typeof(exports) != 'undefined' then exports._: _
39
40
41
42 slice: Array::slice
43 unshift: Array::unshift
44 toString: Object::toString
45 hasOwnProperty: Object::hasOwnProperty
46 propertyIsEnumerable: Object::propertyIsEnumerable
47
48
49
50 _.VERSION: '0.5.8'
51
52
53
54
55
56
57 _.each: (obj, iterator, context) ->
58 index: 0
59 try
60 return obj.forEach(iterator, context) if obj.forEach
61 if _.isNumber(obj.length)
62 return iterator.call(context, obj[i], i, obj) for i in [0...obj.length]
63 iterator.call(context, val, key, obj) for key, val of obj
64 catch e
65 throw e if e isnt breaker
66 obj
67
68
69
70
71 _.map: (obj, iterator, context) ->
72 return obj.map(iterator, context) if (obj and _.isFunction(obj.map))
73 results: []
74 _.each obj, (value, index, list) ->
75 results.push(iterator.call(context, value, index, list))
76 results
77
78
79
80
81 _.reduce: (obj, memo, iterator, context) ->
82 return obj.reduce(_.bind(iterator, context), memo) if (obj and _.isFunction(obj.reduce))
83 _.each obj, (value, index, list) ->
84 memo: iterator.call(context, memo, value, index, list)
85 memo
86
87
88
89
90 _.reduceRight: (obj, memo, iterator, context) ->
91 return obj.reduceRight(_.bind(iterator, context), memo) if (obj and _.isFunction(obj.reduceRight))
92 _.each _.clone(_.toArray(obj)).reverse(), (value, index) ->
93 memo: iterator.call(context, memo, value, index, obj)
94 memo
95
96
97
98 _.detect: (obj, iterator, context) ->
99 result: null
100 _.each obj, (value, index, list) ->
101 if iterator.call(context, value, index, list)
102 result: value
103 _.breakLoop()
104 result
105
106
107
108
109 _.select: (obj, iterator, context) ->
110 if obj and _.isFunction(obj.filter) then return obj.filter(iterator, context)
111 results: []
112 _.each obj, (value, index, list) ->
113 results.push(value) if iterator.call(context, value, index, list)
114 results
115
116
117
118 _.reject: (obj, iterator, context) ->
119 results: []
120 _.each obj, (value, index, list) ->
121 results.push(value) if not iterator.call(context, value, index, list)
122 results
123
124
125
126
127 _.all: (obj, iterator, context) ->
128 iterator ||= _.identity
129 return obj.every(iterator, context) if obj and _.isFunction(obj.every)
130 result: true
131 _.each obj, (value, index, list) ->
132 _.breakLoop() unless (result: result and iterator.call(context, value, index, list))
133 result
134
135
136
137
138 _.any: (obj, iterator, context) ->
139 iterator ||= _.identity
140 return obj.some(iterator, context) if obj and _.isFunction(obj.some)
141 result: false
142 _.each obj, (value, index, list) ->
143 _.breakLoop() if (result: iterator.call(context, value, index, list))
144 result
145
146
147
148
149 _.include: (obj, target) ->
150 return _.indexOf(obj, target) isnt -1 if obj and _.isFunction(obj.indexOf)
151 for key, val of obj
152 return true if val is target
153 false
154
155
156
157 _.invoke: (obj, method) ->
158 args: _.rest(arguments, 2)
159 (if method then val[method] else val).apply(val, args) for val in obj
160
161
162
163 _.pluck: (obj, key) ->
164 _.map(obj, ((val) -> val[key]))
165
166
167
168 _.max: (obj, iterator, context) ->
169 return Math.max.apply(Math, obj) if not iterator and _.isArray(obj)
170 result: {computed: -Infinity}
171 _.each obj, (value, index, list) ->
172 computed: if iterator then iterator.call(context, value, index, list) else value
173 computed >= result.computed and (result: {value: value, computed: computed})
174 result.value
175
176
177
178 _.min: (obj, iterator, context) ->
179 return Math.min.apply(Math, obj) if not iterator and _.isArray(obj)
180 result: {computed: Infinity}
181 _.each obj, (value, index, list) ->
182 computed: if iterator then iterator.call(context, value, index, list) else value
183 computed < result.computed and (result: {value: value, computed: computed})
184 result.value
185
186
187
188 _.sortBy: (obj, iterator, context) ->
189 _.pluck(((_.map obj, (value, index, list) ->
190 {value: value, criteria: iterator.call(context, value, index, list)}
191 ).sort((left, right) ->
192 a: left.criteria; b: right.criteria
193 if a < b then -1 else if a > b then 1 else 0
194 )), 'value')
195
196
197
198
199 _.sortedIndex: (array, obj, iterator) ->
200 iterator ||= _.identity
201 low: 0; high: array.length
202 while low < high
203 mid: (low + high) >> 1
204 if iterator(array[mid]) < iterator(obj) then low: mid + 1 else high: mid
205 low
206
207
208
209 _.toArray: (iterable) ->
210 return [] if (!iterable)
211 return iterable.toArray() if (iterable.toArray)
212 return iterable if (_.isArray(iterable))
213 return slice.call(iterable) if (_.isArguments(iterable))
214 _.values(iterable)
215
216
217
218 _.size: (obj) -> _.toArray(obj).length
219
220
221
222
223
224
225
226 _.first: (array, n, guard) ->
227 if n and not guard then slice.call(array, 0, n) else array[0]
228
229
230
231
232
233
234 _.rest: (array, index, guard) ->
235 slice.call(array, if _.isUndefined(index) or guard then 1 else index)
236
237
238
239 _.last: (array) -> array[array.length - 1]
240
241
242
243 _.compact: (array) -> item for item in array when item
244
245
246
247 _.flatten: (array) ->
248 _.reduce array, [], (memo, value) ->
249 return memo.concat(_.flatten(value)) if _.isArray(value)
250 memo.push(value)
251 memo
252
253
254
255 _.without: (array) ->
256 values: _.rest(arguments)
257 val for val in _.toArray(array) when not _.include(values, val)
258
259
260
261
262 _.uniq: (array, isSorted) ->
263 memo: []
264 for el, i in _.toArray(array)
265 memo.push(el) if i is 0 || (if isSorted is true then _.last(memo) isnt el else not _.include(memo, el))
266 memo
267
268
269
270
271 _.intersect: (array) ->
272 rest: _.rest(arguments)
273 _.select _.uniq(array), (item) ->
274 _.all rest, (other) ->
275 _.indexOf(other, item) >= 0
276
277
278
279
280 _.zip: ->
281 length: _.max(_.pluck(arguments, 'length'))
282 results: new Array(length)
283 for i in [0...length]
284 results[i]: _.pluck(arguments, String(i))
285 results
286
287
288
289
290
291 _.indexOf: (array, item) ->
292 return array.indexOf(item) if array.indexOf
293 i: 0; l: array.length
294 while l - i
295 if array[i] is item then return i else i++
296 -1
297
298
299
300
301 _.lastIndexOf: (array, item) ->
302 return array.lastIndexOf(item) if array.lastIndexOf
303 i: array.length
304 while i
305 if array[i] is item then return i else i--
306 -1
307
308
309
310
311
312 _.range: (start, stop, step) ->
313 a: arguments
314 solo: a.length <= 1
315 i: start: if solo then 0 else a[0]
316 stop: if solo then a[0] else a[1]
317 step: a[2] or 1
318 len: Math.ceil((stop - start) / step)
319 return [] if len <= 0
320 range: new Array(len)
321 idx: 0
322 while true
323 return range if (if step > 0 then i - stop else stop - i) >= 0
324 range[idx]: i
325 idx++
326 i+= step
327
328
329
330
331
332
333 _.bind: (func, obj) ->
334 args: _.rest(arguments, 2)
335 -> func.apply(obj or root, args.concat(arguments))
336
337
338
339
340 _.bindAll: (obj) ->
341 funcs: if arguments.length > 1 then _.rest(arguments) else _.functions(obj)
342 _.each(funcs, (f) -> obj[f]: _.bind(obj[f], obj))
343 obj
344
345
346
347
348 _.delay: (func, wait) ->
349 args: _.rest(arguments, 2)
350 setTimeout((-> func.apply(func, args)), wait)
351
352
353
354
355 _.defer: (func) ->
356 _.delay.apply(_, [func, 1].concat(_.rest(arguments)))
357
358
359
360
361
362 _.wrap: (func, wrapper) ->
363 -> wrapper.apply(wrapper, [func].concat(arguments))
364
365
366
367
368 _.compose: ->
369 funcs: arguments
370 ->
371 args: arguments
372 for i in [(funcs.length - 1)..0]
373 args: [funcs[i].apply(this, args)]
374 args[0]
375
376
377
378
379
380 _.keys: (obj) ->
381 return _.range(0, obj.length) if _.isArray(obj)
382 key for key, val of obj
383
384
385
386 _.values: (obj) ->
387 _.map(obj, _.identity)
388
389
390
391 _.functions: (obj) ->
392 _.select(_.keys(obj), (key) -> _.isFunction(obj[key])).sort()
393
394
395
396 _.extend: (destination, source) ->
397 for key, val of source
398 destination[key]: val
399 destination
400
401
402
403 _.clone: (obj) ->
404 return obj.slice(0) if _.isArray(obj)
405 _.extend({}, obj)
406
407
408
409
410 _.tap: (obj, interceptor) ->
411 interceptor(obj)
412 obj
413
414
415
416 _.isEqual: (a, b) ->
417
418 return true if a is b
419
420 atype: typeof(a); btype: typeof(b)
421 return false if atype isnt btype
422
423 return true if `a == b`
424
425 return false if (!a and b) or (a and !b)
426
427 return a.isEqual(b) if a.isEqual
428
429 return a.getTime() is b.getTime() if _.isDate(a) and _.isDate(b)
430
431 return true if _.isNaN(a) and _.isNaN(b)
432
433 if _.isRegExp(a) and _.isRegExp(b)
434 return a.source is b.source and
435 a.global is b.global and
436 a.ignoreCase is b.ignoreCase and
437 a.multiline is b.multiline
438
439 return false if atype isnt 'object'
440
441 return false if a.length and (a.length isnt b.length)
442
443 aKeys: _.keys(a); bKeys: _.keys(b)
444
445 return false if aKeys.length isnt bKeys.length
446
447
448 return true
449
450
451
452 _.isEmpty: (obj) -> _.keys(obj).length is 0
453
454
455
456 _.isElement: (obj) -> obj and obj.nodeType is 1
457
458
459
460 _.isArray: (obj) -> !!(obj and obj.concat and obj.unshift)
461
462
463
464 _.isArguments: (obj) -> obj and _.isNumber(obj.length) and not obj.concat and
465 not obj.substr and not obj.apply and not propertyIsEnumerable.call(obj, 'length')
466
467
468
469 _.isFunction: (obj) -> !!(obj and obj.constructor and obj.call and obj.apply)
470
471
472
473 _.isString: (obj) -> !!(obj is '' or (obj and obj.charCodeAt and obj.substr))
474
475
476
477 _.isNumber: (obj) -> (obj is +obj) or toString.call(obj) is '[object Number]'
478
479
480
481 _.isDate: (obj) -> !!(obj and obj.getTimezoneOffset and obj.setUTCFullYear)
482
483
484
485 _.isRegExp: (obj) -> !!(obj and obj.exec and (obj.ignoreCase or obj.ignoreCase is false))
486
487
488
489
490 _.isNaN: (obj) -> _.isNumber(obj) and window.isNaN(obj)
491
492
493
494 _.isNull: (obj) -> obj is null
495
496
497
498 _.isUndefined: (obj) -> typeof obj is 'undefined'
499
500
501
502
503
504
505 _.noConflict: ->
506 root._: previousUnderscore
507 this
508
509
510
511 _.identity: (value) -> value
512
513
514
515 _.breakLoop: -> throw breaker
516
517
518
519
520 idCounter: 0
521 _.uniqueId: (prefix) ->
522 (prefix or '') + idCounter++
523
524
525
526
527 _.templateSettings: {
528 start: '<%'
529 end: '%>'
530 interpolate: /<%=(.+?)%>/g
531 }
532
533
534
535
536
537 _.template: (str, data) ->
538 c: _.templateSettings
539 fn: new Function 'obj',
540 'var p=[],print=function(){p.push.apply(p,arguments);};' +
541 'with(obj){p.push(\'' +
542 str.replace(/[\r\t\n]/g, " ")
543 .replace(new RegExp("'(?=[^"+c.end[0]+"]*"+c.end+")","g"),"\t")
544 .split("'").join("\\'")
545 .split("\t").join("'")
546 .replace(c.interpolate, "',$1,'")
547 .split(c.start).join("');")
548 .split(c.end).join("p.push('") +
549 "');}return p.join('');"
550 if data then fn(data) else fn
551
552
553
554
555 _.forEach: _.each
556 _.foldl: _.inject: _.reduce
557 _.foldr: _.reduceRight
558 _.filter: _.select
559 _.every: _.all
560 _.some: _.any
561 _.head: _.first
562 _.tail: _.rest
563 _.methods: _.functions
564
565
566
567
568
569 result: (obj, chain) ->
570 if chain then _(obj).chain() else obj
571
572
573
574 _.each _.functions(_), (name) ->
575 method: _[name]
576 wrapper.prototype[name]: ->
577 unshift.call(arguments, this._wrapped)
578 result(method.apply(_, arguments), this._chain)
579
580
581
582 _.each ['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], (name) ->
583 method: Array.prototype[name]
584 wrapper.prototype[name]: ->
585 method.apply(this._wrapped, arguments)
586 result(this._wrapped, this._chain)
587
588
589
590 _.each ['concat', 'join', 'slice'], (name) ->
591 method: Array.prototype[name]
592 wrapper.prototype[name]: ->
593 result(method.apply(this._wrapped, arguments), this._chain)
594
595
596
597 wrapper::chain: ->
598 this._chain: true
599 this
600
601
602
603 wrapper::value: -> this._wrapped