SlideShare a Scribd company logo
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   = 42
opposite = 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   = 42
opposite = 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 = 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();
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
Classes
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()
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 Grail
Reflecting on a Sunday afternoon
In The Red Room
Fall down mountains, just don't fall on me
Midnight Black
Orrery Steam Punk Assemblage by urbandon
Steampunk Time Contraption

More Related Content

Damn Fine CoffeeScript

  • 1. Damn Fine CoffeeScript
  • 3. Some Kind of Holy Python Ruby JavaScrip t
  • 4. 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); }); };
  • 5. 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}"
  • 6. Basically ● function is () -> ● local variables ● indentation ● omittable parentheses
  • 7. True To JavaScript The golden rule of CoffeeScript is: "It's just JavaScript"
  • 8. Less Syntactic Noise stream.on('end', function() { console.log("Created: " + filePath); });
  • 9. stream.on 'end', -> console.log "Created: #{filePath}"
  • 10. My perspective Node A platform: JS machine + CommonJS stdlib
  • 14. Convert & Eval... <script src="/extras/coffee-script.js"></script> <script type="text/coffeescript"> # coffee time </script>
  • 15. Node $ npm install coffee-script
  • 17. 101 # Assignment: number = 42 opposite = true
  • 18. Conditions if happy and knowsIt clapsHands() chaChaCha() else showIt() date = if friday then sue else jill options or= defaults number = -42 if opposite
  • 19. Functions square = (x) -> x * x cube = (x) -> square(x) * x fill = (container, liquid="coffee") -> "Filling the #{container} with #{liquid}..." noop = ->
  • 20. In JQuery $('span').each -> it = $(this) if it.is('.style-1, .style-20') or not it.attr('class') it.replaceWith(it.html())
  • 21. Data # Arrays: list = [1, 2, 3, 4, 5] # Objects: math = root: Math.sqrt square: square cube: (x) -> x * square x
  • 22. modes = {ready: yes, balance: off} bitlist = [ 1, 0, 1 0, 0, 1 1, 1, 0 ]
  • 23. How True To JavaScript?
  • 24. Compile $ coffee -c some.coffee # or just print out $ coffee -p some.coffee
  • 25. number = 42 opposite = true number = -42 if opposite list = [1, 2, 3, 4, 5] math = root: Math.sqrt square: square cube: (x) -> x * square x
  • 26. 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); } };
  • 27. Lexical Scopes & Safety outer = 1 changeNumbers = -> inner = -1 outer = 10 inner = changeNumbers()
  • 28. var changeNumbers, inner, outer; outer = 1; changeNumbers = function() { var inner; inner = -1; return outer = 10; }; inner = changeNumbers();
  • 29. Syntactic Thin Coat of Sugar And Some Boilerplate
  • 30. Sugar++ # Splats: race = (winner, runners...) -> print winner, runners # Existence: alert "I knew it!" if elvis?
  • 31. 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!"); }
  • 33. Unpacking [first, second] = [1, 2, 3, 4] _ref = [1, 2, 3], first = _ref[0], second = _ref[1];
  • 34. {puts, inspect} = require 'util' _ref2 = require('util'), puts = _ref2.puts, inspect = _ref2.inspect;
  • 35. Comprehensions! cubes = (math.cube num for num in list)
  • 36. 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; })();
  • 37. Comprehensive yearsOld = max: 10, ida: 9, tim: 11 ages = for child, age of yearsOld child + " is " + age
  • 38. Closing Over Loops for filename in list do (filename) -> fs.readFile filename, (err, contents) -> compile filename, contents.toString()
  • 39. 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
  • 40. Different Kinds of Else ● unless ● a? ●a ? b ● a ?= b ● a?.b
  • 41. Classes 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()
  • 42. 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; };
  • 43. Animal = (function() { function Animal(name) { this.name = name; } Animal.prototype.move = function(meters) { return alert(this.name + " moved " + meters + "m."); }; return Animal; })();
  • 44. 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; })();
  • 45. Binding => This Account = (customer, cart) -> @customer = customer @cart = cart $('.shopping_cart').bind 'click', (event) => @customer.purchase @cart
  • 46. 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)); };
  • 48. ● Literals: Functions, Objects and Arrays ● If, Else, Unless, and Conditional Assignment
  • 49. ● Splats... ● Array Slicing and Splicing ● Loops and Comprehensions ● Destructuring Assignment ● Everything is an Expression
  • 50. ● Operators and Aliases ● Lexical Scoping and Variable Safety ● Classes, Inheritance, and Super ● Function Binding
  • 51. ● Switch and Try/Catch ● Chained Comparisons ● String Interpolation, Heredocs, and Block Comments ● Extended Regular Expressions ● Embedded JavaScript
  • 53. Coding in Coffee sameness? seeing clearly.. transparencies.. choices...
  • 55. Tinkering Fun! Node goodies: Zombie.js, Canvas, ...
  • 57. $ npm link . $ coffee --watch src $ cake
  • 58. 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
  • 60. Image Tributes (CC) "Black as midnight on a moonless night." Knight of the Holy Grail Reflecting on a Sunday afternoon In The Red Room Fall down mountains, just don't fall on me Midnight Black Orrery Steam Punk Assemblage by urbandon Steampunk Time Contraption