Coffee Script

Coffee Script
Command
-c, --compile Compile a .coffee script into a .js JavaScript file of the same name.
-i, --interactive Launch an interactive CoffeeScript session to try short snippets. More pleasant if wrapped with rlwrap.
-o, --output [DIR] Write out all compiled JavaScript files into the specified directory. Use in conjunction with --compile or --watch.
-j, --join [FILE] Before compiling, concatenate all scripts together in the order they were passed, and write them into the specified file. Useful for building large projects.
-w, --watch Watch the modification times of the coffee-scripts, recompiling as soon as a change occurs.
-p, --print Instead of writing out the JavaScript as a file, print it directly to stdout.
-l, --lint If the jsl (JavaScript Lint) command is installed, use it to check the compilation of a CoffeeScript file. (Handy in conjunction with --watch)
-s, --stdio Pipe in CoffeeScript to STDIN and get back JavaScript over STDOUT. Good for use with processes written in other languages.
An example:
cat src/cake.coffee | coffee -sc
-e, --eval Compile and print a little snippet of CoffeeScript directly from the command line. For example: coffee -e "console.log num for num in [10..1]"
-r, --require Load a library before compiling or executing your script. Can be used to hook in to the compiler (to add Growl notifications, for example).
-b, --bare Compile the JavaScript without the top-level function safety wrapper. (Used for CoffeeScript as a Node.js module.)
-t, --tokens Instead of parsing the CoffeeScript, just lex it, and print out the token stream: [IDENTIFIER square] [ASSIGN =] [PARAM_START (] ...
-n, --nodes Instead of compiling the CoffeeScript, just lex and parse it, and print out the parse tree:
Expressions
Assign
Value "square"
Code "x"
Op *
Value "x"
Value "x"
--nodejs The node executable has some useful options you can set, such as
--debug, --debug-brk and --max-stack-size. Use this flag to forward options directly to Node.js.
Function
example (no default value)
square = (x) -> x * x
cube = (x) -> square(x) * x
var cube, square;
square = function(x) {
return x * x;
};
cube = function(x) {
return square(x) * x;
};
example (with default value)
fill = (container, liquid = "coffee") ->
"Filling the #{container} with #{liquid}..."
var fill;
fill = function(container, liquid) {
if (liquid == null) liquid = "coffee";
return "Filling the " + container + " with " + liquid + "...";
};
closure
for filename in list
do (filename) ->
fs.readFile filename, (err, contents) ->
compile filename, contents.toString()
var filename, _fn, _i, _len;
_fn = function(filename) {
return fs.readFile(filename, function(err, contents) {
return compile(filename, contents.toString());
});
};
for (_i = 0, _len = list.length; _i < _len; _i++) {
filename = list[_i];
_fn(filename);
}
load
Objects and Arrays Define
define Object and Array
song = ["do", "re", "mi", "fa", "so"]
singers = {Jagger: "Rock", Elvis: "Roll"}
bitlist = [
1, 0, 1
0, 0, 1
1, 1, 0
]
kids =
brother:
name: "Max"
age: 11
sister:
name: "Ida"
age: 9
var bitlist, kids, singers, song;
song = ["do", "re", "mi", "fa", "so"];
singers = {
Jagger: "Rock",
Elvis: "Roll"
};
bitlist = [1, 0, 1, 0, 0, 1, 1, 1, 0];
kids = {
brother: {
name: "Max",
age: 11
},
sister: {
name: "Ida",
age: 9
}
};
define with reversed words
$('.account').attr class: 'active'
log object.class
$('.account').attr({
"class": 'active'
});
log(object["class"]);
Lexical Scoping and Variable Safety
outer = 1
changeNumbers = ->
inner = -1
outer = 10
inner = changeNumbers()
var changeNumbers, inner, outer;
outer = 1;
changeNumbers = function() {
var inner;
inner = -1;
return outer = 10;
};
inner = changeNumbers();
If, Else, Unless, and Conditional Assignment
mood = greatlyImproved if singing
if happy and knowsIt
clapsHands()
chaChaCha()
else
showIt()
date = if friday then sue else jill
options or= defaults
var date, mood;
if (singing) mood = greatlyImproved;
if (happy && knowsIt) {
clapsHands();
chaChaCha();
} else {
showIt();
}
date = friday ? sue : jill;
options || (options = defaults);
Splats...
gold = silver = rest = "unknown"
awardMedals = (first, second, others...) ->
gold = first
silver = second
rest = others
contenders = [
"Michael Phelps"
"Liu Xiang"
"Yao Ming"
"Allyson Felix"
"Shawn Johnson"
"Roman Sebrle"
"Guo Jingjing"
"Tyson Gay"
"Asafa Powell"
"Usain Bolt"
]
awardMedals contenders...
alert "Gold: " + gold
alert "Silver: " + silver
alert "The Field: " + rest
var awardMedals, contenders, gold, rest, silver;
var __slice = Array.prototype.slice;
gold = silver = rest = "unknown";
awardMedals = function() {
var first, others, second;
first = arguments[0], second = arguments[1], others = 3 <= arguments.length ? __slice.call(arguments, 2) : [];
gold = first;
silver = second;
return rest = others;
};
contenders = ["Michael Phelps", "Liu Xiang", "Yao Ming", "Allyson Felix", "Shawn Johnson", "Roman Sebrle", "Guo Jingjing", "Tyson Gay", "Asafa Powell", "Usain Bolt"];
awardMedals.apply(null, contenders);
alert("Gold: " + gold);
alert("Silver: " + silver);
alert("The Field: " + rest);
Loops and Comprehensions
for
var food, _i, _len, _ref;
_ref = ['toast', 'cheese', 'wine'];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
food = _ref[_i];
eat(food);
}
# Eat lunch.
eat food for food in ['toast', 'cheese', 'wine']
each/forEach, map, or select/filter
yearsOld = max: 10, ida: 9, tim: 11
ages = for child, age of yearsOld
"#{child} is #{age}"
var age, ages, child, yearsOld;
yearsOld = {
max: 10,
ida: 9,
tim: 11
};
ages = (function() {
var _results;
_results = [];
for (child in yearsOld) {
age = yearsOld[child];
_results.push("" + child + " is " + age);
}
return _results;
})();
while
# Econ 101
if this.studyingEconomics
buy() while supply > demand
sell() until supply > demand
# Nursery Rhyme
num = 6
lyrics = while num -= 1
"#{num} little monkeys, jumping on the bed.
One fell out and bumped his head."
var lyrics, num;
if (this.studyingEconomics) {
while (supply > demand) {
buy();
}
while (!(supply > demand)) {
sell();
}
}
num = 6;
lyrics = (function() {
var _results;
_results = [];
while (num -= 1) {
_results.push("" + num + " little monkeys, jumping on the bed. One fell out and bumped his head.");
}
return _results;
})();
loadrun: lyrics.join("\n")
Array
Array Slicing and Splicing with Ranges
example1
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
copy = numbers[0...numbers.length]
middle = copy[3..6]
var copy, middle, numbers;
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
copy = numbers.slice(0, numbers.length);
middle = copy.slice(3, 7);
example2
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
numbers[3..6] = [-3, -4, -5, -6]
var numbers, _ref;
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
[].splice.apply(numbers, [3, 4].concat(_ref = [-3, -4, -5, -6])), _ref;
Everything is an Expression (at least, as much as possible)
grade = (student) ->
if student.excellentWork
"A+"
else if student.okayStuff
if student.triedHard then "B" else "B-"
else
"C"
eldest = if 24 > 21 then "Liz" else "Ike"
var eldest, grade;
grade = function(student) {
if (student.excellentWork) {
return "A+";
} else if (student.okayStuff) {
if (student.triedHard) {
return "B";
} else {
return "B-";
}
} else {
return "C";
}
};
eldest = 24 > 21 ? "Liz" : "Ike";
Operators and Aliases
CoffeeScript JavaScript
is ===
isnt !==
not !
and &&
or ||
true, yes, on true
false, no, off false
@, this this
of in
in no JS equivalent
example
launch() if ignition is on
volume = 10 if band isnt SpinalTap
letTheWildRumpusBegin() unless answer is no
if car.speed < limit then accelerate()
winner = yes if pick in [47, 92, 13]
print inspect "My name is #{@name}"
var volume, winner;
if (ignition === true) launch();
if (band !== SpinalTap) volume = 10;
if (answer !== false) letTheWildRumpusBegin();
if (car.speed < limit) accelerate();
if (pick === 47 || pick === 92 || pick === 13) winner = true;
print(inspect("My name is " + this.name));
load
The Existential Operator
solipsism = true if mind? and not world?
speed ?= 75
footprints = yeti ? "bear"
zip = lottery.drawWinner?().address?.zipcode
var footprints, solipsism;
if ((typeof mind !== "undefined" && mind !== null) && !(typeof world !== "undefined" && world !== null)) {
solipsism = true;
}
if (typeof speed === "undefined" || speed === null) speed = 75;
footprints = typeof yeti !== "undefined" && yeti !== null ? yeti : "bear";
var zip, _ref;
zip = typeof lottery.drawWinner === "function" ? (_ref = lottery.drawWinner().address) != null ? _ref.zipcode : void 0 : void 0;
Classes, Inheritance, and Super
class Animal
constructor: (@name) ->
move: (meters) ->
alert @name + " moved #{meters}m."
class Snake extends Animal
move: ->
alert "Slithering..."
super 5
class Horse extends Animal
move: ->
alert "Galloping..."
super 45
sam = new Snake "Sammy the Python"
tom = new Horse "Tommy the Palomino"
sam.move()
tom.move()
String::dasherize = ->
this.replace /_/g, "-"
var Animal, Horse, Snake, sam, tom;
var __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) {
for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; }
function ctor() { this.constructor = child; }
ctor.prototype = parent.prototype;
child.prototype = new ctor;
child.__super__ = parent.prototype;
return child;
};
Animal = (function() {
function Animal(name) {
this.name = name;
}
Animal.prototype.move = function(meters) {
return alert(this.name + (" moved " + meters + "m."));
};
return Animal;
})();
Snake = (function() {
__extends(Snake, Animal);
function Snake() {
Snake.__super__.constructor.apply(this, arguments);
}
Snake.prototype.move = function() {
alert("Slithering...");
return Snake.__super__.move.call(this, 5);
};
return Snake;
})();
Horse = (function() {
__extends(Horse, Animal);
function Horse() {
Horse.__super__.constructor.apply(this, arguments);
}
Horse.prototype.move = function() {
alert("Galloping...");
return Horse.__super__.move.call(this, 45);
};
return Horse;
})();
sam = new Snake("Sammy the Python");
tom = new Horse("Tommy the Palomino");
sam.move();
tom.move();
String.prototype.dasherize = function() {
return this.replace(/_/g, "-");
};
loadrun: "one_two".dasherize()
Destructuring Assignment
theBait = 1000
theSwitch = 0
[theBait, theSwitch] = [theSwitch, theBait]
weatherReport = (location) ->
# Make an Ajax request to fetch the weather...
[location, 72, "Mostly Sunny"]
[city, temp, forecast] = weatherReport "Berkeley, CA"
futurists =
sculptor: "Umberto Boccioni"
painter: "Vladimir Burliuk"
poet:
name: "F.T. Marinetti"
address: [
"Via Roma 42R"
"Bellagio, Italy 22021"
]
{poet: {name, address: [street, city]}} = futurists
tag = "<impossible>"
[open, contents..., close] = tag.split("")
var theBait, theSwitch, _ref;
theBait = 1000;
theSwitch = 0;
_ref = [theSwitch, theBait], theBait = _ref[0], theSwitch = _ref[1];
var city, forecast, temp, weatherReport, _ref;
weatherReport = function(location) {
return [location, 72, "Mostly Sunny"];
};
_ref = weatherReport("Berkeley, CA"), city = _ref[0], temp = _ref[1], forecast = _ref[2];
var city, futurists, name, street, _ref, _ref2;
futurists = {
sculptor: "Umberto Boccioni",
painter: "Vladimir Burliuk",
poet: {
name: "F.T. Marinetti",
address: ["Via Roma 42R", "Bellagio, Italy 22021"]
}
};
_ref = futurists.poet, name = _ref.name, _ref2 = _ref.address, street = _ref2[0], city = _ref2[1];
var close, contents, open, tag, _i, _ref;
var __slice = Array.prototype.slice;
tag = "<impossible>";
_ref = tag.split(""), open = _ref[0], contents = 3 <= _ref.length ? __slice.call(_ref, 1, _i = _ref.length - 1) : (_i = 1, []), close = _ref[_i++];
Function binding
Account = (customer, cart) ->
@customer = customer
@cart = cart
$('.shopping_cart').bind 'click', (event) =>
@customer.purchase @cart
var Account;
var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
Account = function(customer, cart) {
this.customer = customer;
this.cart = cart;
return $('.shopping_cart').bind('click', __bind(function(event) {
return this.customer.purchase(this.cart);
}, this));
};
Embedded JavaScript
hi = `function() {
return [document.title, "Hello JavaScript"].join(": ");
}`
var hi;
hi = function() {
return [document.title, "Hello JavaScript"].join(": ");
};
Switch/When/Else
switch day
when "Mon" then go work
when "Tue" then go relax
when "Thu" then go iceFishing
when "Fri", "Sat"
if day is bingoDay
go bingo
go dancing
when "Sun" then go church
else go work
switch (day) {
case "Mon":
go(work);
break;
case "Tue":
go(relax);
break;
case "Thu":
go(iceFishing);
break;
case "Fri":
case "Sat":
if (day === bingoDay) {
go(bingo);
go(dancing);
}
break;
case "Sun":
go(church);
break;
default:
go(work);
}
Try/Catch/Finally
try
allHellBreaksLoose()
catsAndDogsLivingTogether()
catch error
print error
finally
cleanUp()
try {
allHellBreaksLoose();
catsAndDogsLivingTogether();
} catch (error) {
print(error);
} finally {
cleanUp();
}
Chained Comparisons
cholesterol = 127
healthy = 200 > cholesterol > 60
var cholesterol, healthy;
cholesterol = 127;
healthy = (200 > cholesterol && cholesterol > 60);
loadrun: healthy
String Interpolation, Heredocs, and Block Comments
author = "Wittgenstein"
quote = "A picture is a fact. -- #{ author }"
sentence = "#{ 22 / 7 } is a decent approximation of π"
mobyDick = "Call me Ishmael. Some years ago --
never mind how long precisely -- having little
or no money in my purse, and nothing particular
to interest me on shore, I thought I would sail
about a little and see the watery part of the
world..."
html = '''
<strong>
cup of coffeescript
</strong>
'''
###
CoffeeScript Compiler v1.1.2
Released under the MIT License
###
var author, quote, sentence;
author = "Wittgenstein";
quote = "A picture is a fact. -- " + author;
sentence = "" + (22 / 7) + " is a decent approximation of π";
var mobyDick;
mobyDick = "Call me Ishmael. Some years ago -- never mind how long precisely -- having
little or no money in my purse, and nothing particular to interest me on shore,
I thought I would sail about a little and see the watery part of the world...";
var html;
html = '<strong>\n cup of coffeescript\n</strong>';
/*
CoffeeScript Compiler v1.1.2
Released under the MIT License
*/
Extended Regular Expressions
OPERATOR = /// ^ (
?: [-=]> # function
| [-+*/%<>&|^!?=]= # compound assign / compare
| >>>=? # zero-fill right shift
| ([-+:])\1 # doubles
| ([&|<>])\2=? # logic / shift
| \?\. # soak access
| \.{2,3} # range or splat
) ///
var OPERATOR;
OPERATOR = /^(?:[-=]>|[-+*\/%<>&|^!?=]=|>>>=?|([-+:])\1|([&|<>])\2=?|\?\.|\.{2,3})/;
Cake, and Cakefiles
fs = require 'fs'
option '-o', '--output [DIR]', 'directory for compiled code'
task 'build:parser', 'rebuild the Jison parser', (options) ->
require 'jison'
code = require('./lib/grammar').parser.generate()
dir = options.output or 'lib'
fs.writeFile "#{dir}/parser.js", code
var fs;
fs = require('fs');
option('-o', '--output [DIR]', 'directory for compiled code');
task('build:parser', 'rebuild the Jison parser', function(options) {
var code, dir;
require('jison');
code = require('./lib/grammar').parser.generate();
dir = options.output || 'lib';
return fs.writeFile("" + dir + "/parser.js", code);
});
"text/coffeescript" Script Tags
Books and Screencasts
Examples
Resources
12