Chapter 2

Simplified syntax

2.1 Your first program

Listing 2.1 The coffee machine


houseRoast = null
hasMilk = (style) -> switch style when "latte", "cappuccino" yes else
no
makeCoffee = (requestedStyle) -> style = requestedStyle || 'Espresso' if houseRoast? "#{houseRoast} #{style}" else
style
barista = (style) -> time = (new Date()).getHours() if hasMilk(style) and time > 12 then "No!" else coffee = makeCoffee style "Enjoy your #{coffee}!"





Listing 2.2 Comparing CoffeeScript to JavaScript

CoffeeScript
hasMilk = (style) ->
  switch style
    when "latte", "cappuccino"
      yes
    else
      no




makeCoffee = (style) ->
  style || 'Espresso'


barista = (style) -> 
  now = new Date()       
  time = now.getHours()  
  if hasMilk(style) and time > 12 
    "No!"              
  else                           
    coffee = makeCoffee style   
    "Enjoy your #{coffee}!"     




barista "latte"
JavaScript
var hasMilk = function (style) { 
  switch (style) {
    case "latte":
    case "cappuccino":
      return true;
    default:
      return false;
  }
};

var makeCoffee = function (style) { 
  return style || 'Espresso';
};

var barista = function (style) {   
  var now = new Date();
  var time = now.getHours();
  var coffee; 
  if (hasMilk(style) && time > 12) {
    return "No!";
  } else {
    coffee = makeCoffee(style);
    return "Enjoy your "+coffee+"!";
  }
};

barista("latte");





2.2 Simple expressions


> coffee
coffee> 





0                              
2.4                            
'Chuck Norris'                 
'Bruce Lee'                    
'Espresso'                     
"Bender Bending Rodgiguez"     
true                           
null                           
/script/                       
{actor: 'Chuck Norris'}        
{movie: "Delta Force"}         
[0,1,1,2,3]





(x) -> x





function (x) { return x; }





movie: "Delta Force"
# { movie: "Delta Force"}





on
# true
yes
# true
off
# false
no
# false





/abc/
# /abc/





/ abc/
# error: unexpected / 





pegasus
# ReferenceError: pegasus is not defined





answer = 42
neighborOfTheBeast = 668
blameItOnTheBoogie = yes
texasRanger = {actor: 'Chuck Norris'}





answer
# 42





texasRanger = true
texasRanger
# true





2.3 Operators

+  -  !  /  %  >  <  >=  <=  .  &&  || *





wuss = 'A weak or ineffectual person'
chuckNorris = 'Chuck Norris'





!true
# false





chuckNorris = 'Chuck Norris'
weak = 'weak'
chuckNorris is weak
# false
chuckNorris isnt weak
# true





5 isnt 6      
# true
5 is not 6    
# false





'' == false
# false





1 == '1'
# false





3 + 3
# 6
'string' + ' concatenation'
# 'string concatenation'





4 + '3'
# '43'





3 - 3
# 0





'apples' ? 'oranges'
# NaN





3*3
# 9





'3'*3
# 9





'bork'*3
# NaN





3%2
# 1
4%2
# 0
not (3%2)
# false
not (4%2) # true





42 > 0
# true
42 >= 42 # true





time = 13
time > 12
# true





'Aardvark' < 'Zebra'
# true





2 > 'giraffe'
# false





chuckNorris is weak and pickFight





chuckNorris is weak
# false





chuckNorris is weak and pickFight 
# false





runAway = 'Running away!'
chuckNorris is weak or runAway





makeCoffee = (requestedStyle) ->
requestedStyle || 'Espresso'
makeCoffee() # 'Espresso'





chuckNorris is weak
# false





runaway
# 'Running away!'





makeCoffee = (style) ->
  style || 'Espresso'





makeCoffee 'Cappuccino'
# 'Cappuccino'





new Date()
# Sun, 21 Aug 2011 00:14:34 GMT





texasRanger = actor: 'Chuck Norris'    
texasRanger.actor
# 'Chuck Norris'





movie = title: 'Way of the Dragon', star: 'Bruce Lee'  
myPropertyName = 'title'
movie[myPropertyName]
# 'Way of the Dragon'





now = new Date()
# Sun, 21 Aug 2011 00:14:34 GMT
now.getHours()
# 0





houseRoast?





pegasus
# ReferenceError: pegasus is not defined





reference = null
reference == null
# true





typeof null
# 'object'





dynamicAndWeak = '3'
weakAndDynamic = 5
dynamicAndWeak + weakAndDynamic   
# '35'
dynamicAndWeak = 3                  
dynamicAndWeak + weakAndDynamic
# 8





pegasus?
# false
roundSquare?
# false
pegasus = 'Horse with wings'
pegasus?
# true





typeof roundSquare
# 'undefined'





typeof pegasus !== "undefined" and pegasus !== null
#false





pegasus?
# false





torch = {}
umbrella = {}





2.4 Statements

balance = 1000
while balance > 0
  balance = balance ? 100





if raining
  'Stay inside'
else 
  'Go out'





raining = true
activity = if raining 'Stay inside' else
'Go out'
activity # 'Stay inside'





connectJackNumber = (number) ->
"Connecting jack #{number}"
receiver = 'Betty'
switch receiver when 'Betty' connectJackNumber 4 when 'Sandra' connectJackNumber 22 when 'Toby' connectJackNumber 9 else
'I am sorry, your call cannot be connected'
# 'Connecting jack 4'





month = 3
monthName = switch month
  when 1
    'January'
  when 2
    'February'
  when 3
    'March'
  when 4
    'April'
  else
'Some other month'
monthName # 'March'





style = 'latte'
milk = switch style
  when "latte", "cappuccino"
    yes
  else
no
milk # true





hasMilk = (style) ->
  switch style
    when "latte", "cappuccino"    
      yes
    else
no
hasMilk 'espresso' # false





pseudonym = 'Thomas Veil'
identity = switch pseudonym when 'Richard Bachman' 'Stephen King' when 'Ringo Starr'
'Richard Starkey'
identity #





clean = (what) ->
  if what is 'House'
    'Now cleaning house'
  else 
'Now cleaning everything'
clean 'House' # 'Now cleaning house'





messy = true
while messy
  clean 'House'
  messy = false





spotless = false
until spotless
  clean 'Everything'
  spotless = true





loop clean 'Everything'





x = 0
evenNumbers = while x < 6
  x = x + 1
x * 2
evenNumbers # [2, 4, 6, 8, 10, 12]





flyAway = (animal) ->
  if animal is 'pig'
    throw 'Pigs cannot fly'
  else
'Fly away!'
peter = 'pig' try flyAway peter catch error error finally 'Clean up!'





charlotte = 'spider'
whatHappened = try
  flyAway charlotte
catch error
error
whatHappened # Fly away!





whatHappened = try
  flyAway peter
catch error
error
whatHappened # Pigs cannot fly





try definedOutsideTheTry = true
definedOutsideTheTry
# true





year = 1983
if year is 1983 then hair = 'perm'
hair # 'perm'





while messy then clean 'Everything'





lastDigit = 4
daySuffix = switch lastDigit
  when 1 then 'st'
  when 2 then 'nd'
  when 3 then 'rd'
  else 'th'





time = 15
allowed = if time < 12 then 'Yes' else 'No!'
allowed
# 'No!'  





hair = 'permed' if year is 1983





loop                           
  line = reader.readLine()     
  if not line then break  





animal = 'crocodile'
# 
collective
# bask





2.5 Strings

'haystack'.search 'needle'
# -1
'haystack'.search 'hay'
# 0
'haystack'.search 'stack' # 3





'latte,mocha,cappuccino,flat white,eiskaffee'





milkDrinks = 'latté,mocha,cappuccino,flat white,eiskaffee'
hasMilk = (style) ->
milkDrinks.search(style) isnt -1
hasMilk 'mocha'
# true
hasMilk 'espresso romano' # false





'haystack'.replace 'hay', 'needle'
# 'needlestack'





milkDrinks.replace 'latté', 'latte'





'Cappuccino'.toLowerCase()
# 'cappuccino'
'I am shouting!'.toUpperCase() # 'I AM SHOUTING!'





'Banana,Banana'.split /,/
# [ 'Banana', 'Banana' ]
'latte,mocha,cappuccino,flat white,eiskaffee'.split /,/ # [ 'latte', 'mocha', 'cappuccino', 'flat white', 'eiskaffee' ]





userName = 'Scruffy'





"Affirmative, Dave. I read you."





"Affirmative, #{userName}. I read you."





coffee = 'Ristresso'
"Enjoy your #{coffee}!" 
# 'Enjoy your Ristresso!'





"Affirmative," + userName + ". I read you."





userName = 'Scruffy'
dayOfWeek = new Date().getDay()
dayName = switch dayOfWeek when 0 then 'Sunday' when 1 then 'Monday' when 2 then 'Tuesday' when 3 then 'Wednesday' when 4 then 'Thursday' when 5 then 'Friday'
when 6 then 'Saturday'
"Hi, my name is #{userName}. Today is #{dayName}."





"The collective of cobra is quiver"





2.6 Arrays

macgyverTools = ['Swiss Army knife', 'duct tape']
macgyverTools[0]
# 'Swiss Army knife'
macgyverTools[1] # 'duct tape'





fence = ['fence pail', 'fence pail']
fence.length
# 2





fence[999] = 'fence pail'
fence.length
# 1000





['double', 'barreled'].join '-'
# 'double-barreled'





['good', 'bad', 'ugly'].slice 0, 2
# ['good', 'bad']





[0,1,2,3,4,5].slice 0,1
# [0]
[0,1,2,3,4,5].slice 3,5 # [3,4]





['mythril', 'energon'].concat ['nitron', 'durasteel', 'unobtanium']
# [ 'mythril', 'energon', 'nitron', 'durasteel', 'unobtanium' ]





potatoes = ['coliban', 'desiree', 'kipfler']
saladPotatoes = potatoes.slice 2,3 saladPotatoes
# ['kipfler']
potatoes
# ['coliban', 'desiree', 'kipfler']
potatoes.join 'mayonnnaise'
potatoes
# ['coliban', 'desiree', 'kipfler']
potatoes.concat ['pumpkin']
potatoes # ['coliban', 'desiree', 'kipfler']





'to be' in ['to be', 'not to be']
# true
living = 'the present' living in ['the past', 'the present'] # true





milkBeverages = 'latte,mocha,cappuccino'.split /,/





'mocha' in milkBeverages





[1..10]
# [ 1,2,3,4,5,6,7,8,9,10 ]
[5..1] # [ 5,4,3,2,1 ]





[1...10]
# [ 1,2,3,4,5,6,7,8,9 ]





['good', 'bad', 'ugly'][0..1]
# ['good', 'bad']





number for number in [9,0,2,1,0]
# [9,0,2,1,0]





x for x in [9,0,2,1,0]
# [9,0,2,1,0]





number + 1 for number in [9,0,2,1,0]
# [10,1,3,2,1]





0 for number in [9,0,2,1,0]
# [0,0,0,0,0]





letter for letter in ['x','y','z']
# [x,y,z]
letter # 'z'





ingredients = [
  'block of dark chocolate'
  'stick butter'
  'cup of water'
  'cup of brown sugar'
  'packet of flour'
  'egg'
]





doubleIngredients = ("2x #{ingredient}" for ingredient in ingredients)
doubleIngredients # [ # '2x block of dark chocolate' # '2x stick butter' # '2x cup of water' # '2x cup of brown sugar' # '2x packet of flour' # '2x egg' # ]





mix = (ingredient) ->
  "Put #{ingredient} in the bowl"





instructions = (mix ingredient for ingredient in doubleIngredients)





[
  'Put 2x block of dark chocolate in the bowl'
  'Put 2x stick butter in the bowl'
  'Put 2x cup of water in the bowl'
  'Put 2x cup of brown sugar in the bowl'
  'Put 2x packet of flour in the bowl'
  'Put 2x egg in the bowl'
]





hasMilk = (style) ->
  switch style
    when 'latte', 'cappuccino', 'mocha'
      yes
    else
      no





styles = ['cappuccino', 'mocha', 'latte', 'espresso']





hasMilk style for style in styles
# [true, true, true, false]





mix = (ingredient) -> "Mixing #{ingredient}"
for ingredient in ingredients when ingredient.search('flour') < 0
  mix ingredient 





num for num in [1..10] when not (num%2)
# [ 2, 4, 6, 8, 10]





day = [0..23]
sleep = (hour) -> "Sleeping at #{hour}"
sleep hour for hour in day by 6
# [ 'Sleeping at 0','Sleeping at 6','Sleeping at 12','Sleeping at 18' ]





person for person in ['Kingpin', 'Galactus', 'Thanos', 'Doomsday'] by 2
# ['Kingpin', 'Thanos']





luckyNumbers = [3,4,8,2,1,8]





i = 0
twiceAsLucky = []
while i != luckyNumbers.length twiceAsLucky[i] = luckyNumbers[i]*2 i = i + 1
# [1,2,3,4,5,6]
twiceAsLucky # [6,8,16,4,2,16]





number * 2 for number in luckyNumbers





animals = 'baboons badgers antelopes cobras crocodiles'





['A rumpus of baboons',
 'A cete of badgers',
 'A herd of antelopes',
 'A quiver of cobras',
 'A bask of crocodiles']





2.7 Heres for comments, docs, and regexes

# This is a comment





###
This is a herecomment
It will be a block comment in the generated JavaScript
###





/*
This is a herecomment
It will be a block comment in the generated JavaScript
*/





'''
This
String
Contains
Whitespace
'''





stanza = '''
Tyger! Tyger! burning bright 
In the forests of the night, 
What immortal hand or eye 
Could frame thy fearful symmetry?
'''





title = 'Tiny HTML5 document' 
doc = """
<!doctype html>
<title>#{title}</title>
<body>
"""
doc # '<!doctype html>\n<title>Tiny HTML5 document</title>\n<body>'





/[0-9]/





leadingWhitespace = ///
  ^\s\s*  # start and pre-check optimizations for performance
///g





2.8 Putting it together

> coffee ?c barista.coffee





<!doctype html>
<title>Barista</title>
<body>
<form id='order'>
<input id='request' />
<input type='submit' value ='order' />
</form>
The barista.
<div id='response'></div>
</body>
<script src='barista.js'></script>
</html>





Listing 2.3 A browser barista (barista.coffee)

houseRoast = 'Yirgacheffe'
hasMilk = (style) -> switch style.toLowerCase() when 'latte', 'cappuccino', 'mocha' yes else
no
makeCoffee = (requestedStyle) -> style = requestedStyle || 'Espresso' console.log houseRoast if houseRoast? "#{houseRoast} #{style}" else
style
barista = (style) -> time = (new Date()).getHours() if hasMilk(style) and time > 12 then "No!" else coffee = makeCoffee style
"Enjoy your #{coffee}!"
order = document.querySelector '#order' request = document.querySelector '#request'
response = document.querySelector '#response'
order.onsubmit = -> response.innerHTML = barista(request.value) false





> coffee 2.4.coffee
You need to specify an order.





> coffee 2.4.coffee 'Cappuccino'





fs = require 'fs'





Listing 2.4 A command-line barista

fs = require 'fs'
houseRoast = null
hasMilk = (style) -> switch style.toLowerCase() when "latte", "cappuccino" yes else
no
makeCoffee = (requestedStyle) -> style = requestedStyle || 'Espresso' if houseRoast? "#{houseRoast} #{style}" else
style
barista = (style) -> time = (new Date()).getHours() if hasMilk(style) and time > 12 then "No!" else coffee = makeCoffee style
"Enjoy your #{coffee}!"
main = -> requestedCoffee = process.argv[2] if !requestedCoffee? console.log 'You need to specify an order' else fs.readFile 'house_roast.txt', 'utf-8', (err, data) -> if data then houseRoast = data.replace /\n/, ''
console.log barista(requestedCoffee)
main()





> coffee 2.4.coffee 
You need to specify an order.
> coffee 2.4.coffee 'Ristretto' Enjoy your Yirgacheffe Ristretto!





2.9 Summary