diff --git a/.gitignore b/.gitignore index 115973f647..5381d48f23 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,6 @@ presentation test.coffee parser.output -lib/coffee_script/parser.rb test/fixtures/underscore examples/beautiful_code/parse.coffee *.gem \ No newline at end of file diff --git a/Rakefile b/Rakefile index 8409bfad28..ce2a0b9783 100644 --- a/Rakefile +++ b/Rakefile @@ -25,7 +25,7 @@ namespace :build do desc "Compile and install the Ultraviolet syntax highlighter" task :ultraviolet do - sh "plist2syntax lib/coffee_script/CoffeeScript.tmbundle/Syntaxes/CoffeeScript.tmLanguage" + sh "plist2syntax extras/CoffeeScript.tmbundle/Syntaxes/CoffeeScript.tmLanguage" sh "sudo mv coffeescript.yaml /usr/local/lib/ruby/gems/1.8/gems/ultraviolet-0.10.2/syntax/coffeescript.syntax" end @@ -58,6 +58,8 @@ namespace :gem do desc 'Build and install the coffee-script gem' task :install do + verbose = "lib/coffee_script/parser.output" + FileUtils.rm(verbose) if File.exists?(verbose) sh "gem build coffee-script.gemspec" sh "sudo gem install #{Dir['*.gem'].join(' ')} --local --no-ri --no-rdoc" end diff --git a/coffee-script.gemspec b/coffee-script.gemspec index df04ad5e5f..8fdf3e5341 100644 --- a/coffee-script.gemspec +++ b/coffee-script.gemspec @@ -1,7 +1,7 @@ Gem::Specification.new do |s| s.name = 'coffee-script' - s.version = '0.2.6' # Keep version in sync with coffee-script.rb - s.date = '2010-1-17' + s.version = '0.3.0' # Keep version in sync with coffee-script.rb + s.date = '2010-1-26' s.homepage = "http://jashkenas.github.com/coffee-script/" s.summary = "The CoffeeScript Compiler" @@ -22,5 +22,6 @@ Gem::Specification.new do |s| s.require_paths = ['lib'] s.executables = ['coffee'] - s.files = Dir['bin/*', 'examples/*', 'lib/**/*', 'coffee-script.gemspec', 'LICENSE', 'README', 'package.json'] + s.files = Dir['bin/*', 'examples/*', 'extras/**/*', 'lib/**/*', + 'coffee-script.gemspec', 'LICENSE', 'README', 'package.json'] end \ No newline at end of file diff --git a/documentation/coffee/arguments.coffee b/documentation/coffee/arguments.coffee index fd4f2fbaee..ac548c127b 100644 --- a/documentation/coffee/arguments.coffee +++ b/documentation/coffee/arguments.coffee @@ -1,4 +1,4 @@ -backwards: => - alert(arguments.reverse()) +backwards: -> + alert arguments.reverse() -backwards("stairway", "to", "heaven") \ No newline at end of file +backwards "stairway", "to", "heaven" \ No newline at end of file diff --git a/documentation/coffee/array_comprehensions.coffee b/documentation/coffee/array_comprehensions.coffee index 3510e1fb0a..2a90a136e7 100644 --- a/documentation/coffee/array_comprehensions.coffee +++ b/documentation/coffee/array_comprehensions.coffee @@ -4,4 +4,4 @@ lunch: eat(food) for food in ['toast', 'cheese', 'wine'] # Naive collision detection. for roid in asteroids for roid2 in asteroids when roid isnt roid2 - roid.explode() if roid.overlaps(roid2) \ No newline at end of file + roid.explode() if roid.overlaps roid2 \ No newline at end of file diff --git a/documentation/coffee/blocks.coffee b/documentation/coffee/blocks.coffee deleted file mode 100644 index 6f31ee164c..0000000000 --- a/documentation/coffee/blocks.coffee +++ /dev/null @@ -1,4 +0,0 @@ -$('table.list').each() table => - $('tr.account', table).each() row => - row.show() - row.highlight() diff --git a/documentation/coffee/expressions.coffee b/documentation/coffee/expressions.coffee index fa0c1e3af4..74a02466df 100644 --- a/documentation/coffee/expressions.coffee +++ b/documentation/coffee/expressions.coffee @@ -1,4 +1,4 @@ -grade: student => +grade: (student) -> if student.excellent_work "A+" else if student.okay_stuff diff --git a/documentation/coffee/expressions_try.coffee b/documentation/coffee/expressions_try.coffee index 7b635287db..13fdfec201 100644 --- a/documentation/coffee/expressions_try.coffee +++ b/documentation/coffee/expressions_try.coffee @@ -2,5 +2,5 @@ alert( try nonexistent / undefined catch error - "Caught an error: " + error + "And the error is ... " + error ) \ No newline at end of file diff --git a/documentation/coffee/fat_arrow.coffee b/documentation/coffee/fat_arrow.coffee new file mode 100644 index 0000000000..4b7759d37f --- /dev/null +++ b/documentation/coffee/fat_arrow.coffee @@ -0,0 +1,6 @@ +Account: (customer, cart) -> + this.customer: customer + this.cart: cart + + $('.shopping_cart').bind 'click', (event) => + this.customer.purchase this.cart \ No newline at end of file diff --git a/documentation/coffee/functions.coffee b/documentation/coffee/functions.coffee index ccc9401df5..4fd48d32f7 100644 --- a/documentation/coffee/functions.coffee +++ b/documentation/coffee/functions.coffee @@ -1,2 +1,2 @@ -square: x => x * x -cube: x => square(x) * x +square: (x) -> x * x +cube: (x) -> square(x) * x diff --git a/documentation/coffee/long_arrow.coffee b/documentation/coffee/long_arrow.coffee deleted file mode 100644 index 86c64e9be4..0000000000 --- a/documentation/coffee/long_arrow.coffee +++ /dev/null @@ -1,6 +0,0 @@ -Account: customer, cart => - this.customer: customer - this.cart: cart - - $('.shopping_cart').bind('click') event ==> - this.customer.purchase(this.cart) \ No newline at end of file diff --git a/documentation/coffee/multiple_return_values.coffee b/documentation/coffee/multiple_return_values.coffee index d175cc8043..3fe572b1d9 100644 --- a/documentation/coffee/multiple_return_values.coffee +++ b/documentation/coffee/multiple_return_values.coffee @@ -1,5 +1,5 @@ -weather_report: location => +weather_report: (location) -> # Make an Ajax request to fetch the weather... [location, 72, "Mostly Sunny"] -[city, temp, forecast]: weather_report("Berkeley, CA") \ No newline at end of file +[city, temp, forecast]: weather_report "Berkeley, CA" \ No newline at end of file diff --git a/documentation/coffee/overview.coffee b/documentation/coffee/overview.coffee index 6c940d9fd2..23bdb4bd85 100644 --- a/documentation/coffee/overview.coffee +++ b/documentation/coffee/overview.coffee @@ -6,7 +6,7 @@ opposite_day: true number: -42 if opposite_day # Functions: -square: x => x * x +square: (x) -> x * x # Arrays: list: [1, 2, 3, 4, 5] @@ -15,15 +15,15 @@ list: [1, 2, 3, 4, 5] math: { root: Math.sqrt square: square - cube: x => x * square(x) + cube: (x) -> x * square x } # Splats: -race: winner, runners... => - print(winner, runners) +race: (winner, runners...) -> + print winner, runners # Existence: -alert("I knew it!") if elvis? +alert "I knew it!" if elvis? # Array comprehensions: -cubed_list: math.cube(num) for num in list +cubed_list: math.cube num for num in list diff --git a/documentation/coffee/range_comprehensions.coffee b/documentation/coffee/range_comprehensions.coffee index 63ee92e2e2..33790f5a29 100644 --- a/documentation/coffee/range_comprehensions.coffee +++ b/documentation/coffee/range_comprehensions.coffee @@ -1,6 +1,6 @@ countdown: num for num in [10..1] -egg_delivery: => +egg_delivery: -> for i in [0...eggs.length] by 12 dozen_eggs: eggs[i...i+12] - deliver(new egg_carton(dozen)) + deliver new egg_carton(dozen) diff --git a/documentation/coffee/scope.coffee b/documentation/coffee/scope.coffee index b074dad293..30eedacf8a 100644 --- a/documentation/coffee/scope.coffee +++ b/documentation/coffee/scope.coffee @@ -1,5 +1,5 @@ num: 1 -change_numbers: => +change_numbers: -> new_num: -1 num: 10 new_num: change_numbers() \ No newline at end of file diff --git a/documentation/coffee/soaks.coffee b/documentation/coffee/soaks.coffee new file mode 100644 index 0000000000..964fef5b72 --- /dev/null +++ b/documentation/coffee/soaks.coffee @@ -0,0 +1 @@ +lottery.draw_winner()?.address?.zipcode diff --git a/documentation/coffee/splats.coffee b/documentation/coffee/splats.coffee index 035b902f51..9faf40155e 100644 --- a/documentation/coffee/splats.coffee +++ b/documentation/coffee/splats.coffee @@ -1,6 +1,6 @@ gold: silver: the_field: "unknown" -medalists: first, second, rest... => +award_medals: (first, second, rest...) -> gold: first silver: second the_field: rest @@ -18,8 +18,8 @@ contenders: [ "Usain Bolt" ] -medalists(contenders...) +award_medals contenders... -alert("Gold: " + gold) -alert("Silver: " + silver) -alert("The Field: " + the_field) \ No newline at end of file +alert "Gold: " + gold +alert "Silver: " + silver +alert "The Field: " + the_field \ No newline at end of file diff --git a/documentation/coffee/super.coffee b/documentation/coffee/super.coffee index a64eff39b2..b45faff0ff 100644 --- a/documentation/coffee/super.coffee +++ b/documentation/coffee/super.coffee @@ -1,21 +1,21 @@ -Animal: => -Animal::move: meters => - alert(this.name + " moved " + meters + "m.") +Animal: -> +Animal::move: (meters) -> + alert this.name + " moved " + meters + "m." -Snake: name => this.name: name +Snake: (name) -> this.name: name Snake extends Animal -Snake::move: => - alert("Slithering...") - super(5) +Snake::move: -> + alert "Slithering..." + super 5 -Horse: name => this.name: name +Horse: (name) -> this.name: name Horse extends Animal -Horse::move: => - alert("Galloping...") - super(45) +Horse::move: -> + alert "Galloping..." + super 45 -sam: new Snake("Sammy the Python") -tom: new Horse("Tommy the Palomino") +sam: new Snake "Sammy the Python" +tom: new Horse "Tommy the Palomino" sam.move() tom.move() diff --git a/documentation/coffee/try.coffee b/documentation/coffee/try.coffee index 169df020af..67f4d19763 100644 --- a/documentation/coffee/try.coffee +++ b/documentation/coffee/try.coffee @@ -2,6 +2,6 @@ try all_hell_breaks_loose() cats_and_dogs_living_together() catch error - print(error) + print error finally clean_up() \ No newline at end of file diff --git a/documentation/coffee/while.coffee b/documentation/coffee/while.coffee index 625e6ed6a1..0d2b3a21da 100644 --- a/documentation/coffee/while.coffee +++ b/documentation/coffee/while.coffee @@ -1,7 +1,9 @@ +# Econ 101 if this.studying_economics while supply > demand then buy() while supply < demand then sell() +# Nursery Rhyme num: 6 lyrics: while num -= 1 num + " little monkeys, jumping on the bed. diff --git a/documentation/css/docs.css b/documentation/css/docs.css index 1a4361f3a1..b105dd8319 100644 --- a/documentation/css/docs.css +++ b/documentation/css/docs.css @@ -6,7 +6,7 @@ body { font-family: Arial, Helvetica, sans-serif; } div.container { - width: 850px; + width: 950px; margin: 50px 0 50px 50px; } p { @@ -77,7 +77,7 @@ div.code { } div.code pre { float: left; - width: 410px; + width: 450px; border-left: 1px dotted #559; padding: 0 0 0 12px; margin: 0; diff --git a/documentation/css/idle.css b/documentation/css/idle.css index eca8faf960..23667531d3 100644 --- a/documentation/css/idle.css +++ b/documentation/css/idle.css @@ -28,6 +28,7 @@ pre.idle .LibraryConstant { color: #A535AE; } pre.idle .FunctionArgument { + color: #0076ad; } pre.idle .BuiltInConstant { color: #A535AE; diff --git a/documentation/index.html.erb b/documentation/index.html.erb index 145d2e097b..6ab260f8c0 100644 --- a/documentation/index.html.erb +++ b/documentation/index.html.erb @@ -51,7 +51,7 @@
Latest Version: - 0.2.6 + 0.3.0
-e, --eval
-v, --verbose
+ You don't need to use parentheses to invoke a function, if you're passing
+ arguments:
print "coffee"
+
You can use newlines to break up your expression into smaller pieces, - as long as CoffeeScript can tell that the line hasn't finished - (similar to how Ruby handles it). For example, - if the line ends in an operator, dot, or keyword. + as long as CoffeeScript can determine that the line hasn't finished yet.
Functions and Invocation Functions are defined by a list of parameters, an arrow, and the - function body. The empty function looks like this: =>. All - functions in CoffeeScript are named by default, for the benefit of debug messages. - If you'd like to create an anonymous function, just wrap it in parentheses. + function body. The empty function looks like this: ->. All + functions in CoffeeScript are named by default, for easier debugging.
<%= code_for('functions', 'cube(5)') %> ++ If you'd like to create an anonymous function, just wrap it in parentheses: + ((x) -> x * x) +
Assignment @@ -272,7 +276,7 @@ coffee --print app/scripts/*.coffee > concatenation.js
<%= code_for('assignment', 'greeting') %>- Declarations of new variables are pushed up to the top of the nearest + Declaration of new variables are pushed up to the top of the nearest lexical scope, so that assignment may always be performed within expressions.
@@ -281,7 +285,7 @@ coffee --print app/scripts/*.coffee > concatenation.js Object and Array literals look very similar to their JavaScript cousins. When you spread out each assignment on a separate line, the commas are optional. In this way, assigning object properties looks the same as - assigning local variables, and can be moved around freely. You can mix + assigning local variables, and can be moved around freely. Feel free to mix and match the two styles. <%= code_for('objects_and_arrays', 'song.join(",")') %> @@ -306,9 +310,14 @@ coffee --print app/scripts/*.coffee > concatenation.js CoffeeScript output is wrapped in an anonymous function: (function(){ ... })(); This safety wrapper, combined with the automatic generation of the var keyword, make it exceedingly difficult - to pollute the global namespace by accident. If you'd like to create - global variables, attach them as properties on window, - or on the exports object in CommonJS. + to pollute the global namespace by accident. + ++ If you'd like to create top-level variables for other scripts to use, + attach them as properties on window, or on the exports + object in CommonJS. The existential operator (below), gives you a + reliable way to figure out where to add them, if you're targeting both + CommonJS and the browser: root: exports ? this
@@ -330,20 +339,6 @@ coffee --print app/scripts/*.coffee > concatenation.js truthy variables.
-- The Existential Operator - It's a little difficult to check for the existence of a variable in - JavaScript. if (variable) ... comes close, but fails for zero, - the empty string, and false. The existential operator ? returns true unless - a variable is null or undefined, which makes it analogous - to Ruby's nil? -
-- It can also be used for safer conditional assignment than ||= - provides, for cases where you may be handling numbers or strings. -
- <%= code_for('existence', 'speed') %> -Aliases Because the == operator frequently causes undesirable coercion, @@ -379,7 +374,7 @@ coffee --print app/scripts/*.coffee > concatenation.js The JavaScript arguments object is a useful way to work with functions that accept variable numbers of arguments. CoffeeScript provides splats ..., both for function definition as well as invocation, - making variable arguments a little bit more palatable. + making variable numbers of arguments a little bit more palatable.
<%= code_for('splats', true) %> @@ -481,10 +476,39 @@ coffee --print app/scripts/*.coffee > concatenation.js <%= code_for('expressions_try', true) %>There are a handful of statements in JavaScript that can't be meaningfully - converted into expressions: break, continue, - and return. If you make use of them within a block of code, + converted into expressions, namely break, continue, + and return. If you make use of them within a block of code, CoffeeScript won't try to perform the conversion.
+ ++ The Existential Operator + It's a little difficult to check for the existence of a variable in + JavaScript. if (variable) ... comes close, but fails for zero, + the empty string, and false. CoffeeScript's existential operator ? returns true unless + a variable is null or undefined, which makes it analogous + to Ruby's nil? +
++ It can also be used for safer conditional assignment than ||= + provides, for cases where you may be handling numbers or strings. +
+ <%= code_for('existence', 'speed') %> ++ The accessor variant of the existential operator ?. can be used to soak + up null references in a chain of properties. Use it instead + of the dot accessor . in cases where the base value may be null + or undefined. If all of the properties exist then you'll get the expected + result, if the chain is broken, undefined is returned instead of + the TypeError that would be raised otherwise. +
+ <%= code_for('soaks') %> ++ Soaking up nulls is similar to Ruby's + andand gem, and to the + safe navigation operator + in Groovy. +
Inheritance, and Calling Super from a Subclass @@ -508,20 +532,6 @@ coffee --print app/scripts/*.coffee > concatenation.js
<%= code_for('super', true) %> -- Blocks - Many common looping functions (in Prototype, jQuery, and Underscore, - for example) take a single function as their final argument. To make - final functions easier to pass, CoffeeScript includes block syntax, - so you don't have to close the parentheses on the other side. -
- <%= code_for('blocks') %> -- If you prefer not to use blocks, you'll need to add a pair of parentheses - to help distinguish the arguments from the definition of the function: - _.map(array, (num => num * 2)) -
-Pattern Matching (Destructuring Assignment) To make extracting values from complex arrays and objects more convenient, @@ -544,16 +554,16 @@ coffee --print app/scripts/*.coffee > concatenation.js
<%= code_for('object_extraction', 'poet + " — " + street') %> -+
Function binding - The long arrow ==> can be used to both define a function, and to bind + The fat arrow => can be used to both define a function, and to bind it to the current value of this, right on the spot. This is helpful when using callback-based libraries like Prototype or jQuery, for creating iterator functions to pass to each, or event-handler functions - to use with bind. Functions created with the long arrow are able to access + to use with bind. Functions created with the fat arrow are able to access properties of the this where they're defined.
- <%= code_for('long_arrow') %> + <%= code_for('fat_arrow') %>Embedded JavaScript @@ -624,6 +634,12 @@ coffee --print app/scripts/*.coffee > concatenation.js
- Here's a wish list of things that would be wonderful to have contributed:
+ 0.3.0
+ CoffeeScript 0.3 includes major syntax changes:
+
+ The function symbol was changed to
+ ->, and the bound function symbol is now =>.
+
+ Parameter lists in function definitions must now be wrapped in parentheses.
+
+ Added property soaking, with the ?. operator.
+
+ Made parentheses optional, when invoking functions with arguments.
+
+ Removed the obsolete block literal syntax.
0.2.6 Added Python-style chained comparisons, the conditional existence diff --git a/documentation/js/array_comprehensions.js b/documentation/js/array_comprehensions.js index fae31ce941..85ca79927b 100644 --- a/documentation/js/array_comprehensions.js +++ b/documentation/js/array_comprehensions.js @@ -8,7 +8,7 @@ __a.push(eat(food)); } return __a; - })(); + }).call(this); // Naive collision detection. __d = asteroids; for (__e = 0; __e < __d.length; __e++) { diff --git a/documentation/js/blocks.js b/documentation/js/blocks.js deleted file mode 100644 index f95dd31b45..0000000000 --- a/documentation/js/blocks.js +++ /dev/null @@ -1,8 +0,0 @@ -(function(){ - $('table.list').each(function(table) { - return $('tr.account', table).each(function(row) { - row.show(); - return row.highlight(); - }); - }); -})(); \ No newline at end of file diff --git a/documentation/js/expressions_comprehension.js b/documentation/js/expressions_comprehension.js index 294c3db4ed..01d5ba45a5 100644 --- a/documentation/js/expressions_comprehension.js +++ b/documentation/js/expressions_comprehension.js @@ -10,5 +10,5 @@ } } return __a; - })()).slice(0, 10); + }).call(this)).slice(0, 10); })(); \ No newline at end of file diff --git a/documentation/js/expressions_try.js b/documentation/js/expressions_try.js index 7787cfb74e..79c77e40c7 100644 --- a/documentation/js/expressions_try.js +++ b/documentation/js/expressions_try.js @@ -3,7 +3,7 @@ try { return nonexistent / undefined; } catch (error) { - return "Caught an error: " + error; + return "And the error is ... " + error; } - })()); + }).call(this)); })(); \ No newline at end of file diff --git a/documentation/js/long_arrow.js b/documentation/js/fat_arrow.js similarity index 100% rename from documentation/js/long_arrow.js rename to documentation/js/fat_arrow.js diff --git a/documentation/js/object_comprehensions.js b/documentation/js/object_comprehensions.js index 9c7d3783b9..ddc81f0526 100644 --- a/documentation/js/object_comprehensions.js +++ b/documentation/js/object_comprehensions.js @@ -15,5 +15,5 @@ } } return __a; - })(); + }).call(this); })(); \ No newline at end of file diff --git a/documentation/js/overview.js b/documentation/js/overview.js index 2098e3a30f..97b0f43589 100644 --- a/documentation/js/overview.js +++ b/documentation/js/overview.js @@ -39,5 +39,5 @@ __a.push(math.cube(num)); } return __a; - })(); + }).call(this); })(); \ No newline at end of file diff --git a/documentation/js/range_comprehensions.js b/documentation/js/range_comprehensions.js index 9272dcff38..a67917f4bb 100644 --- a/documentation/js/range_comprehensions.js +++ b/documentation/js/range_comprehensions.js @@ -6,7 +6,7 @@ __a.push(num); } return __a; - })(); + }).call(this); egg_delivery = function egg_delivery() { var __f, __g, __h, __i, __j, dozen_eggs, i; __f = []; __i = 0; __j = eggs.length; @@ -14,7 +14,7 @@ __f.push((function() { dozen_eggs = eggs.slice(i, i + 12); return deliver(new egg_carton(dozen)); - })()); + }).call(this)); } return __f; }; diff --git a/documentation/js/soaks.js b/documentation/js/soaks.js new file mode 100644 index 0000000000..efacb69265 --- /dev/null +++ b/documentation/js/soaks.js @@ -0,0 +1,4 @@ +(function(){ + var __a; + ((__a = lottery.draw_winner()) == undefined ? undefined : __a.address == undefined ? undefined : __a.address.zipcode); +})(); \ No newline at end of file diff --git a/documentation/js/splats.js b/documentation/js/splats.js index 4fb2085bca..052437fe47 100644 --- a/documentation/js/splats.js +++ b/documentation/js/splats.js @@ -1,7 +1,7 @@ (function(){ - var contenders, gold, medalists, silver, the_field; + var award_medals, contenders, gold, silver, the_field; gold = (silver = (the_field = "unknown")); - medalists = function medalists(first, second) { + award_medals = function award_medals(first, second) { var rest; rest = Array.prototype.slice.call(arguments, 2); gold = first; @@ -9,7 +9,7 @@ return the_field = rest; }; contenders = ["Michael Phelps", "Liu Xiang", "Yao Ming", "Allyson Felix", "Shawn Johnson", "Roman Sebrle", "Guo Jingjing", "Tyson Gay", "Asafa Powell", "Usain Bolt"]; - medalists.apply(this, contenders); + award_medals.apply(this, contenders); alert("Gold: " + gold); alert("Silver: " + silver); alert("The Field: " + the_field); diff --git a/documentation/js/while.js b/documentation/js/while.js index 0ac87e11a4..ee7f0b06bb 100644 --- a/documentation/js/while.js +++ b/documentation/js/while.js @@ -1,5 +1,6 @@ (function(){ var __a, lyrics, num; + // Econ 101 if (this.studying_economics) { while (supply > demand) { buy(); @@ -8,6 +9,7 @@ sell(); } } + // Nursery Rhyme num = 6; lyrics = (function() { __a = []; @@ -16,5 +18,5 @@ One fell out and bumped his head."); } return __a; - })(); + }).call(this); })(); \ No newline at end of file diff --git a/documentation/underscore.html b/documentation/underscore.html index 5ce7f0cc61..357a94c0a7 100644 --- a/documentation/underscore.html +++ b/documentation/underscore.html @@ -19,7 +19,7 @@
1 2 # Underscore.coffee - 3 # (c) 2009 Jeremy Ashkenas, DocumentCloud Inc. + 3 # (c) 2010 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. @@ -40,7 +40,7 @@ 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 => + 24 wrapper: (obj) -> 25 this._wrapped: obj 26 this 27 @@ -50,7 +50,7 @@ 31 32 33 # Create a safe reference to the Underscore object forreference below. - 34 _: root._: obj => new wrapper(obj) + 34 _: root._: (obj) -> new wrapper(obj) 35 36 37 # Export the Underscore object for CommonJS. @@ -58,22 +58,22 @@ 39 40 41 # Create quick reference variables for speed access to core prototypes. - 42 slice: Array::slice - 43 unshift: Array::unshift - 44 toString: Object::toString - 45 hasOwnProperty: Object::hasOwnProperty - 46 propertyIsEnumerable: Object::propertyIsEnumerable + 42 slice: Array::slice + 43 unshift: Array::unshift + 44 toString: Object::toString + 45 hasOwnProperty: Object::hasOwnProperty + 46 propertyIsEnumerable: Object::propertyIsEnumerable 47 48 49 # Current version. - 50 _.VERSION: '0.5.5' + 50 _.VERSION: '0.5.7' 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 => + 57 _.each: (obj, iterator, context) -> 58 index: 0 59 try 60 return obj.forEach(iterator, context) if obj.forEach @@ -87,36 +87,36 @@ 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 => + 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 => + 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 => + 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 => + 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 => + 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 => + 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 => + 98 _.detect: (obj, iterator, context) -> 99 result: null - 100 _.each(obj) value, index, list => + 100 _.each obj, (value, index, list) -> 101 if iterator.call(context, value, index, list) 102 result: value 103 _.breakLoop() @@ -125,47 +125,47 @@ 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 => + 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 => + 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 => + 118 _.reject: (obj, iterator, context) -> 119 results: [] - 120 _.each(obj) value, index, list => + 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 => + 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 => + 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 => + 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 => + 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 => + 149 _.include: (obj, target) -> 150 return _.indexOf(obj, target) isnt -1 if _.isArray(obj) 151 for key, val of obj 152 return true if val is target @@ -173,49 +173,49 @@ 154 155 156 # Invoke a method with arguments on every item in a collection. - 157 _.invoke: obj, method => + 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])) + 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 => + 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 => + 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 => + 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 => + 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 => + 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 => + 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') + 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 => + 199 _.sortedIndex: (array, obj, iterator) -> 200 iterator ||= _.identity 201 low: 0; high: array.length 202 while low < high @@ -225,7 +225,7 @@ 206 207 208 # Convert anything iterable into a real, live array. - 209 _.toArray: iterable => + 209 _.toArray: (iterable) -> 210 return [] if (!iterable) 211 return iterable.toArray() if (iterable.toArray) 212 return iterable if (_.isArray(iterable)) @@ -234,7 +234,7 @@ 215 216 217 # Return the number of elements in an object. - 218 _.size: obj => _.toArray(obj).length + 218 _.size: (obj) -> _.toArray(obj).length 219 220 221 # -------------------------- Array Functions: ------------------------------ @@ -242,7 +242,7 @@ 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 => + 226 _.first: (array, n, guard) -> 227 if n and not guard then slice.call(array, 0, n) else array[0] 228 229 @@ -250,35 +250,35 @@ 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 => + 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] + 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] + 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 => + 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 => + 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 => + 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)) @@ -287,330 +287,339 @@ 268 269 # Produce an array that contains every item shared between all the 270 # passed-in arrays. - 271 _.intersect: array => + 271 _.intersect: (array) -> 272 rest: _.rest(arguments) - 273 _.select(_.uniq(array)) item => - 274 _.all(rest) other => + 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 + 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 # 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 + 288 # If the browser doesn't supply us with indexOf (I'm looking at you, MSIE), + 289 # we need this function. Return the position of the first occurence of an + 290 # item in an array, or -1 if the item is not included in the array. + 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 # 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 + 299 # Provide JavaScript 1.6's lastIndexOf, delegating to the native function, + 300 # if possible. + 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 # 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 + 309 # Generate an integer Array containing an arithmetic progression. A port of + 310 # the native Python range() function. See: + 311 # http://docs.python.org/library/functions.html#range + 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 # ----------------------- 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))) + 329 # ----------------------- Function Functions: ----------------------------- + 330 + 331 # Create a function bound to a given object (assigning 'this', and arguments, + 332 # optionally). Binding with arguments is also known as 'curry'. + 333 _.bind: (func, obj) -> + 334 args: _.rest(arguments, 2) + 335 -> func.apply(obj or root, args.concat(arguments)) + 336 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 + 338 # Bind all of an object's methods to that object. Useful for ensuring that + 339 # all callbacks defined on an object belong to it. + 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 # 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) + 346 # Delays a function for the given number of milliseconds, and then calls + 347 # it with the arguments supplied. + 348 _.delay: (func, wait) -> + 349 args: _.rest(arguments, 2) + 350 setTimeout((-> func.apply(func, args)), wait) + 351 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))) + 353 # Defers a function, scheduling it to run after the current call stack has + 354 # cleared. + 355 _.defer: (func) -> + 356 _.delay.apply(_, [func, 1].concat(_.rest(arguments))) + 357 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))) + 359 # Returns the first function passed as an argument to the second, + 360 # allowing you to adjust arguments, run code before and after, and + 361 # conditionally execute the original function. + 362 _.wrap: (func, wrapper) -> + 363 -> wrapper.apply(wrapper, [func].concat(arguments)) + 364 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] + 366 # Returns a function that is the composition of a list of functions, each + 367 # consuming the return value of the function that follows. + 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 # ------------------------- 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 key, val of obj + 377 # ------------------------- Object Functions: ---------------------------- + 378 + 379 # Retrieve the names of an object's properties. + 380 _.keys: (obj) -> + 381 return _.range(0, obj.length) if _.isArray(obj) + 382 key for key, val of obj + 383 384 - 385 - 386 # Retrieve the values of an object's properties. - 387 _.values: obj => - 388 _.map(obj, _.identity) + 385 # Retrieve the values of an object's properties. + 386 _.values: (obj) -> + 387 _.map(obj, _.identity) + 388 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() + 390 # Return a sorted list of the function names available in Underscore. + 391 _.functions: (obj) -> + 392 _.select(_.keys(obj), (key) -> _.isFunction(obj[key])).sort() + 393 394 - 395 - 396 # Extend a given object with all of the properties in a source object. - 397 _.extend: destination, source => - 398 for key, val of source - 399 destination[key]: val - 400 destination + 395 # Extend a given object with all of the properties in a source object. + 396 _.extend: (destination, source) -> + 397 for key, val of source + 398 destination[key]: val + 399 destination + 400 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) + 402 # Create a (shallow-cloned) duplicate of an object. + 403 _.clone: (obj) -> + 404 return obj.slice(0) if _.isArray(obj) + 405 _.extend({}, obj) + 406 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 + 408 # Invokes interceptor with the obj, and then returns obj. + 409 # The primary purpose of this method is to "tap into" a method chain, in order to perform operations on intermediate results within the chain. + 410 _.tap: (obj, interceptor) -> + 411 interceptor(obj) + 412 obj + 413 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 + 415 # Perform a deep comparison to check if two objects are equal. + 416 _.isEqual: (a, b) -> + 417 # Check object identity. + 418 return true if a is b + 419 # Different types? + 420 atype: typeof(a); btype: typeof(b) + 421 return false if atype isnt btype + 422 # Basic equality test (watch out for coercions). + 423 return true if `a == b` + 424 # One is falsy and the other truthy. + 425 return false if (!a and b) or (a and !b) + 426 # One of them implements an isEqual()? + 427 return a.isEqual(b) if a.isEqual + 428 # Check dates' integer values. + 429 return a.getTime() is b.getTime() if _.isDate(a) and _.isDate(b) + 430 # Both are NaN? + 431 return true if _.isNaN(a) and _.isNaN(b) + 432 # Compare regular expressions. + 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 # If a is not an object by this point, we can't handle it. + 439 return false if atype isnt 'object' + 440 # Check for different array lengths before comparing contents. + 441 return false if a.length and (a.length isnt b.length) + 442 # Nothing else worked, deep compare the contents. + 443 aKeys: _.keys(a); bKeys: _.keys(b) + 444 # Different object sizes? + 445 return false if aKeys.length isnt bKeys.length + 446 # Recursive comparison of contents. + 447 # for (var key in a) if (!_.isEqual(a[key], b[key])) return false; + 448 return true + 449 450 - 451 - 452 # Is a given array or object empty? - 453 _.isEmpty: obj => _.keys(obj).length is 0 + 451 # Is a given array or object empty? + 452 _.isEmpty: (obj) -> _.keys(obj).length is 0 + 453 454 - 455 - 456 # Is a given value a DOM element? - 457 _.isElement: obj => obj and obj.nodeType is 1 + 455 # Is a given value a DOM element? + 456 _.isElement: (obj) -> obj and obj.nodeType is 1 + 457 458 - 459 - 460 # Is a given value an array? - 461 _.isArray: obj => !!(obj and obj.concat and obj.unshift) + 459 # Is a given value an array? + 460 _.isArray: (obj) -> !!(obj and obj.concat and obj.unshift) + 461 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') + 463 # Is a given variable an arguments object? + 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 # Is the given value a function? - 469 _.isFunction: obj => !!(obj and obj.constructor and obj.call and obj.apply) + 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)) + 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]' + 477 _.isNumber: (obj) -> (obj is +obj) or 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) + 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)) + 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) + 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 + 494 _.isNull: (obj) -> obj is null 495 496 497 # Is a given variable undefined? - 498 _.isUndefined: obj => typeof obj is '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: => + 505 _.noConflict: -> 506 root._: previousUnderscore 507 this 508 509 510 # Keep the identity function around for default iterators. - 511 _.identity: value => value + 511 _.identity: (value) -> value 512 513 514 # Break out of the middle of an iteration. - 515 _.breakLoop: => throw breaker + 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 => + 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 + 525 # By default, Underscore uses ERB-style template delimiters, change the + 526 # following template settings to use alternative delimiters. + 527 _.templateSettings: { + 528 start: '<%' + 529 end: '%>' + 530 interpolate: /<%=(.+?)%>/g + 531 } + 532 + 533 + 534 # JavaScript templating a-la ERB, pilfered from John Resig's + 535 # "Secrets of the JavaScript Ninja", page 83. + 536 # Single-quotea fix from Rick Strahl's version. + 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 # ------------------------------- Aliases ---------------------------------- 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 args: _.toArray(arguments) - 568 unshift.call(args, this._wrapped) - 569 result(method.apply(_, args), this._chain) - 570 + 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 # /*------------------------ Setup the OOP Wrapper: --------------------------*/ + 567 + 568 # Helper function to continue chaining intermediate results. + 569 result: (obj, chain) -> + 570 if chain then _(obj).chain() else obj 571 - 572 # Add all mutator Array functions to the wrapper. - 573 _.each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift']) name => - 574 method: Array.prototype[name] - 575 wrapper.prototype[name]: => - 576 method.apply(this._wrapped, arguments) - 577 result(this._wrapped, this._chain) - 578 + 572 + 573 # Add all of the Underscore functions to the wrapper object. + 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 # Add all accessor Array functions to the wrapper. - 581 _.each(['concat', 'join', 'slice']) name => - 582 method: Array.prototype[name] - 583 wrapper.prototype[name]: => - 584 result(method.apply(this._wrapped, arguments), this._chain) - 585 - 586 - 587 # Start chaining a wrapped Underscore object. - 588 wrapper::chain: => - 589 this._chain: true - 590 this - 591 - 592 - 593 # Extracts the result from a wrapped and chained object. - 594 wrapper::value: => this._wrapped + 580 + 581 # Add all mutator Array functions to the wrapper. + 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 # Add all accessor Array functions to the wrapper. + 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 # Start chaining a wrapped Underscore object. + 597 wrapper::chain: -> + 598 this._chain: true + 599 this + 600 + 601 + 602 # Extracts the result from a wrapped and chained object. + 603 wrapper::value: -> this._wrapped
Latest Version:
- 0.2.6
+ 0.3.0
+index: (list, target) ->
[low, high]: [0, list.length]
while low < high
mid: (low + high) >> 1
diff --git a/examples/beautiful_code/quicksort_runtime.coffee b/examples/beautiful_code/quicksort_runtime.coffee
index bbba050443..affd775a5e 100644
--- a/examples/beautiful_code/quicksort_runtime.coffee
+++ b/examples/beautiful_code/quicksort_runtime.coffee
@@ -1,7 +1,7 @@
# Beautiful Code, Chapter 3.
# Produces the expected runtime of Quicksort, for every integer from 1 to N.
-runtime: N =>
+runtime: (N) ->
[sum, t]: [0, 0]
for n in [1..N]
sum += 2 * t
diff --git a/examples/beautiful_code/regular_expression_matcher.coffee b/examples/beautiful_code/regular_expression_matcher.coffee
index da6bd6962c..4ef8237e11 100644
--- a/examples/beautiful_code/regular_expression_matcher.coffee
+++ b/examples/beautiful_code/regular_expression_matcher.coffee
@@ -3,7 +3,7 @@
# '.', '^', '$', and '*'.
# Search for the regexp anywhere in the text.
-match: regexp, text =>
+match: (regexp, text) ->
return match_here(regexp.slice(1), text) if regexp[0] is '^'
while text
return true if match_here(regexp, text)
@@ -11,7 +11,7 @@ match: regexp, text =>
false
# Search for the regexp at the beginning of the text.
-match_here: regexp, text =>
+match_here: (regexp, text) ->
[cur, next]: [regexp[0], regexp[1]]
if regexp.length is 0 then return true
if next is '*' then return match_star(cur, regexp.slice(2), text)
@@ -20,7 +20,7 @@ match_here: regexp, text =>
false
# Search for a kleene star match at the beginning of the text.
-match_star: c, regexp, text =>
+match_star: (c, regexp, text) ->
while true
return true if match_here(regexp, text)
return false unless text and (text[0] is c or c is '.')
diff --git a/examples/code.coffee b/examples/code.coffee
index 4917d0feee..85b7516948 100644
--- a/examples/code.coffee
+++ b/examples/code.coffee
@@ -1,14 +1,14 @@
# Functions:
-square: x => x * x
+square: (x) -> x * x
-sum: x, y => x + y
+sum: (x, y) -> x + y
-odd: x => x % 2 is 0
+odd: (x) -> x % 2 isnt 0
-even: x => x % 2 isnt 0
+even: (x) -> x % 2 is 0
-run_loop: =>
- fire_events(e => e.stopPropagation())
+run_loop: ->
+ fire_events((e) -> e.stopPropagation())
listen()
wait()
@@ -22,14 +22,14 @@ spaced_out_multiline_object: {
three: new Idea()
inner_obj: {
- freedom: => _.freedom()
+ freedom: -> _.freedom()
}
}
# Arrays:
stooges: [{moe: 45}, {curly: 43}, {larry: 46}]
-exponents: [(x => x), (x => x * x), (x => x * x * x)]
+exponents: [(x) -> x, (x) -> x * x, (x) -> x * x * x]
empty: []
@@ -54,7 +54,7 @@ decoration: medal_of_honor if war_hero
go_to_sleep() unless coffee
# Returning early:
-race: =>
+race: ->
run()
walk()
crawl()
@@ -103,7 +103,7 @@ while true
# Lexical scoping.
v_1: 5
-change_a_and_set_b: =>
+change_a_and_set_b: ->
v_1: 10
v_2: 15
v_2: 20
@@ -128,7 +128,7 @@ activity: switch day
else go_to_work()
# Semicolons can optionally be used instead of newlines.
-wednesday: => eat_breakfast(); go_to_work(); eat_dinner()
+wednesday: -> eat_breakfast(); go_to_work(); eat_dinner()
# Array slice literals.
zero_to_nine: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
@@ -140,19 +140,19 @@ sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna
aliquam erat volutpat. Ut wisi enim ad."
# Inheritance and calling super.
-Animal: =>
-Animal::move: meters =>
+Animal: ->
+Animal::move: (meters) ->
alert(this.name + " moved " + meters + "m.")
-Snake: name => this.name: name
+Snake: (name) -> this.name: name
Snake extends Animal
-Snake::move: =>
+Snake::move: ->
alert('Slithering...')
super(5)
-Horse: name => this.name: name
+Horse: (name) -> this.name: name
Horse extends Animal
-Horse::move: =>
+Horse::move: ->
alert('Galloping...')
super(45)
diff --git a/examples/computer_science/README b/examples/computer_science/README
new file mode 100644
index 0000000000..1046f9f9b5
--- /dev/null
+++ b/examples/computer_science/README
@@ -0,0 +1,4 @@
+Ported from Nicholas Zakas' collection of computer science fundamentals, written
+in JavaScript. Originals available here:
+
+http://github.com/nzakas/computer-science-in-javascript
diff --git a/examples/computer_science/binary_search.coffee b/examples/computer_science/binary_search.coffee
new file mode 100644
index 0000000000..443eaaa0fe
--- /dev/null
+++ b/examples/computer_science/binary_search.coffee
@@ -0,0 +1,25 @@
+# Uses a binary search algorithm to locate a value in the specified array.
+binary_search: (items, value) ->
+
+ start: 0
+ stop: items.length - 1
+ pivot: Math.floor((start + stop) / 2)
+
+ while items[pivot] isnt value and start < stop
+
+ # Adjust the search area.
+ stop: pivot - 1 if value < items[pivot]
+ start: pivot + 1 if value > items[pivot]
+
+ # Recalculate the pivot.
+ pivot: Math.floor((stop + start) / 2)
+
+ # Make sure we've found the correct value.
+ if items[pivot] is value then pivot else -1
+
+
+# Test the function.
+print(2 is binary_search([10, 20, 30, 40, 50], 30))
+print(4 is binary_search([-97, 35, 67, 88, 1200], 1200))
+print(0 is binary_search([0, 45, 70], 0))
+print(-1 is binary_search([0, 45, 70], 10))
\ No newline at end of file
diff --git a/examples/computer_science/bubble_sort.coffee b/examples/computer_science/bubble_sort.coffee
new file mode 100644
index 0000000000..f671bedd98
--- /dev/null
+++ b/examples/computer_science/bubble_sort.coffee
@@ -0,0 +1,11 @@
+# A bubble sort implementation, sorting the given array in-place.
+bubble_sort: (list) ->
+ for i in [0...list.length]
+ for j in [0...list.length - i]
+ [list[j], list[j+1]]: [list[j+1], list[j]] if list[j] > list[j+1]
+ list
+
+
+# Test the function.
+print(bubble_sort([3, 2, 1]).join(' ') is '1 2 3')
+print(bubble_sort([9, 2, 7, 0, 1]).join(' ') is '0 1 2 7 9')
\ No newline at end of file
diff --git a/examples/computer_science/linked_list.coffee b/examples/computer_science/linked_list.coffee
new file mode 100644
index 0000000000..6af3fddfd0
--- /dev/null
+++ b/examples/computer_science/linked_list.coffee
@@ -0,0 +1,106 @@
+# "Classic" linked list implementation that doesn't keep track of its size.
+LinkedList: ->
+ this._head: null # Pointer to the first item in the list.
+
+
+# Appends some data to the end of the list. This method traverses the existing
+# list and places the value at the end in a new node.
+LinkedList::add: (data) ->
+
+ # Create a new node object to wrap the data.
+ node: {data: data, next: null}
+
+ current: this._head ||= node
+
+ if this._head isnt node
+ current: current.next while current.next
+ current.next: node
+
+ this
+
+
+# Retrieves the data at the given position in the list.
+LinkedList::item: (index) ->
+
+ # Check for out-of-bounds values.
+ return null if index < 0
+
+ current: this._head or null
+ i: -1
+
+ # Advance through the list.
+ current: current.next while current and index > (i += 1)
+
+ # Return null if we've reached the end.
+ current and current.data
+
+
+# Remove the item from the given location in the list.
+LinkedList::remove: (index) ->
+
+ # Check for out-of-bounds values.
+ return null if index < 0
+
+ current: this._head or null
+ i: -1
+
+ # Special case: removing the first item.
+ if index is 0
+ this._head: current.next
+ else
+
+ # Find the right location.
+ [previous, current]: [current, current.next] while index > (i += 1)
+
+ # Skip over the item to remove.
+ previous.next: current.next
+
+ # Return the value.
+ current and current.data
+
+
+# Calculate the number of items in the list.
+LinkedList::size: ->
+ current: this._head
+ count: 0
+
+ while current
+ count += 1
+ current: current.next
+
+ count
+
+
+# Convert the list into an array.
+LinkedList::toArray: ->
+ result: []
+ current: this._head
+
+ while current
+ result.push(current.data)
+ current: current.next
+
+ result
+
+
+# The string representation of the linked list.
+LinkedList::toString: -> this.toArray().toString()
+
+
+# Tests.
+list: new LinkedList()
+
+list.add("Hi")
+print(list.size() is 1)
+print(list.item(0) is "Hi")
+print(list.item(1) is null)
+
+list: new LinkedList()
+list.add("zero").add("one").add("two")
+print(list.size() is 3)
+print(list.item(2) is "two")
+print(list.remove(1) is "one")
+print(list.item(0) is "zero")
+print(list.item(1) is "two")
+print(list.size() is 2)
+print(list.item(-10) is null)
diff --git a/examples/computer_science/luhn_algorithm.coffee b/examples/computer_science/luhn_algorithm.coffee
new file mode 100644
index 0000000000..042b249d6c
--- /dev/null
+++ b/examples/computer_science/luhn_algorithm.coffee
@@ -0,0 +1,36 @@
+# Use the Luhn algorithm to validate a numeric identifier, such as credit card
+# numbers, national insurance numbers, etc.
+# See: http://en.wikipedia.org/wiki/Luhn_algorithm
+
+is_valid_identifier: (identifier) ->
+
+ sum: 0
+ alt: false
+
+ for i in [(identifier.length - 1)..0]
+
+ # Get the next digit.
+ num: parseInt(identifier.charAt(i), 10)
+
+ # If it's not a valid number, abort.
+ return false if isNaN(num)
+
+ # If it's an alternate number...
+ if alt
+ num *= 2
+ num: (num % 10) + 1 if num > 9
+
+ # Flip the alternate bit.
+ alt: !alt
+
+ # Add to the rest of the sum.
+ sum += num
+
+ # Determine if it's valid.
+ sum % 10 is 0
+
+
+# Tests.
+print(is_valid_identifier("49927398716") is true)
+print(is_valid_identifier("4408041234567893") is true)
+print(is_valid_identifier("4408041234567890") is false)
diff --git a/examples/computer_science/merge_sort.coffee b/examples/computer_science/merge_sort.coffee
new file mode 100644
index 0000000000..fb3f8ce8fc
--- /dev/null
+++ b/examples/computer_science/merge_sort.coffee
@@ -0,0 +1,19 @@
+# Sorts an array in ascending natural order using merge sort.
+merge_sort: (list) ->
+
+ return list if list.length is 1
+
+ result: []
+ pivot: Math.floor(list.length / 2)
+ left: merge_sort(list.slice(0, pivot))
+ right: merge_sort(list.slice(pivot))
+
+ while left.length and right.length
+ result.push(if left[0] < right[0] then left.shift() else right.shift())
+
+ result.concat(left).concat(right)
+
+
+# Test the function.
+print(merge_sort([3, 2, 1]).join(' ') is '1 2 3')
+print(merge_sort([9, 2, 7, 0, 1]).join(' ') is '0 1 2 7 9')
\ No newline at end of file
diff --git a/examples/computer_science/selection_sort.coffee b/examples/computer_science/selection_sort.coffee
new file mode 100644
index 0000000000..f4b970a14a
--- /dev/null
+++ b/examples/computer_science/selection_sort.coffee
@@ -0,0 +1,23 @@
+# An in-place selection sort.
+selection_sort: (list) ->
+ len: list.length
+
+ # For each item in the list.
+ for i in [0...len]
+
+ # Set the minimum to this position.
+ min: i
+
+ # Check the rest of the array to see if anything is smaller.
+ (min: j if list[j] < list[min]) for j in [i+1...len]
+
+ # Swap if a smaller item has been found.
+ [list[i], list[min]]: [list[min], list[i]] if i isnt min
+
+ # The list is now sorted.
+ list
+
+
+# Test the function.
+print(selection_sort([3, 2, 1]).join(' ') is '1 2 3')
+print(selection_sort([9, 2, 7, 0, 1]).join(' ') is '0 1 2 7 9')
\ No newline at end of file
diff --git a/examples/documents.coffee b/examples/documents.coffee
deleted file mode 100644
index 31d38d8ed4..0000000000
--- a/examples/documents.coffee
+++ /dev/null
@@ -1,72 +0,0 @@
-# Document Model
-dc.model.Document: dc.Model.extend({
-
- constructor: attributes => this.base(attributes)
-
- # For display, show either the highlighted search results, or the summary,
- # if no highlights are available.
- # The import process will take care of this in the future, but the inline
- # version of the summary has all runs of whitespace squeezed out.
- displaySummary: =>
- text: this.get('highlight') or this.get('summary') or ''
- text and text.replace(/\s+/g, ' ')
-
- # Return a list of the document's metadata. Think about caching this on the
- # document by binding to Metadata, instead of on-the-fly.
- metadata: =>
- docId: this.id
- _.select(Metadata.models(), (meta =>
- _.any(meta.get('instances'), instance =>
- instance.document_id is docId)))
-
- bookmark: pageNumber =>
- bookmark: new dc.model.Bookmark({title: this.get('title'), page_number: pageNumber, document_id: this.id})
- Bookmarks.create(bookmark)
-
- # Inspect.
- toString: => 'Document ' + this.id + ' "' + this.get('title') + '"'
-
-})
-
-# Document Set
-dc.model.DocumentSet: dc.model.RESTfulSet.extend({
-
- resource: 'documents'
-
- SELECTION_CHANGED: 'documents:selection_changed'
-
- constructor: options =>
- this.base(options)
- _.bindAll(this, 'downloadSelectedViewers', 'downloadSelectedPDF', 'downloadSelectedFullText')
-
- selected: => _.select(this.models(), m => m.get('selected'))
-
- selectedIds: => _.pluck(this.selected(), 'id')
-
- countSelected: => this.selected().length
-
- downloadSelectedViewers: =>
- dc.app.download('/download/' + this.selectedIds().join('/') + '/document_viewer.zip')
-
- downloadSelectedPDF: =>
- if this.countSelected() <= 1 then return window.open(this.selected()[0].get('pdf_url'))
- dc.app.download('/download/' + this.selectedIds().join('/') + '/document_pdfs.zip')
-
- downloadSelectedFullText: =>
- if this.countSelected() <= 1 then return window.open(this.selected()[0].get('full_text_url'))
- dc.app.download('/download/' + this.selectedIds().join('/') + '/document_text.zip')
-
- # We override "_onModelEvent" to fire selection changed events when documents
- # change their selected state.
- _onModelEvent: e, model =>
- this.base(e, model)
- fire: e is dc.Model.CHANGED and model.hasChanged('selected')
- if fire then _.defer(_(this.fire).bind(this, this.SELECTION_CHANGED, this))
-
-})
-
-# The main set of Documents, used by the search tab.
-window.Documents: new dc.model.DocumentSet()
-
-# The set of documents that is used to look at a particular label.
-dc.app.LabeledDocuments: new dc.model.DocumentSet()
diff --git a/examples/poignant.coffee b/examples/poignant.coffee
index 9ed24328c8..0754284a75 100644
--- a/examples/poignant.coffee
+++ b/examples/poignant.coffee
@@ -2,7 +2,7 @@
# ['toast', 'cheese', 'wine'].each { |food| print food.capitalize }
-['toast', 'wine', 'cheese'].each(food => print(food.capitalize()))
+['toast', 'wine', 'cheese'].each (food) -> print(food.capitalize())
@@ -14,10 +14,43 @@
# end
LotteryTicket: {
- get_picks: => this.picks
- set_picks: nums => this.picks: nums
- get_purchase: => this.purchase
- set_purchase: amount => this.purchase: amount
+ get_picks: -> this.picks
+ set_picks: (nums) -> this.picks: nums
+ get_purchase: -> this.purchase
+ set_purchase: (amount) -> this.purchase: amount
+}
+
+
+
+# class << LotteryDraw
+# def play
+# result = LotteryTicket.new_random
+# winners = {}
+# @@tickets.each do |buyer, ticket_list|
+# ticket_list.each do |ticket|
+# score = ticket.score( result )
+# next if score.zero?
+# winners[buyer] ||= []
+# winners[buyer] << [ ticket, score ]
+# end
+# end
+# @@tickets.clear
+# winners
+# end
+# end
+
+LotteryDraw: {
+ play: ->
+ result: LotteryTicket.new_random()
+ winners: {}
+ this.tickets.each (buyer, ticket_list) ->
+ ticket_list.each (ticket) ->
+ score: ticket.score(result)
+ return if score is 0
+ winners[buyer] ||= []
+ winners[buyer].push([ticket, score])
+ this.tickets: {}
+ winners
}
@@ -32,8 +65,8 @@ LotteryTicket: {
# end
WishScanner: {
- scan_for_a_wish: =>
- wish: this.read().detect(thought => thought.index('wish: ') is 0)
+ scan_for_a_wish: ->
+ wish: this.read().detect((thought) -> thought.index('wish: ') is 0)
wish.replace('wish: ', '')
}
@@ -78,7 +111,7 @@ WishScanner: {
Creature : {
# This method applies a hit taken during a fight.
- hit: damage =>
+ hit: (damage) ->
p_up: Math.rand(this.charisma)
if p_up % 9 is 7
this.life += p_up / 4
@@ -87,7 +120,7 @@ Creature : {
if this.life <= 0 then puts("[" + this.name + " has died.]")
# This method takes one turn in a fight.
- fight: enemy, weapon =>
+ fight: (enemy, weapon) ->
if this.life <= 0 then return puts("[" + this.name + "is too dead to fight!]")
# Attack the opponent.
@@ -123,12 +156,12 @@ Creature : {
# Get evil idea and swap in code words
print("Enter your new idea: ")
idea: gets()
-code_words.each(real, code => idea.replace(real, code))
+code_words.each((real, code) -> idea.replace(real, code))
# Save the jibberish to a new file
print("File encoded. Please enter a name for this idea: ")
idea_name: gets().strip()
-File.open("idea-" + idea_name + '.txt', 'w', file => file.write(idea))
+File.open("idea-" + idea_name + '.txt', 'w', (file) -> file.write(idea))
@@ -144,7 +177,7 @@ File.open("idea-" + idea_name + '.txt', 'w', file => file.write(idea))
# end
# end
-wipe_mutterings_from: sentence =>
+wipe_mutterings_from: (sentence) ->
throw new Error("cannot wipe mutterings") unless sentence.indexOf
while sentence.indexOf('(') >= 0
open: sentence.indexOf('(') - 1
diff --git a/examples/potion.coffee b/examples/potion.coffee
index de8f72c591..c8c5ddf9a3 100644
--- a/examples/potion.coffee
+++ b/examples/potion.coffee
@@ -8,7 +8,7 @@ print("Odelay!") for i in [1..5]
# add = (x, y): x + y.
# add(2, 4) string print
-add: x, y => x + y
+add: (x, y) -> x + y
print(add(2, 4))
@@ -31,7 +31,7 @@ print({language: 'Potion', pointless: true}['language'])
# minus = (x, y): x - y.
# minus (y=10, x=6)
-minus: x, y => x - y
+minus: (x, y) -> x - y
minus(6, 10)
@@ -53,8 +53,8 @@ for key, val of {dog: 'canine', cat: 'feline', fox: 'vulpine'}
# Person print = ():
# ('My name is ', /name, '.') join print.
-Person: =>
-Person::print: =>
+Person: ->
+Person::print: ->
print('My name is ' + this.name + '.')
@@ -71,9 +71,9 @@ print(p.name)
#
# Policeman ('Constable') print
-Policeman: rank => this.rank: rank
+Policeman: (rank) -> this.rank: rank
Policeman extends Person
-Policeman::print: =>
+Policeman::print: ->
print('My name is ' + this.name + " and I'm a " + this.rank + '.')
print(new Policeman('Constable'))
@@ -115,13 +115,13 @@ table: {
# String length = (): 10.
# this foul business...
-String::length: => 10
+String::length: -> 10
# block = :
# 'potion' print.
-block: =>
+block: ->
print('potion')
@@ -178,7 +178,7 @@ if (3).gender?
# HomePage get = (url):
# session = url query ? at ('session').
-HomePage::get: url =>
+HomePage::get: (url) ->
session: url.query.session if url.query?
@@ -187,7 +187,7 @@ HomePage::get: url =>
# b /left = BTree ()
# b /right = BTree ()
-BTree: =>
+BTree: ->
b: new BTree()
b.left: new BTree()
b.right: new BTree()
@@ -199,7 +199,7 @@ b.right: new BTree()
# if (b ? /left):
# 'left path found!' print.
-BTree: =>
+BTree: ->
b: new BTree()
print('left path found!') if b.left?
diff --git a/examples/syntax_errors.coffee b/examples/syntax_errors.coffee
deleted file mode 100644
index aa72cd71ee..0000000000
--- a/examples/syntax_errors.coffee
+++ /dev/null
@@ -1,20 +0,0 @@
-# Identifiers run together:
-# a b c
-
-# Trailing comma in array:
-# array: [1, 2, 3, 4, 5,]
-
-# Unterminated object literal:
-# obj: { one: 1, two: 2
-
-# Numbers run together:
-# 101 202
-
-# Strings run together:
-# str: "broken" "words"
-
-# Forgot to terminate a function:
-# obj: {
-# first: a => a[0].
-# last: a => a[a.length-1]
-# }
\ No newline at end of file
diff --git a/examples/underscore.coffee b/examples/underscore.coffee
index edc3cb9a03..a34a1ce869 100644
--- a/examples/underscore.coffee
+++ b/examples/underscore.coffee
@@ -1,6 +1,6 @@
# Underscore.coffee
- # (c) 2009 Jeremy Ashkenas, DocumentCloud Inc.
+ # (c) 2010 Jeremy Ashkenas, DocumentCloud Inc.
# Underscore is freely distributable under the terms of the MIT license.
# Portions of Underscore are inspired by or borrowed from Prototype.js,
# Oliver Steele's Functional, and John Resig's Micro-Templating.
@@ -21,7 +21,7 @@
# If Underscore is called as a function, it returns a wrapped object that
# can be used OO-style. This wrapper holds altered versions of all the
# underscore functions. Wrapped objects may be chained.
- wrapper: obj =>
+ wrapper: (obj) ->
this._wrapped: obj
this
@@ -31,7 +31,7 @@
# Create a safe reference to the Underscore object forreference below.
- _: root._: obj => new wrapper(obj)
+ _: root._: (obj) -> new wrapper(obj)
# Export the Underscore object for CommonJS.
@@ -47,14 +47,14 @@
# Current version.
- _.VERSION: '0.5.5'
+ _.VERSION: '0.5.7'
# ------------------------ Collection Functions: ---------------------------
# The cornerstone, an each implementation.
# Handles objects implementing forEach, arrays, and raw objects.
- _.each: obj, iterator, context =>
+ _.each: (obj, iterator, context) ->
index: 0
try
return obj.forEach(iterator, context) if obj.forEach
@@ -68,36 +68,36 @@
# Return the results of applying the iterator to each element. Use JavaScript
# 1.6's version of map, if possible.
- _.map: obj, iterator, context =>
+ _.map: (obj, iterator, context) ->
return obj.map(iterator, context) if (obj and _.isFunction(obj.map))
results: []
- _.each(obj) value, index, list =>
+ _.each obj, (value, index, list) ->
results.push(iterator.call(context, value, index, list))
results
# Reduce builds up a single result from a list of values. Also known as
# inject, or foldl. Uses JavaScript 1.8's version of reduce, if possible.
- _.reduce: obj, memo, iterator, context =>
+ _.reduce: (obj, memo, iterator, context) ->
return obj.reduce(_.bind(iterator, context), memo) if (obj and _.isFunction(obj.reduce))
- _.each(obj) value, index, list =>
+ _.each obj, (value, index, list) ->
memo: iterator.call(context, memo, value, index, list)
memo
# The right-associative version of reduce, also known as foldr. Uses
# JavaScript 1.8's version of reduceRight, if available.
- _.reduceRight: obj, memo, iterator, context =>
+ _.reduceRight: (obj, memo, iterator, context) ->
return obj.reduceRight(_.bind(iterator, context), memo) if (obj and _.isFunction(obj.reduceRight))
- _.each(_.clone(_.toArray(obj)).reverse()) value, index =>
+ _.each _.clone(_.toArray(obj)).reverse(), (value, index) ->
memo: iterator.call(context, memo, value, index, obj)
memo
# Return the first value which passes a truth test.
- _.detect: obj, iterator, context =>
+ _.detect: (obj, iterator, context) ->
result: null
- _.each(obj) value, index, list =>
+ _.each obj, (value, index, list) ->
if iterator.call(context, value, index, list)
result: value
_.breakLoop()
@@ -106,47 +106,47 @@
# Return all the elements that pass a truth test. Use JavaScript 1.6's
# filter(), if it exists.
- _.select: obj, iterator, context =>
+ _.select: (obj, iterator, context) ->
if obj and _.isFunction(obj.filter) then return obj.filter(iterator, context)
results: []
- _.each(obj) value, index, list =>
+ _.each obj, (value, index, list) ->
results.push(value) if iterator.call(context, value, index, list)
results
# Return all the elements for which a truth test fails.
- _.reject: obj, iterator, context =>
+ _.reject: (obj, iterator, context) ->
results: []
- _.each(obj) value, index, list =>
+ _.each obj, (value, index, list) ->
results.push(value) if not iterator.call(context, value, index, list)
results
# Determine whether all of the elements match a truth test. Delegate to
# JavaScript 1.6's every(), if it is present.
- _.all: obj, iterator, context =>
+ _.all: (obj, iterator, context) ->
iterator ||= _.identity
return obj.every(iterator, context) if obj and _.isFunction(obj.every)
result: true
- _.each(obj) value, index, list =>
+ _.each obj, (value, index, list) ->
_.breakLoop() unless (result: result and iterator.call(context, value, index, list))
result
# Determine if at least one element in the object matches a truth test. Use
# JavaScript 1.6's some(), if it exists.
- _.any: obj, iterator, context =>
+ _.any: (obj, iterator, context) ->
iterator ||= _.identity
return obj.some(iterator, context) if obj and _.isFunction(obj.some)
result: false
- _.each(obj) value, index, list =>
+ _.each obj, (value, index, list) ->
_.breakLoop() if (result: iterator.call(context, value, index, list))
result
# Determine if a given value is included in the array or object,
# based on '==='.
- _.include: obj, target =>
+ _.include: (obj, target) ->
return _.indexOf(obj, target) isnt -1 if _.isArray(obj)
for key, val of obj
return true if val is target
@@ -154,49 +154,49 @@
# Invoke a method with arguments on every item in a collection.
- _.invoke: obj, method =>
+ _.invoke: (obj, method) ->
args: _.rest(arguments, 2)
(if method then val[method] else val).apply(val, args) for val in obj
# Convenience version of a common use case of map: fetching a property.
- _.pluck: obj, key =>
- _.map(obj, (val => val[key]))
+ _.pluck: (obj, key) ->
+ _.map(obj, ((val) -> val[key]))
# Return the maximum item or (item-based computation).
- _.max: obj, iterator, context =>
+ _.max: (obj, iterator, context) ->
return Math.max.apply(Math, obj) if not iterator and _.isArray(obj)
result: {computed: -Infinity}
- _.each(obj) value, index, list =>
+ _.each obj, (value, index, list) ->
computed: if iterator then iterator.call(context, value, index, list) else value
computed >= result.computed and (result: {value: value, computed: computed})
result.value
# Return the minimum element (or element-based computation).
- _.min: obj, iterator, context =>
+ _.min: (obj, iterator, context) ->
return Math.min.apply(Math, obj) if not iterator and _.isArray(obj)
result: {computed: Infinity}
- _.each(obj) value, index, list =>
+ _.each obj, (value, index, list) ->
computed: if iterator then iterator.call(context, value, index, list) else value
computed < result.computed and (result: {value: value, computed: computed})
result.value
# Sort the object's values by a criteria produced by an iterator.
- _.sortBy: obj, iterator, context =>
- _.pluck(((_.map(obj) value, index, list =>
+ _.sortBy: (obj, iterator, context) ->
+ _.pluck(((_.map obj, (value, index, list) ->
{value: value, criteria: iterator.call(context, value, index, list)}
- ).sort() left, right =>
+ ).sort((left, right) ->
a: left.criteria; b: right.criteria
if a < b then -1 else if a > b then 1 else 0
- ), 'value')
+ )), 'value')
# Use a comparator function to figure out at what index an object should
# be inserted so as to maintain order. Uses binary search.
- _.sortedIndex: array, obj, iterator =>
+ _.sortedIndex: (array, obj, iterator) ->
iterator ||= _.identity
low: 0; high: array.length
while low < high
@@ -206,7 +206,7 @@
# Convert anything iterable into a real, live array.
- _.toArray: iterable =>
+ _.toArray: (iterable) ->
return [] if (!iterable)
return iterable.toArray() if (iterable.toArray)
return iterable if (_.isArray(iterable))
@@ -215,7 +215,7 @@
# Return the number of elements in an object.
- _.size: obj => _.toArray(obj).length
+ _.size: (obj) -> _.toArray(obj).length
# -------------------------- Array Functions: ------------------------------
@@ -223,7 +223,7 @@
# Get the first element of an array. Passing "n" will return the first N
# values in the array. Aliased as "head". The "guard" check allows it to work
# with _.map.
- _.first: array, n, guard =>
+ _.first: (array, n, guard) ->
if n and not guard then slice.call(array, 0, n) else array[0]
@@ -231,35 +231,35 @@
# Especially useful on the arguments object. Passing an "index" will return
# the rest of the values in the array from that index onward. The "guard"
# check allows it to work with _.map.
- _.rest: array, index, guard =>
+ _.rest: (array, index, guard) ->
slice.call(array, if _.isUndefined(index) or guard then 1 else index)
# Get the last element of an array.
- _.last: array => array[array.length - 1]
+ _.last: (array) -> array[array.length - 1]
# Trim out all falsy values from an array.
- _.compact: array => array[i] for i in [0...array.length] when array[i]
+ _.compact: (array) -> array[i] for i in [0...array.length] when array[i]
# Return a completely flattened version of an array.
- _.flatten: array =>
- _.reduce(array, []) memo, value =>
+ _.flatten: (array) ->
+ _.reduce array, [], (memo, value) ->
return memo.concat(_.flatten(value)) if _.isArray(value)
memo.push(value)
memo
# Return a version of the array that does not contain the specified value(s).
- _.without: array =>
+ _.without: (array) ->
values: _.rest(arguments)
val for val in _.toArray(array) when not _.include(values, val)
# Produce a duplicate-free version of the array. If the array has already
# been sorted, you have the option of using a faster algorithm.
- _.uniq: array, isSorted =>
+ _.uniq: (array, isSorted) ->
memo: []
for el, i in _.toArray(array)
memo.push(el) if i is 0 || (if isSorted is true then _.last(memo) isnt el else not _.include(memo, el))
@@ -268,28 +268,27 @@
# Produce an array that contains every item shared between all the
# passed-in arrays.
- _.intersect: array =>
+ _.intersect: (array) ->
rest: _.rest(arguments)
- _.select(_.uniq(array)) item =>
- _.all(rest) other =>
+ _.select _.uniq(array), (item) ->
+ _.all rest, (other) ->
_.indexOf(other, item) >= 0
# Zip together multiple lists into a single array -- elements that share
# an index go together.
- _.zip: =>
- args: _.toArray(arguments)
- length: _.max(_.pluck(args, 'length'))
+ _.zip: ->
+ length: _.max(_.pluck(arguments, 'length'))
results: new Array(length)
for i in [0...length]
- results[i]: _.pluck(args, String(i))
+ results[i]: _.pluck(arguments, String(i))
results
# If the browser doesn't supply us with indexOf (I'm looking at you, MSIE),
# we need this function. Return the position of the first occurence of an
# item in an array, or -1 if the item is not included in the array.
- _.indexOf: array, item =>
+ _.indexOf: (array, item) ->
return array.indexOf(item) if array.indexOf
i: 0; l: array.length
while l - i
@@ -299,7 +298,7 @@
# Provide JavaScript 1.6's lastIndexOf, delegating to the native function,
# if possible.
- _.lastIndexOf: array, item =>
+ _.lastIndexOf: (array, item) ->
return array.lastIndexOf(item) if array.lastIndexOf
i: array.length
while i
@@ -310,8 +309,8 @@
# Generate an integer Array containing an arithmetic progression. A port of
# the native Python range() function. See:
# http://docs.python.org/library/functions.html#range
- _.range: start, stop, step =>
- a: _.toArray(arguments)
+ _.range: (start, stop, step) ->
+ a: arguments
solo: a.length <= 1
i: start: if solo then 0 else a[0];
stop: if solo then a[0] else a[1];
@@ -331,45 +330,45 @@
# Create a function bound to a given object (assigning 'this', and arguments,
# optionally). Binding with arguments is also known as 'curry'.
- _.bind: func, obj =>
+ _.bind: (func, obj) ->
args: _.rest(arguments, 2)
- => func.apply(obj or root, args.concat(_.toArray(arguments)))
+ -> func.apply(obj or root, args.concat(arguments))
# Bind all of an object's methods to that object. Useful for ensuring that
# all callbacks defined on an object belong to it.
- _.bindAll: obj =>
+ _.bindAll: (obj) ->
funcs: if arguments.length > 1 then _.rest(arguments) else _.functions(obj)
- _.each(funcs, (f => obj[f]: _.bind(obj[f], obj)))
+ _.each(funcs, (f) -> obj[f]: _.bind(obj[f], obj))
obj
# Delays a function for the given number of milliseconds, and then calls
# it with the arguments supplied.
- _.delay: func, wait =>
+ _.delay: (func, wait) ->
args: _.rest(arguments, 2)
- setTimeout((=> func.apply(func, args)), wait)
+ setTimeout((-> func.apply(func, args)), wait)
# Defers a function, scheduling it to run after the current call stack has
# cleared.
- _.defer: func =>
+ _.defer: (func) ->
_.delay.apply(_, [func, 1].concat(_.rest(arguments)))
# Returns the first function passed as an argument to the second,
# allowing you to adjust arguments, run code before and after, and
# conditionally execute the original function.
- _.wrap: func, wrapper =>
- => wrapper.apply(wrapper, [func].concat(_.toArray(arguments)))
+ _.wrap: (func, wrapper) ->
+ -> wrapper.apply(wrapper, [func].concat(arguments))
# Returns a function that is the composition of a list of functions, each
# consuming the return value of the function that follows.
- _.compose: =>
- funcs: _.toArray(arguments)
- =>
- args: _.toArray(arguments)
+ _.compose: ->
+ funcs: arguments
+ ->
+ args: arguments
for i in [(funcs.length - 1)..0]
args: [funcs[i].apply(this, args)]
args[0]
@@ -378,43 +377,43 @@
# ------------------------- Object Functions: ----------------------------
# Retrieve the names of an object's properties.
- _.keys: obj =>
+ _.keys: (obj) ->
return _.range(0, obj.length) if _.isArray(obj)
key for key, val of obj
# Retrieve the values of an object's properties.
- _.values: obj =>
+ _.values: (obj) ->
_.map(obj, _.identity)
# Return a sorted list of the function names available in Underscore.
- _.functions: obj =>
- _.select(_.keys(obj), key => _.isFunction(obj[key])).sort()
+ _.functions: (obj) ->
+ _.select(_.keys(obj), (key) -> _.isFunction(obj[key])).sort()
# Extend a given object with all of the properties in a source object.
- _.extend: destination, source =>
+ _.extend: (destination, source) ->
for key, val of source
destination[key]: val
destination
# Create a (shallow-cloned) duplicate of an object.
- _.clone: obj =>
+ _.clone: (obj) ->
return obj.slice(0) if _.isArray(obj)
_.extend({}, obj)
# Invokes interceptor with the obj, and then returns obj.
# The primary purpose of this method is to "tap into" a method chain, in order to perform operations on intermediate results within the chain.
- _.tap: obj, interceptor =>
+ _.tap: (obj, interceptor) ->
interceptor(obj)
obj
# Perform a deep comparison to check if two objects are equal.
- _.isEqual: a, b =>
+ _.isEqual: (a, b) ->
# Check object identity.
return true if a is b
# Different types?
@@ -450,93 +449,104 @@
# Is a given array or object empty?
- _.isEmpty: obj => _.keys(obj).length is 0
+ _.isEmpty: (obj) -> _.keys(obj).length is 0
# Is a given value a DOM element?
- _.isElement: obj => obj and obj.nodeType is 1
+ _.isElement: (obj) -> obj and obj.nodeType is 1
# Is a given value an array?
- _.isArray: obj => !!(obj and obj.concat and obj.unshift)
+ _.isArray: (obj) -> !!(obj and obj.concat and obj.unshift)
# Is a given variable an arguments object?
- _.isArguments: obj => obj and _.isNumber(obj.length) and !_.isArray(obj) and !propertyIsEnumerable.call(obj, 'length')
+ _.isArguments: (obj) -> obj and _.isNumber(obj.length) and not obj.concat and
+ not obj.substr and not obj.apply and not propertyIsEnumerable.call(obj, 'length')
# Is the given value a function?
- _.isFunction: obj => !!(obj and obj.constructor and obj.call and obj.apply)
+ _.isFunction: (obj) -> !!(obj and obj.constructor and obj.call and obj.apply)
# Is the given value a string?
- _.isString: obj => !!(obj is '' or (obj and obj.charCodeAt and obj.substr))
+ _.isString: (obj) -> !!(obj is '' or (obj and obj.charCodeAt and obj.substr))
# Is a given value a number?
- _.isNumber: obj => toString.call(obj) is '[object Number]'
+ _.isNumber: (obj) -> (obj is +obj) or toString.call(obj) is '[object Number]'
# Is a given value a Date?
- _.isDate: obj => !!(obj and obj.getTimezoneOffset and obj.setUTCFullYear)
+ _.isDate: (obj) -> !!(obj and obj.getTimezoneOffset and obj.setUTCFullYear)
# Is the given value a regular expression?
- _.isRegExp: obj => !!(obj and obj.exec and (obj.ignoreCase or obj.ignoreCase is false))
+ _.isRegExp: (obj) -> !!(obj and obj.exec and (obj.ignoreCase or obj.ignoreCase is false))
# Is the given value NaN -- this one is interesting. NaN != NaN, and
# isNaN(undefined) == true, so we make sure it's a number first.
- _.isNaN: obj => _.isNumber(obj) and window.isNaN(obj)
+ _.isNaN: (obj) -> _.isNumber(obj) and window.isNaN(obj)
# Is a given value equal to null?
- _.isNull: obj => obj is null
+ _.isNull: (obj) -> obj is null
# Is a given variable undefined?
- _.isUndefined: obj => typeof obj is 'undefined'
+ _.isUndefined: (obj) -> typeof obj is 'undefined'
# -------------------------- Utility Functions: --------------------------
# Run Underscore.js in noConflict mode, returning the '_' variable to its
# previous owner. Returns a reference to the Underscore object.
- _.noConflict: =>
+ _.noConflict: ->
root._: previousUnderscore
this
# Keep the identity function around for default iterators.
- _.identity: value => value
+ _.identity: (value) -> value
# Break out of the middle of an iteration.
- _.breakLoop: => throw breaker
+ _.breakLoop: -> throw breaker
# Generate a unique integer id (unique within the entire client session).
# Useful for temporary DOM ids.
idCounter: 0
- _.uniqueId: prefix =>
+ _.uniqueId: (prefix) ->
(prefix or '') + idCounter++
+ # By default, Underscore uses ERB-style template delimiters, change the
+ # following template settings to use alternative delimiters.
+ _.templateSettings: {
+ start: '<%'
+ end: '%>'
+ interpolate: /<%=(.+?)%>/g
+ }
+
+
# JavaScript templating a-la ERB, pilfered from John Resig's
# "Secrets of the JavaScript Ninja", page 83.
- _.template: str, data =>
- `var fn = new Function('obj',
+ # Single-quotea fix from Rick Strahl's version.
+ _.template: (str, data) ->
+ c: _.templateSettings
+ fn: new Function 'obj',
'var p=[],print=function(){p.push.apply(p,arguments);};' +
'with(obj){p.push(\'' +
- str.
- replace(/[\r\t\n]/g, " ").
- split("<%").join("\t").
- replace(/((^|%>)[^\t]*)'/g, "$1\r").
- replace(/\t=(.*?)%>/g, "',$1,'").
- split("\t").join("');").
- split("%>").join("p.push('").
- split("\r").join("\\'") +
- "');}return p.join('');")`
+ str.replace(/[\r\t\n]/g, " ")
+ .replace(new RegExp("'(?=[^"+c.end[0]+"]*"+c.end+")","g"),"\t")
+ .split("'").join("\\'")
+ .split("\t").join("'")
+ .replace(c.interpolate, "',$1,'")
+ .split(c.start).join("');")
+ .split(c.end).join("p.push('") +
+ "');}return p.join('');"
if data then fn(data) else fn
@@ -556,39 +566,38 @@
# /*------------------------ Setup the OOP Wrapper: --------------------------*/
# Helper function to continue chaining intermediate results.
- result: obj, chain =>
+ result: (obj, chain) ->
if chain then _(obj).chain() else obj
# Add all of the Underscore functions to the wrapper object.
- _.each(_.functions(_)) name =>
+ _.each _.functions(_), (name) ->
method: _[name]
- wrapper.prototype[name]: =>
- args: _.toArray(arguments)
- unshift.call(args, this._wrapped)
- result(method.apply(_, args), this._chain)
+ wrapper.prototype[name]: ->
+ unshift.call(arguments, this._wrapped)
+ result(method.apply(_, arguments), this._chain)
# Add all mutator Array functions to the wrapper.
- _.each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift']) name =>
+ _.each ['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], (name) ->
method: Array.prototype[name]
- wrapper.prototype[name]: =>
+ wrapper.prototype[name]: ->
method.apply(this._wrapped, arguments)
result(this._wrapped, this._chain)
# Add all accessor Array functions to the wrapper.
- _.each(['concat', 'join', 'slice']) name =>
+ _.each ['concat', 'join', 'slice'], (name) ->
method: Array.prototype[name]
- wrapper.prototype[name]: =>
+ wrapper.prototype[name]: ->
result(method.apply(this._wrapped, arguments), this._chain)
# Start chaining a wrapped Underscore object.
- wrapper::chain: =>
+ wrapper::chain: ->
this._chain: true
this
# Extracts the result from a wrapped and chained object.
- wrapper::value: => this._wrapped
+ wrapper::value: -> this._wrapped
diff --git a/lib/coffee_script/CoffeeScript.tmbundle/Preferences/CoffeeScript.tmPreferences b/extras/CoffeeScript.tmbundle/Preferences/CoffeeScript.tmPreferences
similarity index 100%
rename from lib/coffee_script/CoffeeScript.tmbundle/Preferences/CoffeeScript.tmPreferences
rename to extras/CoffeeScript.tmbundle/Preferences/CoffeeScript.tmPreferences
diff --git a/lib/coffee_script/CoffeeScript.tmbundle/Syntaxes/CoffeeScript.tmLanguage b/extras/CoffeeScript.tmbundle/Syntaxes/CoffeeScript.tmLanguage
similarity index 92%
rename from lib/coffee_script/CoffeeScript.tmbundle/Syntaxes/CoffeeScript.tmLanguage
rename to extras/CoffeeScript.tmbundle/Syntaxes/CoffeeScript.tmLanguage
index f0daaede1e..49082c8a1b 100644
--- a/lib/coffee_script/CoffeeScript.tmbundle/Syntaxes/CoffeeScript.tmLanguage
+++ b/extras/CoffeeScript.tmbundle/Syntaxes/CoffeeScript.tmLanguage
@@ -19,52 +19,31 @@
☕ CoffeeScript
Table of Contents
@@ -51,7 +51,6 @@ Table of Contents
Objects and Arrays
Lexical Scoping and Variable Safety
Conditionals, Ternaries, and Conditional Assignment
- The Existential Operator
Aliases
Splats...
Arguments are Arrays
@@ -59,17 +58,16 @@ Table of Contents
Comprehensions (Arrays, Objects, and Ranges)
Array Slicing and Splicing with Ranges
Everything is an Expression
+ The Existential Operator
Inheritance, and Calling Super from a Subclass
- Blocks
Pattern Matching
- Function Binding
+ Function Binding
Embedded JavaScript
Switch/When/Else
Try/Catch/Finally
Chained Comparisons
Multiline Strings and Heredocs
Resources
- Contributing
Change Log
var __a, __b, __c, cubed_list, list, math, num, number, opposite_day, race, square; // Assignment: number = 42; @@ -146,7 +144,7 @@Mini Overview
__a.push(math.cube(num)); } return __a; -})(); +}).call(this);
@@ -271,7 +269,7 @@
-e, --eval
-v, --verbose
+ You don't need to use parentheses to invoke a function, if you're passing
+ arguments:
print "coffee"
+
You can use newlines to break up your expression into smaller pieces, - as long as CoffeeScript can tell that the line hasn't finished - (similar to how Ruby handles it). For example, - if the line ends in an operator, dot, or keyword. + as long as CoffeeScript can determine that the line hasn't finished yet.
Functions and Invocation Functions are defined by a list of parameters, an arrow, and the - function body. The empty function looks like this: =>. All - functions in CoffeeScript are named by default, for the benefit of debug messages. - If you'd like to create an anonymous function, just wrap it in parentheses. + function body. The empty function looks like this: ->. All + functions in CoffeeScript are named by default, for easier debugging.
-square: x => x * x -cube: x => square(x) * x ++square: (x) -> x * x +cube: (x) -> square(x) * xvar cube, square; square = function square(x) { return x * x; @@ -376,6 +376,10 @@Language Reference
return square(x) * x; }; ;alert(cube(5));'>run: cube(5)+ If you'd like to create an anonymous function, just wrap it in parentheses: + ((x) -> x * x) +
Assignment @@ -393,7 +397,7 @@
Language Reference
difficulty = 0.5; ;alert(greeting);'>run: greeting
- Declarations of new variables are pushed up to the top of the nearest + Declaration of new variables are pushed up to the top of the nearest lexical scope, so that assignment may always be performed within expressions.
@@ -402,7 +406,7 @@song: ["do", "re", "mi", "fa", "so"] @@ -443,7 +447,7 @@Language Reference
var yourself.num: 1 -change_numbers: => +change_numbers: -> new_num: -1 num: 10 new_num: change_numbers() @@ -477,9 +481,14 @@Language Reference
CoffeeScript output is wrapped in an anonymous function: (function(){ ... })(); This safety wrapper, combined with the automatic generation of the var keyword, make it exceedingly difficult - to pollute the global namespace by accident. If you'd like to create - global variables, attach them as properties on window, - or on the exports object in CommonJS. + to pollute the global namespace by accident. + ++ If you'd like to create top-level variables for other scripts to use, + attach them as properties on window, or on the exports + object in CommonJS. The existential operator (below), gives you a + reliable way to figure out where to add them, if you're targeting both + CommonJS and the browser: root: exports ? this
@@ -520,38 +529,6 @@
Language Reference
truthy variables. -- The Existential Operator - It's a little difficult to check for the existence of a variable in - JavaScript. if (variable) ... comes close, but fails for zero, - the empty string, and false. The existential operator ? returns true unless - a variable is null or undefined, which makes it analogous - to Ruby's nil? -
-- It can also be used for safer conditional assignment than ||= - provides, for cases where you may be handling numbers or strings. -
--solipsism: true if mind? and not world? - -speed ?= 140 - - - - - -var solipsism, speed; -if ((typeof mind !== "undefined" && mind !== null) && !(typeof world !== "undefined" && world !== null)) { - solipsism = true; -} -speed = (typeof speed !== "undefined" && speed !== null) ? speed : 140; -Aliases Because the == operator frequently causes undesirable coercion, @@ -605,11 +582,11 @@
Language Reference
The JavaScript arguments object is a useful way to work with functions that accept variable numbers of arguments. CoffeeScript provides splats ..., both for function definition as well as invocation, - making variable arguments a little bit more palatable. + making variable numbers of arguments a little bit more palatable.gold: silver: the_field: "unknown" -medalists: first, second, rest... => +award_medals: (first, second, rest...) -> gold: first silver: second the_field: rest @@ -627,14 +604,14 @@Language Reference
"Usain Bolt" ] -medalists(contenders...) +award_medals contenders... -alert("Gold: " + gold) -alert("Silver: " + silver) -alert("The Field: " + the_field) -var contenders, gold, medalists, silver, the_field; +alert "Gold: " + gold +alert "Silver: " + silver +alert "The Field: " + the_field +var award_medals, contenders, gold, silver, the_field; gold = (silver = (the_field = "unknown")); -medalists = function medalists(first, second) { +award_medals = function award_medals(first, second) { var rest; rest = Array.prototype.slice.call(arguments, 2); gold = first; @@ -642,13 +619,13 @@Language Reference
return the_field = rest; }; contenders = ["Michael Phelps", "Liu Xiang", "Yao Ming", "Allyson Felix", "Shawn Johnson", "Roman Sebrle", "Guo Jingjing", "Tyson Gay", "Asafa Powell", "Usain Bolt"]; -medalists.apply(this, contenders); +award_medals.apply(this, contenders); alert("Gold: " + gold); alert("Silver: " + silver); alert("The Field: " + the_field); -