1 
   2    # Underscore.coffee
   3    # (c) 2009 Jeremy Ashkenas, DocumentCloud Inc.
   4    # Underscore is freely distributable under the terms of the MIT license.
   5    # Portions of Underscore are inspired by or borrowed from Prototype.js,
   6    # Oliver Steele's Functional, and John Resig's Micro-Templating.
   7    # For all details and documentation:
   8    # http://documentcloud.github.com/underscore/
   9 
  10 
  11    # ------------------------- Baseline setup ---------------------------------
  12 
  13    # Establish the root object, "window" in the browser, or "global" on the server.
  14    root: this
  15 
  16 
  17    # Save the previous value of the "_" variable.
  18    previousUnderscore: root._
  19 
  20 
  21    # If Underscore is called as a function, it returns a wrapped object that
  22    # can be used OO-style. This wrapper holds altered versions of all the
  23    # underscore functions. Wrapped objects may be chained.
  24    wrapper: obj =>
  25      this._wrapped: obj
  26      this
  27 
  28 
  29    # Establish the object that gets thrown to break out of a loop iteration.
  30    breaker: if typeof(StopIteration) is 'undefined' then '__break__' else StopIteration
  31 
  32 
  33    # Create a safe reference to the Underscore object for reference below.
  34    _: root._: obj => new wrapper(obj)
  35 
  36 
  37    # Export the Underscore object for CommonJS.
  38    if typeof(exports) != 'undefined' then exports._: _
  39 
  40 
  41    # Create quick reference variables for speed access to core prototypes.
  42    slice:                Array.prototype.slice
  43    unshift:              Array.prototype.unshift
  44    toString:             Object.prototype.toString
  45    hasOwnProperty:       Object.prototype.hasOwnProperty
  46    propertyIsEnumerable: Object.prototype.propertyIsEnumerable
  47 
  48 
  49    # Current version.
  50    _.VERSION: '0.5.3'
  51 
  52 
  53    # ------------------------ Collection Functions: ---------------------------
  54 
  55    # The cornerstone, an each implementation.
  56    # Handles objects implementing forEach, arrays, and raw objects.
  57    _.each: obj, iterator, context =>
  58      index: 0
  59      try
  60        return obj.forEach(iterator, context) if obj.forEach
  61        if _.isArray(obj) or _.isArguments(obj)
  62          return iterator.call(context, obj[i], i, obj) for i in [0...obj.length]
  63        iterator.call(context, val, key, obj) for val, key in obj
  64      catch e
  65        throw e if e isnt breaker
  66      obj
  67 
  68 
  69    # Return the results of applying the iterator to each element. Use JavaScript
  70    # 1.6's version of map, if possible.
  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    # Reduce builds up a single result from a list of values. Also known as
  80    # inject, or foldl. Uses JavaScript 1.8's version of reduce, if possible.
  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    # The right-associative version of reduce, also known as foldr. Uses
  89    # JavaScript 1.8's version of reduceRight, if available.
  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    # Return the first value which passes a truth test.
  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    # Return all the elements that pass a truth test. Use JavaScript 1.6's
 108    # filter(), if it exists.
 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    # Return all the elements for which a truth test fails.
 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    # Determine whether all of the elements match a truth test. Delegate to
 126    # JavaScript 1.6's every(), if it is present.
 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    # Determine if at least one element in the object matches a truth test. Use
 137    # JavaScript 1.6's some(), if it exists.
 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    # Determine if a given value is included in the array or object,
 148    # based on '==='.
 149    _.include: obj, target =>
 150      return _.indexOf(obj, target) isnt -1 if _.isArray(obj)
 151      for val in obj
 152        return true if val is target
 153      false
 154 
 155 
 156    # Invoke a method with arguments on every item in a collection.
 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    # Convenience version of a common use case of map: fetching a property.
 163    _.pluck: obj, key =>
 164      _.map(obj, (val => val[key]))
 165 
 166 
 167    # Return the maximum item or (item-based computation).
 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    # Return the minimum element (or element-based computation).
 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    # Sort the object's values by a criteria produced by an iterator.
 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    # Use a comparator function to figure out at what index an object should
 198    # be inserted so as to maintain order. Uses binary search.
 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    # Convert anything iterable into a real, live array.
 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    # Return the number of elements in an object.
 218    _.size: obj => _.toArray(obj).length
 219 
 220 
 221    # -------------------------- Array Functions: ------------------------------
 222 
 223    # Get the first element of an array. Passing "n" will return the first N
 224    # values in the array. Aliased as "head". The "guard" check allows it to work
 225    # with _.map.
 226    _.first: array, n, guard =>
 227      if n and not guard then slice.call(array, 0, n) else array[0]
 228 
 229 
 230    # Returns everything but the first entry of the array. Aliased as "tail".
 231    # Especially useful on the arguments object. Passing an "index" will return
 232    # the rest of the values in the array from that index onward. The "guard"
 233    # check allows it to work with _.map.
 234    _.rest: array, index, guard =>
 235      slice.call(array, if _.isUndefined(index) or guard then 1 else index)
 236 
 237 
 238    # Get the last element of an array.
 239    _.last: array => array[array.length - 1]
 240 
 241 
 242    # Trim out all falsy values from an array.
 243    _.compact: array => array[i] for i in [0...array.length] when array[i]
 244 
 245 
 246    # Return a completely flattened version of an array.
 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    # Return a version of the array that does not contain the specified value(s).
 255    _.without: array =>
 256      values: _.rest(arguments)
 257      val for val in _.toArray(array) when not _.include(values, val)
 258 
 259 
 260    # Produce a duplicate-free version of the array. If the array has already
 261    # been sorted, you have the option of using a faster algorithm.
 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    # Produce an array that contains every item shared between all the
 270    # passed-in arrays.
 271    _.intersect: array =>
 272      rest: _.rest(arguments)
 273      _.select(_.uniq(array)) item =>
 274        _.all(rest) other =>
 275          _.indexOf(other, item) >= 0
 276 
 277 
 278    # Zip together multiple lists into a single array -- elements that share
 279    # an index go together.
 280    _.zip: =>
 281      args:       _.toArray(arguments)
 282      length:     _.max(_.pluck(args, 'length'))
 283      results:    new Array(length)
 284      for i in [0...length]
 285        results[i]: _.pluck(args, String(i))
 286      results
 287 
 288 
 289    # If the browser doesn't supply us with indexOf (I'm looking at you, MSIE),
 290    # we need this function. Return the position of the first occurence of an
 291    # item in an array, or -1 if the item is not included in the array.
 292    _.indexOf: array, item =>
 293      return array.indexOf(item) if array.indexOf
 294      i: 0; l: array.length
 295      while l - i
 296        if array[i] is item then return i else i++
 297      -1
 298 
 299 
 300    # Provide JavaScript 1.6's lastIndexOf, delegating to the native function,
 301    # if possible.
 302    _.lastIndexOf: array, item =>
 303      return array.lastIndexOf(item) if array.lastIndexOf
 304      i: array.length
 305      while i
 306        if array[i] is item then return i else i--
 307      -1
 308 
 309 
 310    # Generate an integer Array containing an arithmetic progression. A port of
 311    # the native Python range() function. See:
 312    # http://docs.python.org/library/functions.html#range
 313    _.range: start, stop, step =>
 314      a:        _.toArray(arguments)
 315      solo:     a.length <= 1
 316      i: start: if solo then 0 else a[0];
 317      stop:     if solo then a[0] else a[1];
 318      step:     a[2] or 1
 319      len:      Math.ceil((stop - start) / step)
 320      return [] if len <= 0
 321      range:    new Array(len)
 322      idx:      0
 323      while true
 324        return range if (if step > 0 then i - stop else stop - i) >= 0
 325        range[idx]: i
 326        idx++
 327        i+= step
 328 
 329 
 330    # ----------------------- Function Functions: -----------------------------
 331 
 332    # Create a function bound to a given object (assigning 'this', and arguments,
 333    # optionally). Binding with arguments is also known as 'curry'.
 334    _.bind: func, obj =>
 335      args: _.rest(arguments, 2)
 336      => func.apply(obj or root, args.concat(_.toArray(arguments)))
 337 
 338 
 339    # Bind all of an object's methods to that object. Useful for ensuring that
 340    # all callbacks defined on an object belong to it.
 341    _.bindAll: obj =>
 342      funcs: if arguments.length > 1 then _.rest(arguments) else _.functions(obj)
 343      _.each(funcs, (f => obj[f]: _.bind(obj[f], obj)))
 344      obj
 345 
 346 
 347    # Delays a function for the given number of milliseconds, and then calls
 348    # it with the arguments supplied.
 349    _.delay: func, wait =>
 350      args: _.rest(arguments, 2)
 351      setTimeout((=> func.apply(func, args)), wait)
 352 
 353 
 354    # Defers a function, scheduling it to run after the current call stack has
 355    # cleared.
 356    _.defer: func =>
 357      _.delay.apply(_, [func, 1].concat(_.rest(arguments)))
 358 
 359 
 360    # Returns the first function passed as an argument to the second,
 361    # allowing you to adjust arguments, run code before and after, and
 362    # conditionally execute the original function.
 363    _.wrap: func, wrapper =>
 364      => wrapper.apply(wrapper, [func].concat(_.toArray(arguments)))
 365 
 366 
 367    # Returns a function that is the composition of a list of functions, each
 368    # consuming the return value of the function that follows.
 369    _.compose: =>
 370      funcs: _.toArray(arguments)
 371      =>
 372        args: _.toArray(arguments)
 373        for i in [(funcs.length - 1)..0]
 374          args: [funcs[i].apply(this, args)]
 375        args[0]
 376 
 377 
 378    # ------------------------- Object Functions: ----------------------------
 379 
 380    # Retrieve the names of an object's properties.
 381    _.keys: obj =>
 382      return _.range(0, obj.length) if _.isArray(obj)
 383      key for val, key in obj
 384 
 385 
 386    # Retrieve the values of an object's properties.
 387    _.values: obj =>
 388      _.map(obj, _.identity)
 389 
 390 
 391    # Return a sorted list of the function names available in Underscore.
 392    _.functions: obj =>
 393      _.select(_.keys(obj), key => _.isFunction(obj[key])).sort()
 394 
 395 
 396    # Extend a given object with all of the properties in a source object.
 397    _.extend: destination, source =>
 398      for val, key in source
 399        destination[key]: val
 400      destination
 401 
 402 
 403    # Create a (shallow-cloned) duplicate of an object.
 404    _.clone: obj =>
 405      return obj.slice(0) if _.isArray(obj)
 406      _.extend({}, obj)
 407 
 408 
 409    # Invokes interceptor with the obj, and then returns obj.
 410    # The primary purpose of this method is to "tap into" a method chain, in order to perform operations on intermediate results within the chain.
 411    _.tap: obj, interceptor =>
 412      interceptor(obj)
 413      obj
 414 
 415 
 416    # Perform a deep comparison to check if two objects are equal.
 417    _.isEqual: a, b =>
 418      # Check object identity.
 419      return true if a is b
 420      # Different types?
 421      atype: typeof(a); btype: typeof(b)
 422      return false if atype isnt btype
 423      # Basic equality test (watch out for coercions).
 424      return true if `a == b`
 425      # One is falsy and the other truthy.
 426      return false if (!a and b) or (a and !b)
 427      # One of them implements an isEqual()?
 428      return a.isEqual(b) if a.isEqual
 429      # Check dates' integer values.
 430      return a.getTime() is b.getTime() if _.isDate(a) and _.isDate(b)
 431      # Both are NaN?
 432      return true if _.isNaN(a) and _.isNaN(b)
 433      # Compare regular expressions.
 434      if _.isRegExp(a) and _.isRegExp(b)
 435        return a.source     is b.source and
 436               a.global     is b.global and
 437               a.ignoreCase is b.ignoreCase and
 438               a.multiline  is b.multiline
 439      # If a is not an object by this point, we can't handle it.
 440      return false if atype isnt 'object'
 441      # Check for different array lengths before comparing contents.
 442      return false if a.length and (a.length isnt b.length)
 443      # Nothing else worked, deep compare the contents.
 444      aKeys: _.keys(a); bKeys: _.keys(b)
 445      # Different object sizes?
 446      return false if aKeys.length isnt bKeys.length
 447      # Recursive comparison of contents.
 448      # for (var key in a) if (!_.isEqual(a[key], b[key])) return false;
 449      return true
 450 
 451 
 452    # Is a given array or object empty?
 453    _.isEmpty:      obj => _.keys(obj).length is 0
 454 
 455 
 456    # Is a given value a DOM element?
 457    _.isElement:    obj => obj and obj.nodeType is 1
 458 
 459 
 460    # Is a given value an array?
 461    _.isArray:      obj => !!(obj and obj.concat and obj.unshift)
 462 
 463 
 464    # Is a given variable an arguments object?
 465    _.isArguments:  obj => obj and _.isNumber(obj.length) and !_.isArray(obj) and !propertyIsEnumerable.call(obj, 'length')
 466 
 467 
 468    # Is the given value a function?
 469    _.isFunction:   obj => !!(obj and obj.constructor and obj.call and obj.apply)
 470 
 471 
 472    # Is the given value a string?
 473    _.isString:     obj => !!(obj is '' or (obj and obj.charCodeAt and obj.substr))
 474 
 475 
 476    # Is a given value a number?
 477    _.isNumber:     obj => toString.call(obj) is '[object Number]'
 478 
 479 
 480    # Is a given value a Date?
 481    _.isDate:       obj => !!(obj and obj.getTimezoneOffset and obj.setUTCFullYear)
 482 
 483 
 484    # Is the given value a regular expression?
 485    _.isRegExp:     obj => !!(obj and obj.exec and (obj.ignoreCase or obj.ignoreCase is false))
 486 
 487 
 488    # Is the given value NaN -- this one is interesting. NaN != NaN, and
 489    # isNaN(undefined) == true, so we make sure it's a number first.
 490    _.isNaN:        obj => _.isNumber(obj) and window.isNaN(obj)
 491 
 492 
 493    # Is a given value equal to null?
 494    _.isNull:       obj => obj is null
 495 
 496 
 497    # Is a given variable undefined?
 498    _.isUndefined:  obj => typeof obj is 'undefined'
 499 
 500 
 501    # -------------------------- Utility Functions: --------------------------
 502 
 503    # Run Underscore.js in noConflict mode, returning the '_' variable to its
 504    # previous owner. Returns a reference to the Underscore object.
 505    _.noConflict: =>
 506      root._: previousUnderscore
 507      this
 508 
 509 
 510    # Keep the identity function around for default iterators.
 511    _.identity: value => value
 512 
 513 
 514    # Break out of the middle of an iteration.
 515    _.breakLoop: => throw breaker
 516 
 517 
 518    # Generate a unique integer id (unique within the entire client session).
 519    # Useful for temporary DOM ids.
 520    idCounter: 0
 521    _.uniqueId: prefix =>
 522      (prefix or '') + idCounter++
 523 
 524 
 525    # JavaScript templating a-la ERB, pilfered from John Resig's
 526    # "Secrets of the JavaScript Ninja", page 83.
 527    _.template: str, data =>
 528      `var fn = new Function('obj',
 529        'var p=[],print=function(){p.push.apply(p,arguments);};' +
 530        'with(obj){p.push(\'' +
 531        str.
 532          replace(/[\r\t\n]/g, " ").
 533          split("<%").join("\t").
 534          replace(/((^|%>)[^\t]*)'/g, "$1\r").
 535          replace(/\t=(.*?)%>/g, "',$1,'").
 536          split("\t").join("');").
 537          split("%>").join("p.push('").
 538          split("\r").join("\\'") +
 539        "');}return p.join('');")`
 540      if data then fn(data) else fn
 541 
 542 
 543    # ------------------------------- Aliases ----------------------------------
 544 
 545    _.forEach: _.each
 546    _.foldl:   _.inject:      _.reduce
 547    _.foldr:   _.reduceRight
 548    _.filter:  _.select
 549    _.every:   _.all
 550    _.some:    _.any
 551    _.head:    _.first
 552    _.tail:    _.rest
 553    _.methods: _.functions
 554 
 555 
 556    #   /*------------------------ Setup the OOP Wrapper: --------------------------*/
 557 
 558    # Helper function to continue chaining intermediate results.
 559    result: obj, chain =>
 560      if chain then _(obj).chain() else obj
 561 
 562 
 563    # Add all of the Underscore functions to the wrapper object.
 564    _.each(_.functions(_)) name =>
 565      method: _[name]
 566      wrapper.prototype[name]: =>
 567        unshift.call(arguments, this._wrapped)
 568        result(method.apply(_, arguments), this._chain)
 569 
 570 
 571    # Add all mutator Array functions to the wrapper.
 572    _.each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift']) name =>
 573      method: Array.prototype[name]
 574      wrapper.prototype[name]: =>
 575        method.apply(this._wrapped, arguments)
 576        result(this._wrapped, this._chain)
 577 
 578 
 579    # Add all accessor Array functions to the wrapper.
 580    _.each(['concat', 'join', 'slice']) name =>
 581      method: Array.prototype[name]
 582      wrapper.prototype[name]: =>
 583        result(method.apply(this._wrapped, arguments), this._chain)
 584 
 585 
 586    # Start chaining a wrapped Underscore object.
 587    wrapper.prototype.chain: =>
 588      this._chain: true
 589      this
 590 
 591 
 592    # Extracts the result from a wrapped and chained object.
 593    wrapper.prototype.value: => this._wrapped