Compare commits

..

11 Commits
0.2.3 ... 0.2.4

24 changed files with 500 additions and 111 deletions

View File

@@ -1,7 +1,7 @@
Gem::Specification.new do |s|
s.name = 'coffee-script'
s.version = '0.2.3' # Keep version in sync with coffee-script.rb
s.date = '2010-1-10'
s.version = '0.2.4' # Keep version in sync with coffee-script.rb
s.date = '2010-1-12'
s.homepage = "http://jashkenas.github.com/coffee-script/"
s.summary = "The CoffeeScript Compiler"

View File

@@ -0,0 +1,5 @@
html: '''
<strong>
cup of coffeescript
</strong>
'''

View File

@@ -0,0 +1,5 @@
weather_report: location =>
# Make an Ajax request to fetch the weather...
[location, 72, "Mostly Sunny"]
[city, temp, forecast]: weather_report("Berkeley, CA")

View File

@@ -0,0 +1,13 @@
futurists: {
sculptor: "Umberto Boccioni"
painter: "Vladimir Burliuk"
poet: {
name: "F.T. Marinetti"
address: [
"Via Roma 42R"
"Bellagio, Italy 22021"
]
}
}
{poet: {name: poet, address: [street, city]}}: futurists

View File

@@ -0,0 +1,4 @@
bait: 1000
and_switch: 0
[bait, and_switch]: [and_switch, bait]

View File

@@ -51,7 +51,7 @@
<p>
<b>Latest Version:</b>
<a href="http://gemcutter.org/gems/coffee-script">0.2.3</a>
<a href="http://gemcutter.org/gems/coffee-script">0.2.4</a>
</p>
<h2>Table of Contents</h2>
@@ -75,10 +75,11 @@
<a href="#expressions">Everything is an Expression</a><br />
<a href="#inheritance">Inheritance, and Calling Super from a Subclass</a><br />
<a href="#blocks">Blocks</a><br />
<a href="#pattern_matching">Pattern Matching</a><br />
<a href="#embedded">Embedded JavaScript</a><br />
<a href="#switch">Switch/When/Else</a><br />
<a href="#try">Try/Catch/Finally</a><br />
<a href="#strings">Multiline Strings</a><br />
<a href="#strings">Multiline Strings and Heredocs</a><br />
<a href="#resources">Resources</a><br />
<a href="#contributing">Contributing</a><br />
<a href="#change_log">Change Log</a><br />
@@ -95,7 +96,7 @@
<a href="documentation/underscore.html">Underscore.coffee</a>, a port
of the <a href="http://documentcloud.github.com/underscore/">Underscore.js</a>
library of helper functions. Underscore.coffee can pass the entire Underscore.js
test suite. The CoffeeScript version is faster than the original for a number
test suite. The CoffeeScript version is faster than the original for a number
of methods (in general, due to the speed of CoffeeScript's array comprehensions), and
after being minified and gzipped, is only 241 bytes larger than the original
JavaScript version.
@@ -415,7 +416,7 @@ coffee --print app/scripts/*.coffee > concatenation.js</pre>
<%= code_for('range_comprehensions', 'countdown') %>
<p>
Comprehensions can also be used to iterate over the keys and values in
an object. Use <tt>of</tt> to signal comprehension over the properties of
an object. Use <tt>of</tt> to signal comprehension over the properties of
an object instead of the values in an array.
</p>
<%= code_for('object_comprehensions', 'ages.join(", ")') %>
@@ -481,12 +482,12 @@ coffee --print app/scripts/*.coffee > concatenation.js</pre>
be completely usable if it weren't for a couple of small exceptions:
it's awkward to call <b>super</b> (the prototype object's
implementation of the current function), and it's awkward to correctly
set the prototype chain.
set the prototype chain.
</p>
<p>
CoffeeScript provides <tt>extends</tt>
to help with prototype setup, <tt>::</tt> for quick access to an
object's prototype, and converts <tt>super()</tt> into a call against
object's prototype, and converts <tt>super()</tt> into a call against
the immediate ancestor's method of the same name.
</p>
<%= code_for('super', true) %>
@@ -499,11 +500,39 @@ coffee --print app/scripts/*.coffee > concatenation.js</pre>
so you don't have to close the parentheses on the other side.
</p>
<%= code_for('blocks') %>
<p>
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:
<tt>_.map(array, (num => num * 2))</tt>
</p>
<p id="pattern_matching">
<b class="header">Pattern Matching (Destructuring Assignment)</b>
To make extracting values from complex arrays and objects more convenient,
CoffeeScript implements ECMAScript Harmony's proposed
<a href="http://wiki.ecmascript.org/doku.php?id=harmony:destructuring">destructuring assignment</a>
syntax. When you assign an array or object literal to a value, CoffeeScript
breaks up and matches both sides against each other, assigning the values
on the right to the variables on the left. In the simplest case, it can be
used for parallel assignment:
</p>
<%= code_for('parallel_assignment', 'bait') %>
<p>
But it's also helpful for dealing with functions that return multiple
values.
</p>
<%= code_for('multiple_return_values', 'forecast') %>
<p>
Pattern matching can be used with any depth of array and object nesting,
to help pull out deeply nested properties.
</p>
<%= code_for('object_extraction', 'poet + " — " + street') %>
<p id="embedded">
<b class="header">Embedded JavaScript</b>
If you ever need to interpolate literal JavaScript snippets, you can
use backticks to pass JavaScript straight through.
Hopefully, you'll never need to use it, but if you ever need to intersperse
snippets of JavaScript within your CoffeeScript, you can
use backticks to pass it straight through.
</p>
<%= code_for('embedded', 'hi()') %>
@@ -527,10 +556,17 @@ coffee --print app/scripts/*.coffee > concatenation.js</pre>
<%= code_for('try') %>
<p id="strings">
<b class="header">Multiline Strings</b>
<b class="header">Multiline Strings and Heredocs</b>
Multiline strings are allowed in CoffeeScript.
</p>
<%= code_for('strings', 'moby_dick') %>
<p>
Heredocs can be used to hold formatted or indentation-sensitive text
(or, if you just don't feel like escaping quotes and apostrophes). The
indentation level that begins the heredoc is maintained throughout, so
you can keep it all aligned with the body of your code.
</p>
<%= code_for('heredocs') %>
<h2 id="resources">Resources</h2>
@@ -539,7 +575,7 @@ coffee --print app/scripts/*.coffee > concatenation.js</pre>
<a href="http://github.com/jashkenas/coffee-script/">Source Code</a><br />
After checking out the source, make sure to run <tt>rake build:parser</tt>
to generate an up-to-date version of the Racc parser.
Use <tt>bin/coffee</tt> to test your changes,
Use <tt>bin/coffee</tt> to test your changes,
<tt>rake test</tt> to run the test suite,
and <tt>rake gem:install</tt> to
create and install a custom version of the gem.
@@ -589,10 +625,17 @@ coffee --print app/scripts/*.coffee > concatenation.js</pre>
<h2 id="change_log">Change Log</h2>
<p>
<b class="header" style="margin-top: 20px;">0.2.4</b>
Added ECMAScript Harmony style destructuring assignment, for dealing with
extracting values from nested arrays and objects. Added indentation-sensitive
heredocs for nicely formatted strings or chunks of code.
</p>
<p>
<b class="header" style="margin-top: 20px;">0.2.3</b>
Axed the unsatisfactory <tt>ino</tt> keyword, replacing it with <tt>of</tt> for
object comprehensions. They now look like: <tt>for key, value of object</tt>.
object comprehensions. They now look like: <tt>for prop, value of object</tt>.
</p>
<p>

View File

@@ -2,12 +2,12 @@
var __a, __b, __c, __d, __e, __f, __g, food, lunch, roid, roid2;
// Eat lunch.
lunch = (function() {
__c = []; __a = ['toast', 'cheese', 'wine'];
for (__b=0; __b<__a.length; __b++) {
food = __a[__b];
__c.push(eat(food));
__a = []; __b = ['toast', 'cheese', 'wine'];
for (__c=0; __c<__b.length; __c++) {
food = __b[__c];
__a.push(eat(food));
}
return __c;
return __a;
})();
// Naive collision detection.
__d = asteroids;

View File

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

View File

@@ -0,0 +1,4 @@
(function(){
var html;
html = "<strong>\n cup of coffeescript\n</strong>";
})();

View File

@@ -0,0 +1,11 @@
(function(){
var __a, city, forecast, temp, weather_report;
weather_report = function weather_report(location) {
// Make an Ajax request to fetch the weather...
return [location, 72, "Mostly Sunny"];
};
__a = weather_report("Berkeley, CA");
city = __a[0];
temp = __a[1];
forecast = __a[2];
})();

View File

@@ -6,13 +6,13 @@
tim: 11
};
ages = (function() {
__b = []; __a = years_old;
for (child in __a) {
age = __a[child];
if (__a.hasOwnProperty(child)) {
__b.push(child + " is " + age);
__a = []; __b = years_old;
for (child in __b) {
age = __b[child];
if (__b.hasOwnProperty(child)) {
__a.push(child + " is " + age);
}
}
return __b;
return __a;
})();
})();

View File

@@ -0,0 +1,17 @@
(function(){
var __a, __b, __c, city, futurists, poet, street;
futurists = {
sculptor: "Umberto Boccioni",
painter: "Vladimir Burliuk",
poet: {
name: "F.T. Marinetti",
address: ["Via Roma 42R", "Bellagio, Italy 22021"]
}
};
__a = futurists;
__b = __a.poet;
poet = __b.name;
__c = __b.address;
street = __c[0];
city = __c[1];
})();

View File

@@ -33,11 +33,11 @@
}
// Array comprehensions:
cubed_list = (function() {
__c = []; __a = list;
for (__b=0; __b<__a.length; __b++) {
num = __a[__b];
__c.push(math.cube(num));
__a = []; __b = list;
for (__c=0; __c<__b.length; __c++) {
num = __b[__c];
__a.push(math.cube(num));
}
return __c;
return __a;
})();
})();

View File

@@ -0,0 +1,8 @@
(function(){
var __a, and_switch, bait;
bait = 1000;
and_switch = 0;
__a = [and_switch, bait];
bait = __a[0];
and_switch = __a[1];
})();

View File

@@ -1,21 +1,21 @@
(function(){
var __a, __b, __c, __d, __e, countdown, egg_delivery, num;
countdown = (function() {
__b = []; __d = 10; __e = 1;
__a = []; __d = 10; __e = 1;
for (__c=0, num=__d; (__d <= __e ? num <= __e : num >= __e); (__d <= __e ? num += 1 : num -= 1), __c++) {
__b.push(num);
__a.push(num);
}
return __b;
return __a;
})();
egg_delivery = function egg_delivery() {
var __f, __g, __h, __i, __j, dozen_eggs, i;
__g = []; __i = 0; __j = eggs.length;
__f = []; __i = 0; __j = eggs.length;
for (__h=0, i=__i; (__i <= __j ? i < __j : i > __j); (__i <= __j ? i += 12 : i -= 12), __h++) {
__g.push((function() {
__f.push((function() {
dozen_eggs = eggs.slice(i, i + 12);
return deliver(new egg_carton(dozen));
})());
}
return __g;
return __f;
};
})();

View File

@@ -37,7 +37,7 @@
<p>
<b>Latest Version:</b>
<a href="http://gemcutter.org/gems/coffee-script">0.2.3</a>
<a href="http://gemcutter.org/gems/coffee-script">0.2.4</a>
</p>
<h2>Table of Contents</h2>
@@ -61,10 +61,11 @@
<a href="#expressions">Everything is an Expression</a><br />
<a href="#inheritance">Inheritance, and Calling Super from a Subclass</a><br />
<a href="#blocks">Blocks</a><br />
<a href="#pattern_matching">Pattern Matching</a><br />
<a href="#embedded">Embedded JavaScript</a><br />
<a href="#switch">Switch/When/Else</a><br />
<a href="#try">Try/Catch/Finally</a><br />
<a href="#strings">Multiline Strings</a><br />
<a href="#strings">Multiline Strings and Heredocs</a><br />
<a href="#resources">Resources</a><br />
<a href="#contributing">Contributing</a><br />
<a href="#change_log">Change Log</a><br />
@@ -137,12 +138,12 @@ race <span class="Keyword">=</span> <span class="Storage">function</span> <span
}
<span class="Comment"><span class="Comment">//</span> Array comprehensions:</span>
cubed_list <span class="Keyword">=</span> (<span class="Storage">function</span>() {
__c <span class="Keyword">=</span> []; __a <span class="Keyword">=</span> list;
<span class="Keyword">for</span> (__b<span class="Keyword">=</span><span class="Number">0</span>; __b<span class="Keyword">&lt;</span>__a.<span class="LibraryConstant">length</span>; __b<span class="Keyword">++</span>) {
num <span class="Keyword">=</span> __a[__b];
__c.<span class="LibraryFunction">push</span>(math.cube(num));
__a <span class="Keyword">=</span> []; __b <span class="Keyword">=</span> list;
<span class="Keyword">for</span> (__c<span class="Keyword">=</span><span class="Number">0</span>; __c<span class="Keyword">&lt;</span>__b.<span class="LibraryConstant">length</span>; __c<span class="Keyword">++</span>) {
num <span class="Keyword">=</span> __b[__c];
__a.<span class="LibraryFunction">push</span>(math.cube(num));
}
<span class="Keyword">return</span> __c;
<span class="Keyword">return</span> __a;
})();
</pre><button onclick='javascript: var __a, __b, __c, cubed_list, list, math, num, number, opposite_day, race, square;
// Assignment:
@@ -178,12 +179,12 @@ if ((typeof elvis !== "undefined" && elvis !== null)) {
}
// Array comprehensions:
cubed_list = (function() {
__c = []; __a = list;
for (__b=0; __b<__a.length; __b++) {
num = __a[__b];
__c.push(math.cube(num));
__a = []; __b = list;
for (__c=0; __c<__b.length; __c++) {
num = __b[__c];
__a.push(math.cube(num));
}
return __c;
return __a;
})();
;alert(cubed_list);'>run: cubed_list</button><br class='clear' /></div>
@@ -192,7 +193,7 @@ cubed_list = (function() {
<a href="documentation/underscore.html">Underscore.coffee</a>, a port
of the <a href="http://documentcloud.github.com/underscore/">Underscore.js</a>
library of helper functions. Underscore.coffee can pass the entire Underscore.js
test suite. The CoffeeScript version is faster than the original for a number
test suite. The CoffeeScript version is faster than the original for a number
of methods (in general, due to the speed of CoffeeScript's array comprehensions), and
after being minified and gzipped, is only 241 bytes larger than the original
JavaScript version.
@@ -707,12 +708,12 @@ backwards("stairway", "to", "heaven");
</pre><pre class="idle"><span class="Storage">var</span> __a, __b, __c, __d, __e, __f, __g, food, lunch, roid, roid2;
<span class="Comment"><span class="Comment">//</span> Eat lunch.</span>
lunch <span class="Keyword">=</span> (<span class="Storage">function</span>() {
__c <span class="Keyword">=</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>];
<span class="Keyword">for</span> (__b<span class="Keyword">=</span><span class="Number">0</span>; __b<span class="Keyword">&lt;</span>__a.<span class="LibraryConstant">length</span>; __b<span class="Keyword">++</span>) {
food <span class="Keyword">=</span> __a[__b];
__c.<span class="LibraryFunction">push</span>(eat(food));
__a <span class="Keyword">=</span> []; __b <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>];
<span class="Keyword">for</span> (__c<span class="Keyword">=</span><span class="Number">0</span>; __c<span class="Keyword">&lt;</span>__b.<span class="LibraryConstant">length</span>; __c<span class="Keyword">++</span>) {
food <span class="Keyword">=</span> __b[__c];
__a.<span class="LibraryFunction">push</span>(eat(food));
}
<span class="Keyword">return</span> __c;
<span class="Keyword">return</span> __a;
})();
<span class="Comment"><span class="Comment">//</span> Naive collision detection.</span>
__d <span class="Keyword">=</span> asteroids;
@@ -743,46 +744,46 @@ __d <span class="Keyword">=</span> asteroids;
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, countdown, egg_delivery, num;
countdown <span class="Keyword">=</span> (<span class="Storage">function</span>() {
__b <span class="Keyword">=</span> []; __d <span class="Keyword">=</span> <span class="Number">10</span>; __e <span class="Keyword">=</span> <span class="Number">1</span>;
__a <span class="Keyword">=</span> []; __d <span class="Keyword">=</span> <span class="Number">10</span>; __e <span class="Keyword">=</span> <span class="Number">1</span>;
<span class="Keyword">for</span> (__c<span class="Keyword">=</span><span class="Number">0</span>, num<span class="Keyword">=</span>__d; (__d <span class="Keyword">&lt;=</span> __e ? num <span class="Keyword">&lt;=</span> __e : num <span class="Keyword">&gt;=</span> __e); (__d <span class="Keyword">&lt;=</span> __e ? num <span class="Keyword">+</span><span class="Keyword">=</span> <span class="Number">1</span> : num <span class="Keyword">-</span><span class="Keyword">=</span> <span class="Number">1</span>), __c<span class="Keyword">++</span>) {
__b.<span class="LibraryFunction">push</span>(num);
__a.<span class="LibraryFunction">push</span>(num);
}
<span class="Keyword">return</span> __b;
<span class="Keyword">return</span> __a;
})();
egg_delivery <span class="Keyword">=</span> <span class="Storage">function</span> <span class="FunctionName">egg_delivery</span>() {
<span class="Storage">var</span> __f, __g, __h, __i, __j, dozen_eggs, i;
__g <span class="Keyword">=</span> []; __i <span class="Keyword">=</span> <span class="Number">0</span>; __j <span class="Keyword">=</span> eggs.<span class="LibraryConstant">length</span>;
__f <span class="Keyword">=</span> []; __i <span class="Keyword">=</span> <span class="Number">0</span>; __j <span class="Keyword">=</span> eggs.<span class="LibraryConstant">length</span>;
<span class="Keyword">for</span> (__h<span class="Keyword">=</span><span class="Number">0</span>, i<span class="Keyword">=</span>__i; (__i <span class="Keyword">&lt;=</span> __j ? i <span class="Keyword">&lt;</span> __j : i <span class="Keyword">&gt;</span> __j); (__i <span class="Keyword">&lt;=</span> __j ? 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>), __h<span class="Keyword">++</span>) {
__g.<span class="LibraryFunction">push</span>((<span class="Storage">function</span>() {
__f.<span class="LibraryFunction">push</span>((<span class="Storage">function</span>() {
dozen_eggs <span class="Keyword">=</span> eggs.<span class="LibraryFunction">slice</span>(i, i <span class="Keyword">+</span> <span class="Number">12</span>);
<span class="Keyword">return</span> deliver(<span class="Keyword">new</span> <span class="TypeName">egg_carton</span>(dozen));
})());
}
<span class="Keyword">return</span> __g;
<span class="Keyword">return</span> __f;
};
</pre><button onclick='javascript: var __a, __b, __c, __d, __e, countdown, egg_delivery, num;
countdown = (function() {
__b = []; __d = 10; __e = 1;
__a = []; __d = 10; __e = 1;
for (__c=0, num=__d; (__d <= __e ? num <= __e : num >= __e); (__d <= __e ? num += 1 : num -= 1), __c++) {
__b.push(num);
__a.push(num);
}
return __b;
return __a;
})();
egg_delivery = function egg_delivery() {
var __f, __g, __h, __i, __j, dozen_eggs, i;
__g = []; __i = 0; __j = eggs.length;
__f = []; __i = 0; __j = eggs.length;
for (__h=0, i=__i; (__i <= __j ? i < __j : i > __j); (__i <= __j ? i += 12 : i -= 12), __h++) {
__g.push((function() {
__f.push((function() {
dozen_eggs = eggs.slice(i, i + 12);
return deliver(new egg_carton(dozen));
})());
}
return __g;
return __f;
};
;alert(countdown);'>run: countdown</button><br class='clear' /></div>
<p>
Comprehensions can also be used to iterate over the keys and values in
an object. Use <tt>of</tt> to signal comprehension over the properties of
an object. Use <tt>of</tt> to signal comprehension over the properties of
an object instead of the values in an array.
</p>
<div class='code'><pre class="idle"><span class="FunctionName">years_old</span><span class="Keyword">:</span> {<span class="FunctionName">max</span><span class="Keyword">:</span> <span class="Number">10</span>, <span class="FunctionName">ida</span><span class="Keyword">:</span> <span class="Number">9</span>, <span class="FunctionName">tim</span><span class="Keyword">:</span> <span class="Number">11</span>}
@@ -796,14 +797,14 @@ years_old <span class="Keyword">=</span> {
tim: <span class="Number">11</span>
};
ages <span class="Keyword">=</span> (<span class="Storage">function</span>() {
__b <span class="Keyword">=</span> []; __a <span class="Keyword">=</span> years_old;
<span class="Keyword">for</span> (child <span class="Keyword">in</span> __a) {
age <span class="Keyword">=</span> __a[child];
<span class="Keyword">if</span> (__a.hasOwnProperty(child)) {
__b.<span class="LibraryFunction">push</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);
__a <span class="Keyword">=</span> []; __b <span class="Keyword">=</span> years_old;
<span class="Keyword">for</span> (child <span class="Keyword">in</span> __b) {
age <span class="Keyword">=</span> __b[child];
<span class="Keyword">if</span> (__b.hasOwnProperty(child)) {
__a.<span class="LibraryFunction">push</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">return</span> __b;
<span class="Keyword">return</span> __a;
})();
</pre><button onclick='javascript: var __a, __b, age, ages, child, years_old;
years_old = {
@@ -812,14 +813,14 @@ years_old = {
tim: 11
};
ages = (function() {
__b = []; __a = years_old;
for (child in __a) {
age = __a[child];
if (__a.hasOwnProperty(child)) {
__b.push(child + " is " + age);
__a = []; __b = years_old;
for (child in __b) {
age = __b[child];
if (__b.hasOwnProperty(child)) {
__a.push(child + " is " + age);
}
}
return __b;
return __a;
})();
;alert(ages.join(", "));'>run: ages.join(", ")</button><br class='clear' /></div>
@@ -932,24 +933,24 @@ six = (one = 1) + (two = 2) + (three = 3);
</pre><pre class="idle"><span class="Storage">var</span> __a, __b, globals, name;
<span class="Comment"><span class="Comment">//</span> The first ten global properties.</span>
globals <span class="Keyword">=</span> ((<span class="Storage">function</span>() {
__b <span class="Keyword">=</span> []; __a <span class="Keyword">=</span> <span class="LibraryClassType">window</span>;
<span class="Keyword">for</span> (name <span class="Keyword">in</span> __a) {
<span class="Keyword">if</span> (__a.hasOwnProperty(name)) {
__b.<span class="LibraryFunction">push</span>(name);
__a <span class="Keyword">=</span> []; __b <span class="Keyword">=</span> <span class="LibraryClassType">window</span>;
<span class="Keyword">for</span> (name <span class="Keyword">in</span> __b) {
<span class="Keyword">if</span> (__b.hasOwnProperty(name)) {
__a.<span class="LibraryFunction">push</span>(name);
}
}
<span class="Keyword">return</span> __b;
<span class="Keyword">return</span> __a;
})()).<span class="LibraryFunction">slice</span>(<span class="Number">0</span>, <span class="Number">10</span>);
</pre><button onclick='javascript: var __a, __b, globals, name;
// The first ten global properties.
globals = ((function() {
__b = []; __a = window;
for (name in __a) {
if (__a.hasOwnProperty(name)) {
__b.push(name);
__a = []; __b = window;
for (name in __b) {
if (__b.hasOwnProperty(name)) {
__a.push(name);
}
}
return __b;
return __a;
})()).slice(0, 10);
;alert(globals);'>run: globals</button><br class='clear' /></div>
<p>
@@ -990,12 +991,12 @@ globals = ((function() {
be completely usable if it weren't for a couple of small exceptions:
it's awkward to call <b>super</b> (the prototype object's
implementation of the current function), and it's awkward to correctly
set the prototype chain.
set the prototype chain.
</p>
<p>
CoffeeScript provides <tt>extends</tt>
to help with prototype setup, <tt>::</tt> for quick access to an
object's prototype, and converts <tt>super()</tt> into a call against
object's prototype, and converts <tt>super()</tt> into a call against
the immediate ancestor's method of the same name.
</p>
<div class='code'><pre class="idle"><span class="FunctionName">Animal</span><span class="Keyword">:</span> <span class="Storage">=&gt;</span>
@@ -1119,11 +1120,121 @@ tom.move();
});
});
</pre><br class='clear' /></div>
<p>
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:
<tt>_.map(array, (num => num * 2))</tt>
</p>
<p id="pattern_matching">
<b class="header">Pattern Matching (Destructuring Assignment)</b>
To make extracting values from complex arrays and objects more convenient,
CoffeeScript implements ECMAScript Harmony's proposed
<a href="http://wiki.ecmascript.org/doku.php?id=harmony:destructuring">destructuring assignment</a>
syntax. When you assign an array or object literal to a value, CoffeeScript
breaks up and matches both sides against each other, assigning the values
on the right to the variables on the left. In the simplest case, it can be
used for parallel assignment:
</p>
<div class='code'><pre class="idle"><span class="FunctionName">bait</span><span class="Keyword">:</span> <span class="Number">1000</span>
<span class="FunctionName">and_switch</span><span class="Keyword">:</span> <span class="Number">0</span>
[bait, and_switch]<span class="Keyword">:</span> [and_switch, bait]
</pre><pre class="idle"><span class="Storage">var</span> __a, and_switch, bait;
bait <span class="Keyword">=</span> <span class="Number">1000</span>;
and_switch <span class="Keyword">=</span> <span class="Number">0</span>;
__a <span class="Keyword">=</span> [and_switch, bait];
bait <span class="Keyword">=</span> __a[<span class="Number">0</span>];
and_switch <span class="Keyword">=</span> __a[<span class="Number">1</span>];
</pre><button onclick='javascript: var __a, and_switch, bait;
bait = 1000;
and_switch = 0;
__a = [and_switch, bait];
bait = __a[0];
and_switch = __a[1];
;alert(bait);'>run: bait</button><br class='clear' /></div>
<p>
But it's also helpful for dealing with functions that return multiple
values.
</p>
<div class='code'><pre class="idle"><span class="FunctionName">weather_report</span><span class="Keyword">:</span> <span class="FunctionArgument">location</span> <span class="Storage">=&gt;</span>
<span class="Comment"><span class="Comment">#</span> Make an Ajax request to fetch the weather...</span>
[location, <span class="Number">72</span>, <span class="String"><span class="String">&quot;</span>Mostly Sunny<span class="String">&quot;</span></span>]
[city, temp, forecast]<span class="Keyword">:</span> weather_report(<span class="String"><span class="String">&quot;</span>Berkeley, CA<span class="String">&quot;</span></span>)
</pre><pre class="idle"><span class="Storage">var</span> __a, city, forecast, temp, weather_report;
weather_report <span class="Keyword">=</span> <span class="Storage">function</span> <span class="FunctionName">weather_report</span>(<span class="FunctionArgument">location</span>) {
<span class="Comment"><span class="Comment">//</span> Make an Ajax request to fetch the weather...</span>
<span class="Keyword">return</span> [location, <span class="Number">72</span>, <span class="String"><span class="String">&quot;</span>Mostly Sunny<span class="String">&quot;</span></span>];
};
__a <span class="Keyword">=</span> weather_report(<span class="String"><span class="String">&quot;</span>Berkeley, CA<span class="String">&quot;</span></span>);
city <span class="Keyword">=</span> __a[<span class="Number">0</span>];
temp <span class="Keyword">=</span> __a[<span class="Number">1</span>];
forecast <span class="Keyword">=</span> __a[<span class="Number">2</span>];
</pre><button onclick='javascript: var __a, city, forecast, temp, weather_report;
weather_report = function weather_report(location) {
// Make an Ajax request to fetch the weather...
return [location, 72, "Mostly Sunny"];
};
__a = weather_report("Berkeley, CA");
city = __a[0];
temp = __a[1];
forecast = __a[2];
;alert(forecast);'>run: forecast</button><br class='clear' /></div>
<p>
Pattern matching can be used with any depth of array and object nesting,
to help pull out deeply nested properties.
</p>
<div class='code'><pre class="idle"><span class="FunctionName">futurists</span><span class="Keyword">:</span> {
<span class="FunctionName">sculptor</span><span class="Keyword">:</span> <span class="String"><span class="String">&quot;</span>Umberto Boccioni<span class="String">&quot;</span></span>
<span class="FunctionName">painter</span><span class="Keyword">:</span> <span class="String"><span class="String">&quot;</span>Vladimir Burliuk<span class="String">&quot;</span></span>
<span class="FunctionName">poet</span><span class="Keyword">:</span> {
<span class="FunctionName">name</span><span class="Keyword">:</span> <span class="String"><span class="String">&quot;</span>F.T. Marinetti<span class="String">&quot;</span></span>
<span class="FunctionName">address</span><span class="Keyword">:</span> [
<span class="String"><span class="String">&quot;</span>Via Roma 42R<span class="String">&quot;</span></span>
<span class="String"><span class="String">&quot;</span>Bellagio, Italy 22021<span class="String">&quot;</span></span>
]
}
}
{<span class="FunctionName">poet</span><span class="Keyword">:</span> {<span class="FunctionName">name</span><span class="Keyword">:</span> poet, <span class="FunctionName">address</span><span class="Keyword">:</span> [street, city]}}<span class="Keyword">:</span> futurists
</pre><pre class="idle"><span class="Storage">var</span> __a, __b, __c, city, futurists, poet, street;
futurists <span class="Keyword">=</span> {
sculptor: <span class="String"><span class="String">&quot;</span>Umberto Boccioni<span class="String">&quot;</span></span>,
painter: <span class="String"><span class="String">&quot;</span>Vladimir Burliuk<span class="String">&quot;</span></span>,
poet: {
name: <span class="String"><span class="String">&quot;</span>F.T. Marinetti<span class="String">&quot;</span></span>,
address: [<span class="String"><span class="String">&quot;</span>Via Roma 42R<span class="String">&quot;</span></span>, <span class="String"><span class="String">&quot;</span>Bellagio, Italy 22021<span class="String">&quot;</span></span>]
}
};
__a <span class="Keyword">=</span> futurists;
__b <span class="Keyword">=</span> __a.poet;
poet <span class="Keyword">=</span> __b.<span class="LibraryConstant">name</span>;
__c <span class="Keyword">=</span> __b.address;
street <span class="Keyword">=</span> __c[<span class="Number">0</span>];
city <span class="Keyword">=</span> __c[<span class="Number">1</span>];
</pre><button onclick='javascript: var __a, __b, __c, city, futurists, poet, street;
futurists = {
sculptor: "Umberto Boccioni",
painter: "Vladimir Burliuk",
poet: {
name: "F.T. Marinetti",
address: ["Via Roma 42R", "Bellagio, Italy 22021"]
}
};
__a = futurists;
__b = __a.poet;
poet = __b.name;
__c = __b.address;
street = __c[0];
city = __c[1];
;alert(poet + " — " + street);'>run: poet + " — " + street</button><br class='clear' /></div>
<p id="embedded">
<b class="header">Embedded JavaScript</b>
If you ever need to interpolate literal JavaScript snippets, you can
use backticks to pass JavaScript straight through.
Hopefully, you'll never need to use it, but if you ever need to intersperse
snippets of JavaScript within your CoffeeScript, you can
use backticks to pass it straight through.
</p>
<div class='code'><pre class="idle"><span class="FunctionName">hi</span><span class="Keyword">:</span> <span class="String"><span class="String">`</span>function() {</span>
<span class="String"> return [document.title, &quot;Hello JavaScript&quot;].join(&quot;: &quot;);</span>
@@ -1198,7 +1309,7 @@ return [document.title, "Hello JavaScript"].join(": ");
</pre><br class='clear' /></div>
<p id="strings">
<b class="header">Multiline Strings</b>
<b class="header">Multiline Strings and Heredocs</b>
Multiline strings are allowed in CoffeeScript.
</p>
<div class='code'><pre class="idle"><span class="FunctionName">moby_dick</span><span class="Keyword">:</span> <span class="String"><span class="String">&quot;</span>Call me Ishmael. Some years ago --</span>
@@ -1224,6 +1335,20 @@ to interest me on shore, I thought I would sail \
about a little and see the watery part of the \
world...";
;alert(moby_dick);'>run: moby_dick</button><br class='clear' /></div>
<p>
Heredocs can be used to hold formatted or indentation-sensitive text
(or, if you just don't feel like escaping quotes and apostrophes). The
indentation level that begins the heredoc is maintained throughout, so
you can keep it all aligned with the body of your code.
</p>
<div class='code'><pre class="idle"><span class="FunctionName">html</span><span class="Keyword">:</span> <span class="String"><span class="String">'</span><span class="String">'</span></span><span class="String"><span class="String">'</span></span>
<span class="String"> &lt;strong&gt;</span>
<span class="String"> cup of coffeescript</span>
<span class="String"> &lt;/strong&gt;</span>
<span class="String"> <span class="String">'</span></span><span class="String"><span class="String">'</span><span class="String">'</span></span>
</pre><pre class="idle"><span class="Storage">var</span> html;
html <span class="Keyword">=</span> <span class="String"><span class="String">&quot;</span>&lt;strong&gt;<span class="UserDefinedConstant">\n</span> cup of coffeescript<span class="UserDefinedConstant">\n</span>&lt;/strong&gt;<span class="String">&quot;</span></span>;
</pre><br class='clear' /></div>
<h2 id="resources">Resources</h2>
@@ -1232,7 +1357,7 @@ world...";
<a href="http://github.com/jashkenas/coffee-script/">Source Code</a><br />
After checking out the source, make sure to run <tt>rake build:parser</tt>
to generate an up-to-date version of the Racc parser.
Use <tt>bin/coffee</tt> to test your changes,
Use <tt>bin/coffee</tt> to test your changes,
<tt>rake test</tt> to run the test suite,
and <tt>rake gem:install</tt> to
create and install a custom version of the gem.
@@ -1282,10 +1407,17 @@ world...";
<h2 id="change_log">Change Log</h2>
<p>
<b class="header" style="margin-top: 20px;">0.2.4</b>
Added ECMAScript Harmony style destructuring assignment, for dealing with
extracting values from nested arrays and objects. Added indentation-sensitive
heredocs for nicely formatted strings or chunks of code.
</p>
<p>
<b class="header" style="margin-top: 20px;">0.2.3</b>
Axed the unsatisfactory <tt>ino</tt> keyword, replacing it with <tt>of</tt> for
object comprehensions. They now look like: <tt>for key, value of object</tt>.
object comprehensions. They now look like: <tt>for prop, value of object</tt>.
</p>
<p>

View File

@@ -10,7 +10,7 @@ require "coffee_script/parse_error"
# Namespace for all CoffeeScript internal classes.
module CoffeeScript
VERSION = '0.2.3' # Keep in sync with the gemspec.
VERSION = '0.2.4' # Keep in sync with the gemspec.
# Compile a script (String or IO) to JavaScript.
def self.compile(script, options={})

View File

@@ -93,6 +93,30 @@
<key>name</key>
<string>constant.numeric.coffee</string>
</dict>
<dict>
<key>name</key>
<string>string.quoted.heredoc.coffee</string>
<key>begin</key>
<string>("""|''')</string>
<key>end</key>
<string>("""|''')</string>
<key>beginCaptures</key>
<dict>
<key>0</key>
<dict>
<key>name</key>
<string>punctuation.definition.string.begin.coffee</string>
</dict>
</dict>
<key>endCaptures</key>
<dict>
<key>0</key>
<dict>
<key>name</key>
<string>punctuation.definition.string.end.coffee</string>
</dict>
</dict>
</dict>
<dict>
<key>begin</key>
<string>'</string>

View File

@@ -22,6 +22,7 @@ module CoffeeScript
IDENTIFIER = /\A([a-zA-Z$_](\w|\$)*)/
NUMBER = /\A(\b((0(x|X)[0-9a-fA-F]+)|([0-9]+(\.[0-9]+)?(e[+\-]?[0-9]+)?)))\b/i
STRING = /\A(""|''|"(.*?)([^\\]|\\\\)"|'(.*?)([^\\]|\\\\)')/m
HEREDOC = /\A("{6}|'{6}|"{3}\n?(\s*)(.*?)\n?(\s*)"{3}|'{3}\n?(\s*)(.*?)\n?(\s*)'{3})/m
JS = /\A(``|`(.*?)([^\\]|\\\\)`)/m
OPERATOR = /\A([+\*&|\/\-%=<>:!]+)/
WHITESPACE = /\A([ \t]+)/
@@ -69,6 +70,7 @@ module CoffeeScript
def extract_next_token
return if identifier_token
return if number_token
return if heredoc_token
return if string_token
return if js_token
return if regex_token
@@ -87,7 +89,7 @@ module CoffeeScript
# 'if' will result in an [:IF, "if"] token.
tag = KEYWORDS.include?(identifier) ? identifier.upcase.to_sym : :IDENTIFIER
tag = :LEADING_WHEN if tag == :WHEN && [:OUTDENT, :INDENT, "\n"].include?(last_tag)
@tokens[-1][0] = :PROPERTY_ACCESS if tag == :IDENTIFIER && last_value == '.' && !(@tokens[-2][1] == '.')
@tokens[-1][0] = :PROPERTY_ACCESS if tag == :IDENTIFIER && last_value == '.' && !(@tokens[-2] && @tokens[-2][1] == '.')
@tokens[-1][0] = :PROTOTYPE_ACCESS if tag == :IDENTIFIER && last_value == '::'
token(tag, identifier)
@i += identifier.length
@@ -103,14 +105,24 @@ module CoffeeScript
# Matches strings, including multi-line strings.
def string_token
return false unless string = @chunk[STRING, 1]
escaped = string.gsub(MULTILINER) do |match|
@line += 1
" \\\n"
end
escaped = string.gsub(MULTILINER, " \\\n")
token(:STRING, escaped)
@line += string.count("\n")
@i += string.length
end
# Matches heredocs, adjusting indentation to the correct level.
def heredoc_token
return false unless match = @chunk.match(HEREDOC)
indent = match[2] || match[5]
doc = match[3] || match[6]
doc.gsub!(/\n#{indent}/, "\\n")
doc.gsub!('"', '\\"')
token(:STRING, "\"#{doc}\"")
@line += match[1].count("\n")
@i += match[1].length
end
# Matches interpolated JavaScript.
def js_token
return false unless script = @chunk[JS, 1]

View File

@@ -320,6 +320,18 @@ module CoffeeScript
return !@properties.empty?
end
def array?
@base.is_a?(ArrayNode) && !properties?
end
def object?
@base.is_a?(ObjectNode) && !properties?
end
def splice?
properties? && @properties.last.is_a?(SliceNode)
end
# Values are statements if their base is a statement.
def statement?
@base.is_a?(Node) && @base.statement? && !properties?
@@ -435,7 +447,9 @@ module CoffeeScript
end
def compile_node(o)
return compile_splice(o) if @variable.properties.last.is_a?(SliceNode)
return compile_pattern_match(o) if @variable.array? || @variable.object?
return compile_splice(o) if @variable.splice?
stmt = o.delete(:as_statement)
name = @variable.compile(o)
last = @variable.last.to_s.sub(LEADING_DOT, '')
proto = name[PROTO_ASSIGN, 1]
@@ -444,9 +458,31 @@ module CoffeeScript
return write("#{name}: #{@value.compile(o)}") if @context == :object
o[:scope].find(name) unless @variable.properties?
val = "#{name} = #{@value.compile(o)}"
return write("#{idt}#{val};") if stmt
write(o[:return] ? "#{idt}return (#{val})" : val)
end
def statement?
@variable.array? || @variable.object?
end
# Implementation of recursive pattern matching, when assigning array or
# object literals to a value. Peeks at their properties to assign inner names.
# See: http://wiki.ecmascript.org/doku.php?id=harmony:destructuring
def compile_pattern_match(o)
val_var = o[:scope].free_variable
assigns = ["#{idt}#{val_var} = #{@value.compile(o)};"]
o.merge!(:top => true, :as_statement => true)
@variable.base.objects.each_with_index do |obj, i|
obj, i = obj.value, obj.variable.base if @variable.object?
access_class = @variable.array? ? IndexNode : AccessorNode
assigns << AssignNode.new(
obj, ValueNode.new(Value.new(val_var), [access_class.new(Value.new(i.to_s))])
).compile(o)
end
write(assigns.join("\n"))
end
def compile_splice(o)
var = @variable.compile(o.merge(:only_first => true))
range = @variable.properties.last.range
@@ -564,6 +600,7 @@ module CoffeeScript
# An object literal.
class ObjectNode < Node
attr_reader :properties
alias_method :objects, :properties
def initialize(properties = [])
@properties = properties
@@ -655,9 +692,9 @@ module CoffeeScript
name_found = @name && scope.find(@name)
index_found = @index && scope.find(@index)
body_dent = idt(1)
rvar = scope.free_variable unless top_level
svar = scope.free_variable
ivar = range ? name : @index ? @index : scope.free_variable
rvar = scope.free_variable unless top_level
if range
index_var = scope.free_variable
source_part = source.compile_variables(o)

View File

@@ -5,5 +5,5 @@
"description": "Unfancy JavaScript",
"keywords": ["javascript", "language"],
"author": "Jeremy Ashkenas",
"version": "0.2.3"
"version": "0.2.4"
}

View File

@@ -5,8 +5,8 @@ print(results.join(',') is '2,18')
obj: {one: 1, two: 2, three: 3}
names: key + '!' for key of obj
odds: key + '!' for key, value of obj when value % 2 isnt 0
names: prop + '!' for prop of obj
odds: prop + '!' for prop, value of obj when value % 2 isnt 0
print(names.join(' ') is "one! two! three!")
print(odds.join(' ') is "one! three!")

View File

@@ -0,0 +1,46 @@
a: -1
b: -2
[a, b]: [b, a]
print(a is -2)
print(b is -1)
arr: [1, 2, 3]
[a, b, c]: arr
print(a is 1)
print(b is 2)
print(c is 3)
obj: {x: 10, y: 20, z: 30}
{x: a, y: b, z: c}: obj
print(a is 10)
print(b is 20)
print(c is 30)
person: {
name: "Bob"
family: {
brother: {
addresses: [
"first"
{
street: "101 Deercreek Ln."
city: "Moquasset NY, 10021"
}
]
}
}
}
{name: a, family: {brother: {addresses: [one, {city: b}]}}}: person
print(a is "Bob")
print(b is "Moquasset NY, 10021")

View File

@@ -0,0 +1,28 @@
a: """
basic heredoc
on two lines
"""
print(a is "basic heredoc\non two lines")
a: '''
a
"b
c
'''
print(a is "a\n \"b\nc")
a: '''one-liner'''
print(a is 'one-liner')
a: """
out
here
"""
print(a is "out\nhere")