Script
     by
  Scott Leberknight
Created by Jeremy Ashkenas



https://github.com/jashkenas/coffee-script



      Compiles to JavaScript
"It's just JavaScript"
var cube, cubes, num;
cube = function(x) {
   return Math.pow(x, 3);
};
cubes = (function() {
   var _i, _len, _ref, _results;
   _ref = [1, 2, 3, 4, 5];
   _results = [];
   for (_i = 0, _len = _ref.length; _i < _len; _i++) {
     num = _ref[_i];
     _results.push(cube(num));
   }
   return _results;
})();
console.log(cubes);


                                                JavaScript
cube = (x) -> x * x * x
cubes = (cube num for num in [1, 2, 3, 4, 5])
console.log cubes
Let's Get Started..
OS X
 Install Homebrew

 brew install node

 curl http://npmjs.org/install.sh | sh

 npm install coffee-script

 coffee -v

                                 http://mxcl.github.com/homebrew/
Linux*
 install node and npm
       (http://joyeur.com/2010/12/10/installing-node-and-npm/ )


 npm install coffee-script


 coffee -v


                 (* Windoze people can uze these instructions on Cygwin)
Drinking some Coffee..
⌘-R
⌘-B
$ coffee -c my.coffee
$ node my.js
[ 2048, 4096, 6144, 8192, 10240 ]
$ coffee
coffee> nums = (x * 1024 for x in [2..10] by 2)
2048,4096,6144,8192,10240

coffee> typeof(nums)
object

coffee> nums.length
5

coffee> nums[4]
10240

coffee> quit()
$ coffee --watch my.coffee
[ 2048, 4096, 6144, 8192, 10240 ]
[ 1024, 2048, 3072, 4096, 5120 ]
<script type="text/coffeescript">
  nums = (x * 1024 for x in [2..10] by 2)
  console.log nums
</script>
Everything's an expression
result = if (2 > 1) then "Yep" else "Hmmmm..."
console.log result
=> Yep
Look Ma! No var needed
book = "I Am America (And So Can You!)"




    var book;
    book = "I Am America (And So Can You!)";

                   JavaScript

             http://www.amazon.com/Am-America-So-Can-You/dp/0446580503
Significant Whitespace



                     if isFood(animal)
                       strangle()
                       eat()
                     else
                       slitherAlong()22
Significant Whitespace



                     if isFood(animal)
                       strangle()
                       eat()
                     else
                     slitherAlong()  23
Functions.. the basics
noop = ->

-> 'The answer is 42'

console.log do -> 'What is the question?'

answerer -> 'The answer is 42'

mult = (x, y) -> x * y
mult = (x, y) -> x * y




             var mult;
             mult = function(x, y) {
JavaScript
                return x * y;
             };
console.log do -> 'What is the question?'




       console.log((function() {
         return 'What is the question?';
       })());

              JavaScript
Arrays & Objects
a = [1, 2, 3, 4, 5]

a[1..2]    #   inclusive range: [2, 3]
a[1...2]   #   exclusive range: [2]
a[0..-1]   #   [1, 2, 3, 4, 5]
a[2..-2]   #   [3, 4]
range   =   [1..10]
range   =   [1..21]
range   =   [1..22] # Inflection pt! (*)
range   =   [1..100]
range   =   [1..100000]




                              (* in version 1.0.1 )
fellowship =
  wizard: 'Gandalf'
  hobbits: ['Frodo', 'Pippin', 'Sam']
delta = 'u0394'
greekUnicode = { delta }




                 var delta, greekUnicode;
                 delta = 'u0394';
                 greekUnicode = {
    JavaScript
                    delta: delta
                 };
Operators & Aliases
CoffeeScript        JavaScript
   ==, is             ===
   !=, isnt           !===
    and                &&
     or                 ||
     of                in
     in          (no equivalent)
  @, this             this
true, yes, on         true
false, no, off        false
goodStudent = yes if grade in ['A', 'B']



stop() unless greenLight is on



if (book is "1984")
  removeFromAllKindles()
Existential operator

believer = if aliens? then yes else no
console.log "I Believe" if believer



options ?= {}



options or= defaults



customer?.contactInfo?.emailAddress
Getting Loopy
Iterating Arrays using "in"

a = [1, 2, 3, 4, 5]
for val in a
  doSomethingWith(val)
Loops return a value
a = [1, 2, 3, 4, 5]
timesTwo = for val in a
  val * 2

=> [2, 4, 6, 8, 10 ]
Loops do not create scope..
 countdown = [10..0]
 for num in countdown
   break if errorDetected()

 if num is 0
   console.log 'Blast-off!'
 else
   console.log "Aborted with #{num} seconds left!"
Iterating objects using "of"

for prop, val of someObject
  # do something...
Iterating objects with "for
         own" (hasOwnProperty)
Human = ->
Human::species = 'Homo-Sapiens'

ceo = new Human()
ceo.name = "Chris D'Agostino"
ceo.company = 'Near Infinity'
ceo.yearFounded = 2002

for own prop, val of ceo
  console.log "#{prop} = #{val}"
What do vampires do while it's
           dark?
while isDarkOutside()
  suckBlood()
. .or until it's day time?
until isDayTime()
  suckBlood()
¿Comprendo?
Array Comprehensions

foods = ['pizza', 'soda', 'beer']

consume food for food in foods

consume food if food is 'beer' for food in foods

consume food for food in foods when food is 'beer'
nums = [1..10]

doubles = (n * 2 for n in nums)

squares = (n * n for n in nums)

evens = (n for n in nums when n % 2 is 0)

evensSquared = (n * n for n in evens)
Ripping things apart..




     (a.k.a. de-structuring assignment)
[a, b] = [b, a]
[firstName, mi, lastName] = ['Wile', 'E', 'Coyote']
weatherReport = (location) ->
  # Get the weather for real...
  [location, 70, "Partly Cloudy"]

[city, temp, forecast] = weatherReport "Reston, VA"
fellowship =
  maiar: ['Gandalf']
  hobbits: ['Frodo', 'Sam', 'Merry', 'Pippin']
  elves: ['Legolas']
  dwarves: ['Gimli']
  men: ['Aragorn', 'Boromir']

{hobbits: theHobbits, men: theMen} = fellowship

# or simply...

{hobbits, men} = fellowship
[sauce, toppings..., crust] = ['meat', 'pepperoni', 'banana 
peppers', 'green peppers', 'thin']

console.log "Your pizza is a #{crust} crust with #{sauce}
sauce and #{toppings.join(', ')} on top"




                       spl at!


                                                                55
Functions.. the Good Stuff
Functions are bound or unbound


Functions create scope


Variable declarations are pushed to the top of the
closest scope


Variables are not visible outside declared scope
weirdAl = function() {
  a = a + 1;
  // What's a's value at this point?
  var a = 10;
  return a;
}
result = weirdAl();




                                       JavaScript
Scoping..
outer = 1                      var changeNumbers, inner, outer;
changeNumbers = ->             outer = 1;
  inner = -1                   changeNumbers = function() {
  outer = 10                      var inner;
                                  inner = -1;
inner = changeNumbers()
                                  return outer = 10;
                               };
                               inner = changeNumbers();



                                              JavaScript


                          Example from: http://jashkenas.github.com/coffee-script/
Context is key.. but what is
          this?
@ is this, this is @
Bound function
  setAnswer = (answer) -> @answer = answer
  deepThought = {}
  deepThought.setAnswer = setAnswer
  deepThought.setAnswer 42
  console.log deepThought.answer
  => 42
Applying context..
 setAnswer = (answer) -> @answer = answer
 deepThought = {}
 setAnswer.apply deepThought, [ 42 ]
 console.log deepThought.answer
 => 42
Context via new..
 Computer = (answer) ->
   @answer = answer
 deepThought = new Computer(42)
 watson = new Computer("What is Toronto?")
 console.log deepThought.answer
 => 42

 console.log watson.answer
 => "What is Toronto?"
Capturing this..
callback = (message) => @voicemail.push message


          => binds a function to the current scope
default arguments
selectMeals = (breakfast = 'Chick Fil A', 
    lunch = 'Macaroni Grill', dinner = 'Thai Noy') ->
  "You chose #{breakfast}, #{lunch}, and #{dinner}"



console.log selectMeals("McDonald's", 'Subway', 'Outback')
=> You chose McDonald's, Subway, and Outback

console.log selectMeals(null, 'Subway', null)
=> You chose Chick Fil A, Subway, and Thai Noy

console.log selectMeals(null, null, null)
=> You chose Chick Fil A, Macaroni Grill, and Thai Noy
pizza = (sauce = 'tomato', toppings..., crust) ->
  "A #{crust} pizza with #{sauce} sauce #{listOf(toppings)}"



console.log pizza('white', 'thin crust')
console.log pizza('tomato', 'pepperoni', 'pan')
console.log pizza(null, 'pepperoni', 'peppers', 'thin crust')




                                                                67
Class-based OO
Prototypal inheritance
var Animal = function(name, species) {
  this.name = name;
  this.species = species;
}
Animal.prototype.eat = function(food) { ... }
Animal.prototype.sleep = function() { ... }
Animal.prototype.play = function() { ... }

var felix = new Animal('Felix', 'Feline');
felix.sleep();

var fido = new Animal('Fido', 'Canine');
fido.play();
fido.eat();
                                                JavaScript
class Bike
  constructor: (@brand) ->
    @gear = 1

  changeGear: (newGear) ->
    @gear = newGear

  currentGear: ->
    @gear

  status: ->
    "#{@brand} cruising in gear #{@gear}"
class MtnBike extends Bike
  changeGear: (newGear) ->
    # do something special for mtn bikes...
    super newGear



cruiser = new Bike("Schwinn")
cruiser.changeGear(4)
console.log cruiser.status()

mtn = new MtnBike("Specialized")
mtn.changeGear(8)
console.log mtn.status()
Grab-Bag..
string interpolation

embedded JS using `...` (backticks)

switch/when/else

try/catch/finally

multi-line strings

enhanced regular expressions

Cake and Cakefiles
Other Considerations..
  Debugging

  Compilation

  Deployment

  Testing
Let's Review..
"It's just JavaScript"
"Because DHH says so..."



      (yes, this is a joke)
Refs
CoffeeScript: Accelerated JavaScript Development
                  http://pragprog.com/titles/tbcoffee/coffeescript



                         CoffeeScript GitHub page
                        http://jashkenas.github.com/coffee-script/
http://lmgtfy.com/?q=coffeescript
photo attributions
  Coffee # 1 -
  http://www.flickr.com/photos/dyobmit/18588671/

  Coffee # 2 -
  http://www.flickr.com/photos/ibcbulk/86885289/

  Python -
  http://www.flickr.com/photos/lesmontsdore/5513104816/

  Rip Apart Napkin -
  http://www.flickr.com/photos/benreichelt/5543115344/

  Weird Al - http://www.flickr.com/photos/schilder/4749864091/

  Splat Wallpaper -
  http://wallpaperstock.net/digital-splat_wallpapers_11732_1600x1200_1.html

  Grab Bag -
  http://www.flickr.com/photos/maynard/2126229821/


                                                                (others from iStockPhoto...)
(my info)


scott.leberknight@nearinfinity.com
www.nearinfinity.com/blogs/
twitter: sleberknight

CoffeeScript

  • 1.
    Script by Scott Leberknight
  • 2.
    Created by JeremyAshkenas https://github.com/jashkenas/coffee-script Compiles to JavaScript
  • 3.
  • 6.
    var cube, cubes,num; cube = function(x) { return Math.pow(x, 3); }; cubes = (function() { var _i, _len, _ref, _results; _ref = [1, 2, 3, 4, 5]; _results = []; for (_i = 0, _len = _ref.length; _i < _len; _i++) { num = _ref[_i]; _results.push(cube(num)); } return _results; })(); console.log(cubes); JavaScript
  • 7.
    cube = (x)-> x * x * x cubes = (cube num for num in [1, 2, 3, 4, 5]) console.log cubes
  • 8.
  • 9.
    OS X InstallHomebrew brew install node curl http://npmjs.org/install.sh | sh npm install coffee-script coffee -v http://mxcl.github.com/homebrew/
  • 10.
    Linux* install nodeand npm (http://joyeur.com/2010/12/10/installing-node-and-npm/ ) npm install coffee-script coffee -v (* Windoze people can uze these instructions on Cygwin)
  • 11.
  • 12.
  • 13.
  • 14.
    $ coffee -cmy.coffee $ node my.js [ 2048, 4096, 6144, 8192, 10240 ]
  • 15.
    $ coffee coffee> nums= (x * 1024 for x in [2..10] by 2) 2048,4096,6144,8192,10240 coffee> typeof(nums) object coffee> nums.length 5 coffee> nums[4] 10240 coffee> quit()
  • 16.
    $ coffee --watchmy.coffee [ 2048, 4096, 6144, 8192, 10240 ] [ 1024, 2048, 3072, 4096, 5120 ]
  • 18.
    <script type="text/coffeescript"> nums = (x * 1024 for x in [2..10] by 2) console.log nums </script>
  • 19.
    Everything's an expression result= if (2 > 1) then "Yep" else "Hmmmm..." console.log result => Yep
  • 20.
    Look Ma! Novar needed
  • 21.
    book = "IAm America (And So Can You!)" var book; book = "I Am America (And So Can You!)"; JavaScript http://www.amazon.com/Am-America-So-Can-You/dp/0446580503
  • 22.
    Significant Whitespace if isFood(animal) strangle() eat() else slitherAlong()22
  • 23.
    Significant Whitespace if isFood(animal) strangle() eat() else slitherAlong() 23
  • 24.
  • 25.
    noop = -> ->'The answer is 42' console.log do -> 'What is the question?' answerer -> 'The answer is 42' mult = (x, y) -> x * y
  • 26.
    mult = (x,y) -> x * y var mult; mult = function(x, y) { JavaScript return x * y; };
  • 27.
    console.log do ->'What is the question?' console.log((function() { return 'What is the question?'; })()); JavaScript
  • 28.
  • 29.
    a = [1,2, 3, 4, 5] a[1..2] # inclusive range: [2, 3] a[1...2] # exclusive range: [2] a[0..-1] # [1, 2, 3, 4, 5] a[2..-2] # [3, 4]
  • 30.
    range = [1..10] range = [1..21] range = [1..22] # Inflection pt! (*) range = [1..100] range = [1..100000] (* in version 1.0.1 )
  • 31.
    fellowship = wizard: 'Gandalf' hobbits: ['Frodo', 'Pippin', 'Sam']
  • 32.
    delta = 'u0394' greekUnicode= { delta } var delta, greekUnicode; delta = 'u0394'; greekUnicode = { JavaScript delta: delta };
  • 33.
  • 34.
    CoffeeScript JavaScript ==, is === !=, isnt !=== and && or || of in in (no equivalent) @, this this true, yes, on true false, no, off false
  • 35.
    goodStudent = yesif grade in ['A', 'B'] stop() unless greenLight is on if (book is "1984") removeFromAllKindles()
  • 36.
    Existential operator believer =if aliens? then yes else no console.log "I Believe" if believer options ?= {} options or= defaults customer?.contactInfo?.emailAddress
  • 37.
  • 38.
    Iterating Arrays using"in" a = [1, 2, 3, 4, 5] for val in a doSomethingWith(val)
  • 39.
    Loops return avalue a = [1, 2, 3, 4, 5] timesTwo = for val in a val * 2 => [2, 4, 6, 8, 10 ]
  • 40.
    Loops do notcreate scope.. countdown = [10..0] for num in countdown break if errorDetected() if num is 0 console.log 'Blast-off!' else console.log "Aborted with #{num} seconds left!"
  • 41.
    Iterating objects using"of" for prop, val of someObject # do something...
  • 42.
    Iterating objects with"for own" (hasOwnProperty) Human = -> Human::species = 'Homo-Sapiens' ceo = new Human() ceo.name = "Chris D'Agostino" ceo.company = 'Near Infinity' ceo.yearFounded = 2002 for own prop, val of ceo console.log "#{prop} = #{val}"
  • 43.
    What do vampiresdo while it's dark?
  • 44.
  • 45.
    . .or untilit's day time?
  • 46.
    until isDayTime() suckBlood()
  • 47.
  • 48.
    Array Comprehensions foods =['pizza', 'soda', 'beer'] consume food for food in foods consume food if food is 'beer' for food in foods consume food for food in foods when food is 'beer'
  • 49.
    nums = [1..10] doubles= (n * 2 for n in nums) squares = (n * n for n in nums) evens = (n for n in nums when n % 2 is 0) evensSquared = (n * n for n in evens)
  • 50.
    Ripping things apart.. (a.k.a. de-structuring assignment)
  • 51.
    [a, b] =[b, a]
  • 52.
    [firstName, mi, lastName]= ['Wile', 'E', 'Coyote']
  • 53.
    weatherReport = (location)-> # Get the weather for real... [location, 70, "Partly Cloudy"] [city, temp, forecast] = weatherReport "Reston, VA"
  • 54.
    fellowship = maiar: ['Gandalf'] hobbits: ['Frodo', 'Sam', 'Merry', 'Pippin'] elves: ['Legolas'] dwarves: ['Gimli'] men: ['Aragorn', 'Boromir'] {hobbits: theHobbits, men: theMen} = fellowship # or simply... {hobbits, men} = fellowship
  • 55.
    [sauce, toppings..., crust]= ['meat', 'pepperoni', 'banana peppers', 'green peppers', 'thin'] console.log "Your pizza is a #{crust} crust with #{sauce} sauce and #{toppings.join(', ')} on top" spl at! 55
  • 56.
  • 57.
    Functions are boundor unbound Functions create scope Variable declarations are pushed to the top of the closest scope Variables are not visible outside declared scope
  • 58.
    weirdAl = function(){ a = a + 1; // What's a's value at this point? var a = 10; return a; } result = weirdAl(); JavaScript
  • 59.
    Scoping.. outer = 1 var changeNumbers, inner, outer; changeNumbers = -> outer = 1; inner = -1 changeNumbers = function() { outer = 10 var inner; inner = -1; inner = changeNumbers() return outer = 10; }; inner = changeNumbers(); JavaScript Example from: http://jashkenas.github.com/coffee-script/
  • 60.
    Context is key..but what is this?
  • 61.
    @ is this,this is @
  • 62.
    Bound function setAnswer = (answer) -> @answer = answer deepThought = {} deepThought.setAnswer = setAnswer deepThought.setAnswer 42 console.log deepThought.answer => 42
  • 63.
    Applying context.. setAnswer= (answer) -> @answer = answer deepThought = {} setAnswer.apply deepThought, [ 42 ] console.log deepThought.answer => 42
  • 64.
    Context via new.. Computer = (answer) -> @answer = answer deepThought = new Computer(42) watson = new Computer("What is Toronto?") console.log deepThought.answer => 42 console.log watson.answer => "What is Toronto?"
  • 65.
    Capturing this.. callback =(message) => @voicemail.push message => binds a function to the current scope
  • 66.
    default arguments selectMeals =(breakfast = 'Chick Fil A', lunch = 'Macaroni Grill', dinner = 'Thai Noy') -> "You chose #{breakfast}, #{lunch}, and #{dinner}" console.log selectMeals("McDonald's", 'Subway', 'Outback') => You chose McDonald's, Subway, and Outback console.log selectMeals(null, 'Subway', null) => You chose Chick Fil A, Subway, and Thai Noy console.log selectMeals(null, null, null) => You chose Chick Fil A, Macaroni Grill, and Thai Noy
  • 67.
    pizza = (sauce= 'tomato', toppings..., crust) -> "A #{crust} pizza with #{sauce} sauce #{listOf(toppings)}" console.log pizza('white', 'thin crust') console.log pizza('tomato', 'pepperoni', 'pan') console.log pizza(null, 'pepperoni', 'peppers', 'thin crust') 67
  • 68.
  • 69.
    Prototypal inheritance var Animal= function(name, species) { this.name = name; this.species = species; } Animal.prototype.eat = function(food) { ... } Animal.prototype.sleep = function() { ... } Animal.prototype.play = function() { ... } var felix = new Animal('Felix', 'Feline'); felix.sleep(); var fido = new Animal('Fido', 'Canine'); fido.play(); fido.eat(); JavaScript
  • 70.
    class Bike constructor: (@brand) -> @gear = 1 changeGear: (newGear) -> @gear = newGear currentGear: -> @gear status: -> "#{@brand} cruising in gear #{@gear}"
  • 71.
    class MtnBike extendsBike changeGear: (newGear) -> # do something special for mtn bikes... super newGear cruiser = new Bike("Schwinn") cruiser.changeGear(4) console.log cruiser.status() mtn = new MtnBike("Specialized") mtn.changeGear(8) console.log mtn.status()
  • 72.
  • 73.
    string interpolation embedded JSusing `...` (backticks) switch/when/else try/catch/finally multi-line strings enhanced regular expressions Cake and Cakefiles
  • 74.
    Other Considerations.. Debugging Compilation Deployment Testing
  • 75.
  • 76.
  • 77.
    "Because DHH saysso..." (yes, this is a joke)
  • 78.
  • 79.
    CoffeeScript: Accelerated JavaScriptDevelopment http://pragprog.com/titles/tbcoffee/coffeescript CoffeeScript GitHub page http://jashkenas.github.com/coffee-script/
  • 80.
  • 81.
    photo attributions Coffee # 1 - http://www.flickr.com/photos/dyobmit/18588671/ Coffee # 2 - http://www.flickr.com/photos/ibcbulk/86885289/ Python - http://www.flickr.com/photos/lesmontsdore/5513104816/ Rip Apart Napkin - http://www.flickr.com/photos/benreichelt/5543115344/ Weird Al - http://www.flickr.com/photos/schilder/4749864091/ Splat Wallpaper - http://wallpaperstock.net/digital-splat_wallpapers_11732_1600x1200_1.html Grab Bag - http://www.flickr.com/photos/maynard/2126229821/ (others from iStockPhoto...)
  • 82.