├── img ├── eyes.jpg ├── heap.png ├── html.png ├── tree.png ├── height.png ├── queens.png ├── scenic.png ├── sketch.png ├── Hiva Oa.png ├── TadaOnIOS.png ├── WebHeader.png ├── ostrich.jpg ├── CoverCoffee.jpg ├── TadaOnWin7.png ├── objectchain.png ├── TadaOnMacOSX.png ├── diagonalpath.png ├── environments.png └── License.text ├── src ├── prelude │ ├── package.json │ ├── coffeekup-LICENSE │ ├── qc-COPYING │ ├── coffeekup.coffee │ └── ws.coffee ├── 10-CircularTest.coffee ├── A3-Microbench.coffee ├── A3-Microtest.py ├── 01-Introduction.coffee ├── 06-Quote.html ├── 10-Circular.coffee ├── 10-MathFix.coffee ├── node_modules │ └── LICENSE ├── A3-Microrun.cpp ├── 00-Foreword.coffee ├── A3-Queen.coffee ├── A3-Queens.py ├── A2-BinaryHeapTest.coffee ├── 10-Modularity.coffee ├── 10-SeedLife.coffee ├── A4-NoSolutions.coffee ├── 10-TestWebSockets.coffee ├── 04-emails.coffee ├── 10-WebSocketLife.coffee ├── 05-ErrorHandling.coffee ├── A1-LanguageExtras.coffee ├── A2-BinaryHeap.coffee ├── 06-RecluseFile.text ├── 09-RegularExpressions.coffee ├── docs │ ├── 10-CircularTest.html │ ├── A3-Microbench.html │ ├── A3-Microtest.html │ └── docco.css ├── 03-Functions.coffee └── 08-ObjectOrientation.coffee ├── src-no-solutions ├── prelude │ ├── package.json │ ├── coffeekup-LICENSE │ ├── qc-COPYING │ ├── coffeekup.coffee │ └── ws.coffee ├── 10-CircularTest.coffee ├── A3-Microbench.coffee ├── A3-Microtest.py ├── 01-Introduction.coffee ├── 06-Quote.html ├── 10-Circular.coffee ├── 10-MathFix.coffee ├── node_modules │ └── LICENSE ├── A3-Microrun.cpp ├── 00-Foreword.coffee ├── A3-Queen.coffee ├── A3-Queens.py ├── A2-BinaryHeapTest.coffee ├── 10-Modularity.coffee ├── 10-SeedLife.coffee ├── A4-NoSolutions.coffee ├── 10-TestWebSockets.coffee ├── 04-emails.coffee ├── 10-WebSocketLife.coffee ├── 05-ErrorHandling.coffee ├── A1-LanguageExtras.coffee ├── A2-BinaryHeap.coffee ├── 09-RegularExpressions.coffee ├── 06-RecluseFile.text ├── docs │ ├── 10-CircularTest.html │ ├── A3-Microbench.html │ ├── A3-Microtest.html │ └── docco.css └── 03-Functions.coffee ├── Smooth CoffeeScript.pdf ├── Smooth CoffeeScript - No Solutions.pdf ├── readme.md └── changes.md /img/eyes.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simple/Smooth-CoffeeScript/master/img/eyes.jpg -------------------------------------------------------------------------------- /img/heap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simple/Smooth-CoffeeScript/master/img/heap.png -------------------------------------------------------------------------------- /img/html.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simple/Smooth-CoffeeScript/master/img/html.png -------------------------------------------------------------------------------- /img/tree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simple/Smooth-CoffeeScript/master/img/tree.png -------------------------------------------------------------------------------- /src/prelude/package.json: -------------------------------------------------------------------------------- 1 | { "name" : "prelude", 2 | "main" : "./prelude.coffee" } 3 | -------------------------------------------------------------------------------- /img/height.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simple/Smooth-CoffeeScript/master/img/height.png -------------------------------------------------------------------------------- /img/queens.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simple/Smooth-CoffeeScript/master/img/queens.png -------------------------------------------------------------------------------- /img/scenic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simple/Smooth-CoffeeScript/master/img/scenic.png -------------------------------------------------------------------------------- /img/sketch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simple/Smooth-CoffeeScript/master/img/sketch.png -------------------------------------------------------------------------------- /img/Hiva Oa.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simple/Smooth-CoffeeScript/master/img/Hiva Oa.png -------------------------------------------------------------------------------- /img/TadaOnIOS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simple/Smooth-CoffeeScript/master/img/TadaOnIOS.png -------------------------------------------------------------------------------- /img/WebHeader.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simple/Smooth-CoffeeScript/master/img/WebHeader.png -------------------------------------------------------------------------------- /img/ostrich.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simple/Smooth-CoffeeScript/master/img/ostrich.jpg -------------------------------------------------------------------------------- /img/CoverCoffee.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simple/Smooth-CoffeeScript/master/img/CoverCoffee.jpg -------------------------------------------------------------------------------- /img/TadaOnWin7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simple/Smooth-CoffeeScript/master/img/TadaOnWin7.png -------------------------------------------------------------------------------- /img/objectchain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simple/Smooth-CoffeeScript/master/img/objectchain.png -------------------------------------------------------------------------------- /src-no-solutions/prelude/package.json: -------------------------------------------------------------------------------- 1 | { "name" : "prelude", 2 | "main" : "./prelude.coffee" } 3 | -------------------------------------------------------------------------------- /img/TadaOnMacOSX.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simple/Smooth-CoffeeScript/master/img/TadaOnMacOSX.png -------------------------------------------------------------------------------- /img/diagonalpath.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simple/Smooth-CoffeeScript/master/img/diagonalpath.png -------------------------------------------------------------------------------- /img/environments.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simple/Smooth-CoffeeScript/master/img/environments.png -------------------------------------------------------------------------------- /Smooth CoffeeScript.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simple/Smooth-CoffeeScript/master/Smooth CoffeeScript.pdf -------------------------------------------------------------------------------- /Smooth CoffeeScript - No Solutions.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simple/Smooth-CoffeeScript/master/Smooth CoffeeScript - No Solutions.pdf -------------------------------------------------------------------------------- /src/10-CircularTest.coffee: -------------------------------------------------------------------------------- 1 | cp = require "./10-Circular" 2 | show = console.log 3 | 4 | circ = new cp.CircularPosition 0.01 5 | for i in [0...6] 6 | show "#{i}: #{circ.nextPoint()}" 7 | 8 | try 9 | show "Instantiating a new Point:" 10 | p = new cp.Point 0, 0 11 | show "Created a Point" 12 | catch e then show e.message 13 | 14 | show "CircularPosition namespace:" 15 | show cp 16 | -------------------------------------------------------------------------------- /src-no-solutions/10-CircularTest.coffee: -------------------------------------------------------------------------------- 1 | cp = require "./10-Circular" 2 | show = console.log 3 | 4 | circ = new cp.CircularPosition 0.01 5 | for i in [0...6] 6 | show "#{i}: #{circ.nextPoint()}" 7 | 8 | try 9 | show "Instantiating a new Point:" 10 | p = new cp.Point 0, 0 11 | show "Created a Point" 12 | catch e then show e.message 13 | 14 | show "CircularPosition namespace:" 15 | show cp 16 | -------------------------------------------------------------------------------- /src/A3-Microbench.coffee: -------------------------------------------------------------------------------- 1 | # CoffeeScript 2 | show = console.log 3 | 4 | start = new Date() 5 | N = 1000000 6 | a = Array(N) 7 | for i in [0...N] 8 | a[i] = Math.random() 9 | 10 | s = 0 11 | for v in a 12 | s += v 13 | 14 | t = 0 15 | for v in a 16 | t += v*v 17 | t = Math.sqrt t 18 | 19 | duration = new Date() - start 20 | show "N: #{N} in #{duration*0.001} s" 21 | show "Result: #{s} and #{t}" 22 | -------------------------------------------------------------------------------- /src/A3-Microtest.py: -------------------------------------------------------------------------------- 1 | # CPython 2 | import time 3 | import random 4 | import math 5 | 6 | start = time.clock() 7 | N = 1000000 8 | a = [random.random() 9 | for i in range(N)] 10 | 11 | s = 0 12 | for v in a: 13 | s += v 14 | 15 | t = 0 16 | for v in a: 17 | t += v*v 18 | t = math.sqrt(t) 19 | 20 | duration = time.clock() - start 21 | print 'N:', N, 'in', duration, 's' 22 | print 'Result:', s, 'and', t 23 | -------------------------------------------------------------------------------- /src-no-solutions/A3-Microbench.coffee: -------------------------------------------------------------------------------- 1 | # CoffeeScript 2 | show = console.log 3 | 4 | start = new Date() 5 | N = 1000000 6 | a = Array(N) 7 | for i in [0...N] 8 | a[i] = Math.random() 9 | 10 | s = 0 11 | for v in a 12 | s += v 13 | 14 | t = 0 15 | for v in a 16 | t += v*v 17 | t = Math.sqrt t 18 | 19 | duration = new Date() - start 20 | show "N: #{N} in #{duration*0.001} s" 21 | show "Result: #{s} and #{t}" 22 | -------------------------------------------------------------------------------- /src-no-solutions/A3-Microtest.py: -------------------------------------------------------------------------------- 1 | # CPython 2 | import time 3 | import random 4 | import math 5 | 6 | start = time.clock() 7 | N = 1000000 8 | a = [random.random() 9 | for i in range(N)] 10 | 11 | s = 0 12 | for v in a: 13 | s += v 14 | 15 | t = 0 16 | for v in a: 17 | t += v*v 18 | t = math.sqrt(t) 19 | 20 | duration = time.clock() - start 21 | print 'N:', N, 'in', duration, 's' 22 | print 'Result:', s, 'and', t 23 | -------------------------------------------------------------------------------- /src/01-Introduction.coffee: -------------------------------------------------------------------------------- 1 | require './prelude' 2 | 3 | # Summation using a while loop 4 | show '--- Summation using a while loop ---' 5 | total = 0 6 | count = 1 7 | while count <= 10 8 | total += count 9 | count += 1 10 | show total 11 | 12 | 13 | # Summation using a for loop 14 | show '--- Summation using a for loop ---' 15 | total = 0 16 | total += count for count in [1..10] 17 | show total 18 | 19 | 20 | # Summation using a reduce function 21 | show '--- Summation using a reduce function ---' 22 | sum = (v) -> _.reduce v, ((a,b) -> a+b), 0 23 | show sum [1..10] 24 | 25 | 26 | # Summation using reduce attached to Array 27 | show '--- Summation using reduce attached to Array ---' 28 | Array::sum ?= -> @reduce ((a,b) -> a+b), 0 29 | show [1..10].sum() 30 | 31 | -------------------------------------------------------------------------------- /src-no-solutions/01-Introduction.coffee: -------------------------------------------------------------------------------- 1 | require './prelude' 2 | 3 | # Summation using a while loop 4 | show '--- Summation using a while loop ---' 5 | total = 0 6 | count = 1 7 | while count <= 10 8 | total += count 9 | count += 1 10 | show total 11 | 12 | 13 | # Summation using a for loop 14 | show '--- Summation using a for loop ---' 15 | total = 0 16 | total += count for count in [1..10] 17 | show total 18 | 19 | 20 | # Summation using a reduce function 21 | show '--- Summation using a reduce function ---' 22 | sum = (v) -> _.reduce v, ((a,b) -> a+b), 0 23 | show sum [1..10] 24 | 25 | 26 | # Summation using reduce attached to Array 27 | show '--- Summation using reduce attached to Array ---' 28 | Array::sum ?= -> @reduce ((a,b) -> a+b), 0 29 | show [1..10].sum() 30 | 31 | -------------------------------------------------------------------------------- /src/06-Quote.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 |10 |17 |The connection between the language in which we 11 | think/program and the problems and solutions we can 12 | imagine is very close. For this reason restricting 13 | language features with the intent of eliminating 14 | programmer errors is at best dangerous.
15 |-- Bjarne Stroustrup
16 |
Mr. Stroustrup is the inventor of the C++ 18 | programming language, but quite an insightful 19 | person nevertheless.
20 |Also, here is a picture of an ostrich:
21 |
22 |
23 |
--------------------------------------------------------------------------------
/src-no-solutions/06-Quote.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 10 |17 |The connection between the language in which we 11 | think/program and the problems and solutions we can 12 | imagine is very close. For this reason restricting 13 | language features with the intent of eliminating 14 | programmer errors is at best dangerous.
15 |-- Bjarne Stroustrup
16 |
Mr. Stroustrup is the inventor of the C++ 18 | programming language, but quite an insightful 19 | person nevertheless.
20 |Also, here is a picture of an ostrich:
21 |
22 |
23 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | **Smooth CoffeeScript** is a free book about CoffeeScript and programming. No previous programming knowledge is required. Over 200 pages and 35 exercises. Download includes book and full source code with and without solutions. The samples require a functioning installation of CoffeeScript; see page 9 in the book. Tested on Mac OS X 10.6.7 and on Windows 7.
4 |
5 | More information:
6 | [Book webpage](http://autotelicum.github.com/Smooth-CoffeeScript/).
7 | [Online preview](http://issuu.com/autotelicum/docs/smooth_coffeescript).
8 |
9 | This work is licensed under a [Creative Commons Attribution 3.0 Unported License](http://creativecommons.org/licenses/by/3.0/).
10 |
11 | Created by E. Hoigaard based on [Eloquent JavaScript by Marijn Haverbeke](http://eloquentjavascript.net/).
12 |
--------------------------------------------------------------------------------
/src/10-Circular.coffee:
--------------------------------------------------------------------------------
1 |
2 | Pi2 = Math.PI*2
3 | # Create an array with angles on the unit circle.
4 | angles = (angle for angle in [0...Pi2] by 1/3*Math.PI)
5 | # Remove the last element if 2*PI were included
6 | # due to floating point rounding on additions.
7 | epsilon = 1e-14
8 | lastAngle = angles[angles.length - 1]
9 | # Use an interval to test floating point value
10 | if Pi2 - epsilon < lastAngle < Pi2 + epsilon
11 | angles.length = angles.length - 1
12 |
13 | # Encapsulation of a pair of (x, y) coordinates
14 | class Point
15 | constructor: (@x, @y) ->
16 | toString: -> "{x:#{@x.toPrecision 4}," +
17 | " y:#{@y.toPrecision 4}}"
18 |
19 | # Math class that returns points on the unit
20 | # circle, offset by step if given non-zero.
21 | class CircularPosition
22 | constructor: (@_step = 0) -> @_count = 0
23 | nextPoint: ->
24 | index = @_count % angles.length
25 | angle = angles[index] + @_step * @_count++
26 | new Point Math.cos(angle), Math.sin(angle)
27 |
28 | (exports ? this).CircularPosition = CircularPosition
29 |
--------------------------------------------------------------------------------
/src-no-solutions/10-Circular.coffee:
--------------------------------------------------------------------------------
1 |
2 | Pi2 = Math.PI*2
3 | # Create an array with angles on the unit circle.
4 | angles = (angle for angle in [0...Pi2] by 1/3*Math.PI)
5 | # Remove the last element if 2*PI were included
6 | # due to floating point rounding on additions.
7 | epsilon = 1e-14
8 | lastAngle = angles[angles.length - 1]
9 | # Use an interval to test floating point value
10 | if Pi2 - epsilon < lastAngle < Pi2 + epsilon
11 | angles.length = angles.length - 1
12 |
13 | # Encapsulation of a pair of (x, y) coordinates
14 | class Point
15 | constructor: (@x, @y) ->
16 | toString: -> "{x:#{@x.toPrecision 4}," +
17 | " y:#{@y.toPrecision 4}}"
18 |
19 | # Math class that returns points on the unit
20 | # circle, offset by step if given non-zero.
21 | class CircularPosition
22 | constructor: (@_step = 0) -> @_count = 0
23 | nextPoint: ->
24 | index = @_count % angles.length
25 | angle = angles[index] + @_step * @_count++
26 | new Point Math.cos(angle), Math.sin(angle)
27 |
28 | (exports ? this).CircularPosition = CircularPosition
29 |
--------------------------------------------------------------------------------
/src/10-MathFix.coffee:
--------------------------------------------------------------------------------
1 | require "./prelude"
2 |
3 | Pi2 = Math.PI*2
4 | # Create an array with angles on the unit circle.
5 | angles = (angle for angle in [0...Pi2] by 1/3*Math.PI)
6 | # Remove the last element if 2*PI were included
7 | # due to floating point rounding on additions.
8 | epsilon = 1e-14
9 | lastAngle = angles[angles.length - 1]
10 | # Use an interval to test floating point value
11 | if Pi2 - epsilon < lastAngle < Pi2 + epsilon
12 | angles.length = angles.length - 1
13 |
14 | # Encapsulation of a pair of (x, y) coordinates
15 | class Point
16 | constructor: (@x, @y) ->
17 | toString: -> "{x:#{@x.toPrecision 4}," +
18 | " y:#{@y.toPrecision 4}}"
19 |
20 | # Magical class that returns points on the unit
21 | # circle, offset by step if given non-zero.
22 | class CircularPosition
23 | constructor: (@_step = 0) -> @_count = 0
24 | nextPoint: ->
25 | index = @_count % angles.length
26 | angle = angles[index] + @_step * @_count++
27 | new Point Math.cos(angle), Math.sin(angle)
28 |
29 | circ = new CircularPosition 0.01
30 | for i in [0...6]
31 | show "#{i}: #{circ.nextPoint()}"
--------------------------------------------------------------------------------
/src-no-solutions/10-MathFix.coffee:
--------------------------------------------------------------------------------
1 | require "./prelude"
2 |
3 | Pi2 = Math.PI*2
4 | # Create an array with angles on the unit circle.
5 | angles = (angle for angle in [0...Pi2] by 1/3*Math.PI)
6 | # Remove the last element if 2*PI were included
7 | # due to floating point rounding on additions.
8 | epsilon = 1e-14
9 | lastAngle = angles[angles.length - 1]
10 | # Use an interval to test floating point value
11 | if Pi2 - epsilon < lastAngle < Pi2 + epsilon
12 | angles.length = angles.length - 1
13 |
14 | # Encapsulation of a pair of (x, y) coordinates
15 | class Point
16 | constructor: (@x, @y) ->
17 | toString: -> "{x:#{@x.toPrecision 4}," +
18 | " y:#{@y.toPrecision 4}}"
19 |
20 | # Magical class that returns points on the unit
21 | # circle, offset by step if given non-zero.
22 | class CircularPosition
23 | constructor: (@_step = 0) -> @_count = 0
24 | nextPoint: ->
25 | index = @_count % angles.length
26 | angle = angles[index] + @_step * @_count++
27 | new Point Math.cos(angle), Math.sin(angle)
28 |
29 | circ = new CircularPosition 0.01
30 | for i in [0...6]
31 | show "#{i}: #{circ.nextPoint()}"
--------------------------------------------------------------------------------
/src/node_modules/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2011 Jeremy Ashkenas
2 |
3 | Permission is hereby granted, free of charge, to any person
4 | obtaining a copy of this software and associated documentation
5 | files (the "Software"), to deal in the Software without
6 | restriction, including without limitation the rights to use,
7 | copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the
9 | Software is furnished to do so, subject to the following
10 | conditions:
11 |
12 | The above copyright notice and this permission notice shall be
13 | included in all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 | OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/src-no-solutions/node_modules/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2011 Jeremy Ashkenas
2 |
3 | Permission is hereby granted, free of charge, to any person
4 | obtaining a copy of this software and associated documentation
5 | files (the "Software"), to deal in the Software without
6 | restriction, including without limitation the rights to use,
7 | copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the
9 | Software is furnished to do so, subject to the following
10 | conditions:
11 |
12 | The above copyright notice and this permission notice shall be
13 | included in all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 | OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/src/prelude/coffeekup-LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2010 Maurice Machado \"."
175 | show '--- End of Exercise ---'
176 |
177 | # Word filter
178 | show '--- Word filter ---'
179 | badWords = ['ape', 'monkey', 'simian',
180 | 'gorilla', 'evolution']
181 | pattern = new RegExp badWords.join('|'), 'i'
182 | isAcceptable = (text) ->
183 | !pattern.test text
184 |
185 | show isAcceptable 'Mmmm, grapes.'
186 | show isAcceptable 'No more of that monkeybusiness, now.'
187 |
188 | # Escape escapes
189 | show '--- Escape escapes ---'
190 | digits = new RegExp '\\d+'
191 | show digits.test '101'
192 |
193 |
--------------------------------------------------------------------------------
/src/docs/10-CircularTest.html:
--------------------------------------------------------------------------------
1 | 10-CircularTest.coffee Jump To … 00-Foreword.coffee 01-Introduction.coffee 02-BasicCoffeeScript.coffee 03-Functions.coffee 04-DataStructures.coffee 04-emails.coffee 05-ErrorHandling.coffee 06-FunctionalProgramming.coffee 07-Searching.coffee 08-ObjectOrientation.coffee 09-RegularExpressions.coffee 10-Circular.coffee 10-CircularTest.coffee 10-MathFix.coffee 10-Modularity.coffee 10-SeedLife.coffee 10-TestWebSockets.coffee 10-WebSocketLife.coffee A1-LanguageExtras.coffee A2-BinaryHeap.coffee A2-BinaryHeapTest.coffee A3-Microbench.coffee A3-Microtest.py A3-Queen.coffee A3-Queens.py A4-NoSolutions.coffee coffeekup.coffee prelude.coffee underscore.coffee ws.coffee 10-CircularTest.coffee
cp = require "./10-Circular"
2 | show = console.log
3 |
4 | circ = new cp.CircularPosition 0.01
5 | for i in [0...6]
6 | show "#{i}: #{circ.nextPoint()}"
7 |
8 | try
9 | show "Instantiating a new Point:"
10 | p = new cp.Point 0, 0
11 | show "Created a Point"
12 | catch e then show e.message
13 |
14 | show "CircularPosition namespace:"
15 | show cp
16 |
17 |
--------------------------------------------------------------------------------
/src-no-solutions/docs/10-CircularTest.html:
--------------------------------------------------------------------------------
1 | 10-CircularTest.coffee Jump To … 00-Foreword.coffee 01-Introduction.coffee 02-BasicCoffeeScript.coffee 03-Functions.coffee 04-DataStructures.coffee 04-emails.coffee 05-ErrorHandling.coffee 06-FunctionalProgramming.coffee 07-Searching.coffee 08-ObjectOrientation.coffee 09-RegularExpressions.coffee 10-Circular.coffee 10-CircularTest.coffee 10-MathFix.coffee 10-Modularity.coffee 10-SeedLife.coffee 10-TestWebSockets.coffee 10-WebSocketLife.coffee A1-LanguageExtras.coffee A2-BinaryHeap.coffee A2-BinaryHeapTest.coffee A3-Microbench.coffee A3-Microtest.py A3-Queen.coffee A3-Queens.py A4-NoSolutions.coffee coffeekup.coffee prelude.coffee underscore.coffee ws.coffee 10-CircularTest.coffee
cp = require "./10-Circular"
2 | show = console.log
3 |
4 | circ = new cp.CircularPosition 0.01
5 | for i in [0...6]
6 | show "#{i}: #{circ.nextPoint()}"
7 |
8 | try
9 | show "Instantiating a new Point:"
10 | p = new cp.Point 0, 0
11 | show "Created a Point"
12 | catch e then show e.message
13 |
14 | show "CircularPosition namespace:"
15 | show cp
16 |
17 |
--------------------------------------------------------------------------------
/src-no-solutions/03-Functions.coffee:
--------------------------------------------------------------------------------
1 | require './prelude'
2 |
3 | # Pure functions
4 | show '--- Pure functions ---'
5 | add = (a, b) -> a + b
6 | show add 2, 2
7 |
8 | power = (base, exponent) ->
9 | result = 1
10 | for count in [0...exponent]
11 | result *= base
12 | result
13 | show power 2, 10
14 |
15 | # Exercise 7
16 | show '--- Exercise 7 ---'
17 | process.exit() # Replace this line with your solution
18 | show '--- End of Exercise ---'
19 |
20 | # Declarative tests
21 | show '--- Declarative tests ---'
22 | testAbsolute = (name, property) ->
23 | qc.testPure absolute, [qc.arbInt], name, property
24 |
25 | testAbsolute 'returns positive integers',
26 | (c, arg, result) -> result >= 0
27 |
28 | testAbsolute 'positive returns positive',
29 | (c, arg, result) -> c.guard arg >= 0; result is arg
30 |
31 | testAbsolute 'negative returns positive',
32 | (c, arg, result) -> c.guard arg < 0; result is -arg
33 |
34 | qc.testPure power, [qc.arbInt, qc.arbInt],
35 | 'power == Math.pow for integers',
36 | (c, base, exponent, result) ->
37 | result == c.note Math.pow base, exponent
38 |
39 | qc.testPure power, [qc.arbWholeNum, qc.arbWholeNum],
40 | 'power == Math.pow for positive integers',
41 | (c, base, exponent, result) ->
42 | result == c.note Math.pow base, exponent
43 |
44 | qc.test()
45 |
46 | # Quick hack to avoid garbling of output
47 | # when async test cases are reported.
48 | # A better idea is one test suite in one file.
49 | setTimeout ( ->
50 |
51 | # Exercise 8
52 |
53 | intensify = (n) ->
54 | 2 # This will fail
55 |
56 | show '--- Exercise 8 ---'
57 | process.exit() # Replace this line with your solution
58 | show '--- End of Exercise ---'
59 |
60 | qc.testPure intensify, [qc.arbInt],
61 | 'intensify grows by 2 when positive',
62 | (c, arg, result) ->
63 | c.guard arg > 0
64 | arg + 2 == result
65 |
66 | qc.testPure intensify, [qc.arbInt],
67 | 'intensify grows by 2 when negative',
68 | (c, arg, result) ->
69 | c.guard arg < 0
70 | arg - 2 == result
71 |
72 | qc.testPure intensify, [qc.arbConst(0)],
73 | 'only non-zero intensify grows',
74 | (c, arg, result) ->
75 | result is arg
76 |
77 | qc.test()
78 |
79 | setTimeout ( ->
80 |
81 | # Return revisited
82 | show '--- Return revisited ---'
83 | yell = (message) ->
84 | show message + '!!'
85 | return
86 | yell 'Yow'
87 |
88 | # Local scopes
89 | show '--- Local scopes ---'
90 | dino = 'I am alive'
91 | reptile = 'I am A-OK'
92 | meteor = (reptile) ->
93 | show reptile # Argument
94 | dino = 'I am extinct'
95 | reptile = 'I survived'
96 | possum = 'I am new'
97 | show dino # Outer
98 | meteor 'What happened?'
99 | show dino # Outer changed
100 | show reptile # Outer unchanged
101 | try show possum catch e
102 | show e.message # Error undefined
103 |
104 | # Local environment
105 | show '--- Local environment ---'
106 | variable = 'first' # Definition
107 |
108 | showVariable = ->
109 | show 'In showVariable, the variable holds: ' +
110 | variable # second
111 |
112 | test = ->
113 | variable = 'second' # Assignment
114 | show 'In test, the variable holds ' +
115 | variable + '.' # second
116 | showVariable()
117 |
118 | show 'The variable is: ' + variable # first
119 | test()
120 | show 'The variable is: ' + variable # second
121 |
122 | # Siblings and children
123 | show '--- Siblings and children ---'
124 | andHere = ->
125 | try show aLocal # Not defined
126 | catch e then show e.message
127 | isHere = ->
128 | aLocal = 'aLocal is defined'
129 | andHere()
130 | isHere()
131 |
132 | isHere = ->
133 | andHere = ->
134 | try show aLocal # Is defined
135 | catch e then show e.message
136 | aLocal = 'aLocal is defined'
137 | andHere()
138 | isHere()
139 |
140 | # Internal function variable
141 | show '--- Internal function variable ---'
142 | varWhich = 'top-level'
143 | parentFunction = ->
144 | varWhich = 'local'
145 | childFunction = ->
146 | show varWhich
147 | childFunction
148 | child = parentFunction()
149 | child()
150 |
151 | # Synthesized function
152 | show '--- Synthesized function ---'
153 | makeAddFunction = (amount) ->
154 | add = (number) -> number + amount
155 |
156 | addTwo = makeAddFunction 2
157 | addFive = makeAddFunction 5
158 | show addTwo(1) + addFive(1)
159 |
160 | # Recursion
161 | show '--- Recursion ---'
162 | powerRec = (base, exponent) ->
163 | if exponent == 0
164 | 1
165 | else
166 | base * powerRec base, exponent - 1
167 | show 'power 3, 3 = ' + powerRec 3, 3
168 |
169 | # Timing
170 | show '--- Timing ---'
171 | timeIt = (func) ->
172 | start = new Date()
173 | for i in [0...1000000] then func()
174 | show "Timing: #{(new Date() - start)*0.001}s"
175 |
176 | timeIt -> p = add 9,18 # 0.042s
177 | timeIt -> p = Math.pow 9,18 # 0.049s
178 | timeIt -> p = power 9,18 # 0.464s
179 | timeIt -> p = powerRec 9,18 # 0.544s
180 |
181 | # Indirect recursion
182 | show '--- Indirect recursion ---'
183 | chicken = ->
184 | show 'Lay an egg'
185 | egg()
186 | egg = ->
187 | show 'Chick hatched'
188 | chicken()
189 | try show chicken() + ' came first.'
190 | catch error then show error.message
191 |
192 | # Recursive puzzle solving
193 | show '--- Recursive puzzle solving ---'
194 | findSequence = (goal) ->
195 | find = (start, history) ->
196 | if start == goal
197 | history
198 | else if start > goal
199 | null
200 | else
201 | find(start + 5, '(' + history + ' + 5)') ? \
202 | find(start * 3, '(' + history + ' * 3)')
203 | find 1, '1'
204 | show findSequence 24
205 |
206 | # Anonymous functions
207 | show '--- Anonymous functions ---'
208 | makeAddFunction = (amount) ->
209 | (number) -> number + amount
210 | show makeAddFunction(11) 3
211 |
212 | # Exercise 9
213 | show '--- Exercise 9 ---'
214 | process.exit() # Replace this line with your solution
215 | show '--- End of Exercise ---'
216 |
217 | # Extra function arguments
218 | show '--- Extra function arguments ---'
219 | yell 'Hello', 'Good Evening', 'How do you do?'
220 | yell()
221 |
222 | # Variable number of arguments
223 | show '--- Variable number of arguments ---'
224 | console.log 'R', 2, 'D', 2
225 |
226 | ),300
227 | ),300
228 |
229 |
230 |
231 |
232 |
233 |
--------------------------------------------------------------------------------
/src/prelude/coffeekup.coffee:
--------------------------------------------------------------------------------
1 | if window?
2 | coffeekup = window.CoffeeKup = {}
3 | coffee = if CoffeeScript? then CoffeeScript else null
4 | else
5 | coffeekup = exports
6 | coffee = require 'coffee-script'
7 |
8 | coffeekup.version = '0.2.3'
9 |
10 | skeleton = (ck_options = {}) ->
11 | ck_options.context ?= {}
12 | ck_options.locals ?= {}
13 | ck_options.format ?= off
14 | ck_options.autoescape ?= off
15 | ck_buffer = []
16 |
17 | ck_render_attrs = (obj) ->
18 | str = ''
19 | for k, v of obj
20 | str += " #{k}=\"#{ck_esc(v)}\""
21 | str
22 |
23 | ck_doctypes =
24 | '5': ''
25 | 'xml': ''
26 | 'default': ''
27 | 'transitional': ''
28 | 'strict': ''
29 | 'frameset': ''
30 | '1.1': '',
31 | 'basic': ''
32 | 'mobile': ''
33 |
34 | ck_self_closing = ['area', 'base', 'basefont', 'br', 'col', 'frame', 'hr', 'img', 'input', 'link', 'meta', 'param']
35 |
36 | ck_esc = (txt) ->
37 | if ck_options.autoescape then h(txt) else String(txt)
38 |
39 | ck_tabs = 0
40 |
41 | ck_repeat = (string, count) -> Array(count + 1).join string
42 |
43 | ck_indent = -> text ck_repeat(' ', ck_tabs) if ck_options.format
44 |
45 | h = (txt) ->
46 | String(txt).replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"')
47 |
48 | doctype = (type = 5) ->
49 | text ck_doctypes[type]
50 | text '\n' if ck_options.format
51 |
52 | text = (txt) ->
53 | ck_buffer.push String(txt)
54 | null
55 |
56 | comment = (cmt) ->
57 | text ""
58 | text '\n' if ck_options.format
59 |
60 | tag = -> name = arguments[0]; delete arguments[0]; ck_tag(name, arguments)
61 |
62 | ck_tag = (name, opts) ->
63 | ck_indent()
64 | text "<#{name}"
65 |
66 | for o in opts
67 | text ck_render_attrs(o) if typeof o is 'object'
68 |
69 | if name in ck_self_closing
70 | text ' />'
71 | text '\n' if ck_options.format
72 | else
73 | text '>'
74 |
75 | for o in opts
76 | switch typeof o
77 | when 'string', 'number'
78 | text ck_esc(o)
79 | when 'function'
80 | text '\n' if ck_options.format
81 | ck_tabs++
82 | result = o.call ck_options.context
83 | if typeof result is 'string'
84 | ck_indent()
85 | text ck_esc(result)
86 | text '\n' if ck_options.format
87 | ck_tabs--
88 | ck_indent()
89 | text "#{name}>"
90 | text '\n' if ck_options.format
91 |
92 | null
93 |
94 | coffeescript = (code) ->
95 | script ";(#{code})();"
96 |
97 | null
98 |
99 | support = '''
100 | var __slice = Array.prototype.slice;
101 | var __hasProp = Object.prototype.hasOwnProperty;
102 | var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
103 | var __extends = function(child, parent) {
104 | for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; }
105 | function ctor() { this.constructor = child; }
106 | ctor.prototype = parent.prototype; child.prototype = new ctor; child.__super__ = parent.prototype;
107 | return child;
108 | };
109 | var __indexOf = Array.prototype.indexOf || function(item) {
110 | for (var i = 0, l = this.length; i < l; i++) {
111 | if (this[i] === item) return i;
112 | }
113 | return -1;
114 | };
115 | '''
116 |
117 | skeleton = String(skeleton).replace(/function\s*\(ck_options\)\s*\{/, '').replace /return null;\s*\}$/, ''
118 | skeleton = support + skeleton
119 |
120 | tags = 'a|abbr|acronym|address|applet|area|article|aside|audio|b|base|basefont|bdo|big|blockquote|body|br|button|canvas|caption|center|cite|code|col|colgroup|command|datalist|dd|del|details|dfn|dir|div|dl|dt|em|embed|fieldset|figcaption|figure|font|footer|form|frame|frameset|h1|h2|h3|h4|h5|h6|head|header|hgroup|hr|html|i|iframe|img|input|ins|keygen|kbd|label|legend|li|link|map|mark|menu|meta|meter|nav|noframes|noscript|object|ol|optgroup|option|output|p|param|pre|progress|q|rp|rt|ruby|s|samp|script|section|select|small|source|span|strike|strong|style|sub|summary|sup|table|tbody|td|textarea|tfoot|th|thead|time|title|tr|tt|u|ul|video|xmp'.split '|'
121 |
122 | coffeekup.compile = (template, options = {}) ->
123 | options.locals ?= {}
124 |
125 | # Shim for express.
126 | if options.locals.body?
127 | options.context.body = options.locals.body
128 | delete options.locals.body
129 |
130 | if options.body?
131 | options.context.body = options.body
132 | delete options.body
133 |
134 |
135 | if typeof template is 'function' then template = String(template)
136 | else if typeof template is 'string' and coffee?
137 | template = coffee.compile template, bare: yes
138 | template = "function(){#{template}}"
139 |
140 | tags_here = []
141 | for t in tags
142 | if template.indexOf(t) > -1
143 | tags_here.push t
144 |
145 | code = skeleton + "var #{tags_here.join ','};"
146 | for t in tags_here
147 | code += "#{t} = function(){return ck_tag('#{t}', arguments)};"
148 |
149 | for k, v of options.locals
150 | if typeof v is 'function' then code += "var #{k} = #{v};"
151 | else code += "var #{k} = #{JSON.stringify v};"
152 |
153 | code += 'with(ck_options.locals){' if options.dynamic_locals
154 | code += "(#{template}).call(ck_options.context);"
155 | code += '}' if options.dynamic_locals
156 | code += "return ck_buffer.join('');"
157 |
158 | new Function('ck_options', code)
159 |
160 | cache = {}
161 | coffeekup.render = (template, options = {}) ->
162 | options.context ?= {}
163 | options.locals ?= {}
164 | options.cache ?= on
165 |
166 |
167 | if options.cache and cache[template]? then tpl = cache[template]
168 | else if options.cache then tpl = cache[template] = coffeekup.compile(template, options)
169 | else tpl = coffeekup.compile(template, options)
170 | tpl(options)
171 |
172 | unless window?
173 | coffeekup.adapters =
174 | simple: (template, data) -> coffeekup.render template, context: data
175 | coffeekup.adapters.meryl = coffeekup.adapters.simple
176 |
--------------------------------------------------------------------------------
/src-no-solutions/prelude/coffeekup.coffee:
--------------------------------------------------------------------------------
1 | if window?
2 | coffeekup = window.CoffeeKup = {}
3 | coffee = if CoffeeScript? then CoffeeScript else null
4 | else
5 | coffeekup = exports
6 | coffee = require 'coffee-script'
7 |
8 | coffeekup.version = '0.2.3'
9 |
10 | skeleton = (ck_options = {}) ->
11 | ck_options.context ?= {}
12 | ck_options.locals ?= {}
13 | ck_options.format ?= off
14 | ck_options.autoescape ?= off
15 | ck_buffer = []
16 |
17 | ck_render_attrs = (obj) ->
18 | str = ''
19 | for k, v of obj
20 | str += " #{k}=\"#{ck_esc(v)}\""
21 | str
22 |
23 | ck_doctypes =
24 | '5': ''
25 | 'xml': ''
26 | 'default': ''
27 | 'transitional': ''
28 | 'strict': ''
29 | 'frameset': ''
30 | '1.1': '',
31 | 'basic': ''
32 | 'mobile': ''
33 |
34 | ck_self_closing = ['area', 'base', 'basefont', 'br', 'col', 'frame', 'hr', 'img', 'input', 'link', 'meta', 'param']
35 |
36 | ck_esc = (txt) ->
37 | if ck_options.autoescape then h(txt) else String(txt)
38 |
39 | ck_tabs = 0
40 |
41 | ck_repeat = (string, count) -> Array(count + 1).join string
42 |
43 | ck_indent = -> text ck_repeat(' ', ck_tabs) if ck_options.format
44 |
45 | h = (txt) ->
46 | String(txt).replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"')
47 |
48 | doctype = (type = 5) ->
49 | text ck_doctypes[type]
50 | text '\n' if ck_options.format
51 |
52 | text = (txt) ->
53 | ck_buffer.push String(txt)
54 | null
55 |
56 | comment = (cmt) ->
57 | text ""
58 | text '\n' if ck_options.format
59 |
60 | tag = -> name = arguments[0]; delete arguments[0]; ck_tag(name, arguments)
61 |
62 | ck_tag = (name, opts) ->
63 | ck_indent()
64 | text "<#{name}"
65 |
66 | for o in opts
67 | text ck_render_attrs(o) if typeof o is 'object'
68 |
69 | if name in ck_self_closing
70 | text ' />'
71 | text '\n' if ck_options.format
72 | else
73 | text '>'
74 |
75 | for o in opts
76 | switch typeof o
77 | when 'string', 'number'
78 | text ck_esc(o)
79 | when 'function'
80 | text '\n' if ck_options.format
81 | ck_tabs++
82 | result = o.call ck_options.context
83 | if typeof result is 'string'
84 | ck_indent()
85 | text ck_esc(result)
86 | text '\n' if ck_options.format
87 | ck_tabs--
88 | ck_indent()
89 | text "#{name}>"
90 | text '\n' if ck_options.format
91 |
92 | null
93 |
94 | coffeescript = (code) ->
95 | script ";(#{code})();"
96 |
97 | null
98 |
99 | support = '''
100 | var __slice = Array.prototype.slice;
101 | var __hasProp = Object.prototype.hasOwnProperty;
102 | var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
103 | var __extends = function(child, parent) {
104 | for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; }
105 | function ctor() { this.constructor = child; }
106 | ctor.prototype = parent.prototype; child.prototype = new ctor; child.__super__ = parent.prototype;
107 | return child;
108 | };
109 | var __indexOf = Array.prototype.indexOf || function(item) {
110 | for (var i = 0, l = this.length; i < l; i++) {
111 | if (this[i] === item) return i;
112 | }
113 | return -1;
114 | };
115 | '''
116 |
117 | skeleton = String(skeleton).replace(/function\s*\(ck_options\)\s*\{/, '').replace /return null;\s*\}$/, ''
118 | skeleton = support + skeleton
119 |
120 | tags = 'a|abbr|acronym|address|applet|area|article|aside|audio|b|base|basefont|bdo|big|blockquote|body|br|button|canvas|caption|center|cite|code|col|colgroup|command|datalist|dd|del|details|dfn|dir|div|dl|dt|em|embed|fieldset|figcaption|figure|font|footer|form|frame|frameset|h1|h2|h3|h4|h5|h6|head|header|hgroup|hr|html|i|iframe|img|input|ins|keygen|kbd|label|legend|li|link|map|mark|menu|meta|meter|nav|noframes|noscript|object|ol|optgroup|option|output|p|param|pre|progress|q|rp|rt|ruby|s|samp|script|section|select|small|source|span|strike|strong|style|sub|summary|sup|table|tbody|td|textarea|tfoot|th|thead|time|title|tr|tt|u|ul|video|xmp'.split '|'
121 |
122 | coffeekup.compile = (template, options = {}) ->
123 | options.locals ?= {}
124 |
125 | # Shim for express.
126 | if options.locals.body?
127 | options.context.body = options.locals.body
128 | delete options.locals.body
129 |
130 | if options.body?
131 | options.context.body = options.body
132 | delete options.body
133 |
134 |
135 | if typeof template is 'function' then template = String(template)
136 | else if typeof template is 'string' and coffee?
137 | template = coffee.compile template, bare: yes
138 | template = "function(){#{template}}"
139 |
140 | tags_here = []
141 | for t in tags
142 | if template.indexOf(t) > -1
143 | tags_here.push t
144 |
145 | code = skeleton + "var #{tags_here.join ','};"
146 | for t in tags_here
147 | code += "#{t} = function(){return ck_tag('#{t}', arguments)};"
148 |
149 | for k, v of options.locals
150 | if typeof v is 'function' then code += "var #{k} = #{v};"
151 | else code += "var #{k} = #{JSON.stringify v};"
152 |
153 | code += 'with(ck_options.locals){' if options.dynamic_locals
154 | code += "(#{template}).call(ck_options.context);"
155 | code += '}' if options.dynamic_locals
156 | code += "return ck_buffer.join('');"
157 |
158 | new Function('ck_options', code)
159 |
160 | cache = {}
161 | coffeekup.render = (template, options = {}) ->
162 | options.context ?= {}
163 | options.locals ?= {}
164 | options.cache ?= on
165 |
166 |
167 | if options.cache and cache[template]? then tpl = cache[template]
168 | else if options.cache then tpl = cache[template] = coffeekup.compile(template, options)
169 | else tpl = coffeekup.compile(template, options)
170 | tpl(options)
171 |
172 | unless window?
173 | coffeekup.adapters =
174 | simple: (template, data) -> coffeekup.render template, context: data
175 | coffeekup.adapters.meryl = coffeekup.adapters.simple
176 |
--------------------------------------------------------------------------------
/src/03-Functions.coffee:
--------------------------------------------------------------------------------
1 | require './prelude'
2 |
3 | # Pure functions
4 | show '--- Pure functions ---'
5 | add = (a, b) -> a + b
6 | show add 2, 2
7 |
8 | power = (base, exponent) ->
9 | result = 1
10 | for count in [0...exponent]
11 | result *= base
12 | result
13 | show power 2, 10
14 |
15 | # Exercise 7
16 | show '--- Exercise 7 ---'
17 | absolute = (number) ->
18 | if number < 0
19 | -number
20 | else
21 | number
22 | show absolute -144
23 | show '--- End of Exercise ---'
24 |
25 | # Declarative tests
26 | show '--- Declarative tests ---'
27 | testAbsolute = (name, property) ->
28 | qc.testPure absolute, [qc.arbInt], name, property
29 |
30 | testAbsolute 'returns positive integers',
31 | (c, arg, result) -> result >= 0
32 |
33 | testAbsolute 'positive returns positive',
34 | (c, arg, result) -> c.guard arg >= 0; result is arg
35 |
36 | testAbsolute 'negative returns positive',
37 | (c, arg, result) -> c.guard arg < 0; result is -arg
38 |
39 | qc.testPure power, [qc.arbInt, qc.arbInt],
40 | 'power == Math.pow for integers',
41 | (c, base, exponent, result) ->
42 | result == c.note Math.pow base, exponent
43 |
44 | qc.testPure power, [qc.arbWholeNum, qc.arbWholeNum],
45 | 'power == Math.pow for positive integers',
46 | (c, base, exponent, result) ->
47 | result == c.note Math.pow base, exponent
48 |
49 | qc.test()
50 |
51 | # Quick hack to avoid garbling of output
52 | # when async test cases are reported.
53 | # A better idea is one test suite in one file.
54 | setTimeout ( ->
55 |
56 | # Exercise 8
57 |
58 | intensify = (n) ->
59 | 2 # This will fail
60 |
61 | show '--- Exercise 8 ---'
62 | intensify = (n) ->
63 | if n > 0
64 | n + 2
65 | else if n < 0
66 | n - 2
67 | else
68 | n
69 | show '--- End of Exercise ---'
70 |
71 | qc.testPure intensify, [qc.arbInt],
72 | 'intensify grows by 2 when positive',
73 | (c, arg, result) ->
74 | c.guard arg > 0
75 | arg + 2 == result
76 |
77 | qc.testPure intensify, [qc.arbInt],
78 | 'intensify grows by 2 when negative',
79 | (c, arg, result) ->
80 | c.guard arg < 0
81 | arg - 2 == result
82 |
83 | qc.testPure intensify, [qc.arbConst(0)],
84 | 'only non-zero intensify grows',
85 | (c, arg, result) ->
86 | result is arg
87 |
88 | qc.test()
89 |
90 | setTimeout ( ->
91 |
92 | # Return revisited
93 | show '--- Return revisited ---'
94 | yell = (message) ->
95 | show message + '!!'
96 | return
97 | yell 'Yow'
98 |
99 | # Local scopes
100 | show '--- Local scopes ---'
101 | dino = 'I am alive'
102 | reptile = 'I am A-OK'
103 | meteor = (reptile) ->
104 | show reptile # Argument
105 | dino = 'I am extinct'
106 | reptile = 'I survived'
107 | possum = 'I am new'
108 | show dino # Outer
109 | meteor 'What happened?'
110 | show dino # Outer changed
111 | show reptile # Outer unchanged
112 | try show possum catch e
113 | show e.message # Error undefined
114 |
115 | # Local environment
116 | show '--- Local environment ---'
117 | variable = 'first' # Definition
118 |
119 | showVariable = ->
120 | show 'In showVariable, the variable holds: ' +
121 | variable # second
122 |
123 | test = ->
124 | variable = 'second' # Assignment
125 | show 'In test, the variable holds ' +
126 | variable + '.' # second
127 | showVariable()
128 |
129 | show 'The variable is: ' + variable # first
130 | test()
131 | show 'The variable is: ' + variable # second
132 |
133 | # Siblings and children
134 | show '--- Siblings and children ---'
135 | andHere = ->
136 | try show aLocal # Not defined
137 | catch e then show e.message
138 | isHere = ->
139 | aLocal = 'aLocal is defined'
140 | andHere()
141 | isHere()
142 |
143 | isHere = ->
144 | andHere = ->
145 | try show aLocal # Is defined
146 | catch e then show e.message
147 | aLocal = 'aLocal is defined'
148 | andHere()
149 | isHere()
150 |
151 | # Internal function variable
152 | show '--- Internal function variable ---'
153 | varWhich = 'top-level'
154 | parentFunction = ->
155 | varWhich = 'local'
156 | childFunction = ->
157 | show varWhich
158 | childFunction
159 | child = parentFunction()
160 | child()
161 |
162 | # Synthesized function
163 | show '--- Synthesized function ---'
164 | makeAddFunction = (amount) ->
165 | add = (number) -> number + amount
166 |
167 | addTwo = makeAddFunction 2
168 | addFive = makeAddFunction 5
169 | show addTwo(1) + addFive(1)
170 |
171 | # Recursion
172 | show '--- Recursion ---'
173 | powerRec = (base, exponent) ->
174 | if exponent == 0
175 | 1
176 | else
177 | base * powerRec base, exponent - 1
178 | show 'power 3, 3 = ' + powerRec 3, 3
179 |
180 | # Timing
181 | show '--- Timing ---'
182 | timeIt = (func) ->
183 | start = new Date()
184 | for i in [0...1000000] then func()
185 | show "Timing: #{(new Date() - start)*0.001}s"
186 |
187 | timeIt -> p = add 9,18 # 0.042s
188 | timeIt -> p = Math.pow 9,18 # 0.049s
189 | timeIt -> p = power 9,18 # 0.464s
190 | timeIt -> p = powerRec 9,18 # 0.544s
191 |
192 | # Indirect recursion
193 | show '--- Indirect recursion ---'
194 | chicken = ->
195 | show 'Lay an egg'
196 | egg()
197 | egg = ->
198 | show 'Chick hatched'
199 | chicken()
200 | try show chicken() + ' came first.'
201 | catch error then show error.message
202 |
203 | # Recursive puzzle solving
204 | show '--- Recursive puzzle solving ---'
205 | findSequence = (goal) ->
206 | find = (start, history) ->
207 | if start == goal
208 | history
209 | else if start > goal
210 | null
211 | else
212 | find(start + 5, '(' + history + ' + 5)') ? \
213 | find(start * 3, '(' + history + ' * 3)')
214 | find 1, '1'
215 | show findSequence 24
216 |
217 | # Anonymous functions
218 | show '--- Anonymous functions ---'
219 | makeAddFunction = (amount) ->
220 | (number) -> number + amount
221 | show makeAddFunction(11) 3
222 |
223 | # Exercise 9
224 | show '--- Exercise 9 ---'
225 | greaterThan = (x) ->
226 | (y) -> y > x
227 | greaterThanTen = greaterThan 10
228 | show greaterThanTen 9
229 | show '--- End of Exercise ---'
230 |
231 | # Extra function arguments
232 | show '--- Extra function arguments ---'
233 | yell 'Hello', 'Good Evening', 'How do you do?'
234 | yell()
235 |
236 | # Variable number of arguments
237 | show '--- Variable number of arguments ---'
238 | console.log 'R', 2, 'D', 2
239 |
240 | ),300
241 | ),300
242 |
243 |
244 |
245 |
246 |
247 |
--------------------------------------------------------------------------------
/src/docs/A3-Microbench.html:
--------------------------------------------------------------------------------
1 | A3-Microbench.coffee Jump To … 00-Foreword.coffee 01-Introduction.coffee 02-BasicCoffeeScript.coffee 03-Functions.coffee 04-DataStructures.coffee 04-emails.coffee 05-ErrorHandling.coffee 06-FunctionalProgramming.coffee 07-Searching.coffee 08-ObjectOrientation.coffee 09-RegularExpressions.coffee 10-Circular.coffee 10-CircularTest.coffee 10-MathFix.coffee 10-Modularity.coffee 10-SeedLife.coffee 10-TestWebSockets.coffee 10-WebSocketLife.coffee A1-LanguageExtras.coffee A2-BinaryHeap.coffee A2-BinaryHeapTest.coffee A3-Microbench.coffee A3-Microtest.py A3-Queen.coffee A3-Queens.py A4-NoSolutions.coffee coffeekup.coffee prelude.coffee underscore.coffee ws.coffee A3-Microbench.coffee
CoffeeScript
show = console.log
2 |
3 | start = new Date()
4 | N = 1000000
5 | a = Array(N)
6 | for i in [0...N]
7 | a[i] = Math.random()
8 |
9 | s = 0
10 | for v in a
11 | s += v
12 |
13 | t = 0
14 | for v in a
15 | t += v*v
16 | t = Math.sqrt t
17 |
18 | duration = new Date() - start
19 | show "N: #{N} in #{duration*0.001} s"
20 | show "Result: #{s} and #{t}"
21 |
22 |
--------------------------------------------------------------------------------
/src-no-solutions/docs/A3-Microbench.html:
--------------------------------------------------------------------------------
1 | A3-Microbench.coffee Jump To … 00-Foreword.coffee 01-Introduction.coffee 02-BasicCoffeeScript.coffee 03-Functions.coffee 04-DataStructures.coffee 04-emails.coffee 05-ErrorHandling.coffee 06-FunctionalProgramming.coffee 07-Searching.coffee 08-ObjectOrientation.coffee 09-RegularExpressions.coffee 10-Circular.coffee 10-CircularTest.coffee 10-MathFix.coffee 10-Modularity.coffee 10-SeedLife.coffee 10-TestWebSockets.coffee 10-WebSocketLife.coffee A1-LanguageExtras.coffee A2-BinaryHeap.coffee A2-BinaryHeapTest.coffee A3-Microbench.coffee A3-Microtest.py A3-Queen.coffee A3-Queens.py A4-NoSolutions.coffee coffeekup.coffee prelude.coffee underscore.coffee ws.coffee A3-Microbench.coffee
CoffeeScript
show = console.log
2 |
3 | start = new Date()
4 | N = 1000000
5 | a = Array(N)
6 | for i in [0...N]
7 | a[i] = Math.random()
8 |
9 | s = 0
10 | for v in a
11 | s += v
12 |
13 | t = 0
14 | for v in a
15 | t += v*v
16 | t = Math.sqrt t
17 |
18 | duration = new Date() - start
19 | show "N: #{N} in #{duration*0.001} s"
20 | show "Result: #{s} and #{t}"
21 |
22 |
--------------------------------------------------------------------------------
/src/prelude/ws.coffee:
--------------------------------------------------------------------------------
1 | # *WebSocket Draft 75/76 implementation.*
2 | # Straight port to CoffeeScript.
3 | # No intentional changes to style or substance.
4 |
5 | # Github: http://github.com/ncr/node.ws.js
6 | # Compatible with node v0.1.91
7 | # Author: Jacek Becela
8 | # Contributors:
9 | # Michael Stillwell http://github.com/ithinkihaveacat
10 | # Nick Chapman http://github.com/nchapman
11 | # Dmitriy Shalashov http://github.com/skaurus
12 | # Johan Dahlberg
13 | # Andreas Kompanez
14 | # Samuel Cyprian http://github.com/samcyp
15 | # License: MIT
16 | # Based on: http://github.com/Guille/node.websocket.js
17 |
18 | nano = (template, data) ->
19 | template.replace /\{([\w\.]*)}/g, (str, key) ->
20 | keys = key.split "."
21 | value = data[keys.shift()]
22 | keys.forEach (key) -> value = value[key]
23 | value
24 |
25 | pack = (num) ->
26 | result = ''
27 | result += String.fromCharCode(num >> 24 & 0xFF)
28 | result += String.fromCharCode(num >> 16 & 0xFF)
29 | result += String.fromCharCode(num >> 8 & 0xFF)
30 | result += String.fromCharCode(num & 0xFF)
31 | result
32 |
33 | sys = require "sys"
34 | net = require "net"
35 | crypto = require "crypto"
36 | requiredHeaders = {
37 | 'get': /^GET (\/[^\s]*)/,
38 | 'upgrade': /^WebSocket$/,
39 | 'connection': /^Upgrade$/,
40 | 'host': /^(.+)$/,
41 | 'origin': /^(.+)$/
42 | }
43 | handshakeTemplate75 = [
44 | 'HTTP/1.1 101 Web Socket Protocol Handshake',
45 | 'Upgrade: WebSocket',
46 | 'Connection: Upgrade',
47 | 'WebSocket-Origin: {origin}',
48 | 'WebSocket-Location: {protocol}://{host}{resource}',
49 | '',
50 | ''
51 | ].join("\r\n")
52 | handshakeTemplate76 = [
53 | 'HTTP/1.1 101 WebSocket Protocol Handshake', # note a diff here
54 | 'Upgrade: WebSocket',
55 | 'Connection: Upgrade',
56 | 'Sec-WebSocket-Origin: {origin}',
57 | 'Sec-WebSocket-Location: {protocol}://{host}{resource}',
58 | '',
59 | '{data}'
60 | ].join("\r\n")
61 | flashPolicy = ' '
62 |
63 |
64 | exports.createSecureServer = (websocketListener, credentials, options) ->
65 | if !options then options = {}
66 | options.secure = credentials
67 | @createServer websocketListener, options
68 |
69 | exports.createServer = (websocketListener, options) ->
70 | if !options then options = {}
71 | if !options.flashPolicy then options.flashPolicy = flashPolicy
72 | # The value should be a crypto credentials
73 | if !options.secure then options.secure = null
74 |
75 | net.createServer (socket) ->
76 | #Secure WebSockets
77 | wsProtocol = 'ws'
78 | if options.secure
79 | wsProtocol = 'wss'
80 | socket.setSecure options.secure
81 | socket.setTimeout 0
82 | socket.setNoDelay true
83 | socket.setKeepAlive true, 0
84 |
85 | emitter = new process.EventEmitter()
86 | handshaked = false
87 | buffer = ""
88 |
89 | handle = (data) ->
90 | buffer += data
91 |
92 | chunks = buffer.split "\ufffd"
93 | count = chunks.length - 1 # last is "" or a partial packet
94 |
95 | for i in [0...count]
96 | chunk = chunks[i]
97 | if chunk[0] == "\u0000"
98 | emitter.emit "data", chunk.slice 1
99 | else
100 | socket.end()
101 | return
102 |
103 | buffer = chunks[count]
104 |
105 | handshake = (data) ->
106 | _headers = data.split "\r\n"
107 |
108 | if //.exec _headers[0]
109 | socket.write options.flashPolicy
110 | socket.end()
111 | return
112 |
113 | # go to more convenient hash form
114 | headers = {}
115 | upgradeHead = null
116 | len = _headers.length
117 | if _headers[0].match /^GET /
118 | headers["get"] = _headers[0]
119 | else
120 | socket.end()
121 | return
122 |
123 | if _headers[ _headers.length - 1 ]
124 | upgradeHead = _headers[ _headers.length - 1 ]
125 | len--
126 |
127 | while --len # _headers[0] will be skipped
128 | header = _headers[len]
129 | if !header then continue
130 |
131 | split = header.split ": ", 2 # second parameter actually seems to not work in node
132 | headers[ split[0].toLowerCase() ] = split[1]
133 |
134 | # check if we have all needed headers and fetch data from them
135 | data = {}
136 | match = null
137 | for header of requiredHeaders
138 | # regexp actual header value
139 | if match = requiredHeaders[ header ].exec headers[header]
140 | data[header] = match
141 | else
142 | socket.end()
143 | return
144 |
145 | # draft auto-sensing
146 | if headers["sec-websocket-key1"] && headers["sec-websocket-key2"] && upgradeHead # 76
147 | strkey1 = headers["sec-websocket-key1"]
148 | strkey2 = headers["sec-websocket-key2"]
149 |
150 | numkey1 = parseInt strkey1.replace(/[^\d]/g, ""), 10
151 | numkey2 = parseInt strkey2.replace(/[^\d]/g, ""), 10
152 |
153 | spaces1 = strkey1.replace(/[^\ ]/g, "").length
154 | spaces2 = strkey2.replace(/[^\ ]/g, "").length
155 |
156 | if spaces1 == 0 || spaces2 == 0 || numkey1 % spaces1 != 0 || numkey2 % spaces2 != 0
157 | socket.end()
158 | return
159 |
160 | hash = crypto.createHash "md5"
161 | key1 = pack parseInt numkey1/spaces1
162 | key2 = pack parseInt numkey2/spaces2
163 |
164 | hash.update key1
165 | hash.update key2
166 | hash.update upgradeHead
167 |
168 | socket.write(nano(handshakeTemplate76, {
169 | protocol: wsProtocol,
170 | resource: data.get[1],
171 | host: data.host[1],
172 | origin: data.origin[1],
173 | data: hash.digest("binary")
174 | }), "binary")
175 |
176 | else # 75
177 | socket.write(nano(handshakeTemplate75, {
178 | protocol: wsProtocol,
179 | resource: data.get[1],
180 | host: data.host[1],
181 | origin: data.origin[1]
182 | }))
183 |
184 | handshaked = true
185 | emitter.emit "connect", data.get[1]
186 |
187 | socket.addListener("data", (data) ->
188 | if handshaked
189 | handle data.toString "utf8"
190 | else
191 | handshake data.toString "binary" # because of draft76 handshakes
192 | ).addListener("end", ->
193 | socket.end()
194 | ).addListener("close", ->
195 | if handshaked # don't emit close from policy-requests
196 | emitter.emit "close"
197 | ).addListener("error", (exception) ->
198 | if emitter.listeners("error").length > 0
199 | emitter.emit "error", exception
200 | else
201 | throw exception
202 | )
203 |
204 | emitter.remoteAddress = socket.remoteAddress
205 |
206 | emitter.write = (data) ->
207 | try
208 | socket.write '\u0000', 'binary'
209 | socket.write data, 'utf8'
210 | socket.write '\uffff', 'binary'
211 | catch e
212 | # Socket not open for writing,
213 | # should get "close" event just before.
214 | socket.end()
215 |
216 | emitter.end = ->
217 | socket.end()
218 |
219 | # emits: "connect", "data", "close", provides: write(data), end()
220 | websocketListener emitter
221 |
222 |
223 |
--------------------------------------------------------------------------------
/src-no-solutions/prelude/ws.coffee:
--------------------------------------------------------------------------------
1 | # *WebSocket Draft 75/76 implementation.*
2 | # Straight port to CoffeeScript.
3 | # No intentional changes to style or substance.
4 |
5 | # Github: http://github.com/ncr/node.ws.js
6 | # Compatible with node v0.1.91
7 | # Author: Jacek Becela
8 | # Contributors:
9 | # Michael Stillwell http://github.com/ithinkihaveacat
10 | # Nick Chapman http://github.com/nchapman
11 | # Dmitriy Shalashov http://github.com/skaurus
12 | # Johan Dahlberg
13 | # Andreas Kompanez
14 | # Samuel Cyprian http://github.com/samcyp
15 | # License: MIT
16 | # Based on: http://github.com/Guille/node.websocket.js
17 |
18 | nano = (template, data) ->
19 | template.replace /\{([\w\.]*)}/g, (str, key) ->
20 | keys = key.split "."
21 | value = data[keys.shift()]
22 | keys.forEach (key) -> value = value[key]
23 | value
24 |
25 | pack = (num) ->
26 | result = ''
27 | result += String.fromCharCode(num >> 24 & 0xFF)
28 | result += String.fromCharCode(num >> 16 & 0xFF)
29 | result += String.fromCharCode(num >> 8 & 0xFF)
30 | result += String.fromCharCode(num & 0xFF)
31 | result
32 |
33 | sys = require "sys"
34 | net = require "net"
35 | crypto = require "crypto"
36 | requiredHeaders = {
37 | 'get': /^GET (\/[^\s]*)/,
38 | 'upgrade': /^WebSocket$/,
39 | 'connection': /^Upgrade$/,
40 | 'host': /^(.+)$/,
41 | 'origin': /^(.+)$/
42 | }
43 | handshakeTemplate75 = [
44 | 'HTTP/1.1 101 Web Socket Protocol Handshake',
45 | 'Upgrade: WebSocket',
46 | 'Connection: Upgrade',
47 | 'WebSocket-Origin: {origin}',
48 | 'WebSocket-Location: {protocol}://{host}{resource}',
49 | '',
50 | ''
51 | ].join("\r\n")
52 | handshakeTemplate76 = [
53 | 'HTTP/1.1 101 WebSocket Protocol Handshake', # note a diff here
54 | 'Upgrade: WebSocket',
55 | 'Connection: Upgrade',
56 | 'Sec-WebSocket-Origin: {origin}',
57 | 'Sec-WebSocket-Location: {protocol}://{host}{resource}',
58 | '',
59 | '{data}'
60 | ].join("\r\n")
61 | flashPolicy = ' '
62 |
63 |
64 | exports.createSecureServer = (websocketListener, credentials, options) ->
65 | if !options then options = {}
66 | options.secure = credentials
67 | @createServer websocketListener, options
68 |
69 | exports.createServer = (websocketListener, options) ->
70 | if !options then options = {}
71 | if !options.flashPolicy then options.flashPolicy = flashPolicy
72 | # The value should be a crypto credentials
73 | if !options.secure then options.secure = null
74 |
75 | net.createServer (socket) ->
76 | #Secure WebSockets
77 | wsProtocol = 'ws'
78 | if options.secure
79 | wsProtocol = 'wss'
80 | socket.setSecure options.secure
81 | socket.setTimeout 0
82 | socket.setNoDelay true
83 | socket.setKeepAlive true, 0
84 |
85 | emitter = new process.EventEmitter()
86 | handshaked = false
87 | buffer = ""
88 |
89 | handle = (data) ->
90 | buffer += data
91 |
92 | chunks = buffer.split "\ufffd"
93 | count = chunks.length - 1 # last is "" or a partial packet
94 |
95 | for i in [0...count]
96 | chunk = chunks[i]
97 | if chunk[0] == "\u0000"
98 | emitter.emit "data", chunk.slice 1
99 | else
100 | socket.end()
101 | return
102 |
103 | buffer = chunks[count]
104 |
105 | handshake = (data) ->
106 | _headers = data.split "\r\n"
107 |
108 | if //.exec _headers[0]
109 | socket.write options.flashPolicy
110 | socket.end()
111 | return
112 |
113 | # go to more convenient hash form
114 | headers = {}
115 | upgradeHead = null
116 | len = _headers.length
117 | if _headers[0].match /^GET /
118 | headers["get"] = _headers[0]
119 | else
120 | socket.end()
121 | return
122 |
123 | if _headers[ _headers.length - 1 ]
124 | upgradeHead = _headers[ _headers.length - 1 ]
125 | len--
126 |
127 | while --len # _headers[0] will be skipped
128 | header = _headers[len]
129 | if !header then continue
130 |
131 | split = header.split ": ", 2 # second parameter actually seems to not work in node
132 | headers[ split[0].toLowerCase() ] = split[1]
133 |
134 | # check if we have all needed headers and fetch data from them
135 | data = {}
136 | match = null
137 | for header of requiredHeaders
138 | # regexp actual header value
139 | if match = requiredHeaders[ header ].exec headers[header]
140 | data[header] = match
141 | else
142 | socket.end()
143 | return
144 |
145 | # draft auto-sensing
146 | if headers["sec-websocket-key1"] && headers["sec-websocket-key2"] && upgradeHead # 76
147 | strkey1 = headers["sec-websocket-key1"]
148 | strkey2 = headers["sec-websocket-key2"]
149 |
150 | numkey1 = parseInt strkey1.replace(/[^\d]/g, ""), 10
151 | numkey2 = parseInt strkey2.replace(/[^\d]/g, ""), 10
152 |
153 | spaces1 = strkey1.replace(/[^\ ]/g, "").length
154 | spaces2 = strkey2.replace(/[^\ ]/g, "").length
155 |
156 | if spaces1 == 0 || spaces2 == 0 || numkey1 % spaces1 != 0 || numkey2 % spaces2 != 0
157 | socket.end()
158 | return
159 |
160 | hash = crypto.createHash "md5"
161 | key1 = pack parseInt numkey1/spaces1
162 | key2 = pack parseInt numkey2/spaces2
163 |
164 | hash.update key1
165 | hash.update key2
166 | hash.update upgradeHead
167 |
168 | socket.write(nano(handshakeTemplate76, {
169 | protocol: wsProtocol,
170 | resource: data.get[1],
171 | host: data.host[1],
172 | origin: data.origin[1],
173 | data: hash.digest("binary")
174 | }), "binary")
175 |
176 | else # 75
177 | socket.write(nano(handshakeTemplate75, {
178 | protocol: wsProtocol,
179 | resource: data.get[1],
180 | host: data.host[1],
181 | origin: data.origin[1]
182 | }))
183 |
184 | handshaked = true
185 | emitter.emit "connect", data.get[1]
186 |
187 | socket.addListener("data", (data) ->
188 | if handshaked
189 | handle data.toString "utf8"
190 | else
191 | handshake data.toString "binary" # because of draft76 handshakes
192 | ).addListener("end", ->
193 | socket.end()
194 | ).addListener("close", ->
195 | if handshaked # don't emit close from policy-requests
196 | emitter.emit "close"
197 | ).addListener("error", (exception) ->
198 | if emitter.listeners("error").length > 0
199 | emitter.emit "error", exception
200 | else
201 | throw exception
202 | )
203 |
204 | emitter.remoteAddress = socket.remoteAddress
205 |
206 | emitter.write = (data) ->
207 | try
208 | socket.write '\u0000', 'binary'
209 | socket.write data, 'utf8'
210 | socket.write '\uffff', 'binary'
211 | catch e
212 | # Socket not open for writing,
213 | # should get "close" event just before.
214 | socket.end()
215 |
216 | emitter.end = ->
217 | socket.end()
218 |
219 | # emits: "connect", "data", "close", provides: write(data), end()
220 | websocketListener emitter
221 |
222 |
223 |
--------------------------------------------------------------------------------
/src/docs/A3-Microtest.html:
--------------------------------------------------------------------------------
1 | A3-Microtest.py Jump To … 00-Foreword.coffee 01-Introduction.coffee 02-BasicCoffeeScript.coffee 03-Functions.coffee 04-DataStructures.coffee 04-emails.coffee 05-ErrorHandling.coffee 06-FunctionalProgramming.coffee 07-Searching.coffee 08-ObjectOrientation.coffee 09-RegularExpressions.coffee 10-Circular.coffee 10-CircularTest.coffee 10-MathFix.coffee 10-Modularity.coffee 10-SeedLife.coffee 10-TestWebSockets.coffee 10-WebSocketLife.coffee A1-LanguageExtras.coffee A2-BinaryHeap.coffee A2-BinaryHeapTest.coffee A3-Microbench.coffee A3-Microtest.py A3-Queen.coffee A3-Queens.py A4-NoSolutions.coffee coffeekup.coffee prelude.coffee underscore.coffee ws.coffee A3-Microtest.py
CPython
import time
2 | import random
3 | import math
4 |
5 | start = time.clock()
6 | N = 1000000
7 | a = [random.random()
8 | for i in range(N)]
9 |
10 | s = 0
11 | for v in a:
12 | s += v
13 |
14 | t = 0
15 | for v in a:
16 | t += v*v
17 | t = math.sqrt(t)
18 |
19 | duration = time.clock() - start
20 | print 'N:', N, 'in', duration, 's'
21 | print 'Result:', s, 'and', t
22 |
23 |
--------------------------------------------------------------------------------
/src-no-solutions/docs/A3-Microtest.html:
--------------------------------------------------------------------------------
1 | A3-Microtest.py Jump To … 00-Foreword.coffee 01-Introduction.coffee 02-BasicCoffeeScript.coffee 03-Functions.coffee 04-DataStructures.coffee 04-emails.coffee 05-ErrorHandling.coffee 06-FunctionalProgramming.coffee 07-Searching.coffee 08-ObjectOrientation.coffee 09-RegularExpressions.coffee 10-Circular.coffee 10-CircularTest.coffee 10-MathFix.coffee 10-Modularity.coffee 10-SeedLife.coffee 10-TestWebSockets.coffee 10-WebSocketLife.coffee A1-LanguageExtras.coffee A2-BinaryHeap.coffee A2-BinaryHeapTest.coffee A3-Microbench.coffee A3-Microtest.py A3-Queen.coffee A3-Queens.py A4-NoSolutions.coffee coffeekup.coffee prelude.coffee underscore.coffee ws.coffee A3-Microtest.py
CPython
import time
2 | import random
3 | import math
4 |
5 | start = time.clock()
6 | N = 1000000
7 | a = [random.random()
8 | for i in range(N)]
9 |
10 | s = 0
11 | for v in a:
12 | s += v
13 |
14 | t = 0
15 | for v in a:
16 | t += v*v
17 | t = math.sqrt(t)
18 |
19 | duration = time.clock() - start
20 | print 'N:', N, 'in', duration, 's'
21 | print 'Result:', s, 'and', t
22 |
23 |
--------------------------------------------------------------------------------
/src/docs/docco.css:
--------------------------------------------------------------------------------
1 | /*--------------------- Layout and Typography ----------------------------*/
2 | body {
3 | font-family: 'Palatino Linotype', 'Book Antiqua', Palatino, FreeSerif, serif;
4 | font-size: 15px;
5 | line-height: 22px;
6 | color: #252519;
7 | margin: 0; padding: 0;
8 | }
9 | a {
10 | color: #261a3b;
11 | }
12 | a:visited {
13 | color: #261a3b;
14 | }
15 | p {
16 | margin: 0 0 15px 0;
17 | }
18 | h1, h2, h3, h4, h5, h6 {
19 | margin: 0px 0 15px 0;
20 | }
21 | h1 {
22 | margin-top: 40px;
23 | }
24 | #container {
25 | position: relative;
26 | }
27 | #background {
28 | position: fixed;
29 | top: 0; left: 525px; right: 0; bottom: 0;
30 | background: #f5f5ff;
31 | border-left: 1px solid #e5e5ee;
32 | z-index: -1;
33 | }
34 | #jump_to, #jump_page {
35 | background: white;
36 | -webkit-box-shadow: 0 0 25px #777; -moz-box-shadow: 0 0 25px #777;
37 | -webkit-border-bottom-left-radius: 5px; -moz-border-radius-bottomleft: 5px;
38 | font: 10px Arial;
39 | text-transform: uppercase;
40 | cursor: pointer;
41 | text-align: right;
42 | }
43 | #jump_to, #jump_wrapper {
44 | position: fixed;
45 | right: 0; top: 0;
46 | padding: 5px 10px;
47 | }
48 | #jump_wrapper {
49 | padding: 0;
50 | display: none;
51 | }
52 | #jump_to:hover #jump_wrapper {
53 | display: block;
54 | }
55 | #jump_page {
56 | padding: 5px 0 3px;
57 | margin: 0 0 25px 25px;
58 | }
59 | #jump_page .source {
60 | display: block;
61 | padding: 5px 10px;
62 | text-decoration: none;
63 | border-top: 1px solid #eee;
64 | }
65 | #jump_page .source:hover {
66 | background: #f5f5ff;
67 | }
68 | #jump_page .source:first-child {
69 | }
70 | table td {
71 | border: 0;
72 | outline: 0;
73 | }
74 | td.docs, th.docs {
75 | max-width: 450px;
76 | min-width: 450px;
77 | min-height: 5px;
78 | padding: 10px 25px 1px 50px;
79 | overflow-x: hidden;
80 | vertical-align: top;
81 | text-align: left;
82 | }
83 | .docs pre {
84 | margin: 15px 0 15px;
85 | padding-left: 15px;
86 | }
87 | .docs p tt, .docs p code {
88 | background: #f8f8ff;
89 | border: 1px solid #dedede;
90 | font-size: 12px;
91 | padding: 0 0.2em;
92 | }
93 | .pilwrap {
94 | position: relative;
95 | }
96 | .pilcrow {
97 | font: 12px Arial;
98 | text-decoration: none;
99 | color: #454545;
100 | position: absolute;
101 | top: 3px; left: -20px;
102 | padding: 1px 2px;
103 | opacity: 0;
104 | -webkit-transition: opacity 0.2s linear;
105 | }
106 | td.docs:hover .pilcrow {
107 | opacity: 1;
108 | }
109 | td.code, th.code {
110 | padding: 14px 15px 16px 25px;
111 | width: 100%;
112 | vertical-align: top;
113 | background: #f5f5ff;
114 | border-left: 1px solid #e5e5ee;
115 | }
116 | pre, tt, code {
117 | font-size: 12px; line-height: 18px;
118 | font-family: Monaco, Consolas, "Lucida Console", monospace;
119 | margin: 0; padding: 0;
120 | }
121 |
122 |
123 | /*---------------------- Syntax Highlighting -----------------------------*/
124 | td.linenos { background-color: #f0f0f0; padding-right: 10px; }
125 | span.lineno { background-color: #f0f0f0; padding: 0 5px 0 5px; }
126 | body .hll { background-color: #ffffcc }
127 | body .c { color: #408080; font-style: italic } /* Comment */
128 | body .err { border: 1px solid #FF0000 } /* Error */
129 | body .k { color: #954121 } /* Keyword */
130 | body .o { color: #666666 } /* Operator */
131 | body .cm { color: #408080; font-style: italic } /* Comment.Multiline */
132 | body .cp { color: #BC7A00 } /* Comment.Preproc */
133 | body .c1 { color: #408080; font-style: italic } /* Comment.Single */
134 | body .cs { color: #408080; font-style: italic } /* Comment.Special */
135 | body .gd { color: #A00000 } /* Generic.Deleted */
136 | body .ge { font-style: italic } /* Generic.Emph */
137 | body .gr { color: #FF0000 } /* Generic.Error */
138 | body .gh { color: #000080; font-weight: bold } /* Generic.Heading */
139 | body .gi { color: #00A000 } /* Generic.Inserted */
140 | body .go { color: #808080 } /* Generic.Output */
141 | body .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
142 | body .gs { font-weight: bold } /* Generic.Strong */
143 | body .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
144 | body .gt { color: #0040D0 } /* Generic.Traceback */
145 | body .kc { color: #954121 } /* Keyword.Constant */
146 | body .kd { color: #954121; font-weight: bold } /* Keyword.Declaration */
147 | body .kn { color: #954121; font-weight: bold } /* Keyword.Namespace */
148 | body .kp { color: #954121 } /* Keyword.Pseudo */
149 | body .kr { color: #954121; font-weight: bold } /* Keyword.Reserved */
150 | body .kt { color: #B00040 } /* Keyword.Type */
151 | body .m { color: #666666 } /* Literal.Number */
152 | body .s { color: #219161 } /* Literal.String */
153 | body .na { color: #7D9029 } /* Name.Attribute */
154 | body .nb { color: #954121 } /* Name.Builtin */
155 | body .nc { color: #0000FF; font-weight: bold } /* Name.Class */
156 | body .no { color: #880000 } /* Name.Constant */
157 | body .nd { color: #AA22FF } /* Name.Decorator */
158 | body .ni { color: #999999; font-weight: bold } /* Name.Entity */
159 | body .ne { color: #D2413A; font-weight: bold } /* Name.Exception */
160 | body .nf { color: #0000FF } /* Name.Function */
161 | body .nl { color: #A0A000 } /* Name.Label */
162 | body .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
163 | body .nt { color: #954121; font-weight: bold } /* Name.Tag */
164 | body .nv { color: #19469D } /* Name.Variable */
165 | body .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
166 | body .w { color: #bbbbbb } /* Text.Whitespace */
167 | body .mf { color: #666666 } /* Literal.Number.Float */
168 | body .mh { color: #666666 } /* Literal.Number.Hex */
169 | body .mi { color: #666666 } /* Literal.Number.Integer */
170 | body .mo { color: #666666 } /* Literal.Number.Oct */
171 | body .sb { color: #219161 } /* Literal.String.Backtick */
172 | body .sc { color: #219161 } /* Literal.String.Char */
173 | body .sd { color: #219161; font-style: italic } /* Literal.String.Doc */
174 | body .s2 { color: #219161 } /* Literal.String.Double */
175 | body .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
176 | body .sh { color: #219161 } /* Literal.String.Heredoc */
177 | body .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
178 | body .sx { color: #954121 } /* Literal.String.Other */
179 | body .sr { color: #BB6688 } /* Literal.String.Regex */
180 | body .s1 { color: #219161 } /* Literal.String.Single */
181 | body .ss { color: #19469D } /* Literal.String.Symbol */
182 | body .bp { color: #954121 } /* Name.Builtin.Pseudo */
183 | body .vc { color: #19469D } /* Name.Variable.Class */
184 | body .vg { color: #19469D } /* Name.Variable.Global */
185 | body .vi { color: #19469D } /* Name.Variable.Instance */
186 | body .il { color: #666666 } /* Literal.Number.Integer.Long */
--------------------------------------------------------------------------------
/src-no-solutions/docs/docco.css:
--------------------------------------------------------------------------------
1 | /*--------------------- Layout and Typography ----------------------------*/
2 | body {
3 | font-family: 'Palatino Linotype', 'Book Antiqua', Palatino, FreeSerif, serif;
4 | font-size: 15px;
5 | line-height: 22px;
6 | color: #252519;
7 | margin: 0; padding: 0;
8 | }
9 | a {
10 | color: #261a3b;
11 | }
12 | a:visited {
13 | color: #261a3b;
14 | }
15 | p {
16 | margin: 0 0 15px 0;
17 | }
18 | h1, h2, h3, h4, h5, h6 {
19 | margin: 0px 0 15px 0;
20 | }
21 | h1 {
22 | margin-top: 40px;
23 | }
24 | #container {
25 | position: relative;
26 | }
27 | #background {
28 | position: fixed;
29 | top: 0; left: 525px; right: 0; bottom: 0;
30 | background: #f5f5ff;
31 | border-left: 1px solid #e5e5ee;
32 | z-index: -1;
33 | }
34 | #jump_to, #jump_page {
35 | background: white;
36 | -webkit-box-shadow: 0 0 25px #777; -moz-box-shadow: 0 0 25px #777;
37 | -webkit-border-bottom-left-radius: 5px; -moz-border-radius-bottomleft: 5px;
38 | font: 10px Arial;
39 | text-transform: uppercase;
40 | cursor: pointer;
41 | text-align: right;
42 | }
43 | #jump_to, #jump_wrapper {
44 | position: fixed;
45 | right: 0; top: 0;
46 | padding: 5px 10px;
47 | }
48 | #jump_wrapper {
49 | padding: 0;
50 | display: none;
51 | }
52 | #jump_to:hover #jump_wrapper {
53 | display: block;
54 | }
55 | #jump_page {
56 | padding: 5px 0 3px;
57 | margin: 0 0 25px 25px;
58 | }
59 | #jump_page .source {
60 | display: block;
61 | padding: 5px 10px;
62 | text-decoration: none;
63 | border-top: 1px solid #eee;
64 | }
65 | #jump_page .source:hover {
66 | background: #f5f5ff;
67 | }
68 | #jump_page .source:first-child {
69 | }
70 | table td {
71 | border: 0;
72 | outline: 0;
73 | }
74 | td.docs, th.docs {
75 | max-width: 450px;
76 | min-width: 450px;
77 | min-height: 5px;
78 | padding: 10px 25px 1px 50px;
79 | overflow-x: hidden;
80 | vertical-align: top;
81 | text-align: left;
82 | }
83 | .docs pre {
84 | margin: 15px 0 15px;
85 | padding-left: 15px;
86 | }
87 | .docs p tt, .docs p code {
88 | background: #f8f8ff;
89 | border: 1px solid #dedede;
90 | font-size: 12px;
91 | padding: 0 0.2em;
92 | }
93 | .pilwrap {
94 | position: relative;
95 | }
96 | .pilcrow {
97 | font: 12px Arial;
98 | text-decoration: none;
99 | color: #454545;
100 | position: absolute;
101 | top: 3px; left: -20px;
102 | padding: 1px 2px;
103 | opacity: 0;
104 | -webkit-transition: opacity 0.2s linear;
105 | }
106 | td.docs:hover .pilcrow {
107 | opacity: 1;
108 | }
109 | td.code, th.code {
110 | padding: 14px 15px 16px 25px;
111 | width: 100%;
112 | vertical-align: top;
113 | background: #f5f5ff;
114 | border-left: 1px solid #e5e5ee;
115 | }
116 | pre, tt, code {
117 | font-size: 12px; line-height: 18px;
118 | font-family: Monaco, Consolas, "Lucida Console", monospace;
119 | margin: 0; padding: 0;
120 | }
121 |
122 |
123 | /*---------------------- Syntax Highlighting -----------------------------*/
124 | td.linenos { background-color: #f0f0f0; padding-right: 10px; }
125 | span.lineno { background-color: #f0f0f0; padding: 0 5px 0 5px; }
126 | body .hll { background-color: #ffffcc }
127 | body .c { color: #408080; font-style: italic } /* Comment */
128 | body .err { border: 1px solid #FF0000 } /* Error */
129 | body .k { color: #954121 } /* Keyword */
130 | body .o { color: #666666 } /* Operator */
131 | body .cm { color: #408080; font-style: italic } /* Comment.Multiline */
132 | body .cp { color: #BC7A00 } /* Comment.Preproc */
133 | body .c1 { color: #408080; font-style: italic } /* Comment.Single */
134 | body .cs { color: #408080; font-style: italic } /* Comment.Special */
135 | body .gd { color: #A00000 } /* Generic.Deleted */
136 | body .ge { font-style: italic } /* Generic.Emph */
137 | body .gr { color: #FF0000 } /* Generic.Error */
138 | body .gh { color: #000080; font-weight: bold } /* Generic.Heading */
139 | body .gi { color: #00A000 } /* Generic.Inserted */
140 | body .go { color: #808080 } /* Generic.Output */
141 | body .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
142 | body .gs { font-weight: bold } /* Generic.Strong */
143 | body .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
144 | body .gt { color: #0040D0 } /* Generic.Traceback */
145 | body .kc { color: #954121 } /* Keyword.Constant */
146 | body .kd { color: #954121; font-weight: bold } /* Keyword.Declaration */
147 | body .kn { color: #954121; font-weight: bold } /* Keyword.Namespace */
148 | body .kp { color: #954121 } /* Keyword.Pseudo */
149 | body .kr { color: #954121; font-weight: bold } /* Keyword.Reserved */
150 | body .kt { color: #B00040 } /* Keyword.Type */
151 | body .m { color: #666666 } /* Literal.Number */
152 | body .s { color: #219161 } /* Literal.String */
153 | body .na { color: #7D9029 } /* Name.Attribute */
154 | body .nb { color: #954121 } /* Name.Builtin */
155 | body .nc { color: #0000FF; font-weight: bold } /* Name.Class */
156 | body .no { color: #880000 } /* Name.Constant */
157 | body .nd { color: #AA22FF } /* Name.Decorator */
158 | body .ni { color: #999999; font-weight: bold } /* Name.Entity */
159 | body .ne { color: #D2413A; font-weight: bold } /* Name.Exception */
160 | body .nf { color: #0000FF } /* Name.Function */
161 | body .nl { color: #A0A000 } /* Name.Label */
162 | body .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
163 | body .nt { color: #954121; font-weight: bold } /* Name.Tag */
164 | body .nv { color: #19469D } /* Name.Variable */
165 | body .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
166 | body .w { color: #bbbbbb } /* Text.Whitespace */
167 | body .mf { color: #666666 } /* Literal.Number.Float */
168 | body .mh { color: #666666 } /* Literal.Number.Hex */
169 | body .mi { color: #666666 } /* Literal.Number.Integer */
170 | body .mo { color: #666666 } /* Literal.Number.Oct */
171 | body .sb { color: #219161 } /* Literal.String.Backtick */
172 | body .sc { color: #219161 } /* Literal.String.Char */
173 | body .sd { color: #219161; font-style: italic } /* Literal.String.Doc */
174 | body .s2 { color: #219161 } /* Literal.String.Double */
175 | body .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
176 | body .sh { color: #219161 } /* Literal.String.Heredoc */
177 | body .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
178 | body .sx { color: #954121 } /* Literal.String.Other */
179 | body .sr { color: #BB6688 } /* Literal.String.Regex */
180 | body .s1 { color: #219161 } /* Literal.String.Single */
181 | body .ss { color: #19469D } /* Literal.String.Symbol */
182 | body .bp { color: #954121 } /* Name.Builtin.Pseudo */
183 | body .vc { color: #19469D } /* Name.Variable.Class */
184 | body .vg { color: #19469D } /* Name.Variable.Global */
185 | body .vi { color: #19469D } /* Name.Variable.Instance */
186 | body .il { color: #666666 } /* Literal.Number.Integer.Long */
--------------------------------------------------------------------------------
/src/08-ObjectOrientation.coffee:
--------------------------------------------------------------------------------
1 | require './prelude'
2 | # Bring underscore into global
3 | globalize _
4 |
5 | # Attach function
6 | show '--- Attach function ---'
7 | rabbit = {}
8 | rabbit.speak = (line) ->
9 | show "The rabbit says '#{line}'"
10 | rabbit.speak "Well, now you're asking me."
11 |
12 | # Object programming
13 | show '--- Object programming ---'
14 | speak = (line) ->
15 | show "The #{this.adjective} rabbit says '#{line}'"
16 |
17 | whiteRabbit = adjective: "white", speak: speak
18 | fatRabbit = adjective: "fat", speak: speak
19 |
20 | whiteRabbit.speak "Oh my ears and whiskers, " +
21 | "how late it's getting!"
22 | fatRabbit.speak "I could sure use a carrot right now."
23 |
24 | speak.apply fatRabbit, ['Yum.']
25 | speak.call fatRabbit, 'Burp.'
26 |
27 | # Class concept
28 | show '--- Class concept ---'
29 | class Rabbit
30 | constructor: (@adjective) ->
31 | speak: (line) ->
32 | show "The #{@adjective} rabbit says '#{line}'"
33 |
34 | whiteRabbit = new Rabbit "white"
35 | fatRabbit = new Rabbit "fat"
36 |
37 | whiteRabbit.speak "Hurry!"
38 | fatRabbit.speak "Tasty!"
39 |
40 | # New constructor
41 | show '--- New constructor ---'
42 | killerRabbit = new Rabbit 'killer'
43 | killerRabbit.speak 'GRAAAAAAAAAH!'
44 | show killerRabbit
45 |
46 | makeRabbit = (adjective) ->
47 | adjective: adjective
48 | speak: (line) -> show adjective + ': ' + line
49 | blackRabbit = makeRabbit 'black'
50 |
51 | show killerRabbit.constructor.name
52 | show blackRabbit.constructor.name
53 |
54 | # Extends keyword
55 | show '--- Extends keyword ---'
56 | class WeightyRabbit extends Rabbit
57 | constructor: (adjective, @weight) ->
58 | super adjective
59 | adjustedWeight: (relativeGravity) ->
60 | (@weight * relativeGravity).toPrecision 2
61 |
62 | tinyRabbit = new WeightyRabbit "tiny", 1.01
63 | jumboRabbit = new WeightyRabbit "jumbo", 7.47
64 |
65 | moonGravity = 1/6
66 | jumboRabbit.speak "Carry me, I weigh #{jumboRabbit.adjustedWeight(moonGravity)} stones"
67 | tinyRabbit.speak "He ain't heavy, he is my brother"
68 |
69 |
70 | # Inheritance pitfalls
71 | show '--- Inheritance pitfalls ---'
72 | class Account
73 | constructor: -> @balance = 0
74 | transfer: (amount) -> @balance += amount
75 | getBalance: -> @balance
76 | batchTransfer: (amtList) ->
77 | for amount in amtList
78 | @transfer amount
79 |
80 | yourAccount = new Account()
81 | oldBalance = yourAccount.getBalance()
82 | yourAccount.transfer salary = 1000
83 | newBalance = yourAccount.getBalance()
84 | show "Books balance: #{salary == newBalance - oldBalance}."
85 |
86 | # Violation of substitution property
87 | show '--- Violation of substitution property ---'
88 | class AccountWithFee extends Account
89 | fee: 5
90 | transfer: (amount) ->
91 | super amount - @fee
92 | # feeAccount.transfer @fee
93 |
94 | yourAccount = new AccountWithFee()
95 | oldBalance = yourAccount.getBalance()
96 | yourAccount.transfer salary = 1000
97 | newBalance = yourAccount.getBalance()
98 | show "Books balance: #{salary == newBalance - oldBalance}."
99 |
100 | # Limited account class
101 | show '--- Limited account class ---'
102 | class LimitedAccount extends Account
103 | constructor: -> super; @resetLimit()
104 | resetLimit: -> @dailyLimit = 50
105 | transfer: (amount) ->
106 | if amount < 0 and (@dailyLimit += amount) < 0
107 | throw new Error "You maxed out!"
108 | else
109 | super amount
110 | lacc = new LimitedAccount()
111 | lacc.transfer 50
112 | show "Start balance #{lacc.getBalance()}"
113 |
114 | try lacc.batchTransfer [-1..-10]
115 | catch error then show error.message
116 | show "After batch balance #{lacc.getBalance()}"
117 |
118 | # Fragile base class
119 | show '--- Fragile base class ---'
120 | class Account
121 | constructor: -> @balance = 0
122 | transfer: (amount) -> @balance += amount
123 | getBalance: -> @balance
124 | batchTransfer: (amtList) ->
125 | add = (a,b) -> a+b
126 | sum = (list) -> reduce list, add, 0
127 | @balance += sum amtList
128 |
129 | class LimitedAccount extends Account
130 | constructor: -> super; @resetLimit()
131 | resetLimit: -> @dailyLimit = 50
132 | transfer: (amount) ->
133 | if amount < 0 and (@dailyLimit += amount) < 0
134 | throw new Error "You maxed out!"
135 | else
136 | super amount
137 |
138 | lacc = new LimitedAccount()
139 | lacc.transfer 50
140 | show "Starting with #{lacc.getBalance()}"
141 |
142 | try lacc.batchTransfer [-1..-10]
143 | catch error then show error.message
144 | show "After batch balance #{lacc.getBalance()}"
145 |
146 | # Prototypes
147 | show '--- Prototypes ---'
148 | simpleObject = {}
149 | show simpleObject.constructor.name
150 | show simpleObject.toString()
151 |
152 | show Rabbit.prototype
153 | show Rabbit.prototype.constructor.name
154 | Rabbit.prototype.speak 'I am generic'
155 | Rabbit::speak 'I am not initialized'
156 |
157 | show killerRabbit.toString == simpleObject.toString
158 |
159 | # Shared properties
160 | show '--- Shared properties ---'
161 | Rabbit::teeth = 'small'
162 | show killerRabbit.teeth
163 | killerRabbit.teeth = 'long, sharp, and bloody'
164 | show killerRabbit.teeth
165 | show Rabbit::teeth
166 |
167 | Rabbit::dance = ->
168 | show "The #{@adjective} rabbit dances a jig."
169 | killerRabbit.dance()
170 |
171 | Rabbit = (adjective) ->
172 | @adjective = adjective
173 |
174 | Rabbit::speak = (line) ->
175 | show "The #{@adjective} rabbit says '#{line}'"
176 |
177 | hazelRabbit = new Rabbit "hazel"
178 | hazelRabbit.speak "Good Frith!"
179 |
180 | # Exposed properties
181 | show '--- Exposed properties ---'
182 | noCatsAtAll = {}
183 | if "constructor" of noCatsAtAll
184 | show "Yes, there is a cat called 'constructor'."
185 |
186 | Object::allProperties = ->
187 | for property of this
188 | property
189 |
190 | test = x: 10, y: 3
191 | show test.allProperties()
192 |
193 | Object::ownProperties = ->
194 | for own property of @
195 | property
196 |
197 | test = 'Fat Igor': true, 'Fireball': true
198 | show test.ownProperties()
199 |
200 | # Function forEachOf
201 | show '--- Function forEachOf ---'
202 | forEachOf = (object, action) ->
203 | for own property, value of object
204 | action property, value
205 |
206 | chimera = head: "lion", body: "goat", tail: "snake"
207 | forEachOf chimera, (name, value) ->
208 | show "The #{name} of a #{value}."
209 |
210 | # Object methods
211 | show '--- Object methods ---'
212 | forEachIn = (object, action) ->
213 | for property of object
214 | if (Object::hasOwnProperty.call(object, property))
215 | action property, object[property]
216 |
217 | test = name: "Mordecai", hasOwnProperty: "Uh-oh"
218 | forEachIn test, (name, value) ->
219 | show "Property #{name} = #{value}"
220 |
221 | for own property, value of test
222 | show "Property #{property} = #{value}"
223 |
224 | obj = foo: 'bar'
225 | # This test is needed to avoid hidden properties ...
226 | show Object::hasOwnProperty.call(obj, 'foo') and
227 | Object::propertyIsEnumerable.call(obj, 'foo')
228 | # ... because this returns true ...
229 | show Object::hasOwnProperty.call(obj, '__proto__')
230 | # ... this is required to get false.
231 | show Object::hasOwnProperty.call(obj, '__proto__') and
232 | Object::propertyIsEnumerable.call(obj, '__proto__')
233 |
234 | # Dictionary
235 | show '--- Dictionary ---'
236 | class Dictionary
237 | constructor: (@values = {}) ->
238 |
239 | store: (name, value) ->
240 | @values[name] = value
241 |
242 | lookup: (name) ->
243 | @values[name]
244 |
245 | contains: (name) ->
246 | Object::hasOwnProperty.call(@values, name) and
247 | Object::propertyIsEnumerable.call(@values, name)
248 |
249 | each: (action) ->
250 | for own property, value of @values
251 | action property, value
252 |
253 | colours = new Dictionary
254 | Grover: 'blue'
255 | Elmo: 'orange'
256 | Bert: 'yellow'
257 |
258 | show colours.contains 'Grover'
259 | colours.each (name, colour) ->
260 | show name + ' is ' + colour
261 |
262 |
--------------------------------------------------------------------------------