diff --git a/coffee-script.gemspec b/coffee-script.gemspec index f8a1c08a..8fdf3e53 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" diff --git a/documentation/coffee/blocks.coffee b/documentation/coffee/blocks.coffee deleted file mode 100644 index 16d9bc07..00000000 --- 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/long_arrow.coffee b/documentation/coffee/fat_arrow.coffee similarity index 100% rename from documentation/coffee/long_arrow.coffee rename to documentation/coffee/fat_arrow.coffee diff --git a/documentation/coffee/overview.coffee b/documentation/coffee/overview.coffee index 3156f840..23bdb4bd 100644 --- a/documentation/coffee/overview.coffee +++ b/documentation/coffee/overview.coffee @@ -26,4 +26,4 @@ race: (winner, runners...) -> 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/soaks.coffee b/documentation/coffee/soaks.coffee new file mode 100644 index 00000000..964fef5b --- /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 ea27d0c1..9faf4015 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,7 +18,7 @@ contenders: [ "Usain Bolt" ] -medalists contenders... +award_medals contenders... alert "Gold: " + gold alert "Silver: " + silver diff --git a/documentation/index.html.erb b/documentation/index.html.erb index 6b91505e..6ab260f8 100644 --- a/documentation/index.html.erb +++ b/documentation/index.html.erb @@ -51,7 +51,7 @@

Latest Version: - 0.2.6 + 0.3.0

Table of Contents

@@ -65,7 +65,6 @@ Objects and Arrays
Lexical Scoping and Variable Safety
Conditionals, Ternaries, and Conditional Assignment
- The Existential Operator
Aliases
Splats...
Arguments are Arrays
@@ -73,17 +72,16 @@ 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

@@ -188,7 +186,7 @@ gem install coffee-script -v, --verbose As the JavaScript is being generated, print out every step of code - generation, including lexical scope and the node in the + generation, including lexical scope and the nodes in the AST. @@ -248,6 +246,11 @@ coffee --print app/scripts/*.coffee > concatenation.js use indentation.

+

+ 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 determine that the line hasn't finished yet. @@ -307,12 +310,12 @@ 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. + 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 +

+ 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

@@ -336,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, @@ -487,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, namely 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 @@ -514,15 +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') %> -

Pattern Matching (Destructuring Assignment) To make extracting values from complex arrays and objects more convenient, @@ -545,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 @@ -625,6 +634,12 @@ coffee --print app/scripts/*.coffee > concatenation.js

  • Bugs, Feature Requests, and General Discussion
  • +
  • + CoffeePot
    + An implementation of CoffeeScript, written in CoffeeScript, by + Tim Caswell. Compiles just + a limited subset at this point. +
  • BistroCar
    A Rails plugin by @@ -640,39 +655,24 @@ coffee --print app/scripts/*.coffee > concatenation.js
  • -

    Contributing

    +

    Change Log

    - 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.

    - - -

    Change Log

    -

    0.2.6 Added Python-style chained comparisons, the conditional existence diff --git a/documentation/js/blocks.js b/documentation/js/blocks.js deleted file mode 100644 index f95dd31b..00000000 --- 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/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/soaks.js b/documentation/js/soaks.js new file mode 100644 index 00000000..efacb692 --- /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 4fb2085b..052437fe 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/index.html b/index.html index 1447e18e..86ed85b8 100644 --- a/index.html +++ b/index.html @@ -37,7 +37,7 @@

    Latest Version: - 0.2.6 + 0.3.0

    Table of Contents

    @@ -51,7 +51,6 @@ 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 @@ 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

    @@ -85,7 +83,7 @@ number: -42 if opposite_day # Functions: -square: (x) => x * x +square: (x) -> x * x # Arrays: list: [1, 2, 3, 4, 5] @@ -94,18 +92,18 @@ math: { root: Math.sqrt square: square - cube: (x) => x * square x + cube: (x) -> x * square x } # Splats: -race: (winner, runners...) => +race: (winner, runners...) -> print winner, runners # Existence: 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
    var __a, __b, __c, cubed_list, list, math, num, number, opposite_day, race, square;
     // Assignment:
     number = 42;
    @@ -285,7 +283,7 @@ gem install coffee-script
    -v, --verbose As the JavaScript is being generated, print out every step of code - generation, including lexical scope and the node in the + generation, including lexical scope and the nodes in the AST. @@ -345,6 +343,11 @@ coffee --print app/scripts/*.coffee > concatenation.js use indentation.

    +

    + 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 determine that the line hasn't finished yet. @@ -356,8 +359,8 @@ coffee --print app/scripts/*.coffee > concatenation.js 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) * x
     
    var cube, square;
     square = function square(x) {
       return x * x;
    @@ -444,7 +447,7 @@ matrix = [1, 0, 1, 0, 0, 1, 1, 1, 0];
           var yourself.
         

    num: 1
    -change_numbers: () =>
    +change_numbers: ->
       new_num: -1
       num: 10
     new_num: change_numbers()
    @@ -478,12 +481,12 @@ new_num = change_numbers();
           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. 
    +      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 +

    + 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

    @@ -526,38 +529,6 @@ expensive = expensive || -

    - 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, @@ -615,7 +586,7 @@ car.speed < speed_limit ? accelerate() :

    gold: silver: the_field: "unknown"
     
    -medalists: (first, second, rest...) =>
    +award_medals: (first, second, rest...) ->
       gold:       first
       silver:     second
       the_field:  rest
    @@ -633,14 +604,14 @@ car.speed < speed_limit ? accelerate() : "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;
    +
    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;
    @@ -648,13 +619,13 @@ medalists = function <
       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);
    -

    There are a handful of statements in JavaScript that can't be meaningfully - converted into expressions, namely 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. +

    +
    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;
    +

    +

    + 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. +

    +
    lottery.draw_winner()?.address?.zipcode
    +
    var __a;
    +((__a = lottery.draw_winner()) == undefined ? undefined : __a.address == undefined ? undefined : __a.address.zipcode);
    +

    +

    + 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 @@ -1078,19 +1099,19 @@ globals = ((function() { object's prototype, and converts super() into a call against the immediate ancestor's method of the same name.

    -
    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
     
    @@ -1179,25 +1200,6 @@ sam.move();
     tom.move();
     ;'>run
    -

    - 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. -

    -
    $('table.list').each (table) =>
    -  $('tr.account', table).each (row) =>
    -    row.show()
    -    row.highlight()
    -
    $('table.list').each(function(table) {
    -  return $('tr.account', table).each(function(row) {
    -    row.show();
    -    return row.highlight();
    -  });
    -});
    -

    -

    Pattern Matching (Destructuring Assignment) To make extracting values from complex arrays and objects more convenient, @@ -1229,7 +1231,7 @@ and_switch = __a[1]; But it's also helpful for dealing with functions that return multiple values.

    -
    weather_report: (location) =>
    +    
    weather_report: (location) ->
       # Make an Ajax request to fetch the weather...
       [location, 72, "Mostly Sunny"]
     
    @@ -1302,20 +1304,20 @@ street = __c[0];
     city = __c[1];
     ;alert(poet + " — " + street);'>run: 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.

    -
    Account: (customer, cart) =>
    +    
    Account: (customer, cart) ->
       this.customer: customer
       this.cart: cart
     
    -  $('.shopping_cart').bind('click') (event) ==>
    +  $('.shopping_cart').bind 'click', (event) =>
         this.customer.purchase this.cart
     
    var Account;
     Account = function Account(customer, cart) {
    @@ -1497,6 +1499,12 @@ html = &q
           
  • Bugs, Feature Requests, and General Discussion
  • +
  • + CoffeePot
    + An implementation of CoffeeScript, written in CoffeeScript, by + Tim Caswell. Compiles just + a limited subset at this point. +
  • BistroCar
    A Rails plugin by @@ -1512,39 +1520,24 @@ html = &q
  • -

    Contributing

    +

    Change Log

    - 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.

    -
      -
    • - - A CoffeeScript version of the compiler. - -
    • -
    • - Test cases for any syntax errors you encounter that you think CoffeeScript - should be able to compile properly. -
    • -
    • - A tutorial that introduces CoffeeScript from the ground up for folks - without knowledge of JavaScript. -
    • -
    • - Integration with Processing.js's JavaScript API (this would depend on - having a JavaScript version of the compiler). -
    • -
    • - A lot of the code generation in nodes.rb gets into messy - string manipulation. Techniques for cleaning this up across the board - would be appreciated. -
    • -
    - -

    Change Log

    -

    0.2.6 Added Python-style chained comparisons, the conditional existence diff --git a/lib/coffee-script.rb b/lib/coffee-script.rb index 399cb9a8..73189edd 100644 --- a/lib/coffee-script.rb +++ b/lib/coffee-script.rb @@ -10,7 +10,7 @@ require "coffee_script/parse_error" # Namespace for all CoffeeScript internal classes. module CoffeeScript - VERSION = '0.2.6' # Keep in sync with the gemspec. + VERSION = '0.3.0' # Keep in sync with the gemspec. # Compile a script (String or IO) to JavaScript. def self.compile(script, options={}) diff --git a/package.json b/package.json index c1d5b0d7..e891cfa1 100644 --- a/package.json +++ b/package.json @@ -5,5 +5,5 @@ "description": "Unfancy JavaScript", "keywords": ["javascript", "language"], "author": "Jeremy Ashkenas", - "version": "0.2.6" + "version": "0.3.0" }