diff --git a/Rakefile b/Rakefile index 0616f0fc..497d07e8 100644 --- a/Rakefile +++ b/Rakefile @@ -18,6 +18,7 @@ end desc "Build the documentation page" task :doc do source = 'documentation/index.html.erb' + Thread.new { `bin/coffee-script documentation/cs/*.cs -o documentation/js -w` } loop do mtime = File.stat(source).mtime if !@mtime || mtime > @mtime diff --git a/documentation/cs/array_comprehensions.cs b/documentation/cs/array_comprehensions.cs new file mode 100644 index 00000000..ffccbfee --- /dev/null +++ b/documentation/cs/array_comprehensions.cs @@ -0,0 +1,5 @@ +# Eat lunch. +lunch: food.eat() for food in ['toast', 'cheese', 'wine']. + +# Zebra-stripe a table. +highlight(row) for row, i in table if i % 2 is 0. diff --git a/documentation/cs/assignment.cs b/documentation/cs/assignment.cs new file mode 100644 index 00000000..db979f5c --- /dev/null +++ b/documentation/cs/assignment.cs @@ -0,0 +1,2 @@ +greeting: "Hello CoffeeScript" +difficulty: 0.5 diff --git a/documentation/cs/conditionals.cs b/documentation/cs/conditionals.cs new file mode 100644 index 00000000..253d912c --- /dev/null +++ b/documentation/cs/conditionals.cs @@ -0,0 +1,9 @@ +mood: greatly_improved if singing + +if happy and knows_it + claps_hands() + cha_cha_cha(). + +date: if friday then sue else jill. + +expensive ||= do_the_math() \ No newline at end of file diff --git a/documentation/cs/embedded.cs b/documentation/cs/embedded.cs new file mode 100644 index 00000000..5a4f0d24 --- /dev/null +++ b/documentation/cs/embedded.cs @@ -0,0 +1,3 @@ +js: => `alert("Hello JavaScript");`. + +js() if 10 > 9 \ No newline at end of file diff --git a/documentation/cs/expressions.cs b/documentation/cs/expressions.cs new file mode 100644 index 00000000..3309739a --- /dev/null +++ b/documentation/cs/expressions.cs @@ -0,0 +1,9 @@ +grade: student => + if student.excellent_work + "A+" + else if student.okay_stuff + "B" + else + "C".. + +eldest: if 24 > 21 then "Liz" else "Ike". \ No newline at end of file diff --git a/documentation/cs/functions.cs b/documentation/cs/functions.cs new file mode 100644 index 00000000..35f4415a --- /dev/null +++ b/documentation/cs/functions.cs @@ -0,0 +1,2 @@ +square: x => x * x. +cube: x => square(x) * x. \ No newline at end of file diff --git a/documentation/cs/intro.cs b/documentation/cs/intro.cs new file mode 100644 index 00000000..b0f13bb9 --- /dev/null +++ b/documentation/cs/intro.cs @@ -0,0 +1,3 @@ +# CoffeeScript on the left, JS on the right. + +square: x => x * x. diff --git a/documentation/cs/objects_and_arrays.cs b/documentation/cs/objects_and_arrays.cs new file mode 100644 index 00000000..ff10c6ed --- /dev/null +++ b/documentation/cs/objects_and_arrays.cs @@ -0,0 +1,6 @@ +song: ["do", "re", "mi", "fa", "so"] +ages: { + max: 10 + ida: 9 + tim: 11 +} \ No newline at end of file diff --git a/documentation/cs/punctuation.cs b/documentation/cs/punctuation.cs new file mode 100644 index 00000000..3ecf2073 --- /dev/null +++ b/documentation/cs/punctuation.cs @@ -0,0 +1,11 @@ +# Comments start with hash marks. + +# Periods mark the end of a block. +left_hand: if raining then umbrella else parasol. + +# To signal the beginning of the next expression, +# use "then", or a newline. +left_hand: if raining + umbrella +else + parasol. diff --git a/documentation/cs/scope.cs b/documentation/cs/scope.cs new file mode 100644 index 00000000..f15b3eff --- /dev/null +++ b/documentation/cs/scope.cs @@ -0,0 +1,5 @@ +num: 1 +change_numbers: => + num: 2 + new_num: 3. +new_num: change_numbers() \ No newline at end of file diff --git a/documentation/cs/slices.cs b/documentation/cs/slices.cs new file mode 100644 index 00000000..ac34b0b2 --- /dev/null +++ b/documentation/cs/slices.cs @@ -0,0 +1,2 @@ +nums: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] +three_to_six: nums[3, 6] \ No newline at end of file diff --git a/documentation/cs/strings.cs b/documentation/cs/strings.cs new file mode 100644 index 00000000..335d702b --- /dev/null +++ b/documentation/cs/strings.cs @@ -0,0 +1,6 @@ +moby_dick: "Call me Ishmael. Some years ago -- +never mind how long precisely -- having little +or no money in my purse, and nothing particular +to interest me on shore, I thought I would sail +about a little and see the watery part of the +world..." \ No newline at end of file diff --git a/documentation/cs/super.cs b/documentation/cs/super.cs new file mode 100644 index 00000000..21c89a26 --- /dev/null +++ b/documentation/cs/super.cs @@ -0,0 +1,21 @@ +Animal: => . +Animal.prototype.move: meters => + alert(this.name + " moved " + meters + "m."). + +Snake: name => this.name: name. +Snake extends new Animal() +Snake.prototype.move: => + alert("Slithering...") + super(5). + +Horse: name => this.name: name. +Horse extends new Animal() +Horse.prototype.move: => + alert("Galloping...") + super(45). + +sam: new Snake("Sammy the Python") +tom: new Horse("Tommy the Palomino") + +sam.move() +tom.move() diff --git a/documentation/cs/switch.cs b/documentation/cs/switch.cs new file mode 100644 index 00000000..41bf9045 --- /dev/null +++ b/documentation/cs/switch.cs @@ -0,0 +1,7 @@ +switch day +case "Tuesday" then eat_breakfast() +case "Wednesday" then go_to_the_park() +case "Saturday" + if day is bingo_day then go_to_bingo(). +case "Sunday" then go_to_church() +else go_to_work(). \ No newline at end of file diff --git a/documentation/cs/try.cs b/documentation/cs/try.cs new file mode 100644 index 00000000..6664bbd1 --- /dev/null +++ b/documentation/cs/try.cs @@ -0,0 +1,7 @@ +try + all_hell_breaks_loose() + cats_and_dogs_living_together() +catch error + print( error ) +finally + clean_up(). \ No newline at end of file diff --git a/documentation/cs/while.cs b/documentation/cs/while.cs new file mode 100644 index 00000000..ab0a850a --- /dev/null +++ b/documentation/cs/while.cs @@ -0,0 +1,5 @@ +while demand > supply + sell() + restock(). + +while supply > demand then buy(). \ No newline at end of file diff --git a/documentation/css/docs.css b/documentation/css/docs.css index f50ad3b1..cd45d0a8 100644 --- a/documentation/css/docs.css +++ b/documentation/css/docs.css @@ -1,40 +1,34 @@ body { - font-size: 16px; - line-height: 24px; - background: #f0f0e5; - color: #252519; - font-family: "Palatino Linotype", "Book Antiqua", Palatino, FreeSerif, serif; + font-size: 14px; + line-height: 20px; + background: #efefef; + color: #191933; + font-family: Arial, Helvetica, sans-serif; } div.container { - width: 720px; + width: 850px; margin: 50px 0 50px 50px; } p { - width: 550px; + padding-left: 13px; + width: 625px; } - #documentation p { - margin-bottom: 4px; - } -a, a:visited { - padding: 0 2px; - text-decoration: none; - background: #dadaba; - color: #252519; -} -a:active, a:hover { - color: #000; - background: #f0c095; +a { + color: #000055; } h1, h2, h3, h4, h5, h6 { + padding-left: 13px; margin-top: 40px; } -b.header { - font-size: 18px; +br.clear { + height: 0; + clear: both; } -span.alias { - font-size: 14px; - font-style: italic; - margin-left: 20px; +b.header { + color: #000055; + display: block; + margin: 40px 0 5px 0; + font-size: 16px; } table, tr, td { margin: 0; padding: 0; @@ -53,7 +47,24 @@ code, pre, tt { } pre { font-size: 12px; - padding: 2px 0 2px 12px; - border-left: 6px solid #aaaa99; - margin: 0px 0 30px; + padding: 0 0 0 12px; + margin: 0; + width: 410px; + float: left; + border-left: 1px dotted #559; + } + pre:first-child { + border-left: 0; + } +div.code { + position: relative; + border: 1px solid #cacaca; + background: #fff; + padding: 7px 0 10px 0; + -moz-border-radius: 5px; -webkit-border-radius: 5px; border-radius: 5px; + -webkit-box-shadow: 0px 0px 7px #cacaca; +} + div.code button { + position: absolute; + right: 8px; bottom: 8px; } \ No newline at end of file diff --git a/documentation/index.html.erb b/documentation/index.html.erb index 5ea6ffde..d571d13a 100644 --- a/documentation/index.html.erb +++ b/documentation/index.html.erb @@ -1,26 +1,222 @@ +<% + require 'uv' + def code_for(file, executable=false) + @stripper ||= /(\A\(function\(\)\{\n|\}\)\(\);\Z|^ )/ + cs = File.read("documentation/cs/#{file}.cs") + js = File.read("documentation/js/#{file}.js").gsub(@stripper, '') + cshtml = Uv.parse(cs, 'xhtml', 'coffeescript', false, 'idle', false) + jshtml = Uv.parse(js, 'xhtml', 'javascript', false, 'idle', false) + append = executable == true ? '' : "alert(#{executable});" + run = executable == true ? 'run' : "run: #{executable}" + button = executable ? "" : '' + "
CoffeeScript is a little language that compiles into JavaScript. Think of it as JavaScript's simpleminded kid brother — the same genes, - the same accent, but another kind of way of doing things. + the same accent, but a different sense of style. Apart from a handful of + bonus goodies, statements in CoffeeScript correspond one-to-one with their + JavaScript equivalent, it's just another way of saying it.
- + + +
-
+ Disclaimer:
+ CoffeeScript is just for fun and seriously alpha. There is no guarantee,
+ explicit or implied, of its suitability for any purpose. That said, it
+ compiles into pretty-printed JavaScript (the good parts) that can pass through
+ JSLint warning-free.
+ + This document is structured so that it can be read from top to bottom, + if you like. Later sections use ideas and syntax previously introduced. + +
+ +
+ Punctuation Primer
+ Functions and Invocation
+ Objects and Arrays
+ Assignment
+ Lexical Scoping and Variable Safety
+ Conditionals, Ternaries, and Conditional Assignment
+ Everything is an Expression
+ While Loops
+ Array Comprehensions
+ Array Slice Literals
+ Inheritance, and Calling Super from a Subclass
+ Embedded JavaScript
+ Switch/Case/Else
+ Try/Catch/Finally
+ Multiline Strings
+
+ In all of the following examples, the source CoffeeScript is provided on + the left, and the direct compilation into JavaScript is on the right. +
+ ++ Punctuation Primer + You don't need to use semicolons to (;) terminate expressions, ending + the line will do just as well. So newlines can matter, but whitespace is + not otherwise significant. Instead of using curly braces ({ }) + to delimit blocks of code, a period (.) marks the end of a + function, if statement, or try/catch. +
+ + ++ Functions and Invocation + Let's start with the best part, shall we? Function literals are my + absolute favorite thing about CoffeeScript. +
+ <%= code_for('functions', 'cube(5)') %> + ++ Objects and Arrays + Object and Array literals look very similar. When you spread out + each assignment on a separate line, the commas are optional. +
+ <%= code_for('objects_and_arrays', 'song.join(",")') %> ++
+ ++ Assignment + All assignment in CoffeeScript, whether to a variable or to an object + property, uses a colon. Equal signs are only needed for mathy things. +
+ <%= code_for('assignment', 'greeting') %> ++
+ ++ Lexical Scoping and Variable Safety + The CoffeeScript compiler takes care to make sure that all of your variables + are properly defined within lexical scope — you never need to declare + var yourself. +
+ <%= code_for('scope', 'new_num') %> ++ Notice how the variables are declared with var the first time + they appear. The second reference of num, within the function, + is not redeclared because num is still in scope. As opposed + to the second new_num, in the last line. +
+ ++ Conditionals, Ternaries, and Conditional Assignment +
+ <%= code_for('conditionals') %> ++
+ ++ Everything is an Expression + You might have noticed how even though we don't add return statements + to CoffeScript functions, they nonetheless return their final value. + The CoffeeScript compiler tries to make sure that every little language + construct can be used as an expression. +
+ <%= code_for('expressions', 'eldest') %> ++ When compiling a function definition, CoffeeScript tries to push down + the return statement to each of the potential final lines of the function. + It uses the same mechanism to push down assignment statements. If statement + are compiled into ternary operators when possible, so that they can be used + as expressions. +
+ ++ While Loops + The only low-level loop that CoffeeScript provides is the while loop. +
+ <%= code_for('while') %> + ++ Array Comprehensions + Most of your looping needs should be handled by array comprehensions. + They replace (and compile into) for loops, handling + each/forEach style loops, as well as select/filter. + Unlike for loops, array comprehensions are expressions, and can be returned + and assigned. +
+ <%= code_for('array_comprehensions') %> + ++ Array Slice Literals + CoffeeScript includes a literal syntax for extracting slices of arrays. + The first argument is the index of the first element in the slice, and + the second is the index of the last one. +
+ <%= code_for('slices', 'three_to_six') %> + ++ Inheritance, and Calling Super from a Subclass + JavaScript's prototypal inheritance has always been a bit of a + brain-bender, with a whole family tree of libraries (Base2, Prototype + ). +
+ <%= code_for('super', true) %> + ++ Embedded JavaScript + If you ever need to interpolate literal JavaScript snippets, you can + use backticks to pass JavaScript straight through. +
+ <%= code_for('embedded', true) %> + ++ Switch/Case/Else + Switch statements in JavaScript are fundamentally broken. You can only + do string comparisons, and need to break at the end of each case + statment to prevent falling through to the default case. CoffeeScript + compiles switch statements into if-else chains, allowing you to + compare any object (via ===), preventing fall-through, and resulting + in a returnable expression. +
+ <%= code_for('switch') %> + ++ Try/Catch/Finally + Try/catch statements just about the same as JavaScript (although + they work as expressions). No braces required. +
+ <%= code_for('try') %> + ++ Multiline Strings + Multiline strings are allowed in CoffeeScript. +
+ <%= code_for('strings') %> + +CoffeeScript is a little language that compiles into JavaScript. Think of it as JavaScript's simpleminded kid brother — the same genes, - the same accent, but another kind of way of doing things. + the same accent, but a different sense of style. Apart from a handful of + bonus goodies, statements in CoffeeScript correspond one-to-one with their + JavaScript equivalent, it's just another way of saying it.
+ + +
+ Disclaimer:
+ CoffeeScript is just for fun and seriously alpha. There is no guarantee,
+ explicit or implied, of its suitability for any purpose. That said, it
+ compiles into pretty-printed JavaScript (the good parts) that can pass through
+ JSLint warning-free.
+
+ + This document is structured so that it can be read from top to bottom, + if you like. Later sections use ideas and syntax previously introduced. + +
+ +
+ Punctuation Primer
+ Functions and Invocation
+ Objects and Arrays
+ Assignment
+ Lexical Scoping and Variable Safety
+ Conditionals, Ternaries, and Conditional Assignment
+ Everything is an Expression
+ While Loops
+ Array Comprehensions
+ Array Slice Literals
+ Inheritance, and Calling Super from a Subclass
+ Embedded JavaScript
+ Switch/Case/Else
+ Try/Catch/Finally
+ Multiline Strings
+
+ In all of the following examples, the source CoffeeScript is provided on + the left, and the direct compilation into JavaScript is on the right. +
+ ++ Punctuation Primer + You don't need to use semicolons to (;) terminate expressions, ending + the line will do just as well. So newlines can matter, but whitespace is + not otherwise significant. Instead of using curly braces ({ }) + to delimit blocks of code, a period (.) marks the end of a + function, if statement, or try/catch. +
+ + ++ Functions and Invocation + Let's start with the best part, shall we? Function literals are my + absolute favorite thing about CoffeeScript. +
+square: x => x * x. +cube: x => square(x) * x. +
var square = function(x) { + return x * x; +}; +var cube = function(x) { + return square(x) * x; +}; +
+ Objects and Arrays + Object and Array literals look very similar. When you spread out + each assignment on a separate line, the commas are optional. +
+song: ["do", "re", "mi", "fa", "so"] +ages: { + max: 10 + ida: 9 + tim: 11 +} +
var song = ["do", "re", "mi", "fa", "so"]; +var ages = { + max: 10, + ida: 9, + tim: 11 +}; +
+
+ ++ Assignment + All assignment in CoffeeScript, whether to a variable or to an object + property, uses a colon. Equal signs are only needed for mathy things. +
+greeting: "Hello CoffeeScript" +difficulty: 0.5 +
var greeting = "Hello CoffeeScript"; +var difficulty = 0.5; +
+
+ ++ Lexical Scoping and Variable Safety + The CoffeeScript compiler takes care to make sure that all of your variables + are properly defined within lexical scope — you never need to declare + var yourself. +
+num: 1 +change_numbers: => + num: 2 + new_num: 3. +new_num: change_numbers() +
var num = 1; +var change_numbers = function() { + num = 2; + var new_num = 3; + return new_num; +}; +var new_num = change_numbers(); +
+ Notice how the variables are declared with var the first time + they appear. The second reference of num, within the function, + is not redeclared because num is still in scope. As opposed + to the second new_num, in the last line. +
+ ++ Conditionals, Ternaries, and Conditional Assignment +
+mood: greatly_improved if singing + +if happy and knows_it + claps_hands() + cha_cha_cha(). + +date: if friday then sue else jill. + +expensive ||= do_the_math() +
var mood; +if (singing) { + mood = greatly_improved; +} +if (happy && knows_it) { + claps_hands(); + cha_cha_cha(); +} +var date = friday ? sue : jill; +expensive = expensive || do_the_math(); +
+
+ ++ Everything is an Expression + You might have noticed how even though we don't add return statements + to CoffeScript functions, they nonetheless return their final value. + The CoffeeScript compiler tries to make sure that every little language + construct can be used as an expression. +
+grade: student => + if student.excellent_work + "A+" + else if student.okay_stuff + "B" + else + "C".. + +eldest: if 24 > 21 then "Liz" else "Ike". +
var grade = function(student) { + if (student.excellent_work) { + return "A+"; + } else if (student.okay_stuff) { + return "B"; + } else { + return "C"; + } +}; +var eldest = 24 > 21 ? "Liz" : "Ike"; +
+ When compiling a function definition, CoffeeScript tries to push down + the return statement to each of the potential final lines of the function. + It uses the same mechanism to push down assignment statements. If statement + are compiled into ternary operators when possible, so that they can be used + as expressions. +
+ ++ While Loops + The only low-level loop that CoffeeScript provides is the while loop. +
+while demand > supply + sell() + restock(). + +while supply > demand then buy(). +
while (demand > supply) { + sell(); + restock(); +} +while (supply > demand) { + buy(); +} +
+ Array Comprehensions + Most of your looping needs should be handled by array comprehensions. + They replace (and compile into) for loops, handling + each/forEach style loops, as well as select/filter. + Unlike for loops, array comprehensions are expressions, and can be returned + and assigned. +
+# Eat lunch. +lunch: food.eat() for food in ['toast', 'cheese', 'wine']. + +# Zebra-stripe a table. +highlight(row) for row, i in table if i % 2 is 0. +
var lunch; +var a = ['toast', 'cheese', 'wine']; +var d = []; +for (var b=0, c=a.length; b<c; b++) { + var food = a[b]; + d[b] = food.eat(); +} +lunch = d; +var e = table; +for (var f=0, g=e.length; f<g; f++) { + var row = e[f]; + var i = f; + i % 2 === 0 ? highlight(row) : null; +} +
+ Array Slice Literals + CoffeeScript includes a literal syntax for extracting slices of arrays. + The first argument is the index of the first element in the slice, and + the second is the index of the last one. +
+nums: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] +three_to_six: nums[3, 6] +
var nums = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; +var three_to_six = nums.slice(3, 6 + 1); +
+ Inheritance, and Calling Super from a Subclass + JavaScript's prototypal inheritance has always been a bit of a + brain-bender, with a whole family tree of libraries (Base2, Prototype + ). +
+Animal: => . +Animal.prototype.move: meters => + alert(this.name + " moved " + meters + "m."). + +Snake: name => this.name: name. +Snake extends new Animal() +Snake.prototype.move: => + alert("Slithering...") + super(5). + +Horse: name => this.name: name. +Horse extends new Animal() +Horse.prototype.move: => + alert("Galloping...") + super(45). + +sam: new Snake("Sammy the Python") +tom: new Horse("Tommy the Palomino") + +sam.move() +tom.move() +
var Animal = function() { + +}; +Animal.prototype.move = function(meters) { + return alert(this.name + " moved " + meters + "m."); +}; +var Snake = function(name) { + this.name = name; +}; +Snake.prototype = new Animal(); +Snake.prototype.move = function() { + alert("Slithering..."); + return this.constructor.prototype.move.call(this, 5); +}; +var Horse = function(name) { + this.name = name; +}; +Horse.prototype = new Animal(); +Horse.prototype.move = function() { + alert("Galloping..."); + return this.constructor.prototype.move.call(this, 45); +}; +var sam = new Snake("Sammy the Python"); +var tom = new Horse("Tommy the Palomino"); +sam.move(); +tom.move(); +
+ Embedded JavaScript + If you ever need to interpolate literal JavaScript snippets, you can + use backticks to pass JavaScript straight through. +
+js: => `alert("Hello JavaScript");`. + +js() if 10 > 9 +
var js = function() { + return alert("Hello JavaScript"); +}; +if (10 > 9) { + js(); +} +
+ Switch/Case/Else + Switch statements in JavaScript are fundamentally broken. You can only + do string comparisons, and need to break at the end of each case + statment to prevent falling through to the default case. CoffeeScript + compiles switch statements into if-else chains, allowing you to + compare any object (via ===), preventing fall-through, and resulting + in a returnable expression. +
+switch day +case "Tuesday" then eat_breakfast() +case "Wednesday" then go_to_the_park() +case "Saturday" + if day is bingo_day then go_to_bingo(). +case "Sunday" then go_to_church() +else go_to_work(). +
if (day === "Tuesday") { + eat_breakfast(); +} else if (day === "Wednesday") { + go_to_the_park(); +} else if (day === "Saturday") { + day === bingo_day ? go_to_bingo() : null; +} else if (day === "Sunday") { + go_to_church(); +} else { + go_to_work(); +} +
+ Try/Catch/Finally + Try/catch statements just about the same as JavaScript (although + they work as expressions). No braces required. +
+try + all_hell_breaks_loose() + cats_and_dogs_living_together() +catch error + print( error ) +finally + clean_up(). +
try { + all_hell_breaks_loose(); + cats_and_dogs_living_together(); +} catch (error) { + print(error); +} finally { + clean_up(); +} +
+ Multiline Strings + Multiline strings are allowed in CoffeeScript. +
+moby_dick: "Call me Ishmael. Some years ago -- +never mind how long precisely -- having little +or no money in my purse, and nothing particular +to interest me on shore, I thought I would sail +about a little and see the watery part of the +world..." +
var moby_dick = "Call me Ishmael. Some years ago --\ +never mind how long precisely -- having little\ +or no money in my purse, and nothing particular\ +to interest me on shore, I thought I would sail\ +about a little and see the watery part of the\ +world..."; +