From c9d17ba1ff71ec72e9546afc20759a0573566e47 Mon Sep 17 00:00:00 2001 From: onlyjsmith Date: Fri, 23 Nov 2012 10:18:14 +0000 Subject: [PATCH 01/98] Solution was giving wrong answer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Have tested this in Chrome 23, Firefox 17 and Opera 12. This SO page also relates http://stackoverflow.com/questions/222309/calculate-last-day-of-month-in-javascript --- chapters/dates_and_times/finding-last-day-of-the-month.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/chapters/dates_and_times/finding-last-day-of-the-month.md b/chapters/dates_and_times/finding-last-day-of-the-month.md index c054afd..98ccec6 100644 --- a/chapters/dates_and_times/finding-last-day-of-the-month.md +++ b/chapters/dates_and_times/finding-last-day-of-the-month.md @@ -13,9 +13,9 @@ Use JavaScript's Date underflow to find the -1th day of the following month: {% highlight coffeescript %} now = new Date -lastDayOfTheMonth = new Date(1900+now.getYear(), now.getMonth()+1, -1) +lastDayOfTheMonth = new Date(1900+now.getYear(), now.getMonth()+1, 0) {% endhighlight %} ## Discussion -JavaScript's Date constructor cheerfully handles overflow and underflow conditions, which makes date math very easy. Given this ease of manipulation, it doesn't make sense to worry about how many days are in a given month; just nudge the math around. In December, the solution above will actually ask for the -1th day of the 13th month of the current year, which works out to the -1th day of January of NEXT year, which works out to the 31st day of December of the current year. +JavaScript's Date constructor cheerfully handles overflow and underflow conditions, which makes date math very easy. Given this ease of manipulation, it doesn't make sense to worry about how many days are in a given month; just nudge the math around. In December, the solution above will actually ask for the 0th day of the 13th month of the current year, which works out to the day before the 1st day of January of NEXT year, which works out to the 31st day of December of the current year. From 12d5623d7ebfa5b9875577a272ba372f1b906434 Mon Sep 17 00:00:00 2001 From: Devin Weaver Date: Wed, 26 Dec 2012 17:18:37 -0500 Subject: [PATCH 02/98] Refactors the code in the singlton design pattern The original code was a little misleading and it also would compile with a runtime error. This offers a new version that illistrates the use of closures inside a class definition. It also provides an example of how to handle modules (including private classes) The two example together illistrate some of the flexability and elegance CoffeeScript can offer. It also explains how the use of the wrapper around a CS file. --- chapters/design_patterns/singleton.md | 96 ++++++++++++++++----------- 1 file changed, 56 insertions(+), 40 deletions(-) diff --git a/chapters/design_patterns/singleton.md b/chapters/design_patterns/singleton.md index 4f40859..18bbf27 100644 --- a/chapters/design_patterns/singleton.md +++ b/chapters/design_patterns/singleton.md @@ -7,59 +7,75 @@ chapter: Design Patterns Many times you only want one, and only one, instance of a class. For example, you may only need one class that creates server resources and you want to ensure that the one object can control those resources. Beware, however, because the singleton pattern can be easily abused to mimic unwanted global variables. + ## Solution The publicly available class only contains the method to get the one true instance. The instance is kept within the closure of that public object and is always returned. -The actual definition of the singleton class follows. +This is works because CoffeeScript allows you to define executable statements inside a class definition. However, because most CoffeeScript compiles into a [IIFE][] wrapper you do not have to place the private class inside the class definition if this style suits you. The later might be useful when developing modular code such as found in [CommonJS][] (Node.js) or [Require.js][] (See the discussion for an example). -Note that I am using the idiomatic module export feature to emphasize the publicly accessible portion of the module. Remember coffeescript wraps all files in a function block to protect the global namespace. +[IIFE]: http://benalman.com/news/2010/11/immediately-invoked-function-expression/ +[CommonJS]: http://www.commonjs.org/ +[Require.js]: http://requirejs.org/ {% highlight coffeescript %} -root = exports ? this # http://stackoverflow.com/questions/4214731/coffeescript-global-variables - -# The publicly accessible Singleton fetcher -class root.Singleton - _instance = undefined # Must be declared here to force the closure on the class - @get: (args) -> # Must be a static method - _instance ?= new _Singleton args - -# The actual Singleton class -class _Singleton - constructor: (@args) -> - - echo: -> - @args - -a = root.Singleton.get 'Hello A' -a.echo() -# => 'Hello A' - -b = root.Singleton.get 'Hello B' -a.echo() -# => 'Hello A' +class Singleton + # You can add statements inside the class definition + # which helps establish private scope (due to closures) + # instance is defined as null to force correct scope + instance = null + # Create a private class that we can initialize however + # defined inside this scope to force the use of the + # singleton class. + class PrivateClass + constructor: (@message) -> + echo: -> @message + # This is a static method used to either retrieve the + # instance or create a new one. + @get: (message) -> + instance ?= new PrivateClass(message) + +a = Singleton.get "Hello A" +a.echo() # => "Hello A" + +b = Singleton.get "Hello B" +b.echo() # => "Hello A" + +Singleton.instance # => undefined +a.instance # => undefined +Singleton.PrivateClass # => undefined +{% endhighlight %} -b.echo() -# => 'Hello A' -root.Singleton._instance -# => undefined +## Discussion -root.Singleton._instance = 'foo' +See in the above example how all instances are outputting from the same instance of the Singleton class. You can also see that the PrivateClass and instance variable are not accessible outside the Singleton class. In essance the Singleton class provides a static method get which returns only one instance of PrivateClass and only one. It also hides the PrivateClass from the world so that you can not create your own. -root.Singleton._instance -# => 'foo' +The idea of hiding or making private the inner workings is preference. Especially since by default CoffeeScript wraps the compiled code inside it's own IIFE (closure) allowing you to define classes without worry that it might be accessible from outside the file. In this example, note that I am using the idiomatic module export feature to emphasize the publicly accessible portion of the module. (See this discussion for further explanation on [exporting to the global namespace][1]). -c = root.Singleton.get 'Hello C' -c.foo() -# => 'Hello A' +[1]: http://stackoverflow.com/questions/4214731/coffeescript-global-variables -a.foo() -# => 'Hello A' +{% highlight coffeescript %} +root = exports ? this + +# Create a private class that we can initialize however +# defined inside the wrapper scope. +class ProtectedClass + constructor: (@message) -> + echo: -> @message + +class Singleton + # You can add statements inside the class definition + # which helps establish private scope (due to closures) + # instance is defined as null to force correct scope + instance = null + # This is a static method used to either retrieve the + # instance or create a new one. + @get: (message) -> + instance ?= new ProtectedClass(message) + +# Export Singleton as a module +root.Singleton = Singleton {% endhighlight %} -## Discussion - -See in the above example how all instances are outputting from the same instance of the Singleton class. - Note how incredibly simple coffeescript makes this design pattern. For reference and discussion on nice javascript implementations, check out [Essential JavaScript Design Patterns For Beginners](http://addyosmani.com/resources/essentialjsdesignpatterns/book/). From aa07fbd7132b6aa0893908c64d2ad36d54fe6e06 Mon Sep 17 00:00:00 2001 From: Kolja Date: Fri, 18 Jan 2013 12:28:59 +0100 Subject: [PATCH 03/98] Update chapters/jquery/plugin.md --- chapters/jquery/plugin.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/jquery/plugin.md b/chapters/jquery/plugin.md index 481d00e..df95cf1 100644 --- a/chapters/jquery/plugin.md +++ b/chapters/jquery/plugin.md @@ -46,7 +46,7 @@ Here are a couple of examples of how to use your new plugin. {% highlight javascript %} $("body").pluginName({ debug: true -}; +}); {% endhighlight %} From 19d514dfd3cd7096bd42b7c106c70ed2009f1c74 Mon Sep 17 00:00:00 2001 From: wangyang Date: Wed, 30 Jan 2013 10:42:11 +0800 Subject: [PATCH 04/98] fix bug 1."Math.min l1, l2 == 0" is equivalent to "Math.min(l1, (l2 == 0))".I think this is not the author would like to express. 2."[0...l1 + 1]" is equivalent to "[0..l1]". --- chapters/strings/matching-strings.md | 87 ++++++++++++++-------------- 1 file changed, 42 insertions(+), 45 deletions(-) diff --git a/chapters/strings/matching-strings.md b/chapters/strings/matching-strings.md index 100aefa..ecc18a0 100644 --- a/chapters/strings/matching-strings.md +++ b/chapters/strings/matching-strings.md @@ -1,45 +1,42 @@ ---- -layout: recipe -title: Matching Strings -chapter: Strings ---- -## Problem - -You want to match two or more strings. - -## Solution - -Calculate the edit distance, or number of operations required to transform one string into the other. - -{% highlight coffeescript %} - -Levenshtein = - (str1, str2) -> - - l1 = str1.length - l2 = str2.length - - Math.max l1, l2 if Math.min l1, l2 == 0 - - i = 0; j = 0; distance = [] - - for i in [0...l1 + 1] - distance[i] = [] - distance[i][0] = i - - distance[0][j] = j for j in [0...l2 + 1] - - for i in [1...l1 + 1] - for j in [1...l2 + 1] - distance[i][j] = Math.min distance[i - 1][j] + 1, - distance[i][j - 1] + 1, - distance[i - 1][j - 1] + - if (str1.charAt i - 1) == (str2.charAt j - 1) then 0 else 1 - - distance[l1][l2] - -{% endhighlight %} - -## Discussion - -You can use either Hirschberg or Wagner–Fischer's algorithm to calculate a Levenshtein distance. This example uses Wagner–Fischer's algorithm. +--- +layout: recipe +title: Matching Strings +chapter: Strings +--- +## Problem + +You want to match two or more strings. + +## Solution + +Calculate the edit distance, or number of operations required to transform one string into the other. + +{% highlight coffeescript %} + +Levenshtein = + (str1, str2) -> + + l1 = str1.length + l2 = str2.length + + return Math.max l1, l2 unless l1 and l2 + + i = 0; j = 0; distance = [] + + distance[i] = [i] for i in [0..l1] + distance[0][j] = j for j in [0..l2] + + for i in [1..l1] + for j in [1..l2] + distance[i][j] = Math.min distance[i - 1][j] + 1, + distance[i][j - 1] + 1, + distance[i - 1][j - 1] + + if (str1.charAt i - 1) is (str2.charAt j - 1) then 0 else 1 + + distance[l1][l2] + +{% endhighlight %} + +## Discussion + +You can use either Hirschberg or Wagner–Fischer's algorithm to calculate a Levenshtein distance. This example uses Wagner–Fischer's algorithm. From c94b78a51873d6dcf66370182c69c434fe51486f Mon Sep 17 00:00:00 2001 From: Paul Masurel Date: Thu, 31 Jan 2013 02:08:01 +0100 Subject: [PATCH 05/98] Levenshtein, programming style MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The version before this commit was I believe correct. I would therefore totally understand if this pull request was rejected. However I think levenshtein provides a very nice example to demonstrate some of the functionality and pitfalls of coffeescript. First I am not too fond of the "return unless" statement. It feels a bit uncanny to find a non indented return in the middle of a function. Most important I am not fond of what this statement is trying to hide. In most languages, checking for the empty string is not useful.  see Discussion section. --- chapters/strings/matching-strings.md | 43 ++++++++++++++++------------ 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/chapters/strings/matching-strings.md b/chapters/strings/matching-strings.md index ecc18a0..1f16f05 100644 --- a/chapters/strings/matching-strings.md +++ b/chapters/strings/matching-strings.md @@ -13,30 +13,37 @@ Calculate the edit distance, or number of operations required to transform one s {% highlight coffeescript %} -Levenshtein = - (str1, str2) -> - + levenshtein = (str1, str2) -> + l1 = str1.length l2 = str2.length + prevDist = [0..l2] + nextDist = [0..l2] + + for i in [1..l1] by 1 + nextDist[0] = i + for j in [1..l2] by 1 + if (str1.charAt i-1) == (str2.charAt j-1) + nextDist[j] = prevDist[j-1] + else + nextDist[j] = 1 + Math.min prevDist[j], nextDist[j-1], prevDist[j-1] + [prevDist,nextDist]=[nextDist, prevDist] + + prevDist[l2] - return Math.max l1, l2 unless l1 and l2 +{% endhighlight %} - i = 0; j = 0; distance = [] +## Discussion - distance[i] = [i] for i in [0..l1] - distance[0][j] = j for j in [0..l2] +You can use either Hirschberg or Wagner–Fischer's algorithm to calculate a Levenshtein distance. This example uses Wagner–Fischer's algorithm. - for i in [1..l1] - for j in [1..l2] - distance[i][j] = Math.min distance[i - 1][j] + 1, - distance[i][j - 1] + 1, - distance[i - 1][j - 1] + - if (str1.charAt i - 1) is (str2.charAt j - 1) then 0 else 1 +This version of Levenshtein algorithm is linear in memory, quadratic in time. - distance[l1][l2] - -{% endhighlight %} +str.charAt i is preferred here to str[i] because the latter syntax is not supported by some browsers (e.g. IE7). -## Discussion +At first glance the use of "by 1" in the two loops might look useless. It is actually here to avoid a common danger +of the coffeescript [i..j] syntax. If str1 or str2 is an empty string, then [1..l1] or [1..l2] will return [1,0]. +The loops with the "by 1" statement also compiles to cleaner / slightly more performant javascript. -You can use either Hirschberg or Wagner–Fischer's algorithm to calculate a Levenshtein distance. This example uses Wagner–Fischer's algorithm. +Finally the optimization of recycling of arrays at the end of the loops is mainly here to +demonstrate the syntax of coffeescript for swapping two variables. From 3565f28456775cfec79e770f1e728601a9b93f21 Mon Sep 17 00:00:00 2001 From: ZhiCun Date: Thu, 31 Jan 2013 13:49:34 +0800 Subject: [PATCH 06/98] spelling mistake the `function` in "You'd like to know the type of a function without using typeof. " must be `object`. --- chapters/classes_and_objects/type-function.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/classes_and_objects/type-function.md b/chapters/classes_and_objects/type-function.md index 6a7f9b8..42952ac 100644 --- a/chapters/classes_and_objects/type-function.md +++ b/chapters/classes_and_objects/type-function.md @@ -5,7 +5,7 @@ chapter: Classes and Objects --- ## Problem -You'd like to know the type of a function without using typeof. (See http://javascript.crockford.com/remedial.html for more information on why typeof is pretty inferior.) +You'd like to know the type of a object without using typeof. (See http://javascript.crockford.com/remedial.html for more information on why typeof is pretty inferior.) ## Solution From f1d710e78ca0dde34a3bffb265bc93125e9689f4 Mon Sep 17 00:00:00 2001 From: "derek.lee" Date: Mon, 25 Feb 2013 21:06:20 -0700 Subject: [PATCH 07/98] Added a line break to the ajax call so "error:" would be on it's own line. --- chapters/jquery/ajax.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/chapters/jquery/ajax.md b/chapters/jquery/ajax.md index e5563fa..97d0769 100644 --- a/chapters/jquery/ajax.md +++ b/chapters/jquery/ajax.md @@ -25,7 +25,8 @@ $(document).ready -> # Advanced Settings $.ajax '/', type: 'GET' - dataType: 'html' error: (jqXHR, textStatus, errorThrown) -> + dataType: 'html' + error: (jqXHR, textStatus, errorThrown) -> $('body').append "AJAX Error: #{textStatus}" success: (data, textStatus, jqXHR) -> $('body').append "Successful AJAX call: #{data}" From fa13f3bd8ee0eaffe05a721c00b0707b9d41484b Mon Sep 17 00:00:00 2001 From: d8uv Date: Thu, 28 Feb 2013 11:03:08 -0900 Subject: [PATCH 08/98] Change the shuffle to the Fisher-Yates shuffle MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The current "Shuffling Array Elements" page recommends a naive algorithm, which produces  a slow and biased shuffle. Included is a highly idiomatic refactorization of the Fisher- Yates shuffle (aka the Knuth Shuffle), a less-idiomatic-but-better refactorization, and a version of the algorithm that adds to Array.prototype, for those that program in that  style. --- chapters/arrays/shuffling-array-elements.md | 87 +++++++++++++++++++-- 1 file changed, 82 insertions(+), 5 deletions(-) diff --git a/chapters/arrays/shuffling-array-elements.md b/chapters/arrays/shuffling-array-elements.md index 9f2f8e9..7963ac4 100644 --- a/chapters/arrays/shuffling-array-elements.md +++ b/chapters/arrays/shuffling-array-elements.md @@ -9,17 +9,94 @@ You want to shuffle the elements in an array. ## Solution -The JavaScript Array `sort()` method accepts a custom sort function. We can write a `shuffle()` method to add some convenience. +The [Fisher-Yates shuffle] is a highly efficient and completely unbiased way to randomize +the elements in an array. It's a fairly simple method: Start at the end of the list, and +swap the last element with a random element from earlier in the list. Go down one and +repeat, until you're at the beginning of the list, with all of the shuffled elements +at the end of the list. This [Fisher-Yates shuffle Visualization] may help you understand +the algorithm. {% highlight coffeescript %} -Array::shuffle = -> @sort -> 0.5 - Math.random() +shuffle = (a) -> + # From the end of the list to the beginning, pick element `i`. + for i in [a.length-1..1] + # Choose random element `j` to the front of `i` to swap with. + j = Math.floor Math.random() * (i + 1) + # Swap `j` with `i`, using destructured assignment + [a[i], a[j]] = [a[j], a[i]] + # Return the shuffled array. + a -[1..9].shuffle() +shuffle([1..9]) # => [ 3, 1, 5, 6, 4, 8, 2, 9, 7 ] {% endhighlight %} +[Fisher-Yates shuffle]: http://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle +[Fisher-Yates Shuffle Visualization]: http://bost.ocks.org/mike/shuffle/ + ## Discussion -For more background on how this shuffle logic works, see this [discussion at StackOverflow](http://stackoverflow.com/questions/962802/is-it-correct-to-use-javascript-array-sort-method-for-shuffling). +### The Wrong Way to do it + +There is a common--but terribly wrong way--to shuffle an array, by sorting by a random +number. + +{% highlight coffeescript %} +shuffle = (a) -> a.sort -> 0.5 - Math.random() +{% endhighlight %} + +If you do a sort randomly, it should give you a random order, right? Even [Microsoft used +this random-sort algorithm][msftshuffle]. Turns out, [this random-sort algorithm produces +biased results][naive], because it only has the illusion of shuffling. Randomly sorting +will not result in a neat, tidy shuffle; it will result in a wild mass of inconsistent +sorting. + +[msftshuffle]: http://www.robweir.com/blog/2010/02/microsoft-random-browser-ballot.html +[naive]: http://www.codinghorror.com/blog/2007/12/the-danger-of-naivete.html + +### Optimizing for speed and space + +The solution above isn't as fast, or as lean, as it can be. The list comprehension, when +transformed into Javascript, is far more complex than it needs to be, and the +destructured assignment is far slower than dealing with bare variables. The following +code is less idiomatic, and takes up more source-code space... but will compile down +smaller and run a bit faster: + +{% highlight coffeescript %} +shuffle = (a) -> + i = a.length + while --i > 0 + j = ~~(Math.random() * (i + 1)) # ~~ is a common optimization for Math.floor + t = a[j] + a[j] = a[i] + a[i] = t + a +{% endhighlight %} + +### Extending Javascript to include this shuffle. + +The following code adds the shuffle function to the Array prototype, which means that +you are able to run it on any array you wish, in a much more direct manner. + +{% highlight coffeescript %} +Array::shuffle = -> + for i in [@length-1..1] + j = Math.floor Math.random() * (i + 1) + [@[i], @[j]] = [@[j], @[i]] + @ + +[1..9].shuffle() +# => [ 3, 1, 5, 6, 4, 8, 2, 9, 7 ] +{% endhighlight %} + +**Note:** Although it's quite common in languages like Ruby, extending native objects is +often considered bad practice in JavaScript (see: [Maintainable JavaScript: Don’t modify +objects you don’t own][dontown]; [Extending built-in native objects. Evil or not?] +[extendevil]). + +Also, if you think you'll be using a lot of these utility functions, consider using a +utility library, like [Lo-dash](http://lodash.com/). They include a lot of nifty +features, like maps and forEach, in a cross-browser, lean, high-performance way. -**Note:** Although it's quite common in languages like Ruby, extending native objects is often considered bad practice in JavaScript (see: [Maintainable JavaScript: Don’t modify objects you don’t own](http://www.nczonline.net/blog/2010/03/02/maintainable-javascript-dont-modify-objects-you-down-own/); [Extending built-in native objects. Evil or not?](http://perfectionkills.com/extending-built-in-native-objects-evil-or-not/)). \ No newline at end of file +[dontown]: http://www.nczonline.net/blog/2010/03/02/maintainable-javascript-dont-modify-objects-you-down-own/ +[extendevil]: http://perfectionkills.com/extending-built-in-native-objects-evil-or-not/ From 50ab300204df022fedf51ba5117627d01199c31c Mon Sep 17 00:00:00 2001 From: David Brady Date: Thu, 28 Feb 2013 15:56:02 -0700 Subject: [PATCH 09/98] Fixed decorator sample (thanks tixz) * TextDecorator was written in JavaScript-style function assignment, making the @processors variable drop out of scope * Rewrote it as class TextDecorator and included a constructor to set the var --- chapters/design_patterns/decorator.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/chapters/design_patterns/decorator.md b/chapters/design_patterns/decorator.md index 0be3d7a..a40ed5c 100644 --- a/chapters/design_patterns/decorator.md +++ b/chapters/design_patterns/decorator.md @@ -26,7 +26,9 @@ miniMarkdown = (line) -> stripComments = (line) -> line.replace /\s*\/\/.*$/, '' # Removes one-line, double-slash C-style comments -TextProcessor = (@processors) -> +class TextProcessor + constructor: (@processors) -> + reducer: (existing, processor) -> if processor processor(existing or '') From 0648bcf79c475a0313eed4756cce16575169162c Mon Sep 17 00:00:00 2001 From: d8uv Date: Fri, 1 Mar 2013 10:35:26 -0900 Subject: [PATCH 10/98] Make Array::shuffle safer As mentioned by @dbrady in #72 we shouldn't overwrite a native `Array::shuffle` --- chapters/arrays/shuffling-array-elements.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/chapters/arrays/shuffling-array-elements.md b/chapters/arrays/shuffling-array-elements.md index 7963ac4..6e115da 100644 --- a/chapters/arrays/shuffling-array-elements.md +++ b/chapters/arrays/shuffling-array-elements.md @@ -79,7 +79,7 @@ The following code adds the shuffle function to the Array prototype, which means you are able to run it on any array you wish, in a much more direct manner. {% highlight coffeescript %} -Array::shuffle = -> +do -> Array::shuffle ?= -> for i in [@length-1..1] j = Math.floor Math.random() * (i + 1) [@[i], @[j]] = [@[j], @[i]] @@ -92,7 +92,9 @@ Array::shuffle = -> **Note:** Although it's quite common in languages like Ruby, extending native objects is often considered bad practice in JavaScript (see: [Maintainable JavaScript: Don’t modify objects you don’t own][dontown]; [Extending built-in native objects. Evil or not?] -[extendevil]). +[extendevil]). That being said, the code above is really quite safe to add. It only adds +`Array::shuffle` if it doesn't exist already, thanks to the existential assignment +operator (`?=`). That way, we don't overwrite someone else's, or a native browser method. Also, if you think you'll be using a lot of these utility functions, consider using a utility library, like [Lo-dash](http://lodash.com/). They include a lot of nifty From 7eb59ba8fb4b470a3e8f1ac53c33ec1f96842dc4 Mon Sep 17 00:00:00 2001 From: Kevin McDermott Date: Sat, 2 Mar 2013 21:16:40 -0500 Subject: [PATCH 11/98] Adds initial content for testing with nodeunit This commit history was rewriten by Devin Weaver --- chapters/testing/testing_with_nodeunit.md | 172 ++++++++++++++++++++++ 1 file changed, 172 insertions(+) create mode 100644 chapters/testing/testing_with_nodeunit.md diff --git a/chapters/testing/testing_with_nodeunit.md b/chapters/testing/testing_with_nodeunit.md new file mode 100644 index 0000000..ecdd5e9 --- /dev/null +++ b/chapters/testing/testing_with_nodeunit.md @@ -0,0 +1,172 @@ +--- +layout: recipe +title: Testing with Nodeunit +chapter: Testing +--- +## Problem + +You are writing a simple calculator using CoffeeScript and you want to verify it functions as expected. You decide to use the Nodeunit test framework. + +## Discussion + +Nodeunit is a JavaScript implementation of the xUnit family of Unit Testing libraries, similar libraries are available for Java, Python, Ruby, Smalltalk etc. + +When using xUnit family test frameworks, you write tests in a file that describes the expected functionality of the code to be tested. + +For example, we expect our calculator will be able to add and subtract and will function correctly with both positive and negative numbers. Our test is listed below. + +{% highlight coffeescript %} + +# tests/calculator.test.coffee + +Calculator = require '../calculator' + +exports.CalculatorTest = + + 'test can add two positive numbers': (test) -> + calculator = new Calculator + result = calculator.add 2, 3 + test.equal(result, 5) + test.done() + + 'test can handle negative number addition': (test) -> + calculator = new Calculator + result = calculator.add -10, 5 + test.equal(result, -5) + test.done() + + 'test can subtract two positive numbers': (test) -> + calculator = new Calculator + result = calculator.subtract 10, 6 + test.equal(result, 4) + test.done() + + 'test can handle negative number subtraction': (test) -> + calculator = new Calculator + result = calculator.subtract 4, -6 + test.equal(result, 10) + test.done() + +{% endhighlight %} + +### Installing Nodeunit + +Before you can run your tests, you must install Nodeunit: + +First of allcreate a package.json file + +{% highlight javascript %} +{ + "name": "calculator", + "version": "0.0.1", + "scripts": { + "test": "./node_modules/.bin/nodeunit test" + }, + "dependencies": { + "coffee-script": "~1.4.0", + "nodeunit": "~0.7.4" + } +} +{% endhighlight %} + +Next from a terminal run. + +{% highlight bash %} +$ npm install +{% endhighlight %} + +## Running the Tests + +It's easy to run the tests from the command-line: + +{% highlight bash %} +$ npm test +{% endhighlight %} + +The test runner should fail, because we have no calculator.coffee + +All failing tests + +Let's create a simple file + + +{% highlight coffeescript %} + +# calculator.coffee + +class Calculator + +module.exports = Calculator +{% endhighlight %} + +And re-run the test suite. + +Still failing, but better + +## Getting the Tests to Pass + +Let's implement our methods and see if we can get these tests to pass. + +{% highlight coffeescript %} + +# calculator.coffee + +class Calculator + + add: (a, b) -> + a + b + + subtract: (a, b) -> + a - b + +module.exports = Calculator +{% endhighlight %} + +When we rerun the tests we see they're all passing: + +All passing + + +## Refactoring the Tests + +Now that our tests pass, we should look to see if our code or our test(s) can be refactored. + +In our test file, each test creates its own calculator instance. This can make our tests quite repetitive especially for larger test suites. Ideally, we should consider moving that initialization code into a routine that runs before each test. + +In common with other xUnit libraries, Nodeunit provides a setUp (and tearDown) function which will be called before each test. + +{% highlight coffeescript %} + +Calculator = require '../calculator' + +exports.CalculatorTest = + + setUp: (callback) -> + @calculator = new Calculator + callback() + + 'test can add two positive numbers': (test) -> + result = @calculator.add 2, 3 + test.equal(result, 5) + test.done() + + 'test can handle negative number addition': (test) -> + result = @calculator.add -10, 5 + test.equal(result, -5) + test.done() + + 'test can subtract two positive numbers': (test) -> + result = @calculator.subtract 10, 6 + test.equal(result, 4) + test.done() + + 'test can handle negative number subtraction': (test) -> + result = @calculator.subtract 4, -6 + test.equal(result, 10) + test.done() + +{% endhighlight %} + +We can rerun the tests and everything should continue to pass. + +All passing From 5d615dab716fd4879b2a8494a857b2267671b2ec Mon Sep 17 00:00:00 2001 From: Devin Weaver Date: Sat, 2 Mar 2013 21:33:43 -0500 Subject: [PATCH 12/98] Converts screen shots to inline code blocks --- chapters/testing/testing_with_nodeunit.md | 68 ++++++++++++++++++++--- 1 file changed, 61 insertions(+), 7 deletions(-) diff --git a/chapters/testing/testing_with_nodeunit.md b/chapters/testing/testing_with_nodeunit.md index ecdd5e9..30af5b8 100644 --- a/chapters/testing/testing_with_nodeunit.md +++ b/chapters/testing/testing_with_nodeunit.md @@ -53,7 +53,7 @@ exports.CalculatorTest = Before you can run your tests, you must install Nodeunit: -First of allcreate a package.json file +First of all create a `package.json` file {% highlight javascript %} { @@ -85,10 +85,21 @@ $ npm test The test runner should fail, because we have no calculator.coffee -All failing tests + suki@Yuzuki:nodeunit_testing (master)$ npm test + npm WARN package.json calculator@0.0.1 No README.md file found! -Let's create a simple file + > calculator@0.0.1 test /Users/suki/tmp/nodeunit_testing + > ./node_modules/.bin/nodeunit test + + + /Users/suki/tmp/nodeunit_testing/node_modules/nodeunit/lib/nodeunit.js:72 + if (err) throw err; + ^ + Error: ENOENT, stat '/Users/suki/tmp/nodeunit_testing/test' + npm ERR! Test failed. See above for more details. + npm ERR! not ok code 0 +Let's create a simple file {% highlight coffeescript %} @@ -101,7 +112,39 @@ module.exports = Calculator And re-run the test suite. -Still failing, but better + suki@Yuzuki:nodeunit_testing (master)$ npm test + npm WARN package.json calculator@0.0.1 No README.md file found! + + > calculator@0.0.1 test /Users/suki/tmp/nodeunit_testing + > ./node_modules/.bin/nodeunit test + + + calculator.test + ✖ CalculatorTest - test can add two positive numbers + + TypeError: Object # has no method 'add' + ... + + ✖ CalculatorTest - test can handle negative number addition + + TypeError: Object # has no method 'add' + ... + + ✖ CalculatorTest - test can subtract two positive numbers + + TypeError: Object # has no method 'subtract' + ... + + ✖ CalculatorTest - test can handle negative number subtraction + + TypeError: Object # has no method 'subtract' + ... + + + FAILURES: 4/4 assertions failed (31ms) + npm ERR! Test failed. See above for more details. + npm ERR! not ok code 0 + ## Getting the Tests to Pass @@ -124,7 +167,20 @@ module.exports = Calculator When we rerun the tests we see they're all passing: -All passing + suki@Yuzuki:nodeunit_testing (master)$ npm test + npm WARN package.json calculator@0.0.1 No README.md file found! + + > calculator@0.0.1 test /Users/suki/tmp/nodeunit_testing + > ./node_modules/.bin/nodeunit test + + + calculator.test + ✔ CalculatorTest - test can add two positive numbers + ✔ CalculatorTest - test can handle negative number addition + ✔ CalculatorTest - test can subtract two positive numbers + ✔ CalculatorTest - test can handle negative number subtraction + + OK: 4 assertions (27ms) ## Refactoring the Tests @@ -168,5 +224,3 @@ exports.CalculatorTest = {% endhighlight %} We can rerun the tests and everything should continue to pass. - -All passing From d082571bd6776c2d65fd03aa2ad15c89d4c0b727 Mon Sep 17 00:00:00 2001 From: d8uv Date: Mon, 11 Mar 2013 13:51:26 -0700 Subject: [PATCH 13/98] Detecting and Creating Missing Functions rewrite MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New solution, and greatly expanded discussion section to explain it. From:   unless Class::member     Class::member = contents To:   do -> Class::member ?= contents --- .../detecting-and-replacing-functions.md | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/chapters/metaprogramming/detecting-and-replacing-functions.md b/chapters/metaprogramming/detecting-and-replacing-functions.md index 6a99931..f8d81b5 100644 --- a/chapters/metaprogramming/detecting-and-replacing-functions.md +++ b/chapters/metaprogramming/detecting-and-replacing-functions.md @@ -9,12 +9,11 @@ You want to detect if a function exists and create it if it does not (such as an ## Solution -Use `::` to detect the function, and assign to it if it does not exist. +Use the existential assignment operator (`?=`) to assign a function to the classes' prototype (using the `::` shorthand), and wrap it all in a IIFE (`do ->`) to contain the variables. {% highlight coffeescript %} -unless Array::filter - Array::filter = (callback) -> - element for element in this when callback element +do -> Array::filter ?= (callback) -> + element for element in this when callback element array = [1..10] @@ -24,4 +23,10 @@ array.filter (x) -> x > 5 ## Discussion -Objects in JavaScript (and thus, in CoffeeScript) have a prototype member that defines what member functions should be available on all objects based on that prototype. In CoffeeScript, you can access the prototype directly via the `::` operator. +Objects in JavaScript (and thus, in CoffeeScript) have a prototype member that defines what member functions should be available on all objects based on that prototype. +In Coffeescript, you access this prototype using the `::` shortcut. So, if you want to add a filter function to the array class, you do `Array::filter = ...`. This will add the filter function to all arrays. + +However, we don't ever want to overwrite a prototype that we haven't created in the first place. For example, if `Array::filter` already exists in a fast native form in the browser, or a library maker has their own specific version of `Array::filter`, then you'll either replace the quick native version with a slow Javascript version, or you will break the library that depends on their own Array::shuffle. +What you need to do is only add the function if it doesn't already exist. That's where the existential assignment operator (`?=`) comes in. If we do `Array::filter ?= ...` instead, it will see if `Array::filter` already exists. If it does, then it will use the current version. If it doesn't, it will add yours. + +Finally, because the existential assignment operator--when compiled--creates a few variables, we clean up the code by wrapping it in an [Immediately-Invoked Function Expression (IIFE)](http://benalman.com/news/2010/11/immediately-invoked-function-expression/). This hides those internal-use-only variables from leaking outside. So, if the function we're writing already exists, it runs, does basically nothing, and exits, affecting absolutely none of your code. But, if the function we're writing *doesn't* exist, we send out only the function we're writing as a closure, so only the function you've made affects the code. The internal workings of `?=` are hidden either way. From e9076fec3027a267eb585c6ff94e414d445ff29e Mon Sep 17 00:00:00 2001 From: d8uv Date: Mon, 11 Mar 2013 18:11:19 -0700 Subject: [PATCH 14/98] Add annotated javascript of Polyfill pattern rewrite --- .../detecting-and-replacing-functions.md | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/chapters/metaprogramming/detecting-and-replacing-functions.md b/chapters/metaprogramming/detecting-and-replacing-functions.md index f8d81b5..4ba7b64 100644 --- a/chapters/metaprogramming/detecting-and-replacing-functions.md +++ b/chapters/metaprogramming/detecting-and-replacing-functions.md @@ -30,3 +30,33 @@ However, we don't ever want to overwrite a prototype that we haven't created in What you need to do is only add the function if it doesn't already exist. That's where the existential assignment operator (`?=`) comes in. If we do `Array::filter ?= ...` instead, it will see if `Array::filter` already exists. If it does, then it will use the current version. If it doesn't, it will add yours. Finally, because the existential assignment operator--when compiled--creates a few variables, we clean up the code by wrapping it in an [Immediately-Invoked Function Expression (IIFE)](http://benalman.com/news/2010/11/immediately-invoked-function-expression/). This hides those internal-use-only variables from leaking outside. So, if the function we're writing already exists, it runs, does basically nothing, and exits, affecting absolutely none of your code. But, if the function we're writing *doesn't* exist, we send out only the function we're writing as a closure, so only the function you've made affects the code. The internal workings of `?=` are hidden either way. + +### Example + +Below, we've compiled and annotated the coffeescript written in the solution above + +{% highlight javascript %} +// (function(){ ... })() is an IIFE, compiled in thanks to `do ->` +(function() { + + // This is from the `?=` operator, used to check if Array.prototype.filter (`Array::filter`) exists. + // If it does, we set it to itself, and return. If it doesn't, then we set it to the function, and return the function. + // The IIFE is only used to hide _base and _ref from the outside world. + var _base, _ref; + return (_ref = (_base = Array.prototype).filter) != null ? _ref : _base.filter = function(callback) { + + // `element for element in this when callback element` + var element, _i, _len, _results; + _results = []; + for (_i = 0, _len = this.length; _i < _len; _i++) { + element = this[_i]; + if (callback(element)) { + _results.push(element); + } + } + return _results; + + }; +// The end of the IIFE from `do ->` +})(); +{% endhighlight %} From 0836946e99dc65051fc9a91bf568dcc612dc5dd5 Mon Sep 17 00:00:00 2001 From: Kris Budde Date: Mon, 18 Mar 2013 22:30:52 +0100 Subject: [PATCH 15/98] Chaining recipe changed. Property array was shared between instances --- chapters/classes_and_objects/chaining.md | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/chapters/classes_and_objects/chaining.md b/chapters/classes_and_objects/chaining.md index bec3a46..65f450f 100644 --- a/chapters/classes_and_objects/chaining.md +++ b/chapters/classes_and_objects/chaining.md @@ -13,10 +13,11 @@ Return the `this` (i.e. `@`) object after every chained method. {% highlight coffeescript %} class CoffeeCup - properties: - strength: 'medium' - cream: false - sugar: false + constructor: -> + @properties= + strength: 'medium' + cream: false + sugar: false strength: (newStrength) -> @properties.strength = newStrength @ @@ -57,13 +58,13 @@ addChainedAttributeAccessor = (obj, propertyAttr, attr) -> obj class TeaCup - properties: - size: 'medium' - type: 'black' - sugar: false - cream: false - -addChainedAttributeAccessor(TeaCup.prototype, 'properties', attr) for attr of TeaCup.prototype.properties + constructor: -> + @properties= + size: 'medium' + type: 'black' + sugar: false + cream: false + addChainedAttributeAccessor(this, 'properties', attr) for attr of @properties earlgrey = new TeaCup().size('small').type('Earl Grey').sugar('false') From 57c445a9d4f23b1b744c3dd06d3e7f1a85311441 Mon Sep 17 00:00:00 2001 From: Iain Beeston Date: Tue, 9 Apr 2013 15:20:30 +1000 Subject: [PATCH 16/98] Showed how to access from an instance method --- chapters/classes_and_objects/class-variables.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/chapters/classes_and_objects/class-variables.md b/chapters/classes_and_objects/class-variables.md index d48ed9c..b7025bd 100644 --- a/chapters/classes_and_objects/class-variables.md +++ b/chapters/classes_and_objects/class-variables.md @@ -13,6 +13,9 @@ You want to create a class variable. class Zoo @MAX_ANIMALS: 50 MAX_ZOOKEEPERS: 3 + + helpfulInfo: => + "Zoos may contain a maximum of #{@constructor.MAX_ANIMALS} animals" Zoo.MAX_ANIMALS # => 50 @@ -23,6 +26,8 @@ Zoo.MAX_ZOOKEEPERS zoo = new Zoo zoo.MAX_ZOOKEEPERS # => 3 +zoo.helpfulInfo() +# => "Zoos may contain a maximum of 50 animals" {% endhighlight %} ## Discussion From fab61fb07fd55c37f62da1973f38818242ccc002 Mon Sep 17 00:00:00 2001 From: Jameson Quinn Date: Thu, 25 Apr 2013 14:53:15 -0600 Subject: [PATCH 17/98] Mixins recipe --- chapters/classes_and_objects/mixins.md | 49 ++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 chapters/classes_and_objects/mixins.md diff --git a/chapters/classes_and_objects/mixins.md b/chapters/classes_and_objects/mixins.md new file mode 100644 index 0000000..8f99d84 --- /dev/null +++ b/chapters/classes_and_objects/mixins.md @@ -0,0 +1,49 @@ +--- +layout: recipe +title: Mixins for classes +chapter: Classes and Objects +--- +## Problem + +You have a few utility methods that you want to include in a number of different classes. + +## Solution + +Use a mixOf factory function that generates a mixed superclass for you. + +{% highlight coffeescript %} +mixOf = (base, mixins...) -> + class Mixed extends base + for mixin in mixins by -1 #earlier mixins override later ones + for name, method of mixin:: + Mixed::[name] = method + Mixed + +... + +class DeepThought + answer: -> + 42 + +class PhilosopherMixin + pontificate: -> + console.log "hmm..." + @wise = yes + +class DeeperThought extends mixOf DeepThought, PhilosopherMixin + answer: -> + @pontificate() + super() + +earth = new DeeperThought +earth.answer() +# hmm... +# => 42 +{% endhighlight %} + +## Discussion + +This is intended for lightweight mixins. Thus you inherit methods of the +base and its ancestors, and those of the mixins, but not those of the ancestors of +the mixins. Also, after declaring a mixed class, further changes in the mixins are not +reflected. From b16a9071dd6833cf2689e6380b7fc417c99a4f0b Mon Sep 17 00:00:00 2001 From: guillaumebiton Date: Thu, 30 May 2013 12:13:47 +0200 Subject: [PATCH 18/98] new template for arrays of objects (collections?) --- .../arrays/where-for-arrays-of-objects.md | 76 +++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 chapters/arrays/where-for-arrays-of-objects.md diff --git a/chapters/arrays/where-for-arrays-of-objects.md b/chapters/arrays/where-for-arrays-of-objects.md new file mode 100644 index 0000000..1c6d4d7 --- /dev/null +++ b/chapters/arrays/where-for-arrays-of-objects.md @@ -0,0 +1,76 @@ +--- +layout: recipe +title: where for arrays of objects +chapter: Arrays +--- +## Problem + +You want to get an array of objects that match your request for some properties + +You have an Array of Objects, such as: + +{% highlight coffeescript %} +cats = [ + { + name: "Bubbles" + favoriteFood: "mice" + age: 1 + }, + { + name: "Sparkle" + favoriteFood: "tuna" + }, + { + name: "flyingCat" + favoriteFood: "mice" + age: 1 + } +] +{% endhighlight %} + +You want to filter with some properties, like cats.where({ age: 1}) or cats.where({ age: 1, favoriteFood: "mice"}) + +## Solution + +You can extend Array like this : + +{% highlight coffeescript %} +Array::where = (query) -> + return [] if typeof query isnt "object" + hit = Object.keys(query).length + @filter (item) -> + match = 0 + for key, val of query + match += 1 if item[key] is val + if match is hit then true else false + +cats.where age:1 +# => [ { name: 'Bubbles', favoriteFood: 'mice', age: 1 },{ name: 'flyingCat', favoriteFood: 'mice', age: 1 } ] + +cats.where age:1, name: "Bubbles" +# => [ { name: 'Bubbles', favoriteFood: 'mice', age: 1 } ] + +cats.where age:1, favoriteFood:"tuna" +# => [] +{% endhighlight %} + +## Discussion + +This is an exact match. we could make it more flexible with a matcher function : + +{% highlight coffeescript %} +Array::where = (query, matcher = (a,b) -> a is b) -> + return [] if typeof query isnt "object" + hit = Object.keys(query).length + @filter (item) -> + match = 0 + for key, val of query + match += 1 if matcher(item[key], val) + if match is hit then true else false + +cats.where name:"bubbles", (a, b) -> "#{ a }".toLowerCase() is "#{ b }".toLowerCase() +# => [ { name: 'Bubbles', favoriteFood: 'mice', age: 1 } ] +# now it's case insensitive +{% endhighlight %} + +it's more a method to deal with collection and it could be rename as "find" but popular libraires like underscore or lodash name it "where". From 0b3e4cdbdbfa0a10cdc04516aa405a6a1730b9b2 Mon Sep 17 00:00:00 2001 From: guillaumebiton Date: Thu, 30 May 2013 12:20:05 +0200 Subject: [PATCH 19/98] update discussion example --- chapters/arrays/where-for-arrays-of-objects.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/chapters/arrays/where-for-arrays-of-objects.md b/chapters/arrays/where-for-arrays-of-objects.md index 1c6d4d7..51eba6d 100644 --- a/chapters/arrays/where-for-arrays-of-objects.md +++ b/chapters/arrays/where-for-arrays-of-objects.md @@ -68,6 +68,10 @@ Array::where = (query, matcher = (a,b) -> a is b) -> match += 1 if matcher(item[key], val) if match is hit then true else false +cats.where name:"bubbles" +# => [] +# it's case sensitive + cats.where name:"bubbles", (a, b) -> "#{ a }".toLowerCase() is "#{ b }".toLowerCase() # => [ { name: 'Bubbles', favoriteFood: 'mice', age: 1 } ] # now it's case insensitive From 2be90d11d14e1f86e8ce769b3f1efa11c0b414a3 Mon Sep 17 00:00:00 2001 From: Michael Glass Date: Tue, 18 Jun 2013 12:05:55 -0700 Subject: [PATCH 20/98] lesson on class variables is incorrect. putting attributes on the prototype does not use more memory than putting it on the constructor function. --- chapters/classes_and_objects/class-variables.md | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/chapters/classes_and_objects/class-variables.md b/chapters/classes_and_objects/class-variables.md index b7025bd..dd8713f 100644 --- a/chapters/classes_and_objects/class-variables.md +++ b/chapters/classes_and_objects/class-variables.md @@ -15,21 +15,29 @@ class Zoo MAX_ZOOKEEPERS: 3 helpfulInfo: => - "Zoos may contain a maximum of #{@constructor.MAX_ANIMALS} animals" + "Zoos may contain a maximum of #{@constructor.MAX_ANIMALS} animals and #{@MAX_ZOOKEEPERS} zoo keepers." Zoo.MAX_ANIMALS # => 50 Zoo.MAX_ZOOKEEPERS -# => undefined (it is an instance variable) +# => undefined (it is a prototype member) + +Zoo::MAX_ZOOKEEPERS +# => 3 zoo = new Zoo zoo.MAX_ZOOKEEPERS # => 3 zoo.helpfulInfo() -# => "Zoos may contain a maximum of 50 animals" +# => "Zoos may contain a maximum of 50 animals and 3 zoo keepers." + +zoo.MAX_ZOOKEEPERS = "smelly" +zoo.MAX_ANIMALS = "seventeen" +zoo.helpfulInfo() +# => "Zoos may contain a maximum of 50 animals and smelly zoo keepers." {% endhighlight %} ## Discussion -Coffeescript will store these values on the object itself rather than on the object prototype (and thus on individual object instances), which conserves memory and gives a central location to store class-level values. +Coffeescript will store these values on the class itself rather than on the prototype it defines. These are useful for defining variables on classes which can't be overrided by instance attribute variables. From cb75e69b835b1a4bd6ce1295cf0003f42f9d0e2d Mon Sep 17 00:00:00 2001 From: tashemi Date: Sat, 27 Jul 2013 01:37:49 +0300 Subject: [PATCH 21/98] Create observer.md --- chapters/design_patterns/observer.md | 44 ++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 chapters/design_patterns/observer.md diff --git a/chapters/design_patterns/observer.md b/chapters/design_patterns/observer.md new file mode 100644 index 0000000..1fe5ab2 --- /dev/null +++ b/chapters/design_patterns/observer.md @@ -0,0 +1,44 @@ +--- +layout: recipe Observer Pattern +title: Observer Pattern +chapter: Design patterns +--- +## Problem + +You have to notify some objects about an event happen + +## Solution + +Use an [Observer Pattern](http://en.wikipedia.org/wiki/Observer_pattern) + +{% highlight coffeescript %} +class PostOffice + constructor: () -> + @subscribers = [] + sendNewItemReleased: (item) -> + subscriber.callback(item) for subscriber in @subscribers when subscriber.item is item + return + subscribe: (to, onNewItemReleased) -> + @subscribers.push({'item':to, 'callback':onNewItemReleased}) +class MagazineSubscriber + onNewMagazine: (item) -> + alert "I've got new "+item +class NewspaperSubscriber + onNewNewspaper: (item) -> + alert "I've got new "+item + +postOffice = new PostOffice() +sub1 = new MagazineSubscriber() +sub2 = new NewspaperSubscriber() +postOffice.subscribe "Mens Health", sub1.onNewMagazine +postOffice.subscribe "Times", sub2.onNewNewspaper +postOffice.sendNewItemReleased "Times" +postOffice.sendNewItemReleased "Mens Health" +{% endhighlight %} + +## Discussion + +Here you have an observer object (PostOffice) and observable objects (MagazineSubscriber, NewspaperSubscriber). +To be notified about an event of publishing new periodical observable object should make subscribtion on PostOffice. +Every of subscribed objects is stored internaly in the PostOffice array of subscribers. +Every subscriber is notified on new concrete periodical is published. From 28e5392493057dc64b5087bf6eb0671cc30b4fb4 Mon Sep 17 00:00:00 2001 From: tashemi Date: Sat, 27 Jul 2013 01:51:26 +0300 Subject: [PATCH 22/98] Update code --- chapters/design_patterns/observer.md | 31 +++++++++++++++------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/chapters/design_patterns/observer.md b/chapters/design_patterns/observer.md index 1fe5ab2..4976e63 100644 --- a/chapters/design_patterns/observer.md +++ b/chapters/design_patterns/observer.md @@ -12,33 +12,36 @@ You have to notify some objects about an event happen Use an [Observer Pattern](http://en.wikipedia.org/wiki/Observer_pattern) {% highlight coffeescript %} + class PostOffice - constructor: () -> - @subscribers = [] - sendNewItemReleased: (item) -> - subscriber.callback(item) for subscriber in @subscribers when subscriber.item is item - return - subscribe: (to, onNewItemReleased) -> - @subscribers.push({'item':to, 'callback':onNewItemReleased}) + constructor: () -> + @subscribers = [] + notifyNewItemReleased: (item) -> + subscriber.callback(item) for subscriber in @subscribers when subscriber.item is item + subscribe: (to, onNewItemReleased) -> + @subscribers.push {'item':to, 'callback':onNewItemReleased} + class MagazineSubscriber - onNewMagazine: (item) -> - alert "I've got new "+item + onNewMagazine: (item) -> + alert "I've got new "+item + class NewspaperSubscriber - onNewNewspaper: (item) -> - alert "I've got new "+item + onNewNewspaper: (item) -> + alert "I've got new "+item postOffice = new PostOffice() sub1 = new MagazineSubscriber() sub2 = new NewspaperSubscriber() postOffice.subscribe "Mens Health", sub1.onNewMagazine postOffice.subscribe "Times", sub2.onNewNewspaper -postOffice.sendNewItemReleased "Times" -postOffice.sendNewItemReleased "Mens Health" +postOffice.notifyNewItemReleased "Times" +postOffice.notifyNewItemReleased "Mens Health" + {% endhighlight %} ## Discussion Here you have an observer object (PostOffice) and observable objects (MagazineSubscriber, NewspaperSubscriber). To be notified about an event of publishing new periodical observable object should make subscribtion on PostOffice. -Every of subscribed objects is stored internaly in the PostOffice array of subscribers. +Every of subscribed objects is stored internaly in the PostOffice array of subscribtions. Every subscriber is notified on new concrete periodical is published. From 46a0b9e3c2c159b18125aea2cde15a67a52f3ac7 Mon Sep 17 00:00:00 2001 From: Pedro Medeiros Date: Sat, 27 Jul 2013 22:12:15 -0300 Subject: [PATCH 23/98] fix observer page layout and remove :rubygems that is deprecated from Gemfile --- Gemfile | 2 +- chapters/design_patterns/observer.md | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Gemfile b/Gemfile index b744ba1..ebe0f96 100644 --- a/Gemfile +++ b/Gemfile @@ -1,4 +1,4 @@ -source :rubygems +source 'http://rubygems.org/' group :development do gem "RedCloth", "~> 4.2" diff --git a/chapters/design_patterns/observer.md b/chapters/design_patterns/observer.md index 4976e63..f796b78 100644 --- a/chapters/design_patterns/observer.md +++ b/chapters/design_patterns/observer.md @@ -1,5 +1,5 @@ --- -layout: recipe Observer Pattern +layout: recipe title: Observer Pattern chapter: Design patterns --- @@ -20,7 +20,7 @@ class PostOffice subscriber.callback(item) for subscriber in @subscribers when subscriber.item is item subscribe: (to, onNewItemReleased) -> @subscribers.push {'item':to, 'callback':onNewItemReleased} - + class MagazineSubscriber onNewMagazine: (item) -> alert "I've got new "+item @@ -41,7 +41,7 @@ postOffice.notifyNewItemReleased "Mens Health" ## Discussion -Here you have an observer object (PostOffice) and observable objects (MagazineSubscriber, NewspaperSubscriber). -To be notified about an event of publishing new periodical observable object should make subscribtion on PostOffice. -Every of subscribed objects is stored internaly in the PostOffice array of subscribtions. +Here you have an observer object (PostOffice) and observable objects (MagazineSubscriber, NewspaperSubscriber). +To be notified about an event of publishing new periodical observable object should make subscribtion on PostOffice. +Every of subscribed objects is stored internaly in the PostOffice array of subscribtions. Every subscriber is notified on new concrete periodical is published. From 57747556034440204359f767646b458ca4bb0ed9 Mon Sep 17 00:00:00 2001 From: Tatiana Shemiakina Date: Tue, 30 Jul 2013 22:23:19 +0300 Subject: [PATCH 24/98] Create adapter --- chapters/design_patterns/adapter | 60 ++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 chapters/design_patterns/adapter diff --git a/chapters/design_patterns/adapter b/chapters/design_patterns/adapter new file mode 100644 index 0000000..95db31a --- /dev/null +++ b/chapters/design_patterns/adapter @@ -0,0 +1,60 @@ +--- +layout: default +title: Adapter pattern +--- + +## Sample recipe template + +Create a new `my-recipe.md` file and use this text as a start. + +{% highlight text %} +--- +layout: recipe +title: Adapter patter +chapter: Design patterns +--- +## Problem + +Suppose we have 3-rd party grid component. We want to apply there our own custom sorting but a small problem. Our custom sorter does not implement required interface by grid component. +To understand the problem completely best example would be an socket from our usual life. Everybody knows this device. In some countries it has 3 pins and in other contries it has only 2 pins. +This is exactly right situation to use adapter. + +## Solution + +#grid component +class AwesomeGrid + constructor: (@datasource)-> + @sort_order = 'ASC' + @sorter = new NullSorter # in this place we use NullObject pattern (another usefull pattern) + setCustomSorter: (@customSorter) -> + @sorter = customSorter + sort: () -> + @datasource = @sorter.sort @datasource, @sort_order + # don't forget to change sort order + + +class NullSorter + sort: (data, order) -> # do nothing; it is just a stub + +class RandomSorter + sort: (data)-> + for i in [data.length-1..1] #let's shuffle the data a bit + j = Math.floor Math.random() * (i + 1) + [data[i], data[j]] = [data[j], data[i]] + return data + +class RandomSorterAdapter + constructor: (@sorter) -> + sort: (data, order) -> + @sorter.sort data + +agrid = new AwesomeGrid ['a','b','c','d','e','f'] +agrid.setCustomSorter new RandomSorterAdapter(new RandomSorter) +agrid.sort() # sort data with custom sorter through adapter + +## Discussion + +Adapter is usefull when you have to organize an interaction between two objects with different interfaces. It can happen when you use 3-rd party libraries or you work with legacy code. +In any case be carefull with adapter: it can be helpfull but it can instigate design errors. + +{% endhighlight %} From 8a510977fd926dcf3e0ada13545b6990b514a1a5 Mon Sep 17 00:00:00 2001 From: Tatiana Shemiakina Date: Tue, 30 Jul 2013 22:26:02 +0300 Subject: [PATCH 25/98] Update and rename adapter to adapter.md --- chapters/design_patterns/{adapter => adapter.md} | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) rename chapters/design_patterns/{adapter => adapter.md} (95%) diff --git a/chapters/design_patterns/adapter b/chapters/design_patterns/adapter.md similarity index 95% rename from chapters/design_patterns/adapter rename to chapters/design_patterns/adapter.md index 95db31a..e6a3d67 100644 --- a/chapters/design_patterns/adapter +++ b/chapters/design_patterns/adapter.md @@ -20,8 +20,8 @@ To understand the problem completely best example would be an socket from our us This is exactly right situation to use adapter. ## Solution - -#grid component +{% highlight coffeescript %} +# a fragment of 3-rd party grid component class AwesomeGrid constructor: (@datasource)-> @sort_order = 'ASC' @@ -52,6 +52,8 @@ agrid = new AwesomeGrid ['a','b','c','d','e','f'] agrid.setCustomSorter new RandomSorterAdapter(new RandomSorter) agrid.sort() # sort data with custom sorter through adapter +{% endhighlight %} + ## Discussion Adapter is usefull when you have to organize an interaction between two objects with different interfaces. It can happen when you use 3-rd party libraries or you work with legacy code. From 5fc588889f546f4f958f782c6c4b268712dacd6f Mon Sep 17 00:00:00 2001 From: Tatiana Shemiakina Date: Tue, 30 Jul 2013 22:33:03 +0300 Subject: [PATCH 26/98] Update markup; add link to wiki adapter page --- chapters/design_patterns/adapter.md | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/chapters/design_patterns/adapter.md b/chapters/design_patterns/adapter.md index e6a3d67..8be4ece 100644 --- a/chapters/design_patterns/adapter.md +++ b/chapters/design_patterns/adapter.md @@ -1,14 +1,4 @@ --- -layout: default -title: Adapter pattern ---- - -## Sample recipe template - -Create a new `my-recipe.md` file and use this text as a start. - -{% highlight text %} ---- layout: recipe title: Adapter patter chapter: Design patterns @@ -17,9 +7,10 @@ chapter: Design patterns Suppose we have 3-rd party grid component. We want to apply there our own custom sorting but a small problem. Our custom sorter does not implement required interface by grid component. To understand the problem completely best example would be an socket from our usual life. Everybody knows this device. In some countries it has 3 pins and in other contries it has only 2 pins. -This is exactly right situation to use adapter. +This is exactly right situation to use [adapter pattern](https://en.wikipedia.org/wiki/Adapter_pattern). ## Solution + {% highlight coffeescript %} # a fragment of 3-rd party grid component class AwesomeGrid @@ -58,5 +49,3 @@ agrid.sort() # sort data with custom sorter through adapter Adapter is usefull when you have to organize an interaction between two objects with different interfaces. It can happen when you use 3-rd party libraries or you work with legacy code. In any case be carefull with adapter: it can be helpfull but it can instigate design errors. - -{% endhighlight %} From a97b9d157f8bb95c14bb45fca2ed151b27334916 Mon Sep 17 00:00:00 2001 From: erik Date: Tue, 6 Aug 2013 11:51:51 -0500 Subject: [PATCH 27/98] Simplified and sped up the "type-function" example. --- chapters/classes_and_objects/type-function.md | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/chapters/classes_and_objects/type-function.md b/chapters/classes_and_objects/type-function.md index 42952ac..96e8cea 100644 --- a/chapters/classes_and_objects/type-function.md +++ b/chapters/classes_and_objects/type-function.md @@ -12,16 +12,20 @@ You'd like to know the type of a object without using typeof. (See http://javasc Use the following function: {% highlight coffeescript %} -type = (obj) -> - if obj == undefined or obj == null - return String obj - classToType = new Object - for name in "Boolean Number String Function Array Date RegExp".split(" ") - classToType["[object " + name + "]"] = name.toLowerCase() - myClass = Object.prototype.toString.call obj - if myClass of classToType - return classToType[myClass] - return "object" + type = (obj) -> + if obj == undefined or obj == null + return String obj + classToType = { + '[object Boolean]': 'boolean', + '[object Number]': 'number', + '[object String]': 'string', + '[object Function]': 'function', + '[object Array]': 'array', + '[object Date]': 'date', + '[object RegExp]': 'regexp', + '[object Object]': 'object' + } + return classToType[Object.prototype.toString.call(obj)] {% endhighlight %} ## Discussion From 8bd340fb0c863c116e4cf248c7c0d733d6e662fb Mon Sep 17 00:00:00 2001 From: Frankie Bagnardi Date: Sat, 10 Aug 2013 03:01:08 -0700 Subject: [PATCH 28/98] Math.max.apply note is confusing --- chapters/arrays/max-array-value.md | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/chapters/arrays/max-array-value.md b/chapters/arrays/max-array-value.md index 906eaac..ce3adc1 100644 --- a/chapters/arrays/max-array-value.md +++ b/chapters/arrays/max-array-value.md @@ -16,18 +16,14 @@ Math.max [12, 32, 11, 67, 1, 3]... # => 67 {% endhighlight %} -Alternatively, it's possible to use ES5 `reduce` method. For backward compatibility with older JavaScript implementations, use Math.max.apply: +Alternatively, it's possible to use ES5 `reduce` method. For backward compatibility with older JavaScript implementations, use the above. {% highlight coffeescript %} # ECMAScript 5 [12,32,11,67,1,3].reduce (a,b) -> Math.max a, b # => 67 - -# Pre-ES5 -Math.max.apply(null, [12,32,11,67,1,3]) -# => 67 {% endhighlight %} ## Discussion -`Math.max` compares every argument and returns the largest number from arguments. The ellipsis (`...`) converts every array value into argument which is given to the function. You can also use it with other functions which take variable ammount of arguments, such as `console.log`. \ No newline at end of file +`Math.max` compares every argument and returns the largest number from arguments. The ellipsis (`...`) converts every array value into argument which is given to the function. You can also use it with other functions which take variable ammount of arguments, such as `console.log`. From 3d3acde05f6d749adcdf87e85617dd689e96d29c Mon Sep 17 00:00:00 2001 From: Frankie Bagnardi Date: Sat, 10 Aug 2013 03:19:18 -0700 Subject: [PATCH 29/98] r.randi is undefined, should be r.rand --- chapters/math/generating-predictable-random-numbers.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/math/generating-predictable-random-numbers.md b/chapters/math/generating-predictable-random-numbers.md index a7cc561..128bc61 100644 --- a/chapters/math/generating-predictable-random-numbers.md +++ b/chapters/math/generating-predictable-random-numbers.md @@ -62,4 +62,4 @@ Avoid the temptation to modulus the output of this generator. If you need an int r.randn() % 2 {% endhighlight %} -because you will most definitely not get random digits. Use `r.randi(2)` instead. +because you will most definitely not get random digits. Use `r.rand(2)` instead. From c2ff4ae0fa8123dfdefe3f2653fea3c92cc82e5a Mon Sep 17 00:00:00 2001 From: Peter Hellberg Date: Sun, 18 Aug 2013 14:19:13 +0200 Subject: [PATCH 30/98] Updated development dependencies --- Gemfile | 12 +++---- Gemfile.lock | 98 ++++++++++++++++++++++++++++++++++------------------ 2 files changed, 70 insertions(+), 40 deletions(-) diff --git a/Gemfile b/Gemfile index ebe0f96..b4d66ba 100644 --- a/Gemfile +++ b/Gemfile @@ -1,9 +1,9 @@ -source 'http://rubygems.org/' +source 'https://rubygems.org/' group :development do - gem "RedCloth", "~> 4.2" - gem "foreman", "~> 0.13" - gem "serve", "~> 1.0" - gem "jekyll", "~> 0.10" - gem "thin", "~> 1.2" + gem "github-pages" + gem "tzinfo-data" + + gem "foreman", "~> 0.63" + gem "serve", "~> 1.5" end diff --git a/Gemfile.lock b/Gemfile.lock index 0b46357..d8185b6 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,47 +1,77 @@ GEM - remote: http://rubygems.org/ + remote: https://rubygems.org/ specs: RedCloth (4.2.9) - activesupport (3.0.7) + activesupport (3.2.14) + i18n (~> 0.6, >= 0.6.4) + multi_json (~> 1.0) classifier (1.3.3) fast-stemmer (>= 1.0.0) - daemons (1.1.3) - directory_watcher (1.4.0) - eventmachine (0.12.10) - fast-stemmer (1.0.0) - foreman (0.13.0) - term-ansicolor (~> 1.0.5) + colorator (0.1) + commander (4.1.5) + highline (~> 1.6.11) + directory_watcher (1.4.1) + dotenv (0.8.0) + fast-stemmer (1.0.2) + foreman (0.63.0) + dotenv (>= 0.7) thor (>= 0.13.6) - i18n (0.4.2) - jekyll (0.10.0) - classifier (>= 1.3.1) - directory_watcher (>= 1.1.1) - liquid (>= 1.9.0) - maruku (>= 0.5.9) - liquid (2.2.2) - maruku (0.6.0) + github-pages (1) + RedCloth (= 4.2.9) + jekyll (= 1.1.2) + kramdown (= 1.0.2) + liquid (= 2.5.1) + maruku (= 0.6.1) + rdiscount (= 1.6.8) + redcarpet (= 2.2.2) + highline (1.6.19) + i18n (0.6.5) + jekyll (1.1.2) + classifier (~> 1.3) + colorator (~> 0.1) + commander (~> 4.1.3) + directory_watcher (~> 1.4.1) + kramdown (~> 1.0.2) + liquid (~> 2.5.1) + maruku (~> 0.5) + pygments.rb (~> 0.5.0) + redcarpet (~> 2.2.2) + safe_yaml (~> 0.7.0) + kramdown (1.0.2) + liquid (2.5.1) + maruku (0.6.1) syntax (>= 1.0.0) - rack (1.2.2) - serve (1.0.0) - activesupport (~> 3.0.1) - i18n (~> 0.4.1) - rack (~> 1.2.1) - tzinfo (~> 0.3.23) + multi_json (1.7.9) + posix-spawn (0.3.6) + pygments.rb (0.5.2) + posix-spawn (~> 0.3.6) + yajl-ruby (~> 1.1.0) + rack (1.5.2) + rack-test (0.6.2) + rack (>= 1.0) + rdiscount (1.6.8) + redcarpet (2.2.2) + safe_yaml (0.7.1) + serve (1.5.2) + activesupport (~> 3.2.12) + i18n + rack (~> 1.5.2) + rack-test (~> 0.6.2) + tilt (~> 1.3.3) + tzinfo syntax (1.0.0) - term-ansicolor (1.0.5) - thin (1.2.11) - daemons (>= 1.0.9) - eventmachine (>= 0.12.6) - rack (>= 1.0.0) - thor (0.14.6) - tzinfo (0.3.27) + thor (0.18.1) + tilt (1.3.7) + tzinfo (1.0.1) + tzinfo-data (1.2013.4) + tzinfo (>= 1.0.0) + yajl-ruby (1.1.0) PLATFORMS ruby DEPENDENCIES - RedCloth (~> 4.2) - foreman (~> 0.13) - jekyll (~> 0.10) - serve (~> 1.0) - thin (~> 1.2) + foreman (~> 0.63) + github-pages + serve (~> 1.5) + tzinfo-data From fffd98eed9629cb74817e6c9bc2d1a7d906b6b20 Mon Sep 17 00:00:00 2001 From: Peter Hellberg Date: Sun, 18 Aug 2013 14:21:24 +0200 Subject: [PATCH 31/98] Now using the github-pages gem in order to better mirror the production environment. --- .ruby-gemset | 1 + .ruby-version | 1 + Procfile | 2 +- _config.yml | 2 ++ 4 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 .ruby-gemset create mode 100644 .ruby-version diff --git a/.ruby-gemset b/.ruby-gemset new file mode 100644 index 0000000..119b7fd --- /dev/null +++ b/.ruby-gemset @@ -0,0 +1 @@ +coffeescript-cookbook diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..77fee73 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +1.9.3 diff --git a/Procfile b/Procfile index c41ebb6..26a670a 100644 --- a/Procfile +++ b/Procfile @@ -1,2 +1,2 @@ -jekyll: bundle exec jekyll --auto +jekyll: bundle exec jekyll build --watch serve: bundle exec serve 4000 development _site diff --git a/_config.yml b/_config.yml index f61488e..fef8911 100644 --- a/_config.yml +++ b/_config.yml @@ -1,5 +1,7 @@ +safe: true pygments: true lsi: false +markdown: redcarpet exclude: - README.md - CNAME From 7ebd0275b2c5569b7a5f30723551028d8d8ea6b5 Mon Sep 17 00:00:00 2001 From: Peter Hellberg Date: Sun, 18 Aug 2013 15:13:54 +0200 Subject: [PATCH 32/98] Updated the Developer's Guide to better reflect the current workflow. --- developers-guide.md | 54 ++++++++++++++++++++------------------------- 1 file changed, 24 insertions(+), 30 deletions(-) diff --git a/developers-guide.md b/developers-guide.md index 8d8c210..909847e 100644 --- a/developers-guide.md +++ b/developers-guide.md @@ -9,7 +9,8 @@ _Please help out by updating this page_ ### Operating System -It works on Mac OSX. Probably works without any changes or issues on linux. A masochist could probably get it working on Windows. +It works on Mac OSX. Probably works without any changes or issues on Linux. +A masochist could probably get it working on Windows. ## Installation @@ -19,54 +20,47 @@ It works on Mac OSX. Probably works without any changes or issues on linux. A ma git clone git://github.com/coffeescript-cookbook/coffeescript-cookbook.github.com.git {% endhighlight %} -### Create a Ruby Gemset +### Ruby environment -Optional, but highly recommended. +You probably want to have [RVM](http://rvm.io/) installed. -{% highlight bash %} -$ rvm gemset create jekyll -$ echo 'rvm gemset use jekyll' >> .rvmrc -{% endhighlight %} - -### Install Required Gems +The project includes a `.ruby-version` file locked to +*1.9.3* since that is what Github Pages are currently using. -{% highlight bash %} -gem install jekyll # needed for testing building the site -gem install RedCloth # needed for .md rendering -gem install serve # needed for resolving .html files w/o extension -gem install thin # optional; more efficient webserver than Webrick but not strictly necessary -{% endhighlight %} +There is also a `.ruby-gemset` that is set to *coffeescript-cookbook* -### Install pygments +### Required dependencies -You'll need python installed for this. Macs and most linuces come with it preinstalled. +We are using [Bundler](http://bundler.io/) to install the required Ruby dependencies. {% highlight bash %} -easy_install pygments # for syntax highlighting +bundle install {% endhighlight %} -## Building and Viewing the Website - -### Run jekyll +#### Install pygments -Open a terminal window, cd into the project folder and run jekyll from the project root. +You'll need python installed for this. +Macs and most Linuces come with it preinstalled. {% highlight bash %} -jekyll --auto +easy_install pygments # for syntax highlighting {% endhighlight %} -Leave this window running while you work. Any time you change a file, jekyll will rerender it into the `_site` folder. - -### Run serve +## Building and Viewing the Website -Open another terminal window, cd into the project folder, then cd into the `_site` subfolder, and run +Open a terminal window, cd into the project folder and run `foreman start` from the project root. {% highlight bash %} -serve +foreman start {% endhighlight %} -This will start a webserver in the `_site` folder. Open a browser and visit `http://localhost:4000/` and you should see the site. +Leave this window running while you work. +Any time you change a file, jekyll will rerender it into the `_site` folder. + +Open a browser and visit and you should see the site. ## Minutiae and Other Trivialities -jekyll can take a second or two to catch up when you save a file. If you edit a file and don't see the changes in your browser, give it a second or two and try again. You may also see Maruku warnings, but as long as it prints `Successfully generated site` you should be alright. +Jekyll can take a second or two to catch up when you save a file. +If you edit a file and don't see the changes in your browser, give it a second or two and try again. +As long as it prints `Successfully generated site` you should be alright. From 31a0d63425aa933afd11fa3a731fba5d1b06ef77 Mon Sep 17 00:00:00 2001 From: Julien Date: Thu, 5 Sep 2013 18:24:15 +0800 Subject: [PATCH 33/98] Fix 5 typos on the Adapter design pattern page. --- chapters/design_patterns/adapter.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/chapters/design_patterns/adapter.md b/chapters/design_patterns/adapter.md index 8be4ece..2d6fc56 100644 --- a/chapters/design_patterns/adapter.md +++ b/chapters/design_patterns/adapter.md @@ -1,12 +1,12 @@ --- layout: recipe -title: Adapter patter +title: Adapter pattern chapter: Design patterns --- ## Problem Suppose we have 3-rd party grid component. We want to apply there our own custom sorting but a small problem. Our custom sorter does not implement required interface by grid component. -To understand the problem completely best example would be an socket from our usual life. Everybody knows this device. In some countries it has 3 pins and in other contries it has only 2 pins. +To understand the problem completely best example would be an socket from our usual life. Everybody knows this device. In some countries it has 3 pins and in other countries it has only 2 pins. This is exactly right situation to use [adapter pattern](https://en.wikipedia.org/wiki/Adapter_pattern). ## Solution @@ -47,5 +47,5 @@ agrid.sort() # sort data with custom sorter through adapter ## Discussion -Adapter is usefull when you have to organize an interaction between two objects with different interfaces. It can happen when you use 3-rd party libraries or you work with legacy code. -In any case be carefull with adapter: it can be helpfull but it can instigate design errors. +Adapter is useful when you have to organize an interaction between two objects with different interfaces. It can happen when you use 3-rd party libraries or you work with legacy code. +In any case be careful with adapter: it can be helpful but it can instigate design errors. From 68aaa998b96077340a707b5ad286e07b405fb061 Mon Sep 17 00:00:00 2001 From: Julien Date: Thu, 5 Sep 2013 18:26:21 +0800 Subject: [PATCH 34/98] Anglicize the problem statement. --- chapters/design_patterns/adapter.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/chapters/design_patterns/adapter.md b/chapters/design_patterns/adapter.md index 2d6fc56..19aaca9 100644 --- a/chapters/design_patterns/adapter.md +++ b/chapters/design_patterns/adapter.md @@ -5,9 +5,12 @@ chapter: Design patterns --- ## Problem -Suppose we have 3-rd party grid component. We want to apply there our own custom sorting but a small problem. Our custom sorter does not implement required interface by grid component. -To understand the problem completely best example would be an socket from our usual life. Everybody knows this device. In some countries it has 3 pins and in other countries it has only 2 pins. -This is exactly right situation to use [adapter pattern](https://en.wikipedia.org/wiki/Adapter_pattern). +Imagine you are traveling to a foreign country and once at your hotel room you realize your power cord is not compatible with the wall electric socket. +Luckily you remember you brought with you a socket adapter. +It will connect to the wall socket on one side and to your power cord on the other side, allowing for communication between them. + +The same situation may arise in code, when 2 (or more) instances (of classes, modules, etc.) want to talk to each other, but whose communication protocol (e.i. the language they use to communicate) is different from each other. +In such a situation, the [Adapter Pattern](//en.wikipedia.org/wiki/Adapter_pattern) comes in handy. It will do the translation, from one side to the other. ## Solution @@ -47,5 +50,5 @@ agrid.sort() # sort data with custom sorter through adapter ## Discussion -Adapter is useful when you have to organize an interaction between two objects with different interfaces. It can happen when you use 3-rd party libraries or you work with legacy code. +Adapter is useful when you have to organize an interaction between two objects with different interfaces. It can happen when you use 3rd party libraries or you work with legacy code. In any case be careful with adapter: it can be helpful but it can instigate design errors. From 2324b0344fb569798d30db10de69287554826d0a Mon Sep 17 00:00:00 2001 From: Julien Date: Thu, 5 Sep 2013 19:06:11 +0800 Subject: [PATCH 35/98] Bring CoffeeScript idiom to conditional statement. An advantage of CoffeeScript compared to JavaScript is its ability to check for array membership with the `in` keyword. A feature it borrowed from Python. --- chapters/ajax/ajax_request_without_jquery.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/ajax/ajax_request_without_jquery.md b/chapters/ajax/ajax_request_without_jquery.md index 5956548..7f69c93 100644 --- a/chapters/ajax/ajax_request_without_jquery.md +++ b/chapters/ajax/ajax_request_without_jquery.md @@ -47,7 +47,7 @@ loadDataFromServer = -> req.addEventListener 'readystatechange', -> if req.readyState is 4 # ReadyState Compelte - if req.status is 200 or req.status is 304 # Success result codes + if req.status in [200, 304] # Success result codes data = eval '(' + req.responseText + ')' console.log 'data message: ', data.message else From cf2867beba00fe2cc0dbe9bf315086b4b7cd615f Mon Sep 17 00:00:00 2001 From: Julien Date: Thu, 5 Sep 2013 19:29:49 +0800 Subject: [PATCH 36/98] Amount takes only 1 'm'. --- chapters/arrays/max-array-value.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/arrays/max-array-value.md b/chapters/arrays/max-array-value.md index ce3adc1..25f1472 100644 --- a/chapters/arrays/max-array-value.md +++ b/chapters/arrays/max-array-value.md @@ -26,4 +26,4 @@ Alternatively, it's possible to use ES5 `reduce` method. For backward compatibil ## Discussion -`Math.max` compares every argument and returns the largest number from arguments. The ellipsis (`...`) converts every array value into argument which is given to the function. You can also use it with other functions which take variable ammount of arguments, such as `console.log`. +`Math.max` compares every argument and returns the largest number from arguments. The ellipsis (`...`) converts every array value into argument which is given to the function. You can also use it with other functions which take variable amount of arguments, such as `console.log`. From 227978f0c15f08ff7b4970cd531f8354e44496c3 Mon Sep 17 00:00:00 2001 From: Julien Date: Thu, 5 Sep 2013 21:29:53 +0800 Subject: [PATCH 37/98] Improve readability. --- chapters/ajax/ajax_request_without_jquery.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/chapters/ajax/ajax_request_without_jquery.md b/chapters/ajax/ajax_request_without_jquery.md index 7f69c93..d95713c 100644 --- a/chapters/ajax/ajax_request_without_jquery.md +++ b/chapters/ajax/ajax_request_without_jquery.md @@ -47,7 +47,8 @@ loadDataFromServer = -> req.addEventListener 'readystatechange', -> if req.readyState is 4 # ReadyState Compelte - if req.status in [200, 304] # Success result codes + successResultCodes = [200, 304] + if req.status in successResultCodes data = eval '(' + req.responseText + ')' console.log 'data message: ', data.message else From 026fd00545b36330624e6de3189ee0864ef60539 Mon Sep 17 00:00:00 2001 From: Julien Date: Sat, 7 Sep 2013 13:21:39 +0800 Subject: [PATCH 38/98] Better rephrase the problem statement. --- chapters/design_patterns/adapter.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/chapters/design_patterns/adapter.md b/chapters/design_patterns/adapter.md index 19aaca9..7e2af73 100644 --- a/chapters/design_patterns/adapter.md +++ b/chapters/design_patterns/adapter.md @@ -5,9 +5,9 @@ chapter: Design patterns --- ## Problem -Imagine you are traveling to a foreign country and once at your hotel room you realize your power cord is not compatible with the wall electric socket. -Luckily you remember you brought with you a socket adapter. -It will connect to the wall socket on one side and to your power cord on the other side, allowing for communication between them. +Imagine you are traveling to a foreign country and once at your hotel room you realize your power cord socket is not compatible with the wall socket. +Luckily, you remembered you've brought your power adapter with you. +It will connect your power cord socket on one side and wall socket on the other side, allowing for communication between them. The same situation may arise in code, when 2 (or more) instances (of classes, modules, etc.) want to talk to each other, but whose communication protocol (e.i. the language they use to communicate) is different from each other. In such a situation, the [Adapter Pattern](//en.wikipedia.org/wiki/Adapter_pattern) comes in handy. It will do the translation, from one side to the other. From 5f35db8957f5938c27bc9bdf3721a25af075e898 Mon Sep 17 00:00:00 2001 From: Jakob Krigovsky Date: Fri, 13 Sep 2013 19:40:39 +0200 Subject: [PATCH 39/98] =?UTF-8?q?Automatically=20update=20=E2=80=9Clast=20?= =?UTF-8?q?updated=E2=80=9D=20date?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- _layouts/chapter.html | 2 +- _layouts/default.html | 2 +- _layouts/recipe.html | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/_layouts/chapter.html b/_layouts/chapter.html index b075d2c..2bfe664 100644 --- a/_layouts/chapter.html +++ b/_layouts/chapter.html @@ -55,7 +55,7 @@

{{ page.title }}

diff --git a/_layouts/default.html b/_layouts/default.html index 1f00656..b45615d 100644 --- a/_layouts/default.html +++ b/_layouts/default.html @@ -52,7 +52,7 @@

ó diff --git a/_layouts/recipe.html b/_layouts/recipe.html index d71dfba..fd6e969 100644 --- a/_layouts/recipe.html +++ b/_layouts/recipe.html @@ -54,7 +54,7 @@

{{ page.title }}

From 0776427f49975b494a218e3144be078a7ce714bf Mon Sep 17 00:00:00 2001 From: Calum Robertson Date: Thu, 19 Sep 2013 19:08:22 +0100 Subject: [PATCH 40/98] Added the Template Method Pattern. --- authors.md | 1 + chapters/design_patterns/template_method.md | 45 +++++++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 chapters/design_patterns/template_method.md diff --git a/authors.md b/authors.md index be4922c..7876aa2 100644 --- a/authors.md +++ b/authors.md @@ -21,6 +21,7 @@ The following people are totally rad and awesome because they have contributed r * Frederic Hemberger * Mike Hatfield *oakraven13@gmail.com* * [Anton Rissanen](http://github.com/antris) *hello@anton.fi* +* Calum Robertson *http://github.com/randusr836* * ...You! What are you waiting for? Check out the [contributing](/contributing) section and get cracking! # Developers diff --git a/chapters/design_patterns/template_method.md b/chapters/design_patterns/template_method.md new file mode 100644 index 0000000..607be35 --- /dev/null +++ b/chapters/design_patterns/template_method.md @@ -0,0 +1,45 @@ +--- +layout: recipe +title: Template Method Pattern +chapter: Design Patterns +--- +## Problem + +You need to execute a series of steps according to some algorithm or recipe and wish to provide the implementation for any of the steps. + +## Solution + +Use the Template Method to describe each step in a superclass, delegating the implementation of each step to a subclass. + +For example, imagine you wish to model various types of document and each one may contain a header and a body. + +{% highlight coffeescript %} +class Document + produceDocument: -> + @produceHeader() + @produceBody() + + produceHeader: -> + produceBody: -> + +class DocWithHeader extends Document + produceHeader: -> + console.log "Producing header for DocWithHeader" + + produceBody: -> + console.log "Producing body for DocWithHeader" + +class DocWithoutHeader extends Document + produceBody: -> + console.log "Producing body for DocWithoutHeader" + +doc1 = new DocWithHeader +doc1.produceDocument() + +doc2 = new DocWithoutHeader +doc2.produceDocument() +{% endhighlight %} + +## Discussion + +In this example, there are two steps, one for producing a document header and the second for producing the document body; these two steps are given empty implementations in the superclass. The DocWithHeader implements both the body and header steps, whereas the DocWithoutHeader only impements the body step. From 198eed36fca85a819aac55ee534432d4dfcb0b9c Mon Sep 17 00:00:00 2001 From: Calum Robertson Date: Fri, 20 Sep 2013 21:39:13 +0100 Subject: [PATCH 41/98] Changes after feedback. Wrote a little about polymorphism being used in the pattern. Described in greater detail the concepts of the algorithm structure and the specification of algorithm step behaviour. --- chapters/design_patterns/template_method.md | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/chapters/design_patterns/template_method.md b/chapters/design_patterns/template_method.md index 607be35..31fe475 100644 --- a/chapters/design_patterns/template_method.md +++ b/chapters/design_patterns/template_method.md @@ -5,13 +5,13 @@ chapter: Design Patterns --- ## Problem -You need to execute a series of steps according to some algorithm or recipe and wish to provide the implementation for any of the steps. +Define the structure of an algorithm as a series of high-level steps, making it possible to specify the behaviour of each step, giving rise to a family of algorithms that have the same structure but different behaviours. ## Solution -Use the Template Method to describe each step in a superclass, delegating the implementation of each step to a subclass. +Use the Template Method to describe the algorithm structure in a superclass, delegating the implementation of some steps to one or more concrete subclasses. -For example, imagine you wish to model various types of document and each one may contain a header and a body. +For example, imagine you wish to model the production of various types of document and each one may contain a header and a body. {% highlight coffeescript %} class Document @@ -33,13 +33,12 @@ class DocWithoutHeader extends Document produceBody: -> console.log "Producing body for DocWithoutHeader" -doc1 = new DocWithHeader -doc1.produceDocument() - -doc2 = new DocWithoutHeader -doc2.produceDocument() +docs = [new DocWithHeader, new DocWithoutHeader] +doc.produceDocument() for doc in docs {% endhighlight %} ## Discussion -In this example, there are two steps, one for producing a document header and the second for producing the document body; these two steps are given empty implementations in the superclass. The DocWithHeader implements both the body and header steps, whereas the DocWithoutHeader only impements the body step. +In this example, the algorithm consists of two steps describing document production: one for producing a document header and the second for producing the document body. An empty method implementation for each step is present in the superclass and polymorphism is exploited such that each concrete subclass can provide a different implementation for a step by overriding a step method. In this example,the DocWithHeader implements both the body and header steps, whereas the DocWithoutHeader only implements the body step. + +The production of different types of document is then straightforward when document objects are stored in an array, and it is then a simple of matter of iterating over each document object and calling its produceDocument method. \ No newline at end of file From 2228b639d6e1b06cdb9d15b4a18aa1e971e9b0cf Mon Sep 17 00:00:00 2001 From: Devin Weaver Date: Tue, 8 Oct 2013 00:48:21 -0400 Subject: [PATCH 42/98] Changed to best practice of the `this` keyword I've seen several people on IRC talk about readability. It seems there is some opinions that when chaining like this the `this` keyword is more readable then a dangling `@` symbol. I think it is a good idea to offer code readability in this project. Feel free to revert this commit if this is disputed. (Unable to open a PR from in the Github UI). --- chapters/classes_and_objects/chaining.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/chapters/classes_and_objects/chaining.md b/chapters/classes_and_objects/chaining.md index 65f450f..be19212 100644 --- a/chapters/classes_and_objects/chaining.md +++ b/chapters/classes_and_objects/chaining.md @@ -20,13 +20,13 @@ class CoffeeCup sugar: false strength: (newStrength) -> @properties.strength = newStrength - @ + this cream: (newCream) -> @properties.cream = newCream - @ + this sugar: (newSugar) -> @properties.sugar = newSugar - @ + this morningCup = new CoffeeCup() From 5358690140a8d0a8efffe43cf3bac8ccb2857e06 Mon Sep 17 00:00:00 2001 From: Stephen Daves Date: Tue, 22 Oct 2013 23:20:23 -0600 Subject: [PATCH 43/98] Remove unneeded word --- chapters/design_patterns/singleton.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/design_patterns/singleton.md b/chapters/design_patterns/singleton.md index 18bbf27..6aff70c 100644 --- a/chapters/design_patterns/singleton.md +++ b/chapters/design_patterns/singleton.md @@ -12,7 +12,7 @@ Many times you only want one, and only one, instance of a class. For example, yo The publicly available class only contains the method to get the one true instance. The instance is kept within the closure of that public object and is always returned. -This is works because CoffeeScript allows you to define executable statements inside a class definition. However, because most CoffeeScript compiles into a [IIFE][] wrapper you do not have to place the private class inside the class definition if this style suits you. The later might be useful when developing modular code such as found in [CommonJS][] (Node.js) or [Require.js][] (See the discussion for an example). +This works because CoffeeScript allows you to define executable statements inside a class definition. However, because most CoffeeScript compiles into a [IIFE][] wrapper you do not have to place the private class inside the class definition if this style suits you. The later might be useful when developing modular code such as found in [CommonJS][] (Node.js) or [Require.js][] (See the discussion for an example). [IIFE]: http://benalman.com/news/2010/11/immediately-invoked-function-expression/ [CommonJS]: http://www.commonjs.org/ From 2cc50bce27bbd9f70341678c6acf3c565ed255b9 Mon Sep 17 00:00:00 2001 From: Orban Botond Date: Sun, 3 Nov 2013 15:48:40 +0200 Subject: [PATCH 44/98] FIX #95 --- chapters/arrays/testing-every-element.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/arrays/testing-every-element.md b/chapters/arrays/testing-every-element.md index 5978500..4f82c2a 100644 --- a/chapters/arrays/testing-every-element.md +++ b/chapters/arrays/testing-every-element.md @@ -12,7 +12,7 @@ You want to be able to check that every element in an array meets a particular c Use Array.every (ECMAScript 5): {% highlight coffeescript %} -evens = (x for x in [1..10] by 2) +evens = (x for x in [0..10] by 2) evens.every (x)-> x % 2 == 0 # => true From 2d16a576acd38b3666737d4861aca87652ee3502 Mon Sep 17 00:00:00 2001 From: jlburkhead Date: Sun, 15 Dec 2013 04:49:15 -0500 Subject: [PATCH 45/98] add an example of generating random numbers in an arbitrary range --- chapters/math/generating-random-numbers.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/chapters/math/generating-random-numbers.md b/chapters/math/generating-random-numbers.md index f181940..afb1c5c 100644 --- a/chapters/math/generating-random-numbers.md +++ b/chapters/math/generating-random-numbers.md @@ -24,6 +24,12 @@ percentile = Math.floor(Math.random() * 100) dice = Math.floor(Math.random() * 6) + 1 1 <= dice <= 6 # => true + +max = 42 +min = -13 +range = Math.random() * (max - min) + min +-13 <= range < 42 +# => true {% endhighlight %} ## Discussion From dd4f0b9ea9a60ba4b3d31abe34f92f643074a129 Mon Sep 17 00:00:00 2001 From: jlburkhead Date: Sun, 15 Dec 2013 05:06:33 -0500 Subject: [PATCH 46/98] add recipe on exponents and logarithms --- .../working-with-exponents-and-logarithms.md | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 chapters/math/working-with-exponents-and-logarithms.md diff --git a/chapters/math/working-with-exponents-and-logarithms.md b/chapters/math/working-with-exponents-and-logarithms.md new file mode 100644 index 0000000..6891530 --- /dev/null +++ b/chapters/math/working-with-exponents-and-logarithms.md @@ -0,0 +1,37 @@ +--- +layout: recipe +title: Working with Exponents and Logarithms +chapter: Math +--- +## Problem + +You need to do some calculations that involve exponents and logarithms. + +## Solution + +Use Javascript's Math object to provide common mathematical functions. + +{% highlight coffeescript %} +# Math.pow(x, y) returns x^y +Math.pow(2, 4) +# => 16 + +# Math.exp(x) returns E^x and is shorthand for Math.pow(Math.E, x) +Math.exp(2) +# => 7.38905609893065 + +# Math.log returns the natural (base E) log +Math.log(5) +# => 1.6094379124341003 +Math.log(Math.exp(42)) +# => 42 + +# To get a log with some other base n, divide by Math.log(n) +Math.log(100) / Math.log(10) +# => 2 + +{% endhighlight %} + +## Discussion + +For more information on the Math object see the documentation on the [Mozilla Developer Netword](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math). Also refer to [Converting Radians and Degrees](/chapters/math/radians-degrees) for discussion of the various constants in the Math object. From 658abba3357ff67286019b5a376a0642be341ca3 Mon Sep 17 00:00:00 2001 From: jlburkhead Date: Sun, 15 Dec 2013 15:10:48 -0500 Subject: [PATCH 47/98] fix another typo and link to correct reference --- authors.md | 1 + chapters/math/working-with-exponents-and-logarithms.md | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/authors.md b/authors.md index 7876aa2..70bea43 100644 --- a/authors.md +++ b/authors.md @@ -22,6 +22,7 @@ The following people are totally rad and awesome because they have contributed r * Mike Hatfield *oakraven13@gmail.com* * [Anton Rissanen](http://github.com/antris) *hello@anton.fi* * Calum Robertson *http://github.com/randusr836* +* Jake Burkhead *https://github.com/jlburkhead* * ...You! What are you waiting for? Check out the [contributing](/contributing) section and get cracking! # Developers diff --git a/chapters/math/working-with-exponents-and-logarithms.md b/chapters/math/working-with-exponents-and-logarithms.md index 6891530..c8e7c49 100644 --- a/chapters/math/working-with-exponents-and-logarithms.md +++ b/chapters/math/working-with-exponents-and-logarithms.md @@ -34,4 +34,4 @@ Math.log(100) / Math.log(10) ## Discussion -For more information on the Math object see the documentation on the [Mozilla Developer Netword](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math). Also refer to [Converting Radians and Degrees](/chapters/math/radians-degrees) for discussion of the various constants in the Math object. +For more information on the Math object see the documentation on the [Mozilla Developer Network](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math). Also refer to [Math Constants](/chapters/math/constants) for discussion of the various constants in the Math object. From 3ff4351575f1dd89e9689a8b78ab7710a0e44961 Mon Sep 17 00:00:00 2001 From: Ayush Gupta Date: Tue, 18 Mar 2014 17:20:15 +0530 Subject: [PATCH 48/98] updated string interpolation to mention that it works only with double quoted strings --- chapters/strings/interpolation.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/chapters/strings/interpolation.md b/chapters/strings/interpolation.md index b1e1e9e..a437be4 100644 --- a/chapters/strings/interpolation.md +++ b/chapters/strings/interpolation.md @@ -11,7 +11,8 @@ CoffeeScript Variable. ## Solution Use CoffeeScript's ruby-like string interpolation instead of -JavaScript's string addition. +JavaScript's string addition. You must use Double-quoted strings to +allow for interpolation. Single-quoted strings are treated as literals. Interpolation: From dc70747b1a4e8679f975b424311ed9ea08943412 Mon Sep 17 00:00:00 2001 From: Marc Bodmer Date: Sat, 29 Mar 2014 16:43:43 -0400 Subject: [PATCH 49/98] Remove completed recipes for wanted recipes documentation --- wanted-recipes.md | 25 +------------------------ 1 file changed, 1 insertion(+), 24 deletions(-) diff --git a/wanted-recipes.md b/wanted-recipes.md index 64eec51..5adc15d 100644 --- a/wanted-recipes.md +++ b/wanted-recipes.md @@ -8,16 +8,10 @@ Here's a list of recipes we think we need. Pick one, implement it, and remove it In the notes below, "JS" means the recipe is just a simple passthrough to an existing JavaScript method. -## Introduction - -We need a better introduction. Right now the first recipe is [Embedding JavaScript](/chapters/syntax/embedding_javascript), which doesn't set the right first impression. How about three or four recipes that hold new users' hands a bit more as the first section? - ## Syntax * Ensuring variables are closed over # with "do" -## Objects - ## Strings * HTML methods # JS .sup(), .sub(), .blink(), .link(url), etc. May not exist in your JS impl! @@ -45,10 +39,6 @@ evens.every even [1..10].some (x) -> x % 2 == 0 # => true {% endhighlight %} -## Dates and Times - -* Empty - ## Math * square root # JS Math.sqrt @@ -89,24 +79,11 @@ foo 1, 2, 3 # => 6 {% endhighlight %} -## jQuery - -## Regular Expressions - -## Networking - -* Streaming HTTP server -* Streaming HTTP client - -## AJAX - -* Getting data from a remote server # using raw XHTTPRequest instead of jQuery's `$.ajax` - ## Design patterns * Creational Patterns * Abstract Factory - * Prototype + * Prototype * Structural Patterns * Adapter From 6fe6cce0b1776795f516415fced927fab29e2c8a Mon Sep 17 00:00:00 2001 From: Simon Taranto Date: Wed, 2 Apr 2014 10:42:38 -0700 Subject: [PATCH 50/98] Remove duplicate words --- chapters/regular_expressions/searching-for-substrings.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/regular_expressions/searching-for-substrings.md b/chapters/regular_expressions/searching-for-substrings.md index 1928591..888c774 100644 --- a/chapters/regular_expressions/searching-for-substrings.md +++ b/chapters/regular_expressions/searching-for-substrings.md @@ -23,7 +23,7 @@ match = /sample/i.test("Sample text") # => true {% endhighlight %} -The next way to is to call the `exec` method on a `RegExp` pattern or object. The `exec` method returns an array an array with the match information or `null`: +The next way to is to call the `exec` method on a `RegExp` pattern or object. The `exec` method returns an array with the match information or `null`: {% highlight coffeescript %} match = /s(amp)le/i.exec "Sample text" From 552577922c2209b10ae250926ceb71eb5a4eeb4d Mon Sep 17 00:00:00 2001 From: rdubigny Date: Sat, 5 Apr 2014 17:17:15 +0200 Subject: [PATCH 51/98] Change folder name "tests" -> "test" I just lost one hour because of that. --- chapters/testing/testing_with_nodeunit.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/testing/testing_with_nodeunit.md b/chapters/testing/testing_with_nodeunit.md index 30af5b8..ec610d2 100644 --- a/chapters/testing/testing_with_nodeunit.md +++ b/chapters/testing/testing_with_nodeunit.md @@ -17,7 +17,7 @@ For example, we expect our calculator will be able to add and subtract and will {% highlight coffeescript %} -# tests/calculator.test.coffee +# test/calculator.test.coffee Calculator = require '../calculator' From 91e7d3eb8a49a124896fc3101cd4bd0195928e61 Mon Sep 17 00:00:00 2001 From: Joseph Chiocchi Date: Mon, 7 Apr 2014 17:08:07 -0500 Subject: [PATCH 52/98] fix typo on testing-every-element.md --- chapters/arrays/testing-every-element.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/arrays/testing-every-element.md b/chapters/arrays/testing-every-element.md index 4f82c2a..12b78a1 100644 --- a/chapters/arrays/testing-every-element.md +++ b/chapters/arrays/testing-every-element.md @@ -20,7 +20,7 @@ evens.every (x)-> x % 2 == 0 Array.every was addded to Mozilla's Javascript 1.6 and made standard with EcmaScript 5. If you to support browsers that do not implement EC5 then check out [`_.all` from underscore.js][underscore]. -For a real world example, prentend you have a multiple select list that looks like: +For a real world example, pretend you have a multiple select list that looks like: {% highlight html %}