From 7eb59ba8fb4b470a3e8f1ac53c33ec1f96842dc4 Mon Sep 17 00:00:00 2001 From: Kevin McDermott Date: Sat, 2 Mar 2013 21:16:40 -0500 Subject: [PATCH 01/88] 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 02/88] 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 03/88] 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 04/88] 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 05/88] 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 06/88] 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 07/88] 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 08/88] 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 09/88] 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 10/88] 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 11/88] 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 12/88] 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 13/88] 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 14/88] 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 15/88] 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 16/88] 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 17/88] 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 18/88] 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 19/88] 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 20/88] 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 21/88] 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 22/88] 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 23/88] 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 24/88] 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 25/88] 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 26/88] 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 27/88] 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 28/88] 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 29/88] =?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 30/88] 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 31/88] 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 32/88] 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 33/88] 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 34/88] 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 35/88] 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 36/88] 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 37/88] 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 38/88] 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 39/88] 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 40/88] 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 41/88] 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 42/88] 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 %}