1
0
Fork 0
mirror of https://github.com/jashkenas/coffeescript.git synced 2022-11-09 12:23:24 -05:00

first pass at 0.2.0 docs

This commit is contained in:
Jeremy Ashkenas 2010-01-04 22:19:45 -05:00
parent 3e24cef69f
commit 6e63a18f86
21 changed files with 430 additions and 116 deletions

View file

@ -1,5 +1,7 @@
# Eat lunch.
lunch: this.eat(food) for food in ['toast', 'cheese', 'wine']
lunch: eat(food) for food in ['toast', 'cheese', 'wine']
# Zebra-stripe a table.
highlight(row) for row, i in table when i % 2 is 0
# Naive collision detection.
for roid in asteroids
for roid2 in asteroids when roid isnt roid2
roid.explode() if roid.overlaps(roid2)

View file

@ -0,0 +1 @@
solipsism: true if mind? and not world?

View file

@ -0,0 +1,3 @@
# The first ten global properties.
globals: (name for property, name in window)[0...10]

View file

@ -0,0 +1,6 @@
alert(
try
nonexistent / undefined
catch error
"The error is: " + error
)

View file

@ -0,0 +1,3 @@
years_old: {max: 10, ida: 9, tim: 11}
ages: child + " is " + age for age, child in years_old

View file

@ -1,6 +1,13 @@
song: ["do", "re", "mi", "fa", "so"]
ages: {
max: 10
ida: 9
tim: 11
}
}
matrix: [
1, 0, 1
0, 0, 1
1, 1, 0
]

View file

@ -0,0 +1,3 @@
for i in [0...eggs.length] by 12
dozen_eggs: eggs[i...i+12]
deliver(new egg_carton(dozen))

View file

@ -1,5 +1,5 @@
num: 1
change_numbers: =>
num: 2
new_num: 3
new_num: -1
num: 10
new_num: change_numbers()

View file

@ -0,0 +1,5 @@
numbers: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
numbers[3..6]: [-3, -4, -5, -6]

View file

@ -63,7 +63,7 @@
output is quite readable — pretty-printed, with comments
preserved intact.
</p>
<p>
<b>Latest Version:</b>
<a href="http://gemcutter.org/gems/coffee-script">0.2.0</a>
@ -74,17 +74,18 @@
<p>
<a href="#overview">Mini Overview</a><br />
<a href="#installation">Installation and Usage</a><br />
<a href="#punctuation">Punctuation Primer</a><br />
<a href="#whitespace">Significant Whitespace</a><br />
<a href="#functions">Functions and Invocation</a><br />
<a href="#assignment">Assignment</a><br />
<a href="#objects_and_arrays">Objects and Arrays</a><br />
<a href="#lexical_scope">Lexical Scoping and Variable Safety</a><br />
<a href="#conditionals">Conditionals, Ternaries, and Conditional Assignment</a><br />
<a href="#existence">The Existence Operator</a><br />
<a href="#expressions">Everything is an Expression</a><br />
<a href="#aliases">Aliases</a><br />
<a href="#while">While Loops</a><br />
<a href="#array_comprehensions">Array Comprehensions</a><br />
<a href="#slice">Slicing Arrays with Ranges</a><br />
<a href="#comprehensions">Comprehensions (Arrays, Objects, and Ranges)</a><br />
<a href="#slice_splice">Array Slicing and Splicing with Ranges</a><br />
<a href="#inheritance">Inheritance, and Calling Super from a Subclass</a><br />
<a href="#embedded">Embedded JavaScript</a><br />
<a href="#switch">Switch/When/Else</a><br />
@ -225,22 +226,22 @@ coffee --print app/scripts/*.coffee > concatenation.js</pre>
</i>
</p>
<p id="punctuation">
<b class="header">Punctuation Primer</b>
You don't need to use semicolons <tt>;</tt> to terminate expressions, ending
the line will do just as well. All other whitespace is
not significant. Instead of using curly braces <tt>{ }</tt>
to delimit a block of code, use a period <tt>.</tt> to mark the end of a
block, for
<a href="#functions">functions</a>,
<p id="whitespace">
<b class="header">Significant Whitespace</b>
CoffeeScript uses Python-style significant whitespace: You don't need to
use semicolons <tt>;</tt> to terminate expressions, ending
the line will do just as well. Semicolons can still be used to fit
multiple expressions onto a single line. Instead of using curly braces
<tt>{ }</tt> to delimit a block of code (like <a href="#functions">functions</a>,
<a href="#conditionals">if-statements</a>,
<a href="#switch">switch</a>, and <a href="#try">try/catch</a>.
<a href="#switch">switch</a>, and <a href="#try">try/catch</a>),
use indentation.
</p>
<p id="functions">
<b class="header">Functions and Invocation</b>
Functions are defined by a list of parameters, an arrow, and the
function body. The empty function looks like this: <tt>=>.</tt>
function body. The empty function looks like this: <tt>=></tt>
</p>
<%= code_for('functions', 'cube(5)') %>
@ -252,8 +253,8 @@ coffee --print app/scripts/*.coffee > concatenation.js</pre>
</p>
<%= code_for('assignment', 'greeting') %>
<p>
Declarations of new variables are pushed up to the top of the current scope,
so that assignments may always be used within expressions.
Declarations of new variables are pushed up to the top of the nearest
lexical scope, so that assignment may always be used within expressions.
</p>
<p id="objects_and_arrays">
@ -261,7 +262,8 @@ coffee --print app/scripts/*.coffee > concatenation.js</pre>
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.
assigning local variables, and can be moved around freely. You can mix
and match the two styles.
</p>
<%= code_for('objects_and_arrays', 'song.join(",")') %>
@ -273,25 +275,29 @@ coffee --print app/scripts/*.coffee > concatenation.js</pre>
</p>
<%= code_for('scope', 'new_num') %>
<p>
Notice how the variables are declared with <tt>var</tt> the first time
they appear. The second reference of <b>num</b>, within the function,
is not redeclared because <b>num</b> is still in scope. As opposed
to the second occurrence of <b>new_num</b>, in the last line.
Notice how the all of the variable declarations have been pushed up to
the top of the closest scope, the first time they appear.
<b>num</b> is not redeclared within the inner function, because it's
already in scope; the <b>new_num</b> within the function, on the other hand,
should not be able to change the value of the external variable of the same name, and
therefore has a declaration of its own.
</p>
<p>
Although suppressed within this documentation for clarity, all
CoffeeScript output is wrapped in an anonymous function:
<tt>(function(){ ... })();</tt> This safety wrapper, combined with the
automatic generation of the <tt>var</tt> 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
global variables, attach them as properties on <b>window</b>,
or on the <b>exports</b> object in CommonJS.
</p>
<p id="conditionals">
<b class="header">Conditionals, Ternaries, and Conditional Assignment</b>
<b>If/else</b> statements can be written without the use of parentheses and
curly brackets. As with functions and other block expressions, conditionals
are closed with periods. No period is necessary when using the single-line
postfix form, with the <tt>if</tt> at the end.
curly brackets. As with functions and other block expressions,
multi-line conditionals are delimited by indentation. There's also a handy
postfix form, with the <tt>if</tt> or <tt>unless</tt> at the end.
</p>
<p>
CoffeeScript will compile <b>if</b> statements using the ternary operator
@ -299,12 +305,22 @@ coffee --print app/scripts/*.coffee > concatenation.js</pre>
</p>
<%= code_for('conditionals') %>
<p>
The conditional assignment operators are available: <tt>||=</tt>,
The conditional assignment operators are included: <tt>||=</tt>,
which only assigns a value to a variable if the variable's current value
is falsy, and <tt>&amp;&amp;=</tt>, which only replaces the value of
truthy variables.
</p>
<p id="existence">
<b class="header">The Existence Operator</b>
It's a little difficult to check for the existence of a variable in
JavaScript. <tt>if (variable) ...</tt> comes close, but fails for zero,
the empty string, and false. The existence operator <tt>?</tt> returns true unless
a variable is <b>null</b> or <b>undefined</b>, which makes it analogous
to <b>nil?</b> in Ruby.
</p>
<%= code_for('existence') %>
<p id="expressions">
<b class="header">Everything is an Expression (at least, as much as possible)</b>
You might have noticed how even though we don't add return statements
@ -316,14 +332,22 @@ coffee --print app/scripts/*.coffee > concatenation.js</pre>
</p>
<%= code_for('expressions', 'eldest') %>
<p>
The same mechanism is used to push down assignment through <b>switch</b>
statements, and <b>if-elses</b> (although the ternary operator is preferred).
Another part of manipulating assignment statements is
CoffeeScript's declaration of new variables at the top of the
current scope. This allows assignment to be used as a piece of an
expression.
Because variable declarations occur at the top of scope, assignment can
be used within expressions, even for variables that haven't been seen before:
</p>
<%= code_for('expressions_assignment', 'six') %>
<p>
Things that would otherwise be statements in JavaScript, when used
as part of an expression in CoffeeScript, are converted into expressions
by wrapping them in a closure. This lets you do useful things, like assign
the result of a comprehension to a variable:
</p>
<%= code_for('expressions_comprehension', 'globals') %>
<p>
As well as silly things, like passing a <b>try/catch</b> statement directly
into a function call:
</p>
<%= code_for('expressions_try', true) %>
<p id="aliases">
<b class="header">Aliases</b>
@ -367,8 +391,8 @@ coffee --print app/scripts/*.coffee > concatenation.js</pre>
<b>each</b> (<b>forEach</b>) style iterators, or...
</p>
<p id="array_comprehensions">
<b class="header">Array Comprehensions</b>
<p id="comprehensions">
<b class="header">Comprehensions (Arrays, Objects, and Ranges)</b>
For your looping needs, CoffeeScript provides array comprehensions
similar to Python's. They replace (and compile into) <b>for</b> loops, with
optional guard clauses and the value of the current array index.
@ -378,13 +402,19 @@ coffee --print app/scripts/*.coffee > concatenation.js</pre>
</p>
<%= code_for('array_comprehensions') %>
<p>
If you're not iterating over an actual array, you can use a range to
specify the start and end of an array comprehension:
<tt>coundown(i) for i in [10..1].</tt>
If you know the start and end of your loop, or would like to step through
in fixed-size increments, you can use a range to specify the start and
end of your comprehension:
</p>
<%= code_for('range_comprehensions') %>
<p>
Comprehensions can also be used to iterate over the values and keys in
an object:
</p>
<%= code_for('object_comprehensions', 'ages.join(", ")') %>
<p id="slice">
<b class="header">Slicing Arrays with Ranges</b>
<p id="slice_splice">
<b class="header">Array Slicing and Splicing with Ranges</b>
CoffeeScript borrows Ruby's
<a href="http://ruby-doc.org/core/classes/Range.html">range syntax</a>
for extracting slices of arrays. With two dots (<tt>3..5</tt>), the range
@ -393,6 +423,11 @@ coffee --print app/scripts/*.coffee > concatenation.js</pre>
a range that excludes the end.
</p>
<%= code_for('slices', 'numbers_copy') %>
<p>
The same syntax can be used with assignment to replace a segment of an
array with new values (to splice it).
</p>
<%= code_for('splices', 'numbers') %>
<p id="inheritance">
<b class="header">Inheritance, and Calling Super from a Subclass</b>

View file

@ -1,5 +1,5 @@
(function(){
var __a, __b, __c, __d, __e, __f, food, i, lunch, row;
var __a, __b, __c, __d, __e, __f, __g, __h, __i, __j, food, lunch, roid, roid2;
// Eat lunch.
lunch = (function() {
__a = ['toast', 'cheese', 'wine'];
@ -7,18 +7,28 @@
for (__b in __a) {
if (__a.hasOwnProperty(__b)) {
food = __a[__b];
__d = this.eat(food);
__d = eat(food);
__c.push(__d);
}
}
return __c;
})();
// Zebra-stripe a table.
__e = table;
for (i in __e) {
if (__e.hasOwnProperty(i)) {
row = __e[i];
i % 2 === 0 ? highlight(row) : null;
// Naive collision detection.
__e = asteroids;
for (__f in __e) {
if (__e.hasOwnProperty(__f)) {
roid = __e[__f];
__h = asteroids;
for (__i in __h) {
if (__h.hasOwnProperty(__i)) {
roid2 = __h[__i];
if (roid !== roid2) {
if (roid.overlaps(roid2)) {
roid.explode();
}
}
}
}
}
}
})();

View file

@ -0,0 +1,6 @@
(function(){
var solipsism;
if ((typeof mind !== 'undefined' && mind !== null) && !(typeof world !== 'undefined' && world !== null)) {
solipsism = true;
}
})();

View file

@ -0,0 +1,16 @@
(function(){
var __a, __b, __c, globals, name, property;
// The first ten global properties.
globals = ((function() {
__a = window;
__b = [];
for (name in __a) {
if (__a.hasOwnProperty(name)) {
property = __a[name];
__c = name;
__b.push(__c);
}
}
return __b;
})()).slice(0, 10);
})();

View file

@ -0,0 +1,9 @@
(function(){
alert((function() {
try {
return nonexistent / undefined;
} catch (error) {
return "The error is: " + error;
}
})());
})();

View file

@ -0,0 +1,20 @@
(function(){
var __a, __b, __c, age, ages, child, years_old;
years_old = {
max: 10,
ida: 9,
tim: 11
};
ages = (function() {
__a = years_old;
__b = [];
for (child in __a) {
if (__a.hasOwnProperty(child)) {
age = __a[child];
__c = child + " is " + age;
__b.push(__c);
}
}
return __b;
})();
})();

View file

@ -1,9 +1,10 @@
(function(){
var ages, song;
var ages, matrix, song;
song = ["do", "re", "mi", "fa", "so"];
ages = {
max: 10,
ida: 9,
tim: 11
};
matrix = [1, 0, 1, 0, 0, 1, 1, 1, 0];
})();

View file

@ -0,0 +1,9 @@
(function(){
var __a, __b, __c, __d, __e, dozen_eggs, i;
__d = 0;
__e = eggs.length;
for (__c=0, i=__d; (__d <= __e ? i < __e : i > __e); (__d <= __e ? i += 12 : i -= 12), __c++) {
dozen_eggs = eggs.slice(i, i + 12);
deliver(new egg_carton(dozen));
}
})();

View file

@ -3,8 +3,8 @@
num = 1;
change_numbers = function change_numbers() {
var new_num;
num = 2;
return new_num = 3;
new_num = -1;
return num = 10;
};
new_num = change_numbers();
})();

View file

@ -0,0 +1,5 @@
(function(){
var numbers;
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
numbers.splice.apply(numbers, [3, 6 - 3 + 1].concat([-3, -4, -5, -6]));
})();

View file

@ -36,7 +36,7 @@
output is quite readable &mdash; pretty-printed, with comments
preserved intact.
</p>
<p>
<b>Latest Version:</b>
<a href="http://gemcutter.org/gems/coffee-script">0.2.0</a>
@ -47,17 +47,18 @@
<p>
<a href="#overview">Mini Overview</a><br />
<a href="#installation">Installation and Usage</a><br />
<a href="#punctuation">Punctuation Primer</a><br />
<a href="#whitespace">Significant Whitespace</a><br />
<a href="#functions">Functions and Invocation</a><br />
<a href="#assignment">Assignment</a><br />
<a href="#objects_and_arrays">Objects and Arrays</a><br />
<a href="#lexical_scope">Lexical Scoping and Variable Safety</a><br />
<a href="#conditionals">Conditionals, Ternaries, and Conditional Assignment</a><br />
<a href="#existence">The Existence Operator</a><br />
<a href="#expressions">Everything is an Expression</a><br />
<a href="#aliases">Aliases</a><br />
<a href="#while">While Loops</a><br />
<a href="#array_comprehensions">Array Comprehensions</a><br />
<a href="#slice">Slicing Arrays with Ranges</a><br />
<a href="#comprehensions">Comprehensions (Arrays, Objects, and Ranges)</a><br />
<a href="#slice_splice">Array Slicing and Splicing with Ranges</a><br />
<a href="#inheritance">Inheritance, and Calling Super from a Subclass</a><br />
<a href="#embedded">Embedded JavaScript</a><br />
<a href="#switch">Switch/When/Else</a><br />
@ -290,22 +291,22 @@ coffee --print app/scripts/*.coffee > concatenation.js</pre>
</i>
</p>
<p id="punctuation">
<b class="header">Punctuation Primer</b>
You don't need to use semicolons <tt>;</tt> to terminate expressions, ending
the line will do just as well. All other whitespace is
not significant. Instead of using curly braces <tt>{ }</tt>
to delimit a block of code, use a period <tt>.</tt> to mark the end of a
block, for
<a href="#functions">functions</a>,
<p id="whitespace">
<b class="header">Significant Whitespace</b>
CoffeeScript uses Python-style significant whitespace: You don't need to
use semicolons <tt>;</tt> to terminate expressions, ending
the line will do just as well. Semicolons can still be used to fit
multiple expressions onto a single line. Instead of using curly braces
<tt>{ }</tt> to delimit a block of code (like <a href="#functions">functions</a>,
<a href="#conditionals">if-statements</a>,
<a href="#switch">switch</a>, and <a href="#try">try/catch</a>.
<a href="#switch">switch</a>, and <a href="#try">try/catch</a>),
use indentation.
</p>
<p id="functions">
<b class="header">Functions and Invocation</b>
Functions are defined by a list of parameters, an arrow, and the
function body. The empty function looks like this: <tt>=>.</tt>
function body. The empty function looks like this: <tt>=></tt>
</p>
<div class='code'><pre class="idle"><span class="FunctionName">square</span><span class="Keyword">:</span> <span class="FunctionArgument">x</span> <span class="Storage">=&gt;</span> x <span class="Keyword">*</span> x
<span class="FunctionName">cube</span><span class="Keyword">:</span> <span class="FunctionArgument">x</span> <span class="Storage">=&gt;</span> square(x) <span class="Keyword">*</span> x
@ -341,8 +342,8 @@ greeting = "Hello CoffeeScript";
difficulty = 0.5;
;alert(greeting);'>run: greeting</button><br class='clear' /></div>
<p>
Declarations of new variables are pushed up to the top of the current scope,
so that assignments may always be used within expressions.
Declarations of new variables are pushed up to the top of the nearest
lexical scope, so that assignment may always be used within expressions.
</p>
<p id="objects_and_arrays">
@ -350,28 +351,38 @@ difficulty = 0.5;
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.
assigning local variables, and can be moved around freely. You can mix
and match the two styles.
</p>
<div class='code'><pre class="idle">song<span class="Keyword">:</span> [<span class="String"><span class="String">&quot;</span>do<span class="String">&quot;</span></span>, <span class="String"><span class="String">&quot;</span>re<span class="String">&quot;</span></span>, <span class="String"><span class="String">&quot;</span>mi<span class="String">&quot;</span></span>, <span class="String"><span class="String">&quot;</span>fa<span class="String">&quot;</span></span>, <span class="String"><span class="String">&quot;</span>so<span class="String">&quot;</span></span>]
ages<span class="Keyword">:</span> {
max<span class="Keyword">:</span> <span class="Number">10</span>
ida<span class="Keyword">:</span> <span class="Number">9</span>
tim<span class="Keyword">:</span> <span class="Number">11</span>
}
</pre><pre class="idle"><span class="Storage">var</span> ages, song;
matrix<span class="Keyword">:</span> [
<span class="Number">1</span>, <span class="Number">0</span>, <span class="Number">1</span>
<span class="Number">0</span>, <span class="Number">0</span>, <span class="Number">1</span>
<span class="Number">1</span>, <span class="Number">1</span>, <span class="Number">0</span>
]
</pre><pre class="idle"><span class="Storage">var</span> ages, matrix, song;
song <span class="Keyword">=</span> [<span class="String"><span class="String">&quot;</span>do<span class="String">&quot;</span></span>, <span class="String"><span class="String">&quot;</span>re<span class="String">&quot;</span></span>, <span class="String"><span class="String">&quot;</span>mi<span class="String">&quot;</span></span>, <span class="String"><span class="String">&quot;</span>fa<span class="String">&quot;</span></span>, <span class="String"><span class="String">&quot;</span>so<span class="String">&quot;</span></span>];
ages <span class="Keyword">=</span> {
max: <span class="Number">10</span>,
ida: <span class="Number">9</span>,
tim: <span class="Number">11</span>
};
</pre><button onclick='javascript: var ages, song;
matrix <span class="Keyword">=</span> [<span class="Number">1</span>, <span class="Number">0</span>, <span class="Number">1</span>, <span class="Number">0</span>, <span class="Number">0</span>, <span class="Number">1</span>, <span class="Number">1</span>, <span class="Number">1</span>, <span class="Number">0</span>];
</pre><button onclick='javascript: var ages, matrix, song;
song = ["do", "re", "mi", "fa", "so"];
ages = {
max: 10,
ida: 9,
tim: 11
};
matrix = [1, 0, 1, 0, 0, 1, 1, 1, 0];
;alert(song.join(","));'>run: song.join(",")</button><br class='clear' /></div>
<p id="lexical_scope">
@ -382,46 +393,50 @@ ages = {
</p>
<div class='code'><pre class="idle">num<span class="Keyword">:</span> <span class="Number">1</span>
<span class="FunctionName">change_numbers</span><span class="Keyword">:</span> <span class="Storage">=&gt;</span>
num<span class="Keyword">:</span> <span class="Number">2</span>
new_num<span class="Keyword">:</span> <span class="Number">3</span>
new_num<span class="Keyword">:</span> <span class="Keyword">-</span><span class="Number">1</span>
num<span class="Keyword">:</span> <span class="Number">10</span>
new_num<span class="Keyword">:</span> change_numbers()
</pre><pre class="idle"><span class="Storage">var</span> change_numbers, new_num, num;
num <span class="Keyword">=</span> <span class="Number">1</span>;
change_numbers <span class="Keyword">=</span> <span class="Storage">function</span> <span class="FunctionName">change_numbers</span>() {
<span class="Storage">var</span> new_num;
num <span class="Keyword">=</span> <span class="Number">2</span>;
<span class="Keyword">return</span> new_num <span class="Keyword">=</span> <span class="Number">3</span>;
new_num <span class="Keyword">=</span> <span class="Keyword">-</span><span class="Number">1</span>;
<span class="Keyword">return</span> num <span class="Keyword">=</span> <span class="Number">10</span>;
};
new_num <span class="Keyword">=</span> change_numbers();
</pre><button onclick='javascript: var change_numbers, new_num, num;
num = 1;
change_numbers = function change_numbers() {
var new_num;
num = 2;
return new_num = 3;
new_num = -1;
return num = 10;
};
new_num = change_numbers();
;alert(new_num);'>run: new_num</button><br class='clear' /></div>
<p>
Notice how the variables are declared with <tt>var</tt> the first time
they appear. The second reference of <b>num</b>, within the function,
is not redeclared because <b>num</b> is still in scope. As opposed
to the second occurrence of <b>new_num</b>, in the last line.
Notice how the all of the variable declarations have been pushed up to
the top of the closest scope, the first time they appear.
<b>num</b> is not redeclared within the inner function, because it's
already in scope; the <b>new_num</b> within the function, on the other hand,
should not be able to change the value of the external variable of the same name, and
therefore has a declaration of its own.
</p>
<p>
Although suppressed within this documentation for clarity, all
CoffeeScript output is wrapped in an anonymous function:
<tt>(function(){ ... })();</tt> This safety wrapper, combined with the
automatic generation of the <tt>var</tt> 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
global variables, attach them as properties on <b>window</b>,
or on the <b>exports</b> object in CommonJS.
</p>
<p id="conditionals">
<b class="header">Conditionals, Ternaries, and Conditional Assignment</b>
<b>If/else</b> statements can be written without the use of parentheses and
curly brackets. As with functions and other block expressions, conditionals
are closed with periods. No period is necessary when using the single-line
postfix form, with the <tt>if</tt> at the end.
curly brackets. As with functions and other block expressions,
multi-line conditionals are delimited by indentation. There's also a handy
postfix form, with the <tt>if</tt> or <tt>unless</tt> at the end.
</p>
<p>
CoffeeScript will compile <b>if</b> statements using the ternary operator
@ -448,12 +463,27 @@ date <span class="Keyword">=</span> friday ? sue : jill;
expensive <span class="Keyword">=</span> expensive <span class="Keyword">||</span> do_the_math();
</pre><br class='clear' /></div>
<p>
The conditional assignment operators are available: <tt>||=</tt>,
The conditional assignment operators are included: <tt>||=</tt>,
which only assigns a value to a variable if the variable's current value
is falsy, and <tt>&amp;&amp;=</tt>, which only replaces the value of
truthy variables.
</p>
<p id="existence">
<b class="header">The Existence Operator</b>
It's a little difficult to check for the existence of a variable in
JavaScript. <tt>if (variable) ...</tt> comes close, but fails for zero,
the empty string, and false. The existence operator <tt>?</tt> returns true unless
a variable is <b>null</b> or <b>undefined</b>, which makes it analogous
to <b>nil?</b> in Ruby.
</p>
<div class='code'><pre class="idle">solipsism<span class="Keyword">:</span> <span class="BuiltInConstant">true</span> <span class="Keyword">if</span> mind<span class="Keyword">?</span> <span class="Keyword">and</span> <span class="Keyword">not</span> world<span class="Keyword">?</span>
</pre><pre class="idle"><span class="Storage">var</span> solipsism;
<span class="Keyword">if</span> ((<span class="Keyword">typeof</span> mind <span class="Keyword">!</span><span class="Keyword">==</span> <span class="String"><span class="String">'</span>undefined<span class="String">'</span></span> <span class="Keyword">&amp;</span><span class="Keyword">&amp;</span> mind <span class="Keyword">!</span><span class="Keyword">==</span> <span class="BuiltInConstant">null</span>) <span class="Keyword">&amp;</span><span class="Keyword">&amp;</span> <span class="Keyword">!</span>(<span class="Keyword">typeof</span> world <span class="Keyword">!</span><span class="Keyword">==</span> <span class="String"><span class="String">'</span>undefined<span class="String">'</span></span> <span class="Keyword">&amp;</span><span class="Keyword">&amp;</span> world <span class="Keyword">!</span><span class="Keyword">==</span> <span class="BuiltInConstant">null</span>)) {
solipsism <span class="Keyword">=</span> <span class="BuiltInConstant">true</span>;
}
</pre><br class='clear' /></div>
<p id="expressions">
<b class="header">Everything is an Expression (at least, as much as possible)</b>
You might have noticed how even though we don't add return statements
@ -496,12 +526,8 @@ grade = function grade(student) {
eldest = 24 > 21 ? "Liz" : "Ike";
;alert(eldest);'>run: eldest</button><br class='clear' /></div>
<p>
The same mechanism is used to push down assignment through <b>switch</b>
statements, and <b>if-elses</b> (although the ternary operator is preferred).
Another part of manipulating assignment statements is
CoffeeScript's declaration of new variables at the top of the
current scope. This allows assignment to be used as a piece of an
expression.
Because variable declarations occur at the top of scope, assignment can
be used within expressions, even for variables that haven't been seen before:
</p>
<div class='code'><pre class="idle">six<span class="Keyword">:</span> (one<span class="Keyword">:</span> <span class="Number">1</span>) <span class="Keyword">+</span> (two<span class="Keyword">:</span> <span class="Number">2</span>) <span class="Keyword">+</span> (three<span class="Keyword">:</span> <span class="Number">3</span>)
</pre><pre class="idle"><span class="Storage">var</span> one, six, three, two;
@ -509,6 +535,69 @@ six <span class="Keyword">=</span> (one <span class="Keyword">=</span> <span cla
</pre><button onclick='javascript: var one, six, three, two;
six = (one = 1) + (two = 2) + (three = 3);
;alert(six);'>run: six</button><br class='clear' /></div>
<p>
Things that would otherwise be statements in JavaScript, when used
as part of an expression in CoffeeScript, are converted into expressions
by wrapping them in a closure. This lets you do useful things, like assign
the result of a comprehension to a variable:
</p>
<div class='code'><pre class="idle"><span class="Comment"><span class="Comment">#</span> The first ten global properties.</span>
globals<span class="Keyword">:</span> (name <span class="Keyword">for</span> property, name <span class="Keyword">in</span> window)[<span class="Number">0</span>...<span class="Number">10</span>]
</pre><pre class="idle"><span class="Storage">var</span> __a, __b, __c, globals, name, property;
<span class="Comment"><span class="Comment">//</span> The first ten global properties.</span>
globals <span class="Keyword">=</span> ((<span class="Storage">function</span>() {
__a <span class="Keyword">=</span> <span class="LibraryClassType">window</span>;
__b <span class="Keyword">=</span> [];
<span class="Keyword">for</span> (name <span class="Keyword">in</span> __a) {
<span class="Keyword">if</span> (__a.hasOwnProperty(name)) {
property <span class="Keyword">=</span> __a[name];
__c <span class="Keyword">=</span> name;
__b.<span class="LibraryFunction">push</span>(__c);
}
}
<span class="Keyword">return</span> __b;
})()).<span class="LibraryFunction">slice</span>(<span class="Number">0</span>, <span class="Number">10</span>);
</pre><button onclick='javascript: var __a, __b, __c, globals, name, property;
// The first ten global properties.
globals = ((function() {
__a = window;
__b = [];
for (name in __a) {
if (__a.hasOwnProperty(name)) {
property = __a[name];
__c = name;
__b.push(__c);
}
}
return __b;
})()).slice(0, 10);
;alert(globals);'>run: globals</button><br class='clear' /></div>
<p>
As well as silly things, like passing a <b>try/catch</b> statement directly
into a function call:
</p>
<div class='code'><pre class="idle">alert(
<span class="Keyword">try</span>
nonexistent <span class="Keyword">/</span> <span class="BuiltInConstant">undefined</span>
<span class="Keyword">catch</span> error
<span class="String"><span class="String">&quot;</span>The error is: <span class="String">&quot;</span></span> <span class="Keyword">+</span> error
)
</pre><pre class="idle"><span class="LibraryFunction">alert</span>((<span class="Storage">function</span>() {
<span class="Keyword">try</span> {
<span class="Keyword">return</span> nonexistent / undefined;
} <span class="Keyword">catch</span> (error) {
<span class="Keyword">return</span> <span class="String"><span class="String">&quot;</span>The error is: <span class="String">&quot;</span></span> <span class="Keyword">+</span> error;
}
})());
</pre><button onclick='javascript: alert((function() {
try {
return nonexistent / undefined;
} catch (error) {
return "The error is: " + error;
}
})());
;'>run</button><br class='clear' /></div>
<p id="aliases">
<b class="header">Aliases</b>
@ -582,8 +671,8 @@ car.speed <span class="Keyword">&lt;</span> speed_limit ? accelerate() : <span c
<b>each</b> (<b>forEach</b>) style iterators, or...
</p>
<p id="array_comprehensions">
<b class="header">Array Comprehensions</b>
<p id="comprehensions">
<b class="header">Comprehensions (Arrays, Objects, and Ranges)</b>
For your looping needs, CoffeeScript provides array comprehensions
similar to Python's. They replace (and compile into) <b>for</b> loops, with
optional guard clauses and the value of the current array index.
@ -592,11 +681,13 @@ car.speed <span class="Keyword">&lt;</span> speed_limit ? accelerate() : <span c
would use a loop, <b>each</b>/<b>forEach</b>, <b>map</b>, or <b>select</b>/<b>filter</b>.
</p>
<div class='code'><pre class="idle"><span class="Comment"><span class="Comment">#</span> Eat lunch.</span>
lunch<span class="Keyword">:</span> <span class="Variable">this</span>.eat(food) <span class="Keyword">for</span> food <span class="Keyword">in</span> [<span class="String"><span class="String">'</span>toast<span class="String">'</span></span>, <span class="String"><span class="String">'</span>cheese<span class="String">'</span></span>, <span class="String"><span class="String">'</span>wine<span class="String">'</span></span>]
lunch<span class="Keyword">:</span> eat(food) <span class="Keyword">for</span> food <span class="Keyword">in</span> [<span class="String"><span class="String">'</span>toast<span class="String">'</span></span>, <span class="String"><span class="String">'</span>cheese<span class="String">'</span></span>, <span class="String"><span class="String">'</span>wine<span class="String">'</span></span>]
<span class="Comment"><span class="Comment">#</span> Zebra-stripe a table.</span>
highlight(row) <span class="Keyword">for</span> row, i <span class="Keyword">in</span> table <span class="Keyword">when</span> i <span class="Keyword">%</span> <span class="Number">2</span> <span class="Keyword">is</span> <span class="Number">0</span>
</pre><pre class="idle"><span class="Storage">var</span> __a, __b, __c, __d, __e, __f, food, i, lunch, row;
<span class="Comment"><span class="Comment">#</span> Naive collision detection.</span>
<span class="Keyword">for</span> roid <span class="Keyword">in</span> asteroids
<span class="Keyword">for</span> roid2 <span class="Keyword">in</span> asteroids <span class="Keyword">when</span> roid <span class="Keyword">isnt</span> roid2
roid.explode() <span class="Keyword">if</span> roid.overlaps(roid2)
</pre><pre class="idle"><span class="Storage">var</span> __a, __b, __c, __d, __e, __f, __g, __h, __i, __j, food, lunch, roid, roid2;
<span class="Comment"><span class="Comment">//</span> Eat lunch.</span>
lunch <span class="Keyword">=</span> (<span class="Storage">function</span>() {
__a <span class="Keyword">=</span> [<span class="String"><span class="String">'</span>toast<span class="String">'</span></span>, <span class="String"><span class="String">'</span>cheese<span class="String">'</span></span>, <span class="String"><span class="String">'</span>wine<span class="String">'</span></span>];
@ -604,29 +695,94 @@ lunch <span class="Keyword">=</span> (<span class="Storage">function</span>() {
<span class="Keyword">for</span> (__b <span class="Keyword">in</span> __a) {
<span class="Keyword">if</span> (__a.hasOwnProperty(__b)) {
food <span class="Keyword">=</span> __a[__b];
__d <span class="Keyword">=</span> <span class="Variable">this</span>.eat(food);
__d <span class="Keyword">=</span> eat(food);
__c.<span class="LibraryFunction">push</span>(__d);
}
}
<span class="Keyword">return</span> __c;
})();
<span class="Comment"><span class="Comment">//</span> Zebra-stripe a table.</span>
__e <span class="Keyword">=</span> table;
<span class="Keyword">for</span> (i <span class="Keyword">in</span> __e) {
<span class="Keyword">if</span> (__e.hasOwnProperty(i)) {
row <span class="Keyword">=</span> __e[i];
i <span class="Keyword">%</span> <span class="Number">2</span> <span class="Keyword">===</span> <span class="Number">0</span> ? highlight(row) : <span class="BuiltInConstant">null</span>;
<span class="Comment"><span class="Comment">//</span> Naive collision detection.</span>
__e <span class="Keyword">=</span> asteroids;
<span class="Keyword">for</span> (__f <span class="Keyword">in</span> __e) {
<span class="Keyword">if</span> (__e.hasOwnProperty(__f)) {
roid <span class="Keyword">=</span> __e[__f];
__h <span class="Keyword">=</span> asteroids;
<span class="Keyword">for</span> (__i <span class="Keyword">in</span> __h) {
<span class="Keyword">if</span> (__h.hasOwnProperty(__i)) {
roid2 <span class="Keyword">=</span> __h[__i];
<span class="Keyword">if</span> (roid <span class="Keyword">!</span><span class="Keyword">==</span> roid2) {
<span class="Keyword">if</span> (roid.overlaps(roid2)) {
roid.explode();
}
}
}
}
}
}
</pre><br class='clear' /></div>
<p>
If you're not iterating over an actual array, you can use a range to
specify the start and end of an array comprehension:
<tt>coundown(i) for i in [10..1].</tt>
If you know the start and end of your loop, or would like to step through
in fixed-size increments, you can use a range to specify the start and
end of your comprehension:
</p>
<div class='code'><pre class="idle"><span class="Keyword">for</span> i <span class="Keyword">in</span> [<span class="Number">0</span>...eggs.length] <span class="Keyword">by</span> <span class="Number">12</span>
dozen_eggs<span class="Keyword">:</span> eggs[i...i<span class="Keyword">+</span><span class="Number">12</span>]
deliver(<span class="Keyword">new</span> <span class="TypeName">egg_carton</span>(dozen))
</pre><pre class="idle"><span class="Storage">var</span> __a, __b, __c, __d, __e, dozen_eggs, i;
__d <span class="Keyword">=</span> <span class="Number">0</span>;
__e <span class="Keyword">=</span> eggs.<span class="LibraryConstant">length</span>;
<span class="Keyword">for</span> (__c<span class="Keyword">=</span><span class="Number">0</span>, i<span class="Keyword">=</span>__d; (__d <span class="Keyword">&lt;=</span> __e ? i <span class="Keyword">&lt;</span> __e : i <span class="Keyword">&gt;</span> __e); (__d <span class="Keyword">&lt;=</span> __e ? i <span class="Keyword">+</span><span class="Keyword">=</span> <span class="Number">12</span> : i <span class="Keyword">-</span><span class="Keyword">=</span> <span class="Number">12</span>), __c<span class="Keyword">++</span>) {
dozen_eggs <span class="Keyword">=</span> eggs.<span class="LibraryFunction">slice</span>(i, i <span class="Keyword">+</span> <span class="Number">12</span>);
deliver(<span class="Keyword">new</span> <span class="TypeName">egg_carton</span>(dozen));
}
</pre><br class='clear' /></div>
<p>
Comprehensions can also be used to iterate over the values and keys in
an object:
</p>
<div class='code'><pre class="idle">years_old<span class="Keyword">:</span> {max<span class="Keyword">:</span> <span class="Number">10</span>, ida<span class="Keyword">:</span> <span class="Number">9</span>, tim<span class="Keyword">:</span> <span class="Number">11</span>}
<p id="slice">
<b class="header">Slicing Arrays with Ranges</b>
ages<span class="Keyword">:</span> child <span class="Keyword">+</span> <span class="String"><span class="String">&quot;</span> is <span class="String">&quot;</span></span> <span class="Keyword">+</span> age <span class="Keyword">for</span> age, child <span class="Keyword">in</span> years_old
</pre><pre class="idle"><span class="Storage">var</span> __a, __b, __c, age, ages, child, years_old;
years_old <span class="Keyword">=</span> {
max: <span class="Number">10</span>,
ida: <span class="Number">9</span>,
tim: <span class="Number">11</span>
};
ages <span class="Keyword">=</span> (<span class="Storage">function</span>() {
__a <span class="Keyword">=</span> years_old;
__b <span class="Keyword">=</span> [];
<span class="Keyword">for</span> (child <span class="Keyword">in</span> __a) {
<span class="Keyword">if</span> (__a.hasOwnProperty(child)) {
age <span class="Keyword">=</span> __a[child];
__c <span class="Keyword">=</span> child <span class="Keyword">+</span> <span class="String"><span class="String">&quot;</span> is <span class="String">&quot;</span></span> <span class="Keyword">+</span> age;
__b.<span class="LibraryFunction">push</span>(__c);
}
}
<span class="Keyword">return</span> __b;
})();
</pre><button onclick='javascript: var __a, __b, __c, age, ages, child, years_old;
years_old = {
max: 10,
ida: 9,
tim: 11
};
ages = (function() {
__a = years_old;
__b = [];
for (child in __a) {
if (__a.hasOwnProperty(child)) {
age = __a[child];
__c = child + " is " + age;
__b.push(__c);
}
}
return __b;
})();
;alert(ages.join(", "));'>run: ages.join(", ")</button><br class='clear' /></div>
<p id="slice_splice">
<b class="header">Array Slicing and Splicing with Ranges</b>
CoffeeScript borrows Ruby's
<a href="http://ruby-doc.org/core/classes/Range.html">range syntax</a>
for extracting slices of arrays. With two dots (<tt>3..5</tt>), the range
@ -649,6 +805,22 @@ numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
three_to_six = numbers.slice(3, 6 + 1);
numbers_copy = numbers.slice(0, numbers.length);
;alert(numbers_copy);'>run: numbers_copy</button><br class='clear' /></div>
<p>
The same syntax can be used with assignment to replace a segment of an
array with new values (to splice it).
</p>
<div class='code'><pre class="idle">numbers<span class="Keyword">:</span> [<span class="Number">0</span>, <span class="Number">1</span>, <span class="Number">2</span>, <span class="Number">3</span>, <span class="Number">4</span>, <span class="Number">5</span>, <span class="Number">6</span>, <span class="Number">7</span>, <span class="Number">8</span>, <span class="Number">9</span>]
numbers[<span class="Number">3</span>..<span class="Number">6</span>]<span class="Keyword">:</span> [<span class="Keyword">-</span><span class="Number">3</span>, <span class="Keyword">-</span><span class="Number">4</span>, <span class="Keyword">-</span><span class="Number">5</span>, <span class="Keyword">-</span><span class="Number">6</span>]
</pre><pre class="idle"><span class="Storage">var</span> numbers;
numbers <span class="Keyword">=</span> [<span class="Number">0</span>, <span class="Number">1</span>, <span class="Number">2</span>, <span class="Number">3</span>, <span class="Number">4</span>, <span class="Number">5</span>, <span class="Number">6</span>, <span class="Number">7</span>, <span class="Number">8</span>, <span class="Number">9</span>];
numbers.splice.<span class="LibraryFunction">apply</span>(numbers, [<span class="Number">3</span>, <span class="Number">6</span> <span class="Keyword">-</span> <span class="Number">3</span> <span class="Keyword">+</span> <span class="Number">1</span>].<span class="LibraryFunction">concat</span>([<span class="Keyword">-</span><span class="Number">3</span>, <span class="Keyword">-</span><span class="Number">4</span>, <span class="Keyword">-</span><span class="Number">5</span>, <span class="Keyword">-</span><span class="Number">6</span>]));
</pre><button onclick='javascript: var numbers;
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
numbers.splice.apply(numbers, [3, 6 - 3 + 1].concat([-3, -4, -5, -6]));
;alert(numbers);'>run: numbers</button><br class='clear' /></div>
<p id="inheritance">
<b class="header">Inheritance, and Calling Super from a Subclass</b>

View file

@ -19,7 +19,8 @@ token INDENT OUTDENT
# Declare order of operations.
prechigh
nonassoc UMINUS PARAM_SPLAT SPLAT NOT '!' '!!' '~' '++' '--' '?'
left '?'
nonassoc UMINUS PARAM_SPLAT SPLAT NOT '!' '!!' '~' '++' '--'
left '*' '/' '%'
left '+' '-'
left '<<' '>>' '>>>'
@ -368,7 +369,7 @@ rule
# An individual when.
When:
LEADING_WHEN Expression Block { result = IfNode.new(val[1], val[2], nil, {:statement => true}) }
| LEADING_WHEN Expression Block
| LEADING_WHEN Expression Block
Terminator { result = IfNode.new(val[1], val[2], nil, {:statement => true}) }
| Comment
;