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