damn fine coffeescript
DESCRIPTION
Introduction to CoffeeScript held at GTUG Sthlm May 2011.TRANSCRIPT
Damn Fine
CoffeeScript
Focus
Language
Some Kind of Holy
Python
Ruby
JavaScrip t
Raw
var render = function (width, height, draw, filePath) { var canvas = new Canvas(width, height), ctx = canvas.getContext('2d'); draw.call(ctx); var out = fs.createWriteStream(filePath), stream = canvas.createPNGStream(); stream.on('data', function(chunk) { out.write(chunk); }); stream.on('end', function() { console.log("Created: " + filePath); });};
Brewed
render = (width, height, draw, filePath) -> canvas = new Canvas(width, height) draw.call canvas.getContext '2d' out = fs.createWriteStream filePath stream = canvas.createPNGStream() stream.on 'data', (chunk) -> out.write chunk stream.on 'end', -> console.log "Created: #{filePath}"
Basically
●function is () ->● local variables● indentation● omittable parentheses
True To JavaScript
The golden rule of CoffeeScript is: "It's just JavaScript"
Less Syntactic Noise
stream.on('end', function() { console.log("Created: " + filePath);});
stream.on 'end', -> console.log "Created: #{filePath}"
My perspective
Node
A platform: JS machine + CommonJS stdlib
Runtimes
It's just
Coffee In Coffee
Browser
Just JS (generated)
Convert & Eval...
<script src="/extras/coffee-script.js"></script><script type="text/coffeescript"> # coffee time</script>
Node
$ npm install coffee-script
REPL
$ coffee
101
# Assignment:number = 42opposite = true
Conditions
if happy and knowsIt clapsHands() chaChaCha()else showIt()
date = if friday then sue else jill
options or= defaults
number = -42 if opposite
Functions
square = (x) -> x * x
cube = (x) -> square(x) * x
fill = (container, liquid="coffee") -> "Filling the #{container} with #{liquid}..."
noop = ->
In JQuery
$('span').each -> it = $(this) if it.is('.style-1, .style-20') or not it.attr('class') it.replaceWith(it.html())
Data
# Arrays:list = [1, 2, 3, 4, 5]
# Objects:math = root: Math.sqrt square: square cube: (x) -> x * square x
modes = {ready: yes, balance: off}
bitlist = [ 1, 0, 1 0, 0, 1 1, 1, 0]
How True To JavaScript?
Compile
$ coffee -c some.coffee
# or just print out$ coffee -p some.coffee
number = 42opposite = true
number = -42 if opposite
list = [1, 2, 3, 4, 5]
math = root: Math.sqrt square: square cube: (x) -> x * square x
var list, math, number, opposite;number = 42;opposite = true;if (opposite) { number = -42;}list = [1, 2, 3, 4, 5];math = { root: Math.sqrt, square: square, cube: function(x) { return x * square(x); }};
Lexical Scopes & Safety
outer = 1changeNumbers = -> inner = -1 outer = 10inner = changeNumbers()
var changeNumbers, inner, outer;outer = 1;changeNumbers = function() { var inner; inner = -1; return outer = 10;};inner = changeNumbers();
Syntactic
Thin Coat of Sugar
And Some Boilerplate
Sugar++
# Splats:race = (winner, runners...) -> print winner, runners
# Existence:alert "I knew it!" if elvis?
var race;var __slice = Array.prototype.slice;var race = function() { var runners, winner; winner = arguments[0], runners = 2 <= arguments.length ? __slice.call(arguments, 1) : []; return print(winner, runners);};if (typeof elvis !== "undefined" && elvis !== null) { alert("I knew it!");}
Expressions, Implicitness, Return
Unpacking
[first, second] = [1, 2, 3, 4]
_ref = [1, 2, 3], first = _ref[0], second = _ref[1];
{puts, inspect} = require 'util'
_ref2 = require('util'), puts = _ref2.puts, inspect = _ref2.inspect;
Comprehensions!
cubes = (math.cube num for num in list)
var cubes;cubes = (function() { var _i, _len, _results; _results = []; for (_i = 0, _len = list.length; _i < _len; _i++) { num = list[_i]; _results.push(math.cube(num)); } return _results;})();
Comprehensive
yearsOld = max: 10, ida: 9, tim: 11
ages = for child, age of yearsOld child + " is " + age
Closing Over Loops
for filename in list do (filename) -> fs.readFile filename, (err, contents) -> compile filename, contents.toString()
Operator Names
CoffeeScript JavaScript
is, isnt ===, !==
and, or, not &&, ||, !
true, yes, on true
false, no, off false
in, of in, N/A
@, this this
:: prototype
Different Kinds of Else
●unless●a?●a ? b●a ?= b●a?.b
Classesclass 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()
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;})();
Binding => This
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));};
And more...
● Literals: Functions, Objects and Arrays● If, Else, Unless, and Conditional Assignment
● Splats...● Array Slicing and Splicing● Loops and Comprehensions● Destructuring Assignment
● Everything is an Expression
● Operators and Aliases● Lexical Scoping and Variable Safety● Classes, Inheritance, and Super● Function Binding
● Switch and Try/Catch● Chained Comparisons● String Interpolation, Heredocs, and Block
Comments● Extended Regular Expressions● Embedded JavaScript
Future/Now
Coding in Coffee
sameness?
seeing clearly..
transparencies..
choices...
Paths Ahead?
Harmony...
Tinkering Fun!
Node goodies: Zombie.js, Canvas, ...
Developing a CommonJS Lib
$ npm link .
$ coffee --watch src
$ cake
Cakefile{spawn, exec} = require 'child_process'
SRC = 'js/src'LIB = 'js/lib'
task 'build', "compile coffee to js", -> build onErrorExit
task 'watch', "continously compile coffee to js", -> cmd = spawn "coffee", ["-cw", "-o", LIB, SRC] cmd.stdout.on "data", (data)-> process.stdout.write data cmd.on "error", onErrorExit
build = (cb)-> console.log "Coffee compiling..." exec "rm -rf #{LIB} && coffee -c -l -b -o #{LIB} #{SRC}", (err, out)-> cb err
onErrorExit = (err)-> if err process.stdout.write "#{err.stack}\n" process.exit -1
Thanks!
Image Tributes (CC)
"Black as midnight on a moonless night."Knight of the Holy GrailReflecting on a Sunday afternoonIn The Red RoomFall down mountains, just don't fall on meMidnight BlackOrrery Steam Punk Assemblage by urbandonSteampunk Time Contraption