Repository: coffeescript-cookbook/coffeescript-cookbook.github.io
Branch: master
Commit: 53fc0026d147
Files: 147
Total size: 334.9 KB
Directory structure:
gitextract_ml6e9x2u/
├── .gitignore
├── .ruby-gemset
├── .ruby-version
├── Gemfile
├── LICENSE-CC-BY.textile
├── Procfile
├── README.md
├── _config.yml
├── _data/
│ └── chapters.yml
├── _layouts/
│ ├── chapter.html
│ ├── default.html
│ └── recipe.html
├── authors-guide.md
├── authors.md
├── chapters/
│ ├── ajax/
│ │ ├── ajax_request_without_jquery.md
│ │ └── index.html
│ ├── arrays/
│ │ ├── check-type-is-array.md
│ │ ├── concatenating-arrays.md
│ │ ├── creating-a-dictionary-object-from-an-array.md
│ │ ├── creating-a-string-from-an-array.md
│ │ ├── define-ranges.md
│ │ ├── filtering-arrays.md
│ │ ├── index.html
│ │ ├── list-comprehensions.md
│ │ ├── mapping-arrays.md
│ │ ├── max-array-value.md
│ │ ├── reducing-arrays.md
│ │ ├── removing-duplicate-elements-from-arrays.md
│ │ ├── reversing-arrays.md
│ │ ├── shuffling-array-elements.md
│ │ ├── testing-every-element.md
│ │ ├── using-arrays-to-swap-variables.md
│ │ ├── where-for-arrays-of-objects.md
│ │ └── zip-function.md
│ ├── classes_and_objects/
│ │ ├── chaining.md
│ │ ├── class-methods-and-instance-methods.md
│ │ ├── class-variables-and-instance-variables.md
│ │ ├── cloning.md
│ │ ├── index.html
│ │ ├── mixins.md
│ │ ├── object-literal.md
│ │ └── type-function.md
│ ├── databases/
│ │ ├── index.html
│ │ ├── mongodb.md
│ │ └── sqlite.md
│ ├── dates_and_times/
│ │ ├── date-of-easter.md
│ │ ├── date-of-thanksgiving.md
│ │ ├── days-between-two-dates.md
│ │ ├── finding-last-day-of-the-month.md
│ │ ├── finding-last-or-next-month.md
│ │ ├── index.html
│ │ └── moon-phase-for-date.md
│ ├── design_patterns/
│ │ ├── adapter.md
│ │ ├── bridge.md
│ │ ├── builder.md
│ │ ├── command.md
│ │ ├── decorator.md
│ │ ├── factory_method.md
│ │ ├── index.html
│ │ ├── interpreter.md
│ │ ├── memento.md
│ │ ├── observer.md
│ │ ├── singleton.md
│ │ ├── strategy.md
│ │ └── template_method.md
│ ├── functions/
│ │ ├── debounce.md
│ │ ├── index.html
│ │ ├── parentheses.md
│ │ ├── recursion.md
│ │ └── splat_arguments.md
│ ├── index.html
│ ├── jquery/
│ │ ├── ajax.md
│ │ ├── callback-bindings-jquery.md
│ │ ├── index.html
│ │ └── plugin.md
│ ├── math/
│ │ ├── constants.md
│ │ ├── fast-fibonacci.md
│ │ ├── fast-inv-square.md
│ │ ├── generating-predictable-random-numbers.md
│ │ ├── generating-random-numbers.md
│ │ ├── index.html
│ │ ├── radians-degrees.md
│ │ ├── random-integer.md
│ │ └── working-with-exponents-and-logarithms.md
│ ├── metaprogramming/
│ │ ├── detecting-and-replacing-functions.md
│ │ ├── extending-built-in-objects.md
│ │ └── index.html
│ ├── networking/
│ │ ├── basic-client.md
│ │ ├── basic-http-client.md
│ │ ├── basic-http-server.md
│ │ ├── basic-server.md
│ │ ├── bi-directional-client.md
│ │ ├── bi-directional-server.md
│ │ └── index.html
│ ├── regular_expressions/
│ │ ├── heregexes.md
│ │ ├── index.html
│ │ ├── replacing-html-tags-with-html-named-entities.md
│ │ ├── replacing-substrings.md
│ │ └── searching-for-substrings.md
│ ├── strings/
│ │ ├── capitalizing-words.md
│ │ ├── finding-substrings.md
│ │ ├── generating-a-unique-id.md
│ │ ├── index.html
│ │ ├── interpolation.md
│ │ ├── lowercasing-a-string.md
│ │ ├── matching-strings.md
│ │ ├── repeating.md
│ │ ├── replacing-sub-strings.md
│ │ ├── splitting-a-string.md
│ │ ├── trimming-whitespace-from-a-string.md
│ │ └── uppercasing-a-string.md
│ ├── syntax/
│ │ ├── code_reuse_on_client_and_server.md
│ │ ├── comparing_ranges.md
│ │ ├── embedding_javascript.md
│ │ ├── for_loops.md
│ │ └── index.html
│ └── testing/
│ ├── index.html
│ ├── testing_with_jasmine.md
│ └── testing_with_nodeunit.md
├── contributing.md
├── css/
│ ├── autumn.css
│ ├── borland.css
│ ├── bw.css
│ ├── colorful.css
│ ├── default.css
│ ├── emacs.css
│ ├── friendly.css
│ ├── fruity.css
│ ├── manni.css
│ ├── murphy.css
│ ├── native.css
│ ├── pastie.css
│ ├── perldoc.css
│ ├── solarized-light.css
│ ├── style.css
│ ├── tango.css
│ ├── trac.css
│ ├── vim.css
│ └── vs.css
├── designers-guide.md
├── developers-guide.md
├── index.html
├── js/
│ └── scripts.js
├── license.md
├── recipe-template.md
├── terms-of-use.md
└── wanted-recipes.md
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
.rvmrc
_site
*.swp
*.swo
.DS_Store
# IntelliJ IDEA / WebStorm
/.idea/
/*.iml
================================================
FILE: .ruby-gemset
================================================
coffeescript-cookbook
================================================
FILE: .ruby-version
================================================
1.9.3
================================================
FILE: Gemfile
================================================
source 'https://rubygems.org'
group :development do
gem "github-pages"
gem "tzinfo-data"
gem "foreman"
gem "serve"
end
================================================
FILE: LICENSE-CC-BY.textile
================================================
---
layout: default
title: "Creative Commons License: Attribution 3.0 Unported (CC BY 3.0)"
---
License
THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED.
BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS.
1. Definitions
"Adaptation" means a work based upon the Work, or upon the Work and other pre-existing works, such as a translation, adaptation, derivative work, arrangement of music or other alterations of a literary or artistic work, or phonogram or performance and includes cinematographic adaptations or any other form in which the Work may be recast, transformed, or adapted including in any form recognizably derived from the original, except that a work that constitutes a Collection will not be considered an Adaptation for the purpose of this License. For the avoidance of doubt, where the Work is a musical work, performance or phonogram, the synchronization of the Work in timed-relation with a moving image ("synching") will be considered an Adaptation for the purpose of this License.
"Collection" means a collection of literary or artistic works, such as encyclopedias and anthologies, or performances, phonograms or broadcasts, or other works or subject matter other than works listed in Section 1(f) below, which, by reason of the selection and arrangement of their contents, constitute intellectual creations, in which the Work is included in its entirety in unmodified form along with one or more other contributions, each constituting separate and independent works in themselves, which together are assembled into a collective whole. A work that constitutes a Collection will not be considered an Adaptation (as defined above) for the purposes of this License.
"Distribute" means to make available to the public the original and copies of the Work or Adaptation, as appropriate, through sale or other transfer of ownership.
"Licensor" means the individual, individuals, entity or entities that offer(s) the Work under the terms of this License.
"Original Author" means, in the case of a literary or artistic work, the individual, individuals, entity or entities who created the Work or if no individual or entity can be identified, the publisher; and in addition (i) in the case of a performance the actors, singers, musicians, dancers, and other persons who act, sing, deliver, declaim, play in, interpret or otherwise perform literary or artistic works or expressions of folklore; (ii) in the case of a phonogram the producer being the person or legal entity who first fixes the sounds of a performance or other sounds; and, (iii) in the case of broadcasts, the organization that transmits the broadcast.
"Work" means the literary and/or artistic work offered under the terms of this License including without limitation any production in the literary, scientific and artistic domain, whatever may be the mode or form of its expression including digital form, such as a book, pamphlet and other writing; a lecture, address, sermon or other work of the same nature; a dramatic or dramatico-musical work; a choreographic work or entertainment in dumb show; a musical composition with or without words; a cinematographic work to which are assimilated works expressed by a process analogous to cinematography; a work of drawing, painting, architecture, sculpture, engraving or lithography; a photographic work to which are assimilated works expressed by a process analogous to photography; a work of applied art; an illustration, map, plan, sketch or three-dimensional work relative to geography, topography, architecture or science; a performance; a broadcast; a phonogram; a compilation of data to the extent it is protected as a copyrightable work; or a work performed by a variety or circus performer to the extent it is not otherwise considered a literary or artistic work.
"You" means an individual or entity exercising rights under this License who has not previously violated the terms of this License with respect to the Work, or who has received express permission from the Licensor to exercise rights under this License despite a previous violation.
"Publicly Perform" means to perform public recitations of the Work and to communicate to the public those public recitations, by any means or process, including by wire or wireless means or public digital performances; to make available to the public Works in such a way that members of the public may access these Works from a place and at a place individually chosen by them; to perform the Work to the public by any means or process and the communication to the public of the performances of the Work, including by public digital performance; to broadcast and rebroadcast the Work by any means including signs, sounds or images.
"Reproduce" means to make copies of the Work by any means including without limitation by sound or visual recordings and the right of fixation and reproducing fixations of the Work, including storage of a protected performance or phonogram in digital form or other electronic medium.
2. Fair Dealing Rights. Nothing in this License is intended to reduce, limit, or restrict any uses free from copyright or rights arising from limitations or exceptions that are provided for in connection with the copyright protection under copyright law or other applicable laws.
3. License Grant. Subject to the terms and conditions of this License, Licensor hereby grants You a worldwide, royalty-free, non-exclusive, perpetual (for the duration of the applicable copyright) license to exercise the rights in the Work as stated below:
to Reproduce the Work, to incorporate the Work into one or more Collections, and to Reproduce the Work as incorporated in the Collections;
to create and Reproduce Adaptations provided that any such Adaptation, including any translation in any medium, takes reasonable steps to clearly label, demarcate or otherwise identify that changes were made to the original Work. For example, a translation could be marked "The original work was translated from English to Spanish," or a modification could indicate "The original work has been modified.";
to Distribute and Publicly Perform the Work including as incorporated in Collections; and,
to Distribute and Publicly Perform Adaptations.
For the avoidance of doubt:
Non-waivable Compulsory License Schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme cannot be waived, the Licensor reserves the exclusive right to collect such royalties for any exercise by You of the rights granted under this License;
Waivable Compulsory License Schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme can be waived, the Licensor waives the exclusive right to collect such royalties for any exercise by You of the rights granted under this License; and,
Voluntary License Schemes. The Licensor waives the right to collect royalties, whether individually or, in the event that the Licensor is a member of a collecting society that administers voluntary licensing schemes, via that society, from any exercise by You of the rights granted under this License.
The above rights may be exercised in all media and formats whether now known or hereafter devised. The above rights include the right to make such modifications as are technically necessary to exercise the rights in other media and formats. Subject to Section 8(f), all rights not expressly granted by Licensor are hereby reserved.
4. Restrictions. The license granted in Section 3 above is expressly made subject to and limited by the following restrictions:
You may Distribute or Publicly Perform the Work only under the terms of this License. You must include a copy of, or the Uniform Resource Identifier (URI) for, this License with every copy of the Work You Distribute or Publicly Perform. You may not offer or impose any terms on the Work that restrict the terms of this License or the ability of the recipient of the Work to exercise the rights granted to that recipient under the terms of the License. You may not sublicense the Work. You must keep intact all notices that refer to this License and to the disclaimer of warranties with every copy of the Work You Distribute or Publicly Perform. When You Distribute or Publicly Perform the Work, You may not impose any effective technological measures on the Work that restrict the ability of a recipient of the Work from You to exercise the rights granted to that recipient under the terms of the License. This Section 4(a) applies to the Work as incorporated in a Collection, but this does not require the Collection apart from the Work itself to be made subject to the terms of this License. If You create a Collection, upon notice from any Licensor You must, to the extent practicable, remove from the Collection any credit as required by Section 4(b), as requested. If You create an Adaptation, upon notice from any Licensor You must, to the extent practicable, remove from the Adaptation any credit as required by Section 4(b), as requested.
If You Distribute, or Publicly Perform the Work or any Adaptations or Collections, You must, unless a request has been made pursuant to Section 4(a), keep intact all copyright notices for the Work and provide, reasonable to the medium or means You are utilizing: (i) the name of the Original Author (or pseudonym, if applicable) if supplied, and/or if the Original Author and/or Licensor designate another party or parties (e.g., a sponsor institute, publishing entity, journal) for attribution ("Attribution Parties") in Licensor's copyright notice, terms of service or by other reasonable means, the name of such party or parties; (ii) the title of the Work if supplied; (iii) to the extent reasonably practicable, the URI, if any, that Licensor specifies to be associated with the Work, unless such URI does not refer to the copyright notice or licensing information for the Work; and (iv) , consistent with Section 3(b), in the case of an Adaptation, a credit identifying the use of the Work in the Adaptation (e.g., "French translation of the Work by Original Author," or "Screenplay based on original Work by Original Author"). The credit required by this Section 4 (b) may be implemented in any reasonable manner; provided, however, that in the case of a Adaptation or Collection, at a minimum such credit will appear, if a credit for all contributing authors of the Adaptation or Collection appears, then as part of these credits and in a manner at least as prominent as the credits for the other contributing authors. For the avoidance of doubt, You may only use the credit required by this Section for the purpose of attribution in the manner set out above and, by exercising Your rights under this License, You may not implicitly or explicitly assert or imply any connection with, sponsorship or endorsement by the Original Author, Licensor and/or Attribution Parties, as appropriate, of You or Your use of the Work, without the separate, express prior written permission of the Original Author, Licensor and/or Attribution Parties.
Except as otherwise agreed in writing by the Licensor or as may be otherwise permitted by applicable law, if You Reproduce, Distribute or Publicly Perform the Work either by itself or as part of any Adaptations or Collections, You must not distort, mutilate, modify or take other derogatory action in relation to the Work which would be prejudicial to the Original Author's honor or reputation. Licensor agrees that in those jurisdictions (e.g. Japan), in which any exercise of the right granted in Section 3(b) of this License (the right to make Adaptations) would be deemed to be a distortion, mutilation, modification or other derogatory action prejudicial to the Original Author's honor and reputation, the Licensor will waive or not assert, as appropriate, this Section, to the fullest extent permitted by the applicable national law, to enable You to reasonably exercise Your right under Section 3(b) of this License (right to make Adaptations) but not otherwise.
5. Representations, Warranties and Disclaimer
UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING, LICENSOR OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU.
6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
7. Termination
This License and the rights granted hereunder will terminate automatically upon any breach by You of the terms of this License. Individuals or entities who have received Adaptations or Collections from You under this License, however, will not have their licenses terminated provided such individuals or entities remain in full compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will survive any termination of this License.
Subject to the above terms and conditions, the license granted here is perpetual (for the duration of the applicable copyright in the Work). Notwithstanding the above, Licensor reserves the right to release the Work under different license terms or to stop distributing the Work at any time; provided, however that any such election will not serve to withdraw this License (or any other license that has been, or is required to be, granted under the terms of this License), and this License will continue in full force and effect unless terminated as stated above.
8. Miscellaneous
Each time You Distribute or Publicly Perform the Work or a Collection, the Licensor offers to the recipient a license to the Work on the same terms and conditions as the license granted to You under this License.
Each time You Distribute or Publicly Perform an Adaptation, Licensor offers to the recipient a license to the original Work on the same terms and conditions as the license granted to You under this License.
If any provision of this License is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this License, and without further action by the parties to this agreement, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.
No term or provision of this License shall be deemed waived and no breach consented to unless such waiver or consent shall be in writing and signed by the party to be charged with such waiver or consent.
This License constitutes the entire agreement between the parties with respect to the Work licensed here. There are no understandings, agreements or representations with respect to the Work not specified here. Licensor shall not be bound by any additional provisions that may appear in any communication from You. This License may not be modified without the mutual written agreement of the Licensor and You.
The rights granted under, and the subject matter referenced, in this License were drafted utilizing the terminology of the Berne Convention for the Protection of Literary and Artistic Works (as amended on September 28, 1979), the Rome Convention of 1961, the WIPO Copyright Treaty of 1996, the WIPO Performances and Phonograms Treaty of 1996 and the Universal Copyright Convention (as revised on July 24, 1971). These rights and subject matter take effect in the relevant jurisdiction in which the License terms are sought to be enforced according to the corresponding provisions of the implementation of those treaty provisions in the applicable national law. If the standard suite of rights granted under applicable copyright law includes additional rights not granted under this License, such additional rights are deemed to be included in the License; this License is not intended to restrict the license of any rights under applicable law.
================================================
FILE: Procfile
================================================
jekyll: bundle exec jekyll build --watch
serve: bundle exec serve 4000 development _site
================================================
FILE: README.md
================================================
CoffeeScript Cookbook
=============
CoffeeScript Cookbook is a community run website for the CoffeeScript language.
We want you to write recipes and make the site better!
Contributing
-----------
You can find details about contributing [on the site](http://coffeescript-cookbook.github.io/contributing). For now here is a simple formula:
1. Fork the repository at [GitHub](http://github.com/coffeescript-cookbook/coffeescript-cookbook.github.com)
2. Do awesomeness!
3. Send a pull request to [coffeescript-cookbook](http://github.com/coffeescript-cookbook/coffeescript-cookbook.github.com)
4. If we merge your pull request, you get commit access. BAM. Go back to step 2 and stay there as long as you want.
Here are some relevant links from the site.
* [Contributing](http://coffeescript-cookbook.github.io/contributing)
* [Recipe Template](http://coffeescript-cookbook.github.io/recipe-template)
* [Author's Guide](http://coffeescript-cookbook.github.io/authors-guide)
* [Developer's Guide](http://coffeescript-cookbook.github.io/developers-guide)
* [Designer's Guide](http://coffeescript-cookbook.github.io/designers-guide)
Jekyll
------
CoffeeScript Cookbook is currently implemented as a jekyll site. Jekyll is awesome.
* [Site](http://jekyllrb.com/)
* [Code](https://github.com/mojombo/jekyll)
* [Wiki](https://github.com/mojombo/jekyll/wiki)
License
-------
This site and all contributions are [licensed](http://coffeescript-cookbook.github.io/LICENSE-CC-BY) under the Creative Commons Attribution 3.0 Unported (CC BY 3.0) license. By submitting information to this site you agree to grant this license to all users of the site, and that your editing of the authors page constitutes satisfactory attribution.
================================================
FILE: _config.yml
================================================
baseurl: ''
safe: true
highlighter: pygments
lsi: false
markdown: redcarpet
exclude:
- README.md
- CNAME
- TODO.md
- script
- Procfile
- Gemfile
- Gemfile.lock
================================================
FILE: _data/chapters.yml
================================================
---
- Syntax
- Classes and Objects
- Strings
- Arrays
- Dates and Times
- Math
- Functions
- Metaprogramming
- jQuery
- Ajax
- Regular Expressions
- Networking
- Design Patterns
- Databases
- Testing
================================================
FILE: _layouts/chapter.html
================================================
{{ content }}
================================================
FILE: authors-guide.md
================================================
---
layout: default
title: Author's Guide
---
# Author's Guide
## tl;dr: Look at Other Recipes, and Blend In
Look at the source of other recipe pages and follow that page structure. Start with the [Developer's Guide]({{ site.baseurl }}/developers-guide) to get a test version of the cookbook up and running on your machine, and get to work!
## General Guidelines
* Feel free to add new pages, or even chapters. Just keep them organized. _(See "How to Add a Chapter" below)_
* Try to write well-styled, idiomatic CoffeeScript.
* Try to stay within the Problem/Solution/Discussion format. If you can't think of a good problem for your recipe... hang onto it for a while.
* Sharing code that you think might only be used rarely is fine. Sharing esoteric code tricks is less so. There's a difference between sharing a translator for an obscure format and sharing a weird bit-shifting trick that does fast but inaccurate multiplication.
* Don't forget to add your name to the authors page!
## Use Cookbook Problem/Solution/Discussion Format
A typical cookbook page will have three sections (four if you count the title):
* **Problem** A one- or two-sentence description of the problem, such as "You want to access parts of a string" or "You want to format a floating point number as currency, with a leading dollar sign, two digits of precision and comma-separated triples." Where possible, phrase the problem as though speaking directly to the reader: "You want to...", "You have an X but you want a Y", etc.
* **Solution** State the solution as briefly as possible, ideally as a single sentence that identifies the strategy you would use, and give example code. It's tempting to explain the solution, but don't do it yet. Remember that the reader will look this solution up many times after the first time, and that they will be looking for a quick reference each time. You're going to explain the solution in the **Discussion**, and the first time reader will read your solution, think about it, and then proceed to the discussion if necessary. For example, for "accessing parts of a string", a good Solution sentence might be "Use CoffeeScript's array range subscripts, or JavaScript's slice function."
* **Discussion** Here you should explain why your solution works, or give further examples such as edge cases. If your solution can break on some edge cases, be sure to note them here. For example, if a percentage function crashes when given a zero, you could note this in the discussion and give a workaround. NOTE: If your solution has really dangerous edge cases, so dangerous that you would include them in the solution, please consider whether your recipe should be included at all. Remember, this Cookbook is for good code!
## Copyright Issues
Do not post code that is copyrighted by another user, unless you have permission to use that code AND to relicense that code under the [CC BY 3.0]({{ site.baseurl }}/license) license. If you DO have permission and the author would like credit, please add them to the [authors]({{ site.baseurl }}/authors) page.
Also, just a stylistic note, please do not yank code directly from [http://coffeescript.org/](http://coffeescript.org/) and post it with little or no discussion. The CoffeeScript Cookbook is not affiliated with them. We think they're awesome and want them to like us, too! Make sure that anything taken from [http://coffeescript.org/](http://coffeescript.org/) is permissible use and that it stands alone as a valid recipe. If the recipe is too terse, consider adding more examples and discussion.
## Tag the page with Jekyll frontmatter
...that's a lot of fancy words that mean "don't forget to put the layout, chapter and page title at the top of the file in a YAML block". For example, the string interpolation page begins with
{% highlight text %}
---
layout: recipe
title: String Interpolation
chapter: Strings
---
{% endhighlight %}
## Use Liquid highlighting templates
Turn on syntax highlighting for CoffeeScript with `highlight coffeescript`.
test2
{% highlight coffeescript %}
# Calculate the square of a number
square = (x) -> x * x
square(16)
# => 256
{% endhighlight %}
This produces the following:
{% highlight coffeescript %}
# Calculate the square of a number
square = (x) -> x * x
square(16)
# => 256
{% endhighlight %}
## Include Output
After writing an important expression, show the reader what the output would be by adding it with a `# =>` on the following line. Once we get automated script testing working up in this joint, we'll actually load up your recipe snippets and evaluate its expressions against the output comment you wrote. (In other words, `# =>` tells the reader what the output will be, but it tells automated checker what the assertEquals should be)
{% highlight coffeescript %}
# right
[1,2,3].map (x) -> x * 2
# => [ 2, 4, 6 ]
# very wrong!
[1,2,3].map (x) -> x * 2
# right; only add for important/results statements
evens = x for x in [0..10] by 2
evens.some (x) -> x == 6
# => true
# less wrong; may require tweaking the automatic checker
[1,2,3].map (x) -> x * 2 # => [ 2, 4, 6 ]
# less wrong (possibly not wrong at all--the output merely does not match what the coffee interpreter renders)
[1,2,3].map (x) -> x * 2
# => [2,4,6]
{% endhighlight %}
Not all snippets evaluate to something useful. For example, array.forEach has side effects but does not return anything. Also, the console.log() and alert() commands are also side-effect-only commands that return nothing. When possible, try to have your snippets evaluate to something inspectable, and leave displaying to the console or browser out of it. (Unless your snippet is _about_ displaying to the console or browser.)
When in doubt about what output to show, try evaluating your snippet in the coffee interpreter and see what IT thinks. Ideally your output should match, or at least be machine-comparable.
# Grindy HOWTOs
## How to Add a Recipe
Create a new markdown page (or copy the [Recipe Template]({{ site.baseurl }}/recipe-template). The filename should be about the problem, e.g. `finding-last-day-of-the-month.md` or `reversing-arrays.md`. In your file, start with the following template:
{% highlight text %}
---
layout: recipe
title: Title of The Recipe
chapter: Chapter Name
---
## Problem
You have a problem.
## Solution
Do this about it.
## Discussion
Here's why.
{% endhighlight %}
One fussy little bit, the chapter name should match the directory the chapter is in, otherwise the page won't render correctly. For example, if you're writing a recipe for arrays, make sure the chapter is "Arrays", not "arrays" or "aray" ...or especially not "Chapter Name".
## How to Add a Chapter
* Open chapters/index.html and your chapter's name to the yaml list of chapters.
* cd into chapters/ and create the directory for the chapter name. Downcase the name and replace spaces with underscores.
* add an index.html file that uses `layout: chapter`. For convenience, just copy the index.html from another chapter and update the yaml frontmatter to reflect the name of your new chapter.
For example, to add a chapter called "Dates and Times", you would add it to the chapters array:
{% highlight yaml %}
chapters:
- Syntax
- Objects
- Arrays
- Dates and Times
{% endhighlight %}
...and then create that chapter in the file system:
{% highlight bash %}
cd chapters
mkdir dates_and_times
{% endhighlight %}
Now create a new page in that chapter (remember to add its YAML front matter) and once jekyll regenerates the chapter index, your new page should appear.
# FAQ
## I Have a Weird Recipe. Should I Share It?
Maybe! The real question is, is it really useful, or is it just clever? If you have a formatter for a weird Albanian GIS format, that's a real problem that almost nobody would ever have -- but when somebody DOES have that problem, they REALLY need a solution. If you have a bit shifting trick that can swap two numbers using three xor-equals operations, that's a really clever solution but it's not very good CoffeeScript. (For one thing, `x ^= y ^= x ^= y` is not idiomatic, while `[x,y]=[y,x]` is. For another, there's a bug in that code. And once you fix it, there's another bug caused by extrapolating this register trick to a reference-based language where -- look, it's just a bad idea, okay?)
If you have a cool but weird recipe, ask yourself if a reader would genuinely find it useful. Here are two very good questions to consider:
* Does it really solve a problem that an actual person might have?
* If somebody really does have that problem, would your recipe really be the best solution?
If the answer to either question is no, you might have some code that is a "clever solution in search of a problem". If in doubt, ask.
## What If My Recipe is Inefficient/Too Big/Too Slow?
If it solves a problem to which the alternative is to _not_ solve the problem, share it. Let the reader decide if they want to use it. Sometimes we want tight efficient code, other times we want a robust feature set. If the code has abysmal performance characteristics, be sure to warn the reader in the Discussion.
## Can I Edit An Existing Recipe?
Yes. Please improve anything and everything! Be sure to test your changes and make sure that your solution really is better.
## I Have a Really Efficient Solution, But It's Not As Readable As the Existing Recipe. Should I Add It?
See the "Weird Recipe" note above. Do real people in the real world ever hit the performance constraint? If so, then by all means, add your strategy to the existing solution, and be sure to explain why your solution is not idiomatic. If a reader really has that problem, they'll be glad for the extra options.
## I Have A Problem/Solution, But It's Basically Just JavaScript. Should I Add It?
Yes! CoffeeScript compiles to JavaScript, and that means that some of its functionality comes straight from JavaScript. (For example, see [Reversing Arrays]({{ site.baseurl }}/chapters/arrays/reversing-arrays).) But if you're programming in CoffeeScript and you need to reverse an array, this Cookbook should stand ready to tell you it's available to you in CoffeeScript -- even if it's just a straight call into a JavaScript library.
## I Found a Typo. Is That Enough of a Fix? Does That Count?
Absolutely!
================================================
FILE: authors.md
================================================
---
layout: default
title: Authors
---
# Authors
The following people are totally rad and awesome because they have contributed recipes!
* David Brady *ratgeyser@gmail.com*
* John Ford *jwford@gmail.com*
* Steven Reid *steven @ reidnorthwest . com*
* David Moulton *dave@themoultons.net*
* Sebastian Slomski *sebastian@simple-systems.org*
* Aaron Weinberger *aw9994@cs.ship.edu*
* James C. Holder *coffeescriptcookbook.com@thirdtruck.org*
* Jason Giedymin *jasong@apache.org*
* Phil Cohen *github@phlippers.net*
* João Moreno *coffeecb @joaomoreno .com*
* Jeff Pickhardt *pickhardt (at) gmail (dot) com*
* Frederic Hemberger
* 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*
* [Alex Johnson](https://github.com/nonsensery)
* ...You! What are you waiting for? Check out the [contributing]({{ site.baseurl }}/contributing) section and get cracking!
# Developers
*The following people are amazingly rad and awesome because they have helped fix the code for the site!*
* David Brady *ratgeyser@gmail.com*
* Mike Moore *mike@blowmage.com*
* Peter Hellberg *peter@c7.se*
* Jamie Gaskins *jgaskins@gmail.com*
* Sami Pussinen *me@samipussinen.com*
* [Devin Weaver (@sukima)](https://github.com/sukima)
* ...You! What are you waiting for? Check out the [contributing]({{ site.baseurl }}/contributing) section and get cracking!
# Designers
The following people are astonishingly rad and awesome because they did great design for the site!
* [Amsul](http://github.com/amsul) reach@amsul.ca
* ...You! Check out the [contributing]({{ site.baseurl }}/contributing) section and get cracking!
================================================
FILE: chapters/ajax/ajax_request_without_jquery.md
================================================
---
layout: recipe
title: Ajax Request Without jQuery
chapter: Ajax
---
## Problem
You want to load data from your server via AJAX without using the jQuery library.
## Solution
You will use the native XMLHttpRequest object.
Let's set up a simple test HTML page with a button.
{% highlight html %}
XMLHttpRequest Tester
XMLHttpRequest Tester
{% endhighlight %}
When the button is clicked, we want to send an Ajax request to the server to retrieve some data. For this sample, we have a small JSON file.
{% highlight javascript %}
// data.json
{
message: "Hello World"
}
{% endhighlight %}
Next, create the CoffeeScript file to hold the page logic. The code in this file creates a function to be called when the Load Data button is clicked.
{% highlight coffeescript linenos %}
# XMLHttpRequest.coffee
loadDataFromServer = ->
req = new XMLHttpRequest()
req.addEventListener 'readystatechange', ->
if req.readyState is 4 # ReadyState Complete
successResultCodes = [200, 304]
if req.status in successResultCodes
data = eval '(' + req.responseText + ')'
console.log 'data message: ', data.message
else
console.log 'Error loading data...'
req.open 'GET', 'data.json', false
req.send()
loadDataButton = document.getElementById 'loadDataButton'
loadDataButton.addEventListener 'click', loadDataFromServer, false
{% endhighlight %}
## Discussion
In the above code we grab a handle to the button in our HTML (line 16) and add a *click* event listener (line 17). In our event listener, we define our callback function as loadDataFromServer.
We define our loadDataFromServer callback beginning on line 2.
We create a XMLHttpRequest request object (line 3) and add a *readystatechange* event handler. This fires whenever the request's readyState changes.
In the event handler we check to see if the readyState = 4, indicating the request has completed. Then, we check the request status value. Both 200 or 304 represent a successful request. Anything else represents an error condition.
If the request was indeed successful, we eval the JSON returned from the server and assign it to a data variable. At this point, we can use the returned data in any way we need to.
The last thing we need to do is actually make our request.
Line 13 opens a 'GET' request to retrieve the data.json file.
Line 14 sends our request to the server.
## Older Browser Support
If your application needs to target older versions of Internet Explorer, you will need to ensure the XMLHttpRequest object exists. You can do this by including this code before creating the XMLHttpRequest instance.
{% highlight coffeescript %}
if (typeof @XMLHttpRequest == "undefined")
console.log 'XMLHttpRequest is undefined'
@XMLHttpRequest = ->
try
return new ActiveXObject("Msxml2.XMLHTTP.6.0")
catch error
try
return new ActiveXObject("Msxml2.XMLHTTP.3.0")
catch error
try
return new ActiveXObject("Microsoft.XMLHTTP")
catch error
throw new Error("This browser does not support XMLHttpRequest.")
{% endhighlight %}
This code ensures the XMLHttpRequest object is available in the global namespace.
================================================
FILE: chapters/ajax/index.html
================================================
---
layout: chapter
title: Ajax
chapter: Ajax
---
{% capture url %}/chapters/{{ page.chapter | replace: ' ', '_' | downcase }}{% endcapture %}
{% capture indexurl %}{{ url }}/index.html{% endcapture %}
{% for page in site.pages %}
{% if page.url contains url %}
{% unless page.url == indexurl %}
================================================
FILE: chapters/arrays/check-type-is-array.md
================================================
---
layout: recipe
title: Check if type of value is an Array
chapter: Arrays
---
## Problem
You want to check if a value is an `Array`.
{% highlight coffeescript %}
myArray = []
console.log typeof myArray // outputs 'object'
{% endhighlight %}
The `typeof` operator gives a faulty output for arrays.
## Solution
Use the following code:
{% highlight coffeescript %}
typeIsArray = Array.isArray || ( value ) -> return {}.toString.call( value ) is '[object Array]'
{% endhighlight %}
To use this, just call `typeIsArray` as such:
{% highlight coffeescript %}
myArray = []
typeIsArray myArray // outputs true
{% endhighlight %}
## Discussion
The method above has been adopted from "the Miller Device". An alternative is to use Douglas Crockford's snippet:
{% highlight coffeescript %}
typeIsArray = ( value ) ->
value and
typeof value is 'object' and
value instanceof Array and
typeof value.length is 'number' and
typeof value.splice is 'function' and
not ( value.propertyIsEnumerable 'length' )
{% endhighlight %}
================================================
FILE: chapters/arrays/concatenating-arrays.md
================================================
---
layout: recipe
title: Concatenating Arrays
chapter: Arrays
---
## Problem
You want to join two arrays together.
## Solution
There are two standard options for concatenating arrays in JavaScript.
The first is to use JavaScript's Array `concat()` method:
{% highlight coffeescript %}
array1 = [1, 2, 3]
array2 = [4, 5, 6]
array3 = array1.concat array2
# => [1, 2, 3, 4, 5, 6]
{% endhighlight %}
Note that `array1` is _not_ modified by the operation. The concatenated array is returned as a new object.
If you want to merge two arrays without creating a new object, you can use the following technique:
{% highlight coffeescript %}
array1 = [1, 2, 3]
array2 = [4, 5, 6]
Array::push.apply array1, array2
array1
# => [1, 2, 3, 4, 5, 6]
{% endhighlight %}
In the example above, the `Array.prototype.push.apply(a, b)` approach modifies `array1` in place without creating a new array object.
We can simplify the pattern above using CoffeeScript by creating a new `merge()` method for Arrays.
{% highlight coffeescript %}
Array::merge = (other) -> Array::push.apply @, other
array1 = [1, 2, 3]
array2 = [4, 5, 6]
array1.merge array2
array1
# => [1, 2, 3, 4, 5, 6]
{% endhighlight %}
Alternatively, we can pass a CoffeeScript splat (`array2...`) directly into `push()`, avoiding the Array prototype.
{% highlight coffeescript %}
array1 = [1, 2, 3]
array2 = [4, 5, 6]
array1.push array2...
array1
# => [1, 2, 3, 4, 5, 6]
{% endhighlight %}
A more idiomatic approach is to use the splat operator (`...`) directly in an array literal. This can be used to concatenate any number of arrays.
{% highlight coffeescript %}
array1 = [1, 2, 3]
array2 = [4, 5, 6]
array3 = [array1..., array2...]
array3
# => [1, 2, 3, 4, 5, 6]
{% endhighlight %}
## Discussion
CoffeeScript lacks a special syntax for joining arrays, but `concat()` and `push()` are standard JavaScript methods.
================================================
FILE: chapters/arrays/creating-a-dictionary-object-from-an-array.md
================================================
---
layout: recipe
title: Creating a dictionary Object from an Array
chapter: Arrays
---
## Problem
You have an Array of Objects, such as:
{% highlight coffeescript %}
cats = [
{
name: "Bubbles"
age: 1
},
{
name: "Sparkle"
favoriteFood: "tuna"
}
]
{% endhighlight %}
But you want to access it as a dictionary by key, like `cats["Bubbles"]`.
## Solution
You need to convert your array into an Object. Use reduce for this.
{% highlight coffeescript %}
# key = The key by which to index the dictionary
Array::toDict = (key) ->
@reduce ((dict, obj) -> dict[ obj[key] ] = obj if obj[key]?; return dict), {}
{% endhighlight %}
To use this:
{% highlight coffeescript %}
catsDict = cats.toDict('name')
catsDict["Bubbles"]
# => { age: 1, name: "Bubbles" }
{% endhighlight %}
## Discussion
Alternatively, you can use an Array comprehension:
{% highlight coffeescript %}
Array::toDict = (key) ->
dict = {}
dict[obj[key]] = obj for obj in this when obj[key]?
dict
{% endhighlight %}
If you use Underscore.js, you can create a mixin:
{% highlight coffeescript %}
_.mixin toDict: (arr, key) ->
throw new Error('_.toDict takes an Array') unless _.isArray arr
_.reduce arr, ((dict, obj) -> dict[ obj[key] ] = obj if obj[key]?; return dict), {}
catsDict = _.toDict(cats, 'name')
catsDict["Sparkle"]
# => { favoriteFood: "tuna", name: "Sparkle" }
{% endhighlight %}
================================================
FILE: chapters/arrays/creating-a-string-from-an-array.md
================================================
---
layout: recipe
title: Creating a String from an Array
chapter: Arrays
---
## Problem
You want to create a string from an array.
## Solution
Use JavaScript's Array toString() method:
{% highlight coffeescript %}
["one", "two", "three"].toString()
# => 'one,two,three'
{% endhighlight %}
## Discussion
`toString()` is a standard JavaScript method. Don't forget the parentheses.
================================================
FILE: chapters/arrays/define-ranges.md
================================================
---
layout: recipe
title: Define Ranges Array
chapter: Arrays
---
## Problem
You want to define a range in an array.
## Solution
There are two ways to define a range of array elements in CoffeeScript.
{% highlight coffeescript %}
# inclusive
myArray = [1..10]
# => [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]
{% endhighlight %}
{% highlight coffeescript %}
# exclusive
myArray = [1...10]
# => [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
{% endhighlight %}
We can also reverse the range of element by writing it this way.
{% highlight coffeescript %}
myLargeArray = [10..1]
# => [ 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 ]
{% endhighlight %}
{% highlight coffeescript %}
myLargeArray = [10...1]
# => [ 10, 9, 8, 7, 6, 5, 4, 3, 2 ]
{% endhighlight %}
## Discussion
Inclusive ranges are defined by the '..' operator and include the last value.
Exclusive ranges are defined by '...', and always omit the last value.
================================================
FILE: chapters/arrays/filtering-arrays.md
================================================
---
layout: recipe
title: Filtering Arrays
chapter: Arrays
---
## Problem
You want to be able to filter arrays based on a boolean condition.
## Solution
Use Array.filter (ECMAScript 5):
{% highlight coffeescript %}
array = [1..10]
array.filter (x) -> x > 5
# => [6,7,8,9,10]
{% endhighlight %}
In pre-EC5 implementations, extend the Array prototype to add a filter function which will take a callback and perform a comprehension over itself, collecting all elements for which the callback is true. Be sure to check if the function is already implemented before overwriting it:
{% highlight coffeescript %}
# Extending Array's prototype
unless Array::filter
Array::filter = (callback) ->
element for element in this when callback(element)
array = [1..10]
# Filter odd elements
filtered_array = array.filter (x) -> x % 2 == 0
# => [2,4,6,8,10]
# Filter elements less than or equal to 5:
gt_five = (x) -> x > 5
filtered_array = array.filter gt_five
# => [6,7,8,9,10]
{% endhighlight %}
## Discussion
This is similar to using ruby's Array#select method.
================================================
FILE: chapters/arrays/index.html
================================================
---
layout: chapter
title: Arrays
chapter: Arrays
---
{% capture url %}/chapters/{{ page.chapter | replace: ' ', '_' | downcase }}{% endcapture %}
{% capture indexurl %}{{ url }}/index.html{% endcapture %}
{% for page in site.pages %}
{% if page.url contains url %}
{% unless page.url == indexurl %}
================================================
FILE: chapters/arrays/list-comprehensions.md
================================================
---
layout: recipe
title: List Comprehensions
chapter: Arrays
---
## Problem
You have an array of objects and want to map them to another array, similar to Python's list comprehensions.
## Solution
Use a list comprehension, but don't forget about [mapping arrays]({{ site.baseurl }}/chapters/arrays/mapping-arrays).
{% highlight coffeescript %}
electric_mayhem = [ { name: "Doctor Teeth", instrument: "piano" },
{ name: "Janice", instrument: "lead guitar" },
{ name: "Sgt. Floyd Pepper", instrument: "bass" },
{ name: "Zoot", instrument: "sax" },
{ name: "Lips", instrument: "trumpet" },
{ name: "Animal", instrument: "drums" } ]
names = (muppet.name for muppet in electric_mayhem)
# => [ 'Doctor Teeth', 'Janice', 'Sgt. Floyd Pepper', 'Zoot', 'Lips', 'Animal' ]
{% endhighlight %}
## Discussion
Because CoffeeScript directly support list comprehensions, they work pretty much as advertised wherever you would use one in Python. For simple mappings, list comprehensions are much more readable. For complicated transformations or for chained mappings, [mapping arrays]({{ site.baseurl }}/chapters/arrays/mapping-arrays) might be more elegant.
================================================
FILE: chapters/arrays/mapping-arrays.md
================================================
---
layout: recipe
title: Mapping Arrays
chapter: Arrays
---
## Problem
You have an array of objects and want to map them to another array, similar to Ruby's map.
## Solution
Use map() with an anonymous function, but don't forget about list comprehensions.
{% highlight coffeescript %}
electric_mayhem = [ { name: "Doctor Teeth", instrument: "piano" },
{ name: "Janice", instrument: "lead guitar" },
{ name: "Sgt. Floyd Pepper", instrument: "bass" },
{ name: "Zoot", instrument: "sax" },
{ name: "Lips", instrument: "trumpet" },
{ name: "Animal", instrument: "drums" } ]
names = electric_mayhem.map (muppet) -> muppet.name
# => [ 'Doctor Teeth', 'Janice', 'Sgt. Floyd Pepper', 'Zoot', 'Lips', 'Animal' ]
{% endhighlight %}
## Discussion
Because CoffeeScript has clean support for anonymous functions, mapping an array in CoffeeScript is nearly as easy as it is in Ruby.
Maps are are good way to handle complicated transforms and chained mappings in CoffeeScript. If your transformation is as simple as the one above, however, it may read more cleanly as a list comprehension.
================================================
FILE: chapters/arrays/max-array-value.md
================================================
---
layout: recipe
title: Max Array Value
chapter: Arrays
---
## Problem
You need to find the largest value contained in an array.
## Solution
You can use Math.max() JavaScript method along with splats.
{% highlight coffeescript %}
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 the above.
{% highlight coffeescript %}
# ECMAScript 5
[12,32,11,67,1,3].reduce (a,b) -> Math.max a, b
# => 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 amount of arguments, such as `console.log`.
================================================
FILE: chapters/arrays/reducing-arrays.md
================================================
---
layout: recipe
title: Reducing Arrays
chapter: Arrays
---
## Problem
You have an array of objects and want to reduce them to a value, similar to Ruby's `reduce()` and `reduceRight()`.
## Solution
You can simply use Array's `reduce()` and `reduceRight()` methods along with an anonymous function, keeping the code clean and readable. The reduction may be something simple such as using the `+` operator with numbers or strings.
{% highlight coffeescript %}
[1,2,3,4].reduce (x,y) -> x + y
# => 10
{% endhighlight %}
{% highlight coffeescript %}
["words", "of", "bunch", "A"].reduceRight (x, y) -> x + " " + y
# => 'A bunch of words'
{% endhighlight %}
Or it may be something more complex such as aggregating elements from a list into a combined object.
{% highlight coffeescript %}
people = [
{ name: 'alec', age: 10 }
{ name: 'bert', age: 16 }
{ name: 'chad', age: 17 }
]
people.reduce (x, y) ->
x[y.name]= y.age
x
, {}
# => { alec: 10, bert: 16, chad: 17 }
{% endhighlight %}
## Discussion
Javascript introduced `reduce` and `reduceRight` in version 1.8. Coffeescript provides a natural and simple way to express anonymous functions. Both go together cleanly in the problem of merging a collection's items into a combined result.
================================================
FILE: chapters/arrays/removing-duplicate-elements-from-arrays.md
================================================
---
layout: recipe
title: Removing Duplicate Elements from Arrays
chapter: Arrays
---
## Problem
You want to remove duplicate elements from an array.
## Solution
{% highlight coffeescript %}
Array::unique = ->
output = {}
output[@[key]] = @[key] for key in [0...@length]
value for key, value of output
[1,1,2,2,2,3,4,5,6,6,6,"a","a","b","d","b","c"].unique()
# => [ 1, 2, 3, 4, 5, 6, 'a', 'b', 'd', 'c' ]
{% endhighlight %}
## Discussion
There are many implementations of the `unique` method in JavaScript. This one is based on "The fastest method to find unique items in array" found [here](http://www.shamasis.net/2009/09/fast-algorithm-to-find-unique-items-in-javascript-array/).
**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/)).
================================================
FILE: chapters/arrays/reversing-arrays.md
================================================
---
layout: recipe
title: Reversing Arrays
chapter: Arrays
---
## Problem
You want to reverse an array.
## Solution
Use JavaScript's Array reverse() method:
{% highlight coffeescript %}
["one", "two", "three"].reverse()
# => ["three", "two", "one"]
{% endhighlight %}
## Discussion
`reverse()` is a standard JavaScript method. Don't forget the parentheses.
================================================
FILE: chapters/arrays/shuffling-array-elements.md
================================================
---
layout: recipe
title: Shuffling Array Elements
chapter: Arrays
---
## Problem
You want to shuffle the elements in an array.
## Solution
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 %}
shuffle = (source) ->
# Arrays with < 2 elements do not shuffle well. Instead make it a noop.
return source unless source.length >= 2
# From the end of the list to the beginning, pick element `index`.
for index in [source.length-1..1]
# Choose random element `randomIndex` to the front of `index` to swap with.
randomIndex = Math.floor Math.random() * (index + 1)
# Swap `randomIndex` with `index`, using destructured assignment
[source[index], source[randomIndex]] = [source[randomIndex], source[index]]
source
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
### 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 ?= ->
if @length > 1 then for i in [@length-1..1]
j = Math.floor Math.random() * (i + 1)
[@[i], @[j]] = [@[j], @[i]]
this
[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]). 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
features, like maps and forEach, in a cross-browser, lean, high-performance way.
^† [Underscore](http://underscorejs.org/) is also a good alternative to Lo-dash.
[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/
================================================
FILE: chapters/arrays/testing-every-element.md
================================================
---
layout: recipe
title: Testing Every Element
chapter: Arrays
---
## Problem
You want to be able to check that every element in an array meets a particular condition.
## Solution
Use Array.every (ECMAScript 5):
{% highlight coffeescript %}
evens = (x for x in [0..10] by 2)
evens.every (x)-> x % 2 == 0
# => true
{% endhighlight %}
Array.every was added 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, pretend you have a multiple select list that looks like:
{% highlight html %}
{% endhighlight %}
Now you want to verify that the user selected only numbers. Let's use Array.every:
{% highlight coffeescript %}
validateNumeric = (item)->
parseFloat(item) == parseInt(item) && !isNaN(item)
values = $("#my-select-list").val()
values.every validateNumeric
{% endhighlight %}
## Discussion
This is similar to using ruby's Array#all? method.
[underscore]: http://documentcloud.github.com/underscore/
================================================
FILE: chapters/arrays/using-arrays-to-swap-variables.md
================================================
---
layout: recipe
title: Using Arrays to Swap Variables
chapter: Arrays
---
## Problem
You want to use an array to swap variables.
## Solution
Use CoffeeScript's [destructuring assignment](http://jashkenas.github.com/coffee-script/#destructuring) syntax:
{% highlight coffeescript %}
a = 1
b = 3
[a, b] = [b, a]
a
# => 3
b
# => 1
{% endhighlight %}
## Discussion
Destructuring assignment allows swapping two values without the use of a temporary variable.
This can be useful when traversing arrays and ensuring iteration only happens over the shortest one:
{% highlight coffeescript %}
ray1 = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
ray2 = [ 5, 9, 14, 20 ]
intersection = (a, b) ->
[a, b] = [b, a] if a.length > b.length
value for value in a when value in b
intersection ray1, ray2
# => [ 5, 9 ]
intersection ray2, ray1
# => [ 5, 9 ]
{% endhighlight %}
================================================
FILE: chapters/arrays/where-for-arrays-of-objects.md
================================================
---
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"
# => []
# 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
{% endhighlight %}
it's more a method to deal with collection and it could be rename as "find" but popular libraries like underscore or lodash name it "where".
================================================
FILE: chapters/arrays/zip-function.md
================================================
---
layout: recipe
title: Python-like Zip Function
chapter: Arrays
---
## Problem
You want to zip together multiple arrays into an array of arrays, similar to Python's zip function. Python's zip function returns an array of tuples, where each tuple contains the i-th element from each of the argument arrays.
## Solution
Use the following CoffeeScript code:
{% highlight coffeescript %}
# Usage: zip(arr1, arr2, arr3, ...)
zip = () ->
lengthArray = (arr.length for arr in arguments)
length = Math.min(lengthArray...)
for i in [0...length]
arr[i] for arr in arguments
zip([0, 1, 2, 3], [0, -1, -2, -3])
# => [[0, 0], [1, -1], [2, -2], [3, -3]]
{% endhighlight %}
================================================
FILE: chapters/classes_and_objects/chaining.md
================================================
---
layout: recipe
title: Chaining Calls to an Object
chapter: Classes and Objects
---
## Problem
You want to call multiple methods on a single object without having to reference that object each time.
## Solution
Return the `this` (i.e. `@`) object after every chained method.
{% highlight coffeescript %}
class CoffeeCup
constructor: ->
@properties=
strength: 'medium'
cream: false
sugar: false
strength: (newStrength) ->
@properties.strength = newStrength
this
cream: (newCream) ->
@properties.cream = newCream
this
sugar: (newSugar) ->
@properties.sugar = newSugar
this
morningCup = new CoffeeCup()
morningCup.properties # => { strength: 'medium', cream: false, sugar: false }
eveningCup = new CoffeeCup().strength('dark').cream(true).sugar(true)
eveningCup.properties # => { strength: 'dark', cream: true, sugar: true }
{% endhighlight %}
## Discussion
The jQuery library uses a similar approach by returning a selector object from every relevant method, modifying it as subsequent methods tweak the selection:
{% highlight coffeescript %}
$('p').filter('.topic').first()
{% endhighlight %}
For your own objects, a touch of metaprogramming can automate the setup process and explicitly state the purpose of returning *this*.
{% highlight coffeescript %}
addChainedAttributeAccessor = (obj, propertyAttr, attr) ->
obj[attr] = (newValues...) ->
if newValues.length == 0
obj[propertyAttr][attr]
else
obj[propertyAttr][attr] = newValues[0]
obj
class TeaCup
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)
earlgrey.properties # => { size: 'small', type: 'Earl Grey', sugar: false, cream: false }
earlgrey.sugar true
earlgrey.sugar() # => true
{% endhighlight %}
================================================
FILE: chapters/classes_and_objects/class-methods-and-instance-methods.md
================================================
---
layout: recipe
title: Class Methods and Instance Methods
chapter: Classes and Objects
---
## Problem
You want to create class and instance methods.
## Solution
### Class Method
{% highlight coffeescript %}
class Songs
@_titles: 0 # Although it's directly accessible, the leading _ defines it by convention as private property.
@get_count: ->
@_titles
constructor: (@artist, @title) ->
@constructor._titles++ # Refers to ._titles, in this case Songs.titles
Songs.get_count()
# => 0
song = new Songs("Rick Astley", "Never Gonna Give You Up")
Songs.get_count()
# => 1
song.get_count()
# => TypeError: Object has no method 'get_count'
{% endhighlight %}
### Instance Method
{% highlight coffeescript %}
class Songs
_titles: 0 # Although it's directly accessible, the leading _ defines it by convention as private property.
get_count: ->
@_titles
constructor: (@artist, @title) ->
@_titles++
song = new Songs("Rick Astley", "Never Gonna Give You Up")
song.get_count()
# => 1
Songs.get_count()
# => TypeError: Object function Songs(artist, title) ... has no method 'get_count'
{% endhighlight %}
## Discussion
Coffeescript will store class methods (also called static methods) 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.
================================================
FILE: chapters/classes_and_objects/class-variables-and-instance-variables.md
================================================
---
layout: recipe
title: Class Variables and Instance Variables
chapter: Classes and Objects
---
## Problem
You want to create class variables and instance variables (properties).
## Solution
### Class Variables
{% highlight coffeescript %}
class Zoo
@MAX_ANIMALS: 50
MAX_ZOOKEEPERS: 3
helpfulInfo: =>
"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 a prototype member)
Zoo::MAX_ZOOKEEPERS
# => 3
zoo = new Zoo
zoo.MAX_ZOOKEEPERS
# => 3
zoo.helpfulInfo()
# => "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 %}
### Instance Variables
You have to define instance variables (i.e. properties) inside a class' method, initialize your defaults in the constructor.
{% highlight coffeescript %}
class Zoo
constructor: ->
@animals = [] # Here the instance variable is defined
addAnimal: (name) ->
@animals.push name
zoo = new Zoo()
zoo.addAnimal 'elephant'
otherZoo = new Zoo()
otherZoo.addAnimal 'lion'
zoo.animals
# => ['elephant']
otherZoo.animals
# => ['lion']
{% endhighlight %}
#### WARNING!
*Do not add the variable accidently to the prototype, by defining it outside the constructor* (Even if mentioned [elsewhere](http://arcturo.github.io/library/coffeescript/03_classes.html#content), this does not work as intended, due to the underlying JavaScript prototype concept).
{% highlight coffeescript %}
class BadZoo
animals: [] # Translates to BadZoo.prototype.animals = []; and is thus shared between instances
addAnimal: (name) ->
@animals.push name # Works due to the prototype concept of Javascript
zoo = new BadZoo()
zoo.addAnimal 'elephant'
otherZoo = new BadZoo()
otherZoo.addAnimal 'lion'
zoo.animals
# => ['elephant','lion'] # Oops...
otherZoo.animals
# => ['elephant','lion'] # Oops...
BadZoo::animals
# => ['elephant','lion'] # The value is stored in the prototype
{% endhighlight %}
## Discussion
Coffeescript will store the values of class variables on the class itself rather than on the prototype it defines. These are useful for defining variables on classes which can't be overwritten by instance attribute variables.
================================================
FILE: chapters/classes_and_objects/cloning.md
================================================
---
layout: recipe
title: Cloning an Object (Deep Copy)
chapter: Classes and Objects
---
## Problem
You want to clone an object with all its sub-objects.
## Solution
{% highlight coffeescript %}
clone = (obj) ->
if not obj? or typeof obj isnt 'object'
return obj
if obj instanceof Date
return new Date(obj.getTime())
if obj instanceof RegExp
flags = ''
flags += 'g' if obj.global?
flags += 'i' if obj.ignoreCase?
flags += 'm' if obj.multiline?
flags += 'y' if obj.sticky?
return new RegExp(obj.source, flags)
newInstance = new obj.constructor()
for key of obj
newInstance[key] = clone obj[key]
return newInstance
x =
foo: 'bar'
bar: 'foo'
y = clone(x)
y.foo = 'test'
console.log x.foo isnt y.foo, x.foo, y.foo
# => true, bar, test
{% endhighlight %}
## Discussion
The difference between copying an object through assignment and through this clone-function is how they handle references. The assignment only copies the object's reference, whereas the clone-function creates a complete new object by
* creating a new object like the source object,
* copying all attributes form the source object to the new object and
* repeating these steps for all sub-objects by calling the clone-function recursively.
Example of an assignment copy:
{% highlight coffeescript %}
x =
foo: 'bar'
bar: 'foo'
y = x
y.foo = 'test'
console.log x.foo isnt y.foo, x.foo, y.foo
# => false, test, test
{% endhighlight %}
As you can see, when you change `y` after the copy, you also change `x`.
================================================
FILE: chapters/classes_and_objects/index.html
================================================
---
layout: chapter
title: Classes and Objects
chapter: Classes and Objects
---
{% capture url %}/chapters/{{ page.chapter | replace: ' ', '_' | downcase }}{% endcapture %}
{% capture indexurl %}{{ url }}/index.html{% endcapture %}
{% for page in site.pages %}
{% if page.url contains url %}
{% unless page.url == indexurl %}
================================================
FILE: chapters/classes_and_objects/mixins.md
================================================
---
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.
================================================
FILE: chapters/classes_and_objects/object-literal.md
================================================
---
layout: recipe
title: Create an Object Literal if It Does Not Already Exist
chapter: Classes and Objects
---
## Problem
You want to initialize an object literal, but you do not want to overwrite the object if it already exists.
## Solution
Use the Existential operator
{% highlight coffeescript %}
window.MY_NAMESPACE ?= {}
{% endhighlight %}
## Discussion
This is equivalent to the following JavaScript:
{% highlight javascript %}
if(window.MY_NAMESPACE === null || window.MY_NAMESPACE === undefined) {
window.MY_NAMESPACE = {};
}
{% endhighlight %}
## Problem
You want to make a conditonal assignment if it does not exists or if it is falsy (empty, 0, null, false)
## Solution
Use the Conditional assignment operator
{% highlight coffeescript %}
window.my_variable ||= {}
{% endhighlight %}
## Discussion
This is equivalent to the following JavaScript:
{% highlight javascript %}
window.my_variable = window.my_variable || {};
{% endhighlight %}
Common JavaScript technique, using conditional assignment to ensure that we have an object that is not falsy
================================================
FILE: chapters/classes_and_objects/type-function.md
================================================
---
layout: recipe
title: A CoffeeScript Type Function
chapter: Classes and Objects
---
## Problem
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
Use the following function:
{% highlight coffeescript %}
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
This function was modeled on jQuery's [$.type function](http://api.jquery.com/jQuery.type/).
Note that, as an alternative to type checking, you can often use duck typing and the existential operator together to eliminating the need to examine an object's type, in certain cases. For example, here is exception-free code that pushes an element to an array, if myArray is in fact an array (or array-like, with a push function), and does nothing otherwise.
{% highlight coffeescript %}
myArray?.push? myValue
{% endhighlight %}
================================================
FILE: chapters/databases/index.html
================================================
---
layout: chapter
title: Databases
chapter: Databases
---
{% capture url %}/chapters/{{ page.chapter | replace: ' ', '_' | downcase }}{% endcapture %}
{% capture indexurl %}{{ url }}/index.html{% endcapture %}
{% for page in site.pages %}
{% if page.url contains url %}
{% unless page.url == indexurl %}
================================================
FILE: chapters/databases/mongodb.md
================================================
---
layout: recipe
title: MongoDB
chapter: Databases
---
## Problem
You need to interface with a MongoDB database.
## Solution
### For Node.js
### Setup
* [Install MongoDB](http://www.mongodb.org/display/DOCS/Quickstart) on your computer if you have not already.
* [Install the native MongoDB module](https://github.com/christkv/node-mongodb-native).
#### Saving Records
{% highlight coffeescript %}
mongo = require 'mongodb'
server = new mongo.Server "127.0.0.1", 27017, {}
client = new mongo.Db 'test', server, {w:1}
# save() updates existing records or inserts new ones as needed
exampleSave = (dbErr, collection) ->
console.log "Unable to access database: #{dbErr}" if dbErr
collection.save { _id: "my_favorite_latte", flavor: "honeysuckle" }, (err, docs) ->
console.log "Unable to save record: #{err}" if err
client.close()
client.open (err, database) ->
client.collection 'coffeescript_example', exampleSave
{% endhighlight %}
#### Finding Records
{% highlight coffeescript %}
mongo = require 'mongodb'
server = new mongo.Server "127.0.0.1", 27017, {}
client = new mongo.Db 'test', server, {w:1}
exampleFind = (dbErr, collection) ->
console.log "Unable to access database: #{dbErr}" if dbErr
collection.find({ _id: "my_favorite_latte" }).nextObject (err, result) ->
if err
console.log "Unable to find record: #{err}"
else
console.log result # => { id: "my_favorite_latte", flavor: "honeysuckle" }
client.close()
client.open (err, database) ->
client.collection 'coffeescript_example', exampleFind
{% endhighlight %}
### For Browsers
A [REST-based interface](https://github.com/tdegrunt/mongodb-rest) is in the works. This will provide AJAX-based access.
## Discussion
This recipe breaks the *save* and *find* into separate examples in order to separate the MongoDB-specific concerns from the task of connection and callback management. The [async module](https://github.com/caolan/async) can help with that.
================================================
FILE: chapters/databases/sqlite.md
================================================
---
layout: recipe
title: SQLite
chapter: Databases
---
## Problem
You need to interface with a [SQLite](http://www.sqlite.org/) database from inside of Node.js.
## Solution
Use the [SQLite module](http://code.google.com/p/node-sqlite/).
{% highlight coffeescript %}
sqlite = require 'sqlite'
db = new sqlite.Database
# The module uses asynchronous methods,
# so we chain the calls the db.execute
exampleCreate = ->
db.execute "CREATE TABLE snacks (name TEXT(25), flavor TEXT(25))",
(exeErr, rows) ->
throw exeErr if exeErr
exampleInsert()
exampleInsert = ->
db.execute "INSERT INTO snacks (name, flavor) VALUES ($name, $flavor)",
{ $name: "Potato Chips", $flavor: "BBQ" },
(exeErr, rows) ->
throw exeErr if exeErr
exampleSelect()
exampleSelect = ->
db.execute "SELECT name, flavor FROM snacks",
(exeErr, rows) ->
throw exeErr if exeErr
console.log rows[0] # => { name: 'Potato Chips', flavor: 'BBQ' }
# :memory: creates a DB in RAM
# You can supply a filepath (like './example.sqlite') to create/open one on disk
db.open ":memory:", (openErr) ->
throw openErr if openErr
exampleCreate()
{% endhighlight %}
## Discussion
You can also prepare your SQL queries beforehand:
{% highlight coffeescript %}
sqlite = require 'sqlite'
async = require 'async' # Not required but added to make the example more concise
db = new sqlite.Database
createSQL = "CREATE TABLE drinks (name TEXT(25), price NUM)"
insertSQL = "INSERT INTO drinks (name, price) VALUES (?, ?)"
selectSQL = "SELECT name, price FROM drinks WHERE price < ?"
create = (onFinish) ->
db.execute createSQL, (exeErr) ->
throw exeErr if exeErr
onFinish()
prepareInsert = (name, price, onFinish) ->
db.prepare insertSQL, (prepErr, statement) ->
statement.bindArray [name, price], (bindErr) ->
statement.fetchAll (fetchErr, rows) -> # Called so that it executes the insert
onFinish()
prepareSelect = (onFinish) ->
db.prepare selectSQL, (prepErr, statement) ->
statement.bindArray [1.00], (bindErr) ->
statement.fetchAll (fetchErr, rows) ->
console.log rows[0] # => { name: "Mia's Root Beer", price: 0.75 }
onFinish()
db.open ":memory:", (openErr) ->
async.series([
(onFinish) -> create onFinish,
(onFinish) -> prepareInsert "LunaSqueeze", 7.95, onFinish,
(onFinish) -> prepareInsert "Viking Sparkling Grog", 4.00, onFinish,
(onFinish) -> prepareInsert "Mia's Root Beer", 0.75, onFinish,
(onFinish) -> prepareSelect onFinish
])
{% endhighlight %}
The [SQLite version of SQL](http://www.sqlite.org/lang.html) and the [node-sqlite module documentation](https://github.com/orlandov/node-sqlite#readme) provide more complete information.
================================================
FILE: chapters/dates_and_times/date-of-easter.md
================================================
---
layout: recipe
title: Calculate the Date of Easter Sunday
chapter: Dates and Times
---
## Problem
You need to find the month and day of the Easter Sunday for given year.
## Solution
The following function returns array with two elements: month (1-12) and day of the Easter Sunday. If no arguments are given
result is for the current year.
This is an implementation of [Anonymous Gregorian algorithm](http://en.wikipedia.org/wiki/Computus#Anonymous_Gregorian_algorithm) in CoffeeScript.
{% highlight coffeescript %}
gregorianEaster = (year = (new Date).getFullYear()) ->
a = year % 19
b = ~~(year / 100)
c = year % 100
d = ~~(b / 4)
e = b % 4
f = ~~((b + 8) / 25)
g = ~~((b - f + 1) / 3)
h = (19 * a + b - d - g + 15) % 30
i = ~~(c / 4)
k = c % 4
l = (32 + 2 * e + 2 * i - h - k) % 7
m = ~~((a + 11 * h + 22 * l) / 451)
n = h + l - 7 * m + 114
month = ~~(n / 31)
day = (n % 31) + 1
[month, day]
{% endhighlight %}
## Discussion
NB! Javascript numbers months from 0 to 11 so .getMonth() for date in March will return 2, this function will return 3.
You can modify the function if you want this to be consistent.
The function uses ~~ trick instead of Math.floor().
{% highlight coffeescript %}
gregorianEaster() # => [4, 24] (April 24th in 2011)
gregorianEaster 1972 # => [4, 2]
{% endhighlight %}
================================================
FILE: chapters/dates_and_times/date-of-thanksgiving.md
================================================
---
layout: recipe
title: Calculate the Date of Thanksgiving (USA and Canada)
chapter: Dates and Times
---
## Problem
You need to calculate when Thanksgiving is in a given year.
## Solution
The following functions return the day of Thanksgiving for a given year. If no year is given then current year is used.
In the USA Thanksgiving is celebrated on the fourth Thursday in November:
{% highlight coffeescript %}
thanksgivingDayUSA = (year = (new Date).getFullYear()) ->
first = new Date year, 10, 1
day_of_week = first.getDay()
22 + (11 - day_of_week) % 7
{% endhighlight %}
In Canada it is the second Monday in October:
{% highlight coffeescript %}
thanksgivingDayCA = (year = (new Date).getFullYear()) ->
first = new Date year, 9, 1
day_of_week = first.getDay()
8 + (8 - day_of_week) % 7
{% endhighlight %}
## Discussion
{% highlight coffeescript %}
thanksgivingDayUSA() #=> 24 (November 24th, 2011)
thanksgivingDayCA() # => 10 (October 10th, 2011)
thanksgivingDayUSA(2012) # => 22 (November 22nd)
thanksgivingDayCA(2012) # => 8 (October 8th)
{% endhighlight %}
The idea is very simple:
1. Find out what day of the week is the first day of respective month (November for USA, October for Canada).
2. Calculate offset from that day to the next occurrence of weekday required (Thursday for USA, Monday for Canada).
3. Add that offset to the first possible date of the holiday (22nd for USA Thanksgiving, 8th for Canada).
================================================
FILE: chapters/dates_and_times/days-between-two-dates.md
================================================
---
layout: recipe
title: Get Days Between Two Dates
chapter: Dates and Times
---
## Problem
You need to find how many seconds, minutes, hours, days, months or years have passed between two dates.
## Solution
Use JavaScript's Date function getTime(). Which provides how much time in milliseconds have passed since 01/01/1970:
{% highlight coffeescript %}
DAY = 1000 * 60 * 60 * 24
d1 = new Date('02/01/2011')
d2 = new Date('02/06/2011')
days_passed = Math.round((d2.getTime() - d1.getTime()) / DAY)
{% endhighlight %}
## Discussion
Using milliseconds makes the life easier to avoid overflow mistakes with Dates. So we first calculate how many milliseconds are in a day.
Then, given two distinct dates, get the difference in milliseconds between two dates and then divide by how many milliseconds are in a day. It will return the days between two distinct dates.
If you'd like to calculate the hours between two date objects, you can do that by dividing the difference in milliseconds by the conversion of milliseconds to hours. The same goes for minutes and seconds.
{% highlight coffeescript %}
HOUR = 1000 * 60 * 60
d1 = new Date('02/01/2011 02:20')
d2 = new Date('02/06/2011 05:20')
hour_passed = Math.round((d2.getTime() - d1.getTime()) / HOUR)
{% endhighlight %}
================================================
FILE: chapters/dates_and_times/finding-last-day-of-the-month.md
================================================
---
layout: recipe
title: Finding the Last Day of the Month
chapter: Dates and Times
---
## Problem
You need to find the last day of the month, but don't want to keep a lookup table of the number of days in each month of the year.
## Solution
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, 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 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.
================================================
FILE: chapters/dates_and_times/finding-last-or-next-month.md
================================================
---
layout: recipe
title: Finding Last (or Next) Month
chapter: Dates and Times
---
## Problem
You need to calculate a relative date range like "last month" or "next month".
## Solution
Add or subtract from the current month, secure in the knowledge that JavaScript's Date constructor will fix up the math.
{% highlight coffeescript %}
# these examples were written in GMT-6
# Note that these examples WILL work in January!
now = new Date
# => "Sun, 08 May 2011 05:50:52 GMT"
lastMonthStart = new Date 1900+now.getYear(), now.getMonth()-1, 1
# => "Fri, 01 Apr 2011 06:00:00 GMT"
lastMonthEnd = new Date 1900+now.getYear(), now.getMonth(), 0
# => "Sat, 30 Apr 2011 06:00:00 GMT"
{% endhighlight %}
## Discussion
JavaScript Date objects will cheerfully handle underflows and overflows in the month and day fields, and will adjust the date object accordingly. You can ask for the 42nd of March, for example, and will get the 11th of April.
JavaScript Date objects store the year as the number of years since 1900, the month as an integer from 0 to 11, and the date (day of month) as an integer from 1 to 31. In the solution above, last_month_start is obtained by asking for the first day of a month in the current year, but the month is -1 to 10. If month is -1 the Date object will actually return December of the previous year:
{% highlight coffeescript %}
lastNewYearsEve = new Date 1900+now.getYear(), -1, 31
# => "Fri, 31 Dec 2010 07:00:00 GMT"
{% endhighlight %}
The same is true for overflows:
{% highlight coffeescript %}
thirtyNinthOfFourteember = new Date 1900+now.getYear(), 13, 39
# => "Sat, 10 Mar 2012 07:00:00 GMT"
{% endhighlight %}
================================================
FILE: chapters/dates_and_times/index.html
================================================
---
layout: chapter
title: Dates and Times
chapter: Dates and Times
---
{% capture url %}/chapters/{{ page.chapter | replace: ' ', '_' | downcase }}{% endcapture %}
{% capture indexurl %}{{ url }}/index.html{% endcapture %}
{% for page in site.pages %}
{% if page.url contains url %}
{% unless page.url == indexurl %}
================================================
FILE: chapters/dates_and_times/moon-phase-for-date.md
================================================
---
layout: recipe
title: Calculate Phase of the Moon for a Date
chapter: Dates and Times
---
## Problem
You want to find the current phase of the moon.
## Solution
The following code provides a method to calculate the phase of the moon for a given date.
{% highlight coffeescript %}
# moonPhase.coffee
# Moon-phase calculator
# Roger W. Sinnott, Sky & Telescope, June 16, 2006
# http://www.skyandtelescope.com/observing/objects/javascript/moon_phases
#
# Translated to CoffeeScript by Mike Hatfield @WebCoding4Fun
proper_ang = (big) ->
tmp = 0
if big > 0
tmp = big / 360.0
tmp = (tmp - (~~tmp)) * 360.0
else
tmp = Math.ceil(Math.abs(big / 360.0))
tmp = big + tmp * 360.0
tmp
jdn = (date) ->
month = date.getMonth()
day = date.getDate()
year = date.getFullYear()
zone = date.getTimezoneOffset() / 1440
mm = month
dd = day
yy = year
yyy = yy
mmm = mm
if mm < 3
yyy = yyy - 1
mmm = mm + 12
day = dd + zone + 0.5
a = ~~( yyy / 100 )
b = 2 - a + ~~( a / 4 )
jd = ~~( 365.25 * yyy ) + ~~( 30.6001 * ( mmm+ 1 ) ) + day + 1720994.5
jd + b if jd > 2299160.4999999
moonElong = (jd) ->
dr = Math.PI / 180
rd = 1 / dr
meeDT = Math.pow((jd - 2382148), 2) / (41048480 * 86400)
meeT = (jd + meeDT - 2451545.0) / 36525
meeT2 = Math.pow(meeT, 2)
meeT3 = Math.pow(meeT, 3)
meeD = 297.85 + (445267.1115 * meeT) - (0.0016300 * meeT2) + (meeT3 / 545868)
meeD = (proper_ang meeD) * dr
meeM1 = 134.96 + (477198.8676 * meeT) + (0.0089970 * meeT2) + (meeT3 / 69699)
meeM1 = (proper_ang meeM1) * dr
meeM = 357.53 + (35999.0503 * meeT)
meeM = (proper_ang meeM) * dr
elong = meeD * rd + 6.29 * Math.sin( meeM1 )
elong = elong - 2.10 * Math.sin( meeM )
elong = elong + 1.27 * Math.sin( 2*meeD - meeM1 )
elong = elong + 0.66 * Math.sin( 2*meeD )
elong = proper_ang elong
elong = Math.round elong
moonNum = ( ( elong + 6.43 ) / 360 ) * 28
moonNum = ~~( moonNum )
if moonNum is 28 then 0 else moonNum
getMoonPhase = (age) ->
moonPhase = "new Moon"
moonPhase = "first quarter" if age > 3 and age < 11
moonPhase = "full Moon" if age > 10 and age < 18
moonPhase = "last quarter" if age > 17 and age < 25
if ((age is 1) or (age is 8) or (age is 15) or (age is 22))
moonPhase = "1 day past " + moonPhase
if ((age is 2) or (age is 9) or (age is 16) or (age is 23))
moonPhase = "2 days past " + moonPhase
if ((age is 3) or (age is 1) or (age is 17) or (age is 24))
moonPhase = "3 days past " + moonPhase
if ((age is 4) or (age is 11) or (age is 18) or (age is 25))
moonPhase = "3 days before " + moonPhase
if ((age is 5) or (age is 12) or (age is 19) or (age is 26))
moonPhase = "2 days before " + moonPhase
if ((age is 6) or (age is 13) or (age is 20) or (age is 27))
moonPhase = "1 day before " + moonPhase
moonPhase
MoonPhase = exports? and exports or @MoonPhase = {}
class MoonPhase.Calculator
getMoonDays: (date) ->
jd = jdn date
moonElong jd
getMoonPhase: (date) ->
jd = jdn date
getMoonPhase( moonElong jd )
{% endhighlight %}
## Discussion
This code exposes a MoonPhase Calculator object with two methods. Calculator -> getMoonPhase will return a text representation of the lunar phase for the date provided.
This can be used in both the browser and Node.js.
{% highlight console %}
$ node
> var MoonPhase = require('./moonPhase.js');
undefined
> var calc = new MoonPhase.Calculator();
undefined
> calc.getMoonPhase(new Date());
'full moon'
> calc.getMoonPhase(new Date(1972, 6, 30));
'3 days before last quarter'
{% endhighlight %}
================================================
FILE: chapters/design_patterns/adapter.md
================================================
---
layout: recipe
title: Adapter pattern
chapter: Design patterns
---
## Problem
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]({{ site.baseurl }}//en.wikipedia.org/wiki/Adapter_pattern) comes in handy. It will do the translation, from one side to the other.
## Solution
{% highlight coffeescript %}
# a fragment of 3-rd party grid component
class AwesomeGrid
constructor: (@datasource)->
@sort_order = 'ASC'
@sorter = new NullSorter # in this place we use NullObject pattern (another useful 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
{% endhighlight %}
## Discussion
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.
================================================
FILE: chapters/design_patterns/bridge.md
================================================
---
layout: recipe
title: Bridge Pattern
chapter: Design Patterns
---
## Problem
You need to maintain a reliable interface for code that can change frequently or change between multiple implementations.
## Solution
Use the Bridge pattern as an intermediate between the different implementations and the rest of the code.
Assume that you developed an in-browser text editor that saves to the cloud. Now, however, you need to port it to a stand-alone client that saves locally.
{% highlight coffeescript %}
class TextSaver
constructor: (@filename, @options) ->
save: (data) ->
class CloudSaver extends TextSaver
constructor: (@filename, @options) ->
super @filename, @options
save: (data) ->
# Assuming jQuery
# Note the fat arrows
$( =>
$.post "#{@options.url}/#{@filename}", data, =>
alert "Saved '#{data}' to #{@filename} at #{@options.url}."
)
class FileSaver extends TextSaver
constructor: (@filename, @options) ->
super @filename, @options
@fs = require 'fs'
save: (data) ->
@fs.writeFile @filename, data, (err) => # Note the fat arrow
if err? then console.log err
else console.log "Saved '#{data}' to #{@filename} in #{@options.directory}."
filename = "temp.txt"
data = "Example data"
saver = if window?
new CloudSaver filename, url: 'http://localhost' # => Saved "Example data" to temp.txt at http://localhost
else if root?
new FileSaver filename, directory: './' # => Saved "Example data" to temp.txt in ./
saver.save data
{% endhighlight %}
## Discussion
The Bridge pattern helps you to move the implementation-specific code out of sight so that you can focus on your program's specific code. In the above example, the rest of your application can call `saver.save data` without regard for where the file ultimately ends up.
================================================
FILE: chapters/design_patterns/builder.md
================================================
---
layout: recipe
title: Builder Pattern
chapter: Design Patterns
---
## Problem
You need to prepare a complicated, multi-part object, but you expect to do it more than once or with varying configurations.
## Solution
Create a Builder to encapsulate the object production process.
The [Todo.txt](http://todotxt.com) format provides an advanced but still plain-text method for maintaining lists of to-do items. Typing out each item by hand would provide exhausting and error-prone, however, so a TodoTxtBuilder class could save us the trouble:
{% highlight coffeescript %}
class TodoTxtBuilder
constructor: (defaultParameters={ }) ->
@date = new Date(defaultParameters.date) or new Date
@contexts = defaultParameters.contexts or [ ]
@projects = defaultParameters.projects or [ ]
@priority = defaultParameters.priority or undefined
newTodo: (description, parameters={ }) ->
date = (parameters.date and new Date(parameters.date)) or @date
contexts = @contexts.concat(parameters.contexts or [ ])
projects = @projects.concat(parameters.projects or [ ])
priorityLevel = parameters.priority or @priority
createdAt = [date.getFullYear(), date.getMonth()+1, date.getDate()].join("-")
contextNames = ("@#{context}" for context in contexts when context).join(" ")
projectNames = ("+#{project}" for project in projects when project).join(" ")
priority = if priorityLevel then "(#{priorityLevel})" else ""
todoParts = [priority, createdAt, description, contextNames, projectNames]
(part for part in todoParts when part.length > 0).join " "
builder = new TodoTxtBuilder(date: "10/13/2011")
builder.newTodo "Wash laundry"
# => '2011-10-13 Wash laundry'
workBuilder = new TodoTxtBuilder(date: "10/13/2011", contexts: ["work"])
workBuilder.newTodo "Show the new design pattern to Lucy", contexts: ["desk", "xpSession"]
# => '2011-10-13 Show the new design pattern to Lucy @work @desk @xpSession'
workBuilder.newTodo "Remind Sean about the failing unit tests", contexts: ["meeting"], projects: ["compilerRefactor"], priority: 'A'
# => '(A) 2011-10-13 Remind Sean about the failing unit tests @work @meeting +compilerRefactor'
{% endhighlight %}
## Discussion
The TodoTxtBuilder class takes care of all the heavy lifting of text generation and lets the programmer focus on the unique elements of each to-do item. Additionally, a command line tool or GUI could plug into this code and still retain support for later, more advanced versions of the format with ease.
### Pre-Construction
Instead of creating a new instance of the needed object from scratch every time, we shift the burden to a separate object that we can then tweak during the object creation process.
{% highlight coffeescript %}
builder = new TodoTxtBuilder(date: "10/13/2011")
builder.newTodo "Order new netbook"
# => '2011-10-13 Order new netbook'
builder.projects.push "summerVacation"
builder.newTodo "Buy suntan lotion"
# => '2011-10-13 Buy suntan lotion +summerVacation'
builder.contexts.push "phone"
builder.newTodo "Order tickets"
# => '2011-10-13 Order tickets @phone +summerVacation'
delete builder.contexts[0]
builder.newTodo "Fill gas tank"
# => '2011-10-13 Fill gas tank +summerVacation'
{% endhighlight %}
### Exercises
* Expand the project- and context-tag generation code to filter out duplicate entries.
* Some Todo.txt users like to insert project and context tags inside the description of their to-do items. Add code to identify these tags and filter them out of the end tags.
================================================
FILE: chapters/design_patterns/command.md
================================================
---
layout: recipe
title: Command Pattern
chapter: Design Patterns
---
## Problem
You need to let another object handle when your private code is executed.
## Solution
Use the [Command pattern](http://en.wikipedia.org/wiki/Command_pattern) to pass along references to your functions.
{% highlight coffeescript %}
# Using a private variable to simulate external scripts or modules
incrementers = (() ->
privateVar = 0
singleIncrementer = () ->
privateVar += 1
doubleIncrementer = () ->
privateVar += 2
commands =
single: singleIncrementer
double: doubleIncrementer
value: -> privateVar
)()
class RunsAll
constructor: (@commands...) ->
run: -> command() for command in @commands
runner = new RunsAll(incrementers.single, incrementers.double, incrementers.single, incrementers.double)
runner.run()
incrementers.value() # => 6
{% endhighlight %}
## Discussion
With functions as first-class objects and with the function-bound variable scope inherited from Javascript, the CoffeeScript language makes the pattern nearly invisible. In fact, any function passed along as callbacks can act as a *Command*.
The `jqXHR` object returned by jQuery AJAX methods uses this pattern.
{% highlight coffeescript %}
jqxhr = $.ajax
url: "/"
logMessages = ""
jqxhr.success -> logMessages += "Success!\n"
jqxhr.error -> logMessages += "Error!\n"
jqxhr.complete -> logMessages += "Completed!\n"
# On a valid AJAX request:
# logMessages == "Success!\nCompleted!\n"
{% endhighlight %}
================================================
FILE: chapters/design_patterns/decorator.md
================================================
---
layout: recipe
title: Decorator Pattern
chapter: Design Patterns
---
## Problem
You have a set of data that you need to process in multiple, possibly varying ways.
## Solution
Use the Decorator pattern in order to structure how you apply the changes.
{% highlight coffeescript %}
miniMarkdown = (line) ->
if match = line.match /^(#+)\s*(.*)$/
headerLevel = match[1].length
headerText = match[2]
"#{headerText}"
else
if line.length > 0
"
#{line}
"
else
''
stripComments = (line) ->
line.replace /\s*\/\/.*$/, '' # Removes one-line, double-slash C-style comments
class TextProcessor
constructor: (@processors) ->
reducer: (existing, processor) ->
if processor
processor(existing or '')
else
existing
processLine: (text) ->
@processors.reduce @reducer, text
processString: (text) ->
(@processLine(line) for line in text.split("\n")).join("\n")
exampleText = '''
# A level 1 header
A regular line
// a comment
## A level 2 header
A line // with a comment
'''
processor = new TextProcessor [stripComments, miniMarkdown]
processor.processString exampleText
# => "
A level 1 header
\n
A regular line
\n\n
A level 2 header
\n
A line
"
{% endhighlight %}
### Results
{% highlight html %}
A level 1 header
A regular line
A level 1 header
A line
{% endhighlight %}
## Discussion
The TextProcessor serves the role of Decorator by binding the individual, specialized text processors together. This frees up the miniMarkdown and stripComments components to focus on handling nothing but a single line of text. Future developers only have to write functions that return a string and add it to the array of processors.
We can even modify the existing Decorator object on the fly:
{% highlight coffeescript %}
smilies =
':)' : "smile"
':D' : "huge_grin"
':(' : "frown"
';)' : "wink"
smilieExpander = (line) ->
if line
(line = line.replace symbol, "") for symbol, text of smilies
line
processor.processors.unshift smilieExpander
processor.processString "# A header that makes you :) // you may even laugh"
# => "
A header that makes you
"
processor.processors.shift()
# => "
A header that makes you :)
"
{% endhighlight %}
================================================
FILE: chapters/design_patterns/factory_method.md
================================================
---
layout: recipe
title: Factory Method Pattern
chapter: Design Patterns
---
## Problem
You don't know what kind of object you will need until runtime.
## Solution
Use the [Factory Method](http://en.wikipedia.org/wiki/Factory_method_pattern) pattern and choose the object to be generated dynamically.
Say that you need to load a file into an editor but you don't know its format until the user chooses the file. A class using the [Factory Method](http://en.wikipedia.org/wiki/Factory_method_pattern) pattern can serve up different parsers depending on the file's extension.
{% highlight coffeescript %}
class HTMLParser
constructor: ->
@type = "HTML parser"
class MarkdownParser
constructor: ->
@type = "Markdown parser"
class JSONParser
constructor: ->
@type = "JSON parser"
class ParserFactory
makeParser: (filename) ->
matches = filename.match /\.(\w*)$/
extension = matches[1]
switch extension
when "html" then new HTMLParser
when "htm" then new HTMLParser
when "markdown" then new MarkdownParser
when "md" then new MarkdownParser
when "json" then new JSONParser
factory = new ParserFactory
factory.makeParser("example.html").type # => "HTML parser"
factory.makeParser("example.md").type # => "Markdown parser"
factory.makeParser("example.json").type # => "JSON parser"
{% endhighlight %}
## Discussion
In the example, you can ignore the specifics of the file's format and focus on the parsed content. A more advanced Factory Method might, for instance, also search for versioning data within the file itself before returning a more precise parser (e.g. an HTML5 parser instead of an HTML v4 parser).
================================================
FILE: chapters/design_patterns/index.html
================================================
---
layout: chapter
title: Design Patterns
chapter: Design Patterns
---
{% capture url %}/chapters/{{ page.chapter | replace: ' ', '_' | downcase }}{% endcapture %}
{% capture indexurl %}{{ url }}/index.html{% endcapture %}
{% for page in site.pages %}
{% if page.url contains url %}
{% unless page.url == indexurl %}
================================================
FILE: chapters/design_patterns/interpreter.md
================================================
---
layout: recipe
title: Interpreter Pattern
chapter: Design Patterns
---
## Problem
Someone else needs to run parts of your code in a controlled fashion. Alternately, your language of choice cannot express the problem domain in a concise fashion.
## Solution
Use the Interpreter pattern to create a domain-specific language that you translate into specific code.
Assume, for example, that the user wants to perform math inside of your application. You could let them forward code to _eval_ but that would let them run arbitrary code. Instead, you can provide a miniature "stack calculator" language that you parse separately in order to only run mathematical operations while reporting more useful error messages.
{% highlight coffeescript %}
class StackCalculator
parseString: (string) ->
@stack = [ ]
for token in string.split /\s+/
@parseToken token
if @stack.length > 1
throw "Not enough operators: numbers left over"
else
@stack[0]
parseToken: (token, lastNumber) ->
if isNaN parseFloat(token) # Assume that anything other than a number is an operator
@parseOperator token
else
@stack.push parseFloat(token)
parseOperator: (operator) ->
if @stack.length < 2
throw "Can't operate on a stack without at least 2 items"
right = @stack.pop()
left = @stack.pop()
result = switch operator
when "+" then left + right
when "-" then left - right
when "*" then left * right
when "/"
if right is 0
throw "Can't divide by 0"
else
left / right
else
throw "Unrecognized operator: #{operator}"
@stack.push result
calc = new StackCalculator
calc.parseString "5 5 +" # => { result: 10 }
calc.parseString "4.0 5.5 +" # => { result: 9.5 }
calc.parseString "5 5 + 5 5 + *" # => { result: 100 }
try
calc.parseString "5 0 /"
catch error
error # => "Can't divide by 0"
try
calc.parseString "5 -"
catch error
error # => "Can't operate on a stack without at least 2 items"
try
calc.parseString "5 5 5 -"
catch error
error # => "Not enough operators: numbers left over"
try
calc.parseString "5 5 5 foo"
catch error
error # => "Unrecognized operator: foo"
{% endhighlight %}
## Discussion
As an alternative to writing our own interpreter, you can co-op the existing CoffeeScript interpreter in a such a way that its normal syntax makes for more natural (and therefore more comprehensible) expressions of your algorithm.
{% highlight coffeescript %}
class Sandwich
constructor: (@customer, @bread='white', @toppings=[], @toasted=false)->
white = (sw) ->
sw.bread = 'white'
sw
wheat = (sw) ->
sw.bread = 'wheat'
sw
turkey = (sw) ->
sw.toppings.push 'turkey'
sw
ham = (sw) ->
sw.toppings.push 'ham'
sw
swiss = (sw) ->
sw.toppings.push 'swiss'
sw
mayo = (sw) ->
sw.toppings.push 'mayo'
sw
toasted = (sw) ->
sw.toasted = true
sw
sandwich = (customer) ->
new Sandwich customer
to = (customer) ->
customer
send = (sw) ->
toastedState = sw.toasted and 'a toasted' or 'an untoasted'
toppingState = ''
if sw.toppings.length > 0
if sw.toppings.length > 1
toppingState = " with #{sw.toppings[0..sw.toppings.length-2].join ', '} and #{sw.toppings[sw.toppings.length-1]}"
else
toppingState = " with #{sw.toppings[0]}"
"#{sw.customer} requested #{toastedState}, #{sw.bread} bread sandwich#{toppingState}"
send sandwich to 'Charlie' # => "Charlie requested an untoasted, white bread sandwich"
send turkey sandwich to 'Judy' # => "Judy requested an untoasted, white bread sandwich with turkey"
send toasted ham turkey sandwich to 'Rachel' # => "Rachel requested a toasted, white bread sandwich with turkey and ham"
send toasted turkey ham swiss sandwich to 'Matt' # => "Matt requested a toasted, white bread sandwich with swiss, ham and turkey"
{% endhighlight %}
This example allows for layers of functions by how it returns the modified object so that outer functions can modify it in turn. By borrowing a verb and the preposition _to_, the example lends natural grammar to the construction and ends up reading like an actual sentence when used correctly. This way, both your CoffeeScript skills and your existing language skills can help catch code problems.
================================================
FILE: chapters/design_patterns/memento.md
================================================
---
layout: recipe
title: Memento Pattern
chapter: Design Patterns
---
## Problem
You want to anticipate the reversion of changes to an object.
## Solution
Use the [Memento pattern](http://en.wikipedia.org/wiki/Memento_pattern) to track changes to an object. The class using the pattern will export a `memento` object stored elsewhere.
If you have application where the user can edit a text file, for example, they may want to undo their last action. You can save the current state of the file before the user changes it and then roll back to that at a later point.
{% highlight coffeescript %}
class PreserveableText
class Memento
constructor: (@text) ->
constructor: (@text) ->
save: (newText) ->
memento = new Memento @text
@text = newText
memento
restore: (memento) ->
@text = memento.text
pt = new PreserveableText "The original string"
pt.text # => "The original string"
memento = pt.save "A new string"
pt.text # => "A new string"
pt.save "Yet another string"
pt.text # => "Yet another string"
pt.restore memento
pt.text # => "The original string"
{% endhighlight %}
## Discussion
The Memento object returned by `PreserveableText#save` stores the important state information separately for safe-keeping. You could even serialize this Memento in order to maintain an "undo" buffer on the hard disk or remotely for such data-intensive objects as edited images.
================================================
FILE: chapters/design_patterns/observer.md
================================================
---
layout: recipe
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 = []
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
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.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 subscription on PostOffice.
Every of subscribed objects is stored internally in the PostOffice array of subscriptions.
Every subscriber is notified on new concrete periodical is published.
================================================
FILE: chapters/design_patterns/singleton.md
================================================
---
layout: recipe
title: Singleton Pattern
chapter: Design Patterns
---
## Problem
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.
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/
[Require.js]: http://requirejs.org/
{% highlight coffeescript %}
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 %}
## Discussion
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 essence 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.
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]).
[1]: http://stackoverflow.com/questions/4214731/coffeescript-global-variables
{% 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 %}
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/).
================================================
FILE: chapters/design_patterns/strategy.md
================================================
---
layout: recipe
title: Strategy Pattern
chapter: Design Patterns
---
## Problem
You have more than one way to solve a problem but you need to choose (or even switch) between these methods at run time.
## Solution
Encapsulate your algorithms inside of Strategy objects.
Given an unsorted list, for example, we can change the sorting algorithm under different circumstances.
###The base class:
{% highlight coffeescript %}
StringSorter = (algorithm) ->
sort: (list) -> algorithm list
{% endhighlight %}
###The strategies:
{% highlight coffeescript %}
bubbleSort = (list) ->
anySwaps = false
swapPass = ->
for r in [0..list.length-2]
if list[r] > list[r+1]
anySwaps = true
[list[r], list[r+1]] = [list[r+1], list[r]]
swapPass()
while anySwaps
anySwaps = false
swapPass()
list
reverseBubbleSort = (list) ->
anySwaps = false
swapPass = ->
for r in [list.length-1..1]
if list[r] < list[r-1]
anySwaps = true
[list[r], list[r-1]] = [list[r-1], list[r]]
swapPass()
while anySwaps
anySwaps = false
swapPass()
list
{% endhighlight %}
###Using the strategies:
{% highlight coffeescript %}
sorter = new StringSorter bubbleSort
unsortedList = ['e', 'b', 'd', 'c', 'x', 'a']
sorter.sort unsortedList
# => ['a', 'b', 'c', 'd', 'e', 'x']
unsortedList.push 'w'
# => ['a', 'b', 'c', 'd', 'e', 'x', 'w']
sorter.algorithm = reverseBubbleSort
sorter.sort unsortedList
# => ['a', 'b', 'c', 'd', 'e', 'w', 'x']
{% endhighlight %}
## Discussion
"No plan survives first contact with the enemy", nor users, but we can use the knowledge gained from changing circumstances to adapt. Near the end of the example, for instance, the newest item in the array now lies out of order. Knowing that detail, we can then speed the sort up by switching to an algorithm optimized for that exact scenario with nothing but a simple reassignment.
### Exercises
* Expand `StringSorter` into an `AlwaysSortedArray` class that implements all of the functionality of a regular array but which automatically sorts new items based on the method of insertion (e.g. `push` vs. `shift`).
================================================
FILE: chapters/design_patterns/template_method.md
================================================
---
layout: recipe
title: Template Method Pattern
chapter: Design Patterns
---
## Problem
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 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 the production of 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"
docs = [new DocWithHeader, new DocWithoutHeader]
doc.produceDocument() for doc in docs
{% endhighlight %}
## Discussion
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.
================================================
FILE: chapters/functions/debounce.md
================================================
---
layout: recipe
title: Debounce Functions
chapter: Functions
---
## Problem
You want to execute a function only once, coalescing multiple sequential calls into a single execution at the beginning or end.
## Solution
With a named function:
{% highlight coffeescript %}
debounce: (func, threshold, execAsap) ->
timeout = null
(args...) ->
obj = this
delayed = ->
func.apply(obj, args) unless execAsap
timeout = null
if timeout
clearTimeout(timeout)
else if (execAsap)
func.apply(obj, args)
timeout = setTimeout delayed, threshold || 100
{% endhighlight %}
{% highlight coffeescript %}
mouseMoveHandler: (e) ->
@debounce((e) ->
# Do something here, but only once 300 milliseconds after the mouse cursor stops.
300)
someOtherHandler: (e) ->
@debounce((e) ->
# Do something here, but only once 250 milliseconds after initial execution.
250, true)
{% endhighlight %}
## Discussion
Learn about [debouncing JavaScript methods](http://unscriptable.com/2009/03/20/debouncing-javascript-methods/) at John Hann's excellent blog article.
================================================
FILE: chapters/functions/index.html
================================================
---
layout: chapter
title: Functions
chapter: Functions
---
{% capture url %}/chapters/{{ page.chapter | replace: ' ', '_' | downcase }}{% endcapture %}
{% capture indexurl %}{{ url }}/index.html{% endcapture %}
{% for page in site.pages %}
{% if page.url contains url %}
{% unless page.url == indexurl %}
================================================
FILE: chapters/functions/parentheses.md
================================================
---
layout: recipe
title: When Function Parentheses Are Not Optional
chapter: Functions
---
## Problem
You want to call a function that takes no arguments, but don't want to use parentheses.
## Solution
Use parentheses anyway.
Another alternative is to utilize the do-notation like so:
{% highlight coffeescript %}
notify = -> alert "Hello, user!"
do notify if condition
{% endhighlight %}
This compiles to the following JavaScript:
{% highlight javascript %}
var notify;
notify = function() {
return alert("Hello, user!");
};
if (condition) {
notify();
}
{% endhighlight %}
## Discussion
Like Ruby, CoffeeScript allows you to drop parentheses to method calls. Unlike Ruby, however, CoffeeScript treats a bare function name as the pointer to the function. The practical upshot of this is that if you give no arguments to a method, CoffeeScript cannot tell if you want to call the function or use it as a reference.
Is this good or bad? It's just different. It creates an unexpected syntax case -- parentheses aren't _always_ optional -- but in exchange it gives you the ability to pass and receive functions fluently by name, something that's a bit clunky in Ruby.
This usage of the do-notation is a neat approach for CoffeeScript with parenphobia.
Some people simply prefer to write out the parentheses in the function call, though.
================================================
FILE: chapters/functions/recursion.md
================================================
---
layout: recipe
title: Recursive Functions
chapter: Functions
---
## Problem
You want to call a function from within that same function.
## Solution
With a named function:
{% highlight coffeescript %}
ping = ->
console.log "Pinged"
setTimeout ping, 1000
{% endhighlight %}
With an unnamed function, using @arguments.callee@:
{% highlight coffeescript %}
delay = 1000
setTimeout((->
console.log "Pinged"
setTimeout arguments.callee, delay
), delay)
{% endhighlight %}
## Discussion
While `arguments.callee` allows for the recursion of anonymous functions and might have the advantage in a very memory-intensive application, named functions keep their purpose more explicit and make for more maintainable code.
================================================
FILE: chapters/functions/splat_arguments.md
================================================
---
layout: recipe
title: Splat Arguments
chapter: Functions
---
## Problem
Your function will be called with a varying number of arguments.
## Solution
Use _splats_.
{% highlight coffeescript %}
loadTruck = (firstDibs, secondDibs, tooSlow...) ->
truck:
driversSeat: firstDibs
passengerSeat: secondDibs
trunkBed: tooSlow
loadTruck("Amanda", "Joel")
# => { truck: { driversSeat: "Amanda", passengerSeat: "Joel", trunkBed: [] } }
loadTruck("Amanda", "Joel", "Bob", "Mary", "Phillip")
# => { truck: { driversSeat: "Amanda", passengerSeat: "Joel", trunkBed: ["Bob", "Mary", "Phillip"] } }
{% endhighlight %}
With a trailing argument:
{% highlight coffeescript %}
loadTruck = (firstDibs, secondDibs, tooSlow..., leftAtHome) ->
truck:
driversSeat: firstDibs
passengerSeat: secondDibs
trunkBed: tooSlow
taxi:
passengerSeat: leftAtHome
loadTruck("Amanda", "Joel", "Bob", "Mary", "Phillip", "Austin")
# => { truck: { driversSeat: 'Amanda', passengerSeat: 'Joel', trunkBed: [ 'Bob', 'Mary', 'Phillip' ] }, taxi: { passengerSeat: 'Austin' } }
loadTruck("Amanda")
# => { truck: { driversSeat: "Amanda", passengerSeat: undefined, trunkBed: [] }, taxi: undefined }
{% endhighlight %}
## Discussion
By adding an ellipsis (`...`) next to no more than one of a function's arguments, CoffeeScript will combine all of the argument values not captured by other named arguments into a list. It will serve up an empty list even if some of the named arguments were not supplied.
================================================
FILE: chapters/index.html
================================================
---
layout: default
title: Cookbook
---
================================================
FILE: chapters/jquery/plugin.md
================================================
---
layout: recipe
title: Create a jQuery Plugin
chapter: jQuery
---
## Problem
You'd like to create jQuery plugin using CoffeeScript
## Solution
{% highlight coffeescript %}
# Reference jQuery
$ = jQuery
# Adds plugin object to jQuery
$.fn.extend
# Change pluginName to your plugin's name.
pluginName: (options) ->
# Default settings
settings =
option1: true
option2: false
debug: false
# Merge default settings with options.
settings = $.extend settings, options
# Simple logger.
log = (msg) ->
console?.log msg if settings.debug
# _Insert magic here._
return @each ()->
log "Preparing magic show."
# You can use your settings in here now.
log "Option 1 value: #{settings.option1}"
{% endhighlight %}
## Discussion
Here are a couple of examples of how to use your new plugin.
### JavaScript
{% highlight javascript %}
$("body").pluginName({
debug: true
});
{% endhighlight %}
### CoffeeScript:
{% highlight coffeescript %}
$("body").pluginName
debug: true
{% endhighlight %}
================================================
FILE: chapters/math/constants.md
================================================
---
layout: recipe
title: Math Constants
chapter: Math
---
## Problem
You need to use common mathematical constants like pi or e.
## Solution
Use Javascript's Math object to provide commonly needed mathematical constants.
{% highlight coffeescript %}
Math.PI
# => 3.141592653589793
# Note: Capitalization matters! This produces no output, it's undefined.
Math.Pi
# =>
Math.E
# => 2.718281828459045
Math.SQRT2
# => 1.4142135623730951
Math.SQRT1_2
# => 0.7071067811865476
# Natural log of 2. ln(2)
Math.LN2
# => 0.6931471805599453
Math.LN10
# => 2.302585092994046
Math.LOG2E
# => 1.4426950408889634
Math.LOG10E
# => 0.4342944819032518
{% endhighlight %}
## Discussion
For another example of how a math constant is used in a real world problem, refer to the [Converting Radians and Degrees]({{ site.baseurl }}/chapters/math/radians-degrees) section of this Math chapter.
================================================
FILE: chapters/math/fast-fibonacci.md
================================================
---
layout: recipe
title: Faster Fibonacci Algorithm
chapter: Math
---
## Problem
You would like to calculate a number N in the Fibonacci sequence but want
to do it quickly.
## Solution
The following solution (which can still be improved on) was originally
talked about on Robin Houston's blog.
Here are a few links talking about the algorithm and ways to improve it:
* [http://bosker.wordpress.com/2011/04/29/the-worst-algorithm-in-the-world/](http://bosker.wordpress.com/2011/04/29/the-worst-algorithm-in-the-world/)
* [http://www.math.rutgers.edu/~erowland/fibonacci](http://www.math.rutgers.edu/~erowland/fibonacci.html)
* [http://jsfromhell.com/classes/bignumber](http://jsfromhell.com/classes/bignumber)
* [http://www.math.rutgers.edu/~erowland/fibonacci](http://www.math.rutgers.edu/~erowland/fibonacci.html)
* [http://bigintegers.blogspot.com/2010/11/square-division-power-square-root](http://bigintegers.blogspot.com/2010/11/square-division-power-square-root.html)
* [http://bugs.python.org/issue3451](http://bugs.python.org/issue3451)
This code is in gist form here:
[https://gist.github.com/1032685](https://gist.github.com/1032685)
{% highlight coffeescript %}
###
Author: Jason Giedymin
http://www.jasongiedymin.com
https://github.com/JasonGiedymin
This CoffeeScript Javascript Fast Fibonacci code is
based on the python code from Robin Houston's blog.
See below links.
A few things I want to introduce in time are implementations of
Newtonian, Burnikel / Ziegler, and Binet's algorithms on top
of a Big Number framework.
Todo:
- https://github.com/substack/node-bigint
- BZ and Newton mods.
- Timing
###
MAXIMUM_JS_FIB_N = 1476
fib_bits = (n) ->
#Represent an integer as an array of binary digits.
bits = []
while n > 0
[n, bit] = divmodBasic n, 2
bits.push bit
bits.reverse()
return bits
fibFast = (n) ->
#Fast Fibonacci
if n < 0
console.log "Choose an number >= 0"
return
[a, b, c] = [1, 0, 1]
for bit in fib_bits n
if bit
[a, b] = [(a+c)*b, b*b + c*c]
else
[a, b] = [a*a + b*b, (a+c)*b]
c = a + b
return b
divmodNewton = (x, y) ->
throw new Error "Method not yet implemented yet."
divmodBZ = () ->
throw new Error "Method not yet implemented yet."
divmodBasic = (x, y) ->
###
Absolutely nothing special here. Maybe later versions will be Newtonian or
Burnikel / Ziegler _if_ possible...
###
return [(q = Math.floor x/y), (r = if x < y then x else x % y)]
start = (new Date).getTime();
calc_value = fibFast(MAXIMUM_JS_FIB_N)
diff = (new Date).getTime() - start;
console.log "[#{calc_value}] took #{diff} ms."
{% endhighlight %}
## Discussion
Questions?
================================================
FILE: chapters/math/fast-inv-square.md
================================================
---
layout: recipe
title: Fast Inverse Square Root
chapter: Math
---
## Problem
You would like to calculate a the inverse square root of a number [quickly][5].
## Solution
Appearing in the Quake III Arena [source code][1], this strange algorithm uses
integer operations along with a 'magic number' to calculate floating point
approximation values of inverse square roots.
In this CoffeeScript variant I supply the original classic, and newer optimal
32 bit magic numbers found by [Chris Lomont][2]. Also supplied is the 64-bit
sized magic number.
Another feature included is the ability to alter the level of precision.
This is done by controlling the number of iterations for performing [Newton's
method][3].
Depending on the machine and level of precision this algorithm may still
provide performance increases over the classic.
To run this, compile the script with coffee:
coffee -c script.coffee
Then copy & paste the compiled js code in to the JavaScript console of your
browser.
Note: You will need a browser which supports [typed-arrays][4].
References:
1. [ftp://ftp.idsoftware.com/idstuff/source/quake3-1.32b-source.zip](ftp://ftp.idsoftware.com/idstuff/source/quake3-1.32b-source.zip)
2. [http://www.lomont.org/Math/Papers/2003/InvSqrt.pdf](http://www.lomont.org/Math/Papers/2003/InvSqrt.pdf)
3. [http://en.wikipedia.org/wiki/Newton%27s_method](http://en.wikipedia.org/wiki/Newton%27s_method)
4. [https://developer.mozilla.org/en/JavaScript_typed_arrays](https://developer.mozilla.org/en/JavaScript_typed_arrays)
5. [http://en.wikipedia.org/wiki/Fast_inverse_square_root](http://en.wikipedia.org/wiki/Fast_inverse_square_root)
[1]: ftp://ftp.idsoftware.com/idstuff/source/quake3-1.32b-source.zip "ftp://ftp.idsoftware.com/idstuff/source/quake3-1.32b-source.zip"
[2]: http://www.lomont.org/Math/Papers/2003/InvSqrt.pdf "http://www.lomont.org/Math/Papers/2003/InvSqrt.pdf"
[3]: http://en.wikipedia.org/wiki/Newton%27s_method "http://en.wikipedia.org/wiki/Newton%27s_method"
[4]: https://developer.mozilla.org/en/JavaScript_typed_arrays "https://developer.mozilla.org/en/JavaScript_typed_arrays"
[5]: http://en.wikipedia.org/wiki/Fast_inverse_square_root "http://en.wikipedia.org/wiki/Fast_inverse_square_root"
This code is in gist form here:
[https://gist.github.com/1036533](https://gist.github.com/1036533)
{% highlight coffeescript %}
###
Author: Jason Giedymin
http://www.jasongiedymin.com
https://github.com/JasonGiedymin
Appearing in the Quake III Arena source code[1], this strange algorithm uses
integer operations along with a 'magic number' to calculate floating point
approximation values of inverse square roots[5].
In this CoffeeScript variant I supply the original classic, and newer optimal
32 bit magic numbers found by Chris Lomont[2]. Also supplied is the 64-bit
sized magic number.
Another feature included is the ability to alter the level of precision.
This is done by controlling the number of iterations for performing Newton's
method[3].
Depending on the machine and level of precision this algorithm may still
provide performance increases over the classic.
To run this, compile the script with coffee:
coffee -c .coffee
Then copy & paste the compiled js code in to the JavaScript console of your
browser.
Note: You will need a browser which supports typed-arrays[4].
References:
[1] ftp://ftp.idsoftware.com/idstuff/source/quake3-1.32b-source.zip
[2] http://www.lomont.org/Math/Papers/2003/InvSqrt.pdf
[3] http://en.wikipedia.org/wiki/Newton%27s_method
[4] https://developer.mozilla.org/en/JavaScript_typed_arrays
[5] http://en.wikipedia.org/wiki/Fast_inverse_square_root
###
approx_const_quake_32 = 0x5f3759df # See [1]
approx_const_32 = 0x5f375a86 # See [2]
approx_const_64 = 0x5fe6eb50c7aa19f9 # See [2]
fastInvSqrt_typed = (n, precision=1) ->
# Using typed arrays. Right now only works in browsers.
# Node.JS version coming soon.
y = new Float32Array(1)
i = new Int32Array(y.buffer)
y[0] = n
i[0] = 0x5f375a86 - (i[0] >> 1)
for iter in [1...precision]
y[0] = y[0] * (1.5 - ((n * 0.5) * y[0] * y[0]))
return y[0]
### Sample single runs ###
testSingle = () ->
example_n = 10
console.log("Fast InvSqrt of 10, precision 1: #{fastInvSqrt_typed(example_n)}")
console.log("Fast InvSqrt of 10, precision 5: #{fastInvSqrt_typed(example_n, 5)}")
console.log("Fast InvSqrt of 10, precision 10: #{fastInvSqrt_typed(example_n, 10)}")
console.log("Fast InvSqrt of 10, precision 20: #{fastInvSqrt_typed(example_n, 20)}")
console.log("Classic of 10: #{1.0 / Math.sqrt(example_n)}")
testSingle()
{% endhighlight %}
## Discussion
Questions?
================================================
FILE: chapters/math/generating-predictable-random-numbers.md
================================================
---
layout: recipe
title: Generating Predictable Random Numbers
chapter: Math
---
## Problem
You need to generate a random number in a certain range, but you also need to be able to "seed" the generator to deliver predictable values.
## Solution
Write your own random number generator. There are a LOT of ways to do this. Here's a simple one. _This generator is +ABSOLUTELY NOT+ acceptable for cryptographic purposes!_
{% highlight coffeescript %}
class Rand
# if created without a seed, uses current time as seed
constructor: (@seed) ->
# Knuth and Lewis' improvements to Park and Miller's LCPRNG
@multiplier = 1664525
@modulo = 4294967296 # 2**32-1;
@offset = 1013904223
unless @seed? && 0 <= seed < @modulo
@seed = (new Date().valueOf() * new Date().getMilliseconds()) % @modulo
# sets new seed value
seed: (seed) ->
@seed = seed
# return a random integer 0 <= n < @modulo
randn: ->
# new_seed = (a * seed + c) % m
@seed = (@multiplier*@seed + @offset) % @modulo
# return a random float 0 <= f < 1.0
randf: ->
this.randn() / @modulo
# return a random int 0 <= f < n
rand: (n) ->
Math.floor(this.randf() * n)
# return a random int min <= f < max
rand2: (min, max) ->
min + this.rand(max-min)
{% endhighlight %}
## Discussion
JavaScript and CoffeeScript do not provide a seedable random number generator. Writing your own will be an exercise in trading off the amount of randomness with the simplicity of the generator. A full discussion of randomness is beyond the scope of this cookbook; for further reading consult Donald Knuth's _The Art of Computer Programming_, Volume II, Chapter 3, "Random Numbers", and _Numerical Recipes in C_, 2nd Edition, Chapter 7, "Random Numbers".
A brief explanation of this random number generator is in order, however. It is a Linear Congruential Pseudorandom Number Generator. LCPRNG's operate on the mathematical formula `Ij+1 = (aIj+c) % m`, where a is the multiplier, c is the addition offset, and m is the modulus.
Each time a random number is requested, a very large multiplication and addition are performed -- "very large" relative to the key space -- and the resulting number is modulused back down into the keyspace.
This generator has a period of 232. It is absolutely unacceptable for cryptographic purposes, but for most simple randomness requirements it is quite adequate. `randn()` will traverse the entire keyspace before repeating itself, and the next number is determined by the previous one.
If you want to tinker with this generator, you are _strongly_ encouraged to read Chapter 3 of Knuth's _The Art of Computer Programming_. Random number generation is VERY easy to screw up, and Knuth explains how to tell a good RNG from a bad one.
Avoid the temptation to modulus the output of this generator. If you need an integer range, use division. Linear Congruential generators are very nonrandom in their lower bits. This one in particular always generates an odd number from an even seed, and vice versa. So if you need a random 0 or 1, do NOT use
{% highlight coffeescript %}
# NOT random! Do not do this!
r.randn() % 2
{% endhighlight %}
because you will most definitely not get random digits. Use `r.rand(2)` instead.
================================================
FILE: chapters/math/generating-random-numbers.md
================================================
---
layout: recipe
title: Generating Random Numbers
chapter: Math
---
## Problem
You need to generate a random number in a certain range.
## Solution
Use JavaScript's Math.random() to get floating-point numbers from 0 <= x < 1.0. Use multiplication and Math.floor to get a number in a certain range.
{% highlight coffeescript %}
probability = Math.random()
0.0 <= probability < 1.0
# => true
# Note that percentile does NOT ever reach 100. A full range of 0 to 100 is actually a span of 101.
percentile = Math.floor(Math.random() * 100)
0 <= percentile < 100
# => true
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
This is a straight lift from JavaScript.
Note that JavaScript's Math.random() does not allow you to seed the random number generator to force certain values. See [Generating Predictable Random Numbers]({{ site.baseurl }}/chapters/math/generating-predictable-random-numbers) for that.
To generate a number from 0 up to (but not including) n, multiply by n. To generate a number from 1 to n (inclusive), multiply by n and add 1.
================================================
FILE: chapters/math/index.html
================================================
---
layout: chapter
title: Math
chapter: Math
---
{% capture url %}/chapters/{{ page.chapter | replace: ' ', '_' | downcase }}{% endcapture %}
{% capture indexurl %}{{ url }}/index.html{% endcapture %}
{% for page in site.pages %}
{% if page.url contains url %}
{% unless page.url == indexurl %}
================================================
FILE: chapters/math/radians-degrees.md
================================================
---
layout: recipe
title: Converting Radians and Degrees
chapter: Math
---
## Problem
You need to convert between radians and degrees.
## Solution
Use Javascript's Math.PI and a simple formula to convert between the two.
{% highlight coffeescript %}
# To convert from radians to degrees
radiansToDegrees = (radians) ->
degrees = radians * 180 / Math.PI
radiansToDegrees(1)
# => 57.29577951308232
# To convert from degrees to radians
degreesToRadians = (degrees) ->
radians = degrees * Math.PI / 180
degreesToRadians(1)
# => 0.017453292519943295
{% endhighlight %}
## Discussion
Questions?
================================================
FILE: chapters/math/random-integer.md
================================================
---
layout: recipe
title: A Random Integer Function
chapter: Math
---
## Problem
You'd like to get a random integer between two integers, inclusive.
## Solution
Use the following function.
{% highlight coffeescript %}
randomInt = (lower, upper) ->
[lower, upper] = [0, lower] unless upper? # Called with one argument
[lower, upper] = [upper, lower] if lower > upper # Lower must be less then upper
Math.floor(Math.random() * (upper - lower + 1) + lower) # Last statement is a return value
(randomInt(1) for i in [0...10])
# => [0,1,1,0,0,0,1,1,1,0]
(randomInt(1, 10) for i in [0...10])
# => [7,3,9,1,8,5,4,10,10,8]
{% endhighlight %}
## Discussion
Questions?
================================================
FILE: chapters/math/working-with-exponents-and-logarithms.md
================================================
---
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 Network](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math). Also refer to [Math Constants]({{ site.baseurl }}/chapters/math/constants) for discussion of the various constants in the Math object.
================================================
FILE: chapters/metaprogramming/detecting-and-replacing-functions.md
================================================
---
layout: recipe
title: Detecting and Creating Missing Functions
chapter: Metaprogramming
---
## Problem
You want to detect if a function exists and create it if it does not (such as an ECMAScript 5 function in Internet Explorer 8).
## Solution
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 %}
do -> Array::filter ?= (callback) ->
element for element in this when callback element
array = [1..10]
array.filter (x) -> x > 5
# => [6,7,8,9,10]
{% endhighlight %}
## 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 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.
### 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 %}
================================================
FILE: chapters/metaprogramming/extending-built-in-objects.md
================================================
---
layout: recipe
title: Extending Built-in Objects
chapter: Metaprogramming
---
## Problem
You want to extend a class to add new functionality or replace old.
## Solution
Use `::` to assign your new function to the prototype of the object or class.
{% highlight coffeescript %}
String::capitalize = () ->
(this.split(/\s+/).map (word) -> word[0].toUpperCase() + word[1..-1].toLowerCase()).join ' '
"foo bar baz".capitalize()
# => 'Foo Bar Baz'
{% endhighlight %}
## 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.
**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-native-builtins/)).
================================================
FILE: chapters/metaprogramming/index.html
================================================
---
layout: chapter
title: Metaprogramming
chapter: Metaprogramming
---
{% capture url %}/chapters/{{ page.chapter | replace: ' ', '_' | downcase }}{% endcapture %}
{% capture indexurl %}{{ url }}/index.html{% endcapture %}
{% for page in site.pages %}
{% if page.url contains url %}
{% unless page.url == indexurl %}
================================================
FILE: chapters/networking/basic-client.md
================================================
---
layout: recipe
title: Basic Client
chapter: Networking
---
## Problem
You want to access a service provided over the network.
## Solution
Create a basic TCP client.
### In Node.js
{% highlight coffeescript %}
net = require 'net'
domain = 'localhost'
port = 9001
connection = net.createConnection port, domain
connection.on 'connect', () ->
console.log "Opened connection to #{domain}:#{port}."
connection.on 'data', (data) ->
console.log "Received: #{data}"
connection.end()
{% endhighlight %}
### Example Usage
Accessing the [Basic Server]({{ site.baseurl }}/chapters/networking/basic-server):
{% highlight console %}
$ coffee basic-client.coffee
Opened connection to localhost:9001
Received: Hello, World!
{% endhighlight %}
## Discussion
The most important work takes place in the _connection.on 'data'_ handler, where the client receives its response from the server and would most likely arrange for responses to it.
See also the [Basic Server]({{ site.baseurl }}/chapters/networking/basic-server), [Bi-Directional Client]({{ site.baseurl }}/chapters/networking/bi-directional-client), and [Bi-Directional Server]({{ site.baseurl }}/chapters/networking/bi-directional-server) recipes.
### Exercises
* Add support for choosing the target domain and port based on command-line arguments or from a configuration file.
================================================
FILE: chapters/networking/basic-http-client.md
================================================
---
layout: recipe
title: Basic HTTP Client
chapter: Networking
---
## Problem
You want to create a HTTP client.
## Solution
In this recipe, we'll use [node.js](http://nodejs.org/)'s HTTP library. We'll go from a simple GET request example to a client which returns the external IP of a computer.
### GET something
{% highlight coffeescript %}
http = require 'http'
http.get { host: 'www.google.com' }, (res) ->
console.log res.statusCode
{% endhighlight %}
The `get` function, from node.js's `http` module, issues a GET request to a HTTP server. The response comes in the form of a callback, which we can handle in a function. This example merely prints the response status code. Check it out:
{% highlight console %}
$ coffee http-client.coffee
200
{% endhighlight %}
### What's my IP?
If you are inside a network which relies on [NAT](http://en.wikipedia.org/wiki/Network_address_translation) such as a LAN, you probably have faced the issue of finding out what's your external IP address. Let's write a small coffeescript for this.
{% highlight coffeescript %}
http = require 'http'
http.get { host: 'checkip.dyndns.org' }, (res) ->
data = ''
res.on 'data', (chunk) ->
data += chunk.toString()
res.on 'end', () ->
console.log data.match(/([0-9]+\.){3}[0-9]+/)[0]
{% endhighlight %}
We can get the data from the result object by listening on its `'data'` event; and know that it has come to an end once the `'end'` event has been fired. When that happens, we can do a simple regular expression match to extract our IP address. Try it:
{% highlight console %}
$ coffee http-client.coffee
123.123.123.123
{% endhighlight %}
## Discussion
Note that `http.get` is a shortcut of `http.request`. The latter allows you to issue HTTP requests with different methods, such as POST or PUT.
For API and overall information on this subject, check node.js's [http](http://nodejs.org/docs/latest/api/http.html) and [https](http://nodejs.org/docs/latest/api/https.html) documentation pages. Also, the [HTTP spec](http://www.ietf.org/rfc/rfc2616.txt) might come in handy.
### Exercises
* Create a client for the key-value store HTTP server, from the [Basic HTTP Server](basic-http-server) recipe.
================================================
FILE: chapters/networking/basic-http-server.md
================================================
---
layout: recipe
title: Basic HTTP Server
chapter: Networking
---
## Problem
You want to create a HTTP server over a network. Over the course of this recipe, we'll go step by step from the smallest server possible to a functional key-value store.
## Solution
We'll use [node.js](http://nodejs.org/)'s HTTP library to our own selfish purposes and create the simplest web server possible in Coffeescript.
### Say 'hi\n'
We can start by importing node.js's HTTP module. This contains `createServer` which, given a simple request handler, returns a HTTP server. We can use that server to listen on a TCP port.
{% highlight coffeescript %}
http = require 'http'
server = http.createServer (req, res) -> res.end 'hi\n'
server.listen 8000
{% endhighlight %}
To run this example, simply put in a file and run it. You can kill it with `Ctrl-C`. We can test it using the `curl` command, available on most \*nix platforms:
{% highlight console %}
$ curl -D - http://localhost:8000/
HTTP/1.1 200 OK
Connection: keep-alive
Transfer-Encoding: chunked
hi
{% endhighlight %}
### What's going on?
Let's get a little bit more feedback on what's happening on our server. While we're at it, we could also be friendlier to our clients and provide them some HTTP headers.
{% highlight coffeescript %}
http = require 'http'
server = http.createServer (req, res) ->
console.log req.method, req.url
data = 'hi\n'
res.writeHead 200,
'Content-Type': 'text/plain'
'Content-Length': data.length
res.end data
server.listen 8000
{% endhighlight %}
Try to access it once again, but this time use different URL paths, such as `http://localhost:8000/coffee`. You'll see something like this on the server console:
{% highlight console %}
$ coffee http-server.coffee
GET /
GET /coffee
GET /user/1337
{% endhighlight %}
### GETting stuff
What if our webserver was able to hold some data? We'll try to come up with a simple key-value store in which elements are retrievable via GET requests. Provide a key on the request path and the server will return the corresponding value — or 404 if it doesn't exist.
{% highlight coffeescript %}
http = require 'http'
store = # we'll use a simple object as our store
foo: 'bar'
coffee: 'script'
server = http.createServer (req, res) ->
console.log req.method, req.url
value = store[req.url[1..]]
if not value
res.writeHead 404
else
res.writeHead 200,
'Content-Type': 'text/plain'
'Content-Length': value.length + 1
res.write value + '\n'
res.end()
server.listen 8000
{% endhighlight %}
We can try several URLs to see how it responds:
{% highlight console %}
$ curl -D - http://localhost:8000/coffee
HTTP/1.1 200 OK
Content-Type: text/plain
Content-Length: 7
Connection: keep-alive
script
$ curl -D - http://localhost:8000/oops
HTTP/1.1 404 Not Found
Connection: keep-alive
Transfer-Encoding: chunked
{% endhighlight %}
### Use your head(ers)
Let's face it, `text/plain` is kind of lame. How about if we use something hip like `application/json` or `text/xml`? Also, our store retrieval process could use a bit of refactoring — how about some exception throwing & handling? Let's see what we can come up with:
{% highlight coffeescript %}
http = require 'http'
# known mime types
[any, json, xml] = ['*/*', 'application/json', 'text/xml']
# gets a value from the db in format [value, contentType]
get = (store, key, format) ->
value = store[key]
throw 'Unknown key' if not value
switch format
when any, json then [JSON.stringify({ key: key, value: value }), json]
when xml then ["#{ key }\n#{ value }", xml]
else throw 'Unknown format'
store =
foo: 'bar'
coffee: 'script'
server = http.createServer (req, res) ->
console.log req.method, req.url
try
key = req.url[1..]
[value, contentType] = get store, key, req.headers.accept
code = 200
catch error
contentType = 'text/plain'
value = error
code = 404
res.writeHead code,
'Content-Type': contentType
'Content-Length': value.length + 1
res.write value + '\n'
res.end()
server.listen 8000
{% endhighlight %}
This server will still return the value which matches a given key, or 404 if non-existent. But it will structure the response either in JSON or XML, according to the `Accept` header. See for yourself:
{% highlight console %}
$ curl http://localhost:8000/
Unknown key
$ curl http://localhost:8000/coffee
{"key":"coffee","value":"script"}
$ curl -H "Accept: text/xml" http://localhost:8000/coffee
coffeescript
$ curl -H "Accept: image/png" http://localhost:8000/coffee
Unknown format
{% endhighlight %}
### You gotta give to get back
The obvious last step in our adventure is to provide the client the ability to store data. We'll keep our RESTiness by listening to POST requests for this purpose.
{% highlight coffeescript %}
http = require 'http'
# known mime types
[any, json, xml] = ['*/*', 'application/json', 'text/xml']
# gets a value from the db in format [value, contentType]
get = (store, key, format) ->
value = store[key]
throw 'Unknown key' if not value
switch format
when any, json then [JSON.stringify({ key: key, value: value }), json]
when xml then ["#{ key }\n#{ value }", xml]
else throw 'Unknown format'
# puts a value in the db
put = (store, key, value) ->
throw 'Invalid key' if not key or key is ''
store[key] = value
store =
foo: 'bar'
coffee: 'script'
# helper function that responds to the client
respond = (res, code, contentType, data) ->
res.writeHead code,
'Content-Type': contentType
'Content-Length': data.length
res.write data
res.end()
server = http.createServer (req, res) ->
console.log req.method, req.url
key = req.url[1..]
contentType = 'text/plain'
code = 404
switch req.method
when 'GET'
try
[value, contentType] = get store, key, req.headers.accept
code = 200
catch error
value = error
respond res, code, contentType, value + '\n'
when 'POST'
value = ''
req.on 'data', (chunk) -> value += chunk
req.on 'end', () ->
try
put store, key, value
value = ''
code = 200
catch error
value = error + '\n'
respond res, code, contentType, value
server.listen 8000
{% endhighlight %}
Notice how the data is received in a POST request. By attaching some handlers on the `'data'` and `'end'` events of the request object, we're able to buffer and finally save the data from the client in the `store`.
{% highlight console %}
$ curl -D - http://localhost:8000/cookie
HTTP/1.1 404 Not Found # ...
Unknown key
$ curl -D - -d "monster" http://localhost:8000/cookie
HTTP/1.1 200 OK # ...
$ curl -D - http://localhost:8000/cookie
HTTP/1.1 200 OK # ...
{"key":"cookie","value":"monster"}
{% endhighlight %}
## Discussion
Give `http.createServer` a function in the shape of `(request, response) -> ...` and it will return a server object, which we can use to listen on a port. Interact with the `request` and `response` objects to give the server its behaviour. Listen on port 8000 using `server.listen 8000`.
For API and overall information on this subject, check node.js's [http](http://nodejs.org/docs/latest/api/http.html) and [https](http://nodejs.org/docs/latest/api/https.html) documentation pages. Also, the [HTTP spec](http://www.ietf.org/rfc/rfc2616.txt) might come in handy.
### Exercises
* Create a layer in between the server and the developer which would allow the developer to do something like:
{% highlight coffeescript %}
server = layer.createServer
'GET /': (req, res) ->
...
'GET /page': (req, res) ->
...
'PUT /image': (req, res) ->
...
{% endhighlight %}
================================================
FILE: chapters/networking/basic-server.md
================================================
---
layout: recipe
title: Basic Server
chapter: Networking
---
## Problem
You want to provide a service over a network.
## Solution
Create a basic TCP server.
### In Node.js
{% highlight coffeescript %}
net = require 'net'
domain = 'localhost'
port = 9001
server = net.createServer (socket) ->
console.log "Received connection from #{socket.remoteAddress}"
socket.write "Hello, World!\n"
socket.end()
console.log "Listening to #{domain}:#{port}"
server.listen port, domain
{% endhighlight %}
### Example Usage
Accessed by the [Basic Client]({{ site.baseurl }}/chapters/networking/basic-client):
{% highlight console %}
$ coffee basic-server.coffee
Listening to localhost:9001
Received connection from 127.0.0.1
Received connection from 127.0.0.1
[...]
{% endhighlight %}
## Discussion
The function passed to @net.createServer@ receives the new socket provided for each new connection to a client. This basic server simply socializes with its visitors but a hard-working server would pass this socket along to a dedicated handler and then return to the task of waiting for the next client.
See also the [Basic Client]({{ site.baseurl }}/chapters/networking/basic-client), [Bi-Directional Server]({{ site.baseurl }}/chapters/networking/bi-directional-server), and [Bi-Directional Client]({{ site.baseurl }}/chapters/networking/bi-directional-client) recipes.
### Exercises
* Add support for choosing the target domain and port based on command-line arguments or from a configuration file.
================================================
FILE: chapters/networking/bi-directional-client.md
================================================
---
layout: recipe
title: Bi-Directional Client
chapter: Networking
---
## Problem
You want to a persistent service over a network, one which maintains an on-going connection with its clients.
## Solution
Create a bi-directional TCP client.
### In Node.js
{% highlight coffeescript %}
net = require 'net'
domain = 'localhost'
port = 9001
ping = (socket, delay) ->
console.log "Pinging server"
socket.write "Ping"
nextPing = -> ping(socket, delay)
setTimeout nextPing, delay
connection = net.createConnection port, domain
connection.on 'connect', () ->
console.log "Opened connection to #{domain}:#{port}"
ping connection, 2000
connection.on 'data', (data) ->
console.log "Received: #{data}"
connection.on 'end', (data) ->
console.log "Connection closed"
process.exit()
{% endhighlight %}
### Example Usage
Accessing the [Bi-Directional Server]({{ site.baseurl }}/chapters/networking/bi-directional-server):
{% highlight console %}
$ coffee bi-directional-client.coffee
Opened connection to localhost:9001
Pinging server
Received: You have 0 peers on this server
Pinging server
Received: You have 0 peers on this server
Pinging server
Received: You have 1 peer on this server
[...]
Connection closed
{% endhighlight %}
## Discussion
This particular example initiates contact with the server and starts the conversation in the @connection.on 'connect'@ handler. The bulk of the work in a real client, however, will lie in the @connection.on 'data'@ handler, which processes output from the server. The @ping@ function only recurses in order to illustrate continuous communication with the server and can be removed from a real client.
See also the [Bi-Directional Server]({{ site.baseurl }}/chapters/networking/bi-directional-server), [Basic Client]({{ site.baseurl }}/chapters/networking/basic-client), and [Basic Server]({{ site.baseurl }}/chapters/networking/basic-server) recipes.
### Exercises
* Add support for choosing the target domain and port based on command-line arguments or from a configuration file.
================================================
FILE: chapters/networking/bi-directional-server.md
================================================
---
layout: recipe
title: Bi-Directional Server
chapter: Networking
---
## Problem
You want to provide a persistent service over a network, one which maintains an on-going connection with a client.
## Solution
Create a bi-directional TCP server.
### In Node.js
{% highlight coffeescript %}
net = require 'net'
domain = 'localhost'
port = 9001
server = net.createServer (socket) ->
console.log "New connection from #{socket.remoteAddress}"
socket.on 'data', (data) ->
console.log "#{socket.remoteAddress} sent: #{data}"
others = server.connections - 1
socket.write "You have #{others} #{others == 1 and "peer" or "peers"} on this server"
console.log "Listening to #{domain}:#{port}"
server.listen port, domain
{% endhighlight %}
### Example Usage
Accessed by the [Bi-Directional Client]({{ site.baseurl }}/chapters/networking/bi-directional-client):
{% highlight console %}
$ coffee bi-directional-server.coffee
Listening to localhost:9001
New connection from 127.0.0.1
127.0.0.1 sent: Ping
127.0.0.1 sent: Ping
127.0.0.1 sent: Ping
[...]
{% endhighlight %}
## Discussion
The bulk of the work lies in the @socket.on 'data'@ handler, which processes all of the input from the client. A real server would likely pass the data onto another function to process it and generate any responses so that the original handler.
See also the [Bi-Directional Client]({{ site.baseurl }}/chapters/networking/bi-directional-client), [Basic Client]({{ site.baseurl }}/chapters/networking/basic-client), and [Basic Server]({{ site.baseurl }}/chapters/networking/basic-server) recipes.
### Exercises
* Add support for choosing the target domain and port based on command-line arguments or on a configuration file.
================================================
FILE: chapters/networking/index.html
================================================
---
layout: chapter
title: Networking
chapter: Networking
---
{% capture url %}/chapters/{{ page.chapter | replace: ' ', '_' | downcase }}{% endcapture %}
{% capture indexurl %}{{ url }}/index.html{% endcapture %}
{% for page in site.pages %}
{% if page.url contains url %}
{% unless page.url == indexurl %}
================================================
FILE: chapters/regular_expressions/heregexes.md
================================================
---
layout: recipe
title: Using Heregexes
chapter: Regular Expressions
---
## Problem
You need to write a complex regular expression.
## Solution
Use Coffeescript's "heregexes" -- extended regular expressions that ignore internal whitespace and can contain comments.
{% highlight coffeescript %}
pattern = ///
^\(?(\d{3})\)? # Capture area code, ignore optional parens
[-\s]?(\d{3}) # Capture prefix, ignore optional dash or space
-?(\d{4}) # Capture line-number, ignore optional dash
///
[area_code, prefix, line] = "(555)123-4567".match(pattern)[1..3]
# => ['555', '123', '4567']
{% endhighlight %}
## Discussion
Breaking up your complex regular expressions and commenting key sections makes them a lot more decipherable and maintainable. For example, changing this regex to allow an optional space between the prefix and line number would now be fairly obvious.
### Whitespace characters in heregexes
Whitespace is ignored in heregexes -- so what do you do if you need to match a literal ASCII space?
One solution is to use the @\s@ character class, which will match spaces, tabs
and line breaks. If you only want to match a space, though, you'll need to use
`\x20` to denote a literal ASCII space.
================================================
FILE: chapters/regular_expressions/index.html
================================================
---
layout: chapter
title: Regular Expressions
chapter: Regular Expressions
---
{% capture url %}/chapters/{{ page.chapter | replace: ' ', '_' | downcase }}{% endcapture %}
{% capture indexurl %}{{ url }}/index.html{% endcapture %}
{% for page in site.pages %}
{% if page.url contains url %}
{% unless page.url == indexurl %}
================================================
FILE: chapters/regular_expressions/replacing-html-tags-with-html-named-entities.md
================================================
---
layout: recipe
title: Replacing HTML Tags with HTML Named Entities
chapter: Regular Expressions
---
## Problem
You need to replace HTML tags with named entities:
` => <br/>`
## Solution
{% highlight coffeescript %}
htmlEncode = (str) ->
str.replace /[&<>"']/g, ($0) ->
"&" + {"&":"amp", "<":"lt", ">":"gt", '"':"quot", "'":"#39"}[$0] + ";"
htmlEncode('Barnes & Noble')
# => '<a href="http://bn.com">Barnes & Noble</a>'
{% endhighlight %}
## Discussion
There are probably better ways to implement the above method.
================================================
FILE: chapters/regular_expressions/replacing-substrings.md
================================================
---
layout: recipe
title: Replacing Substrings
chapter: Regular Expressions
---
## Problem
You need to replace a portion of a string with another value.
## Solution
Use the JavaScript `replace` method. `replace` matches with the given string, and returns the edited string.
The first version takes 2 arguments: _pattern_ and _string replacement_
{% highlight coffeescript %}
"JavaScript is my favorite!".replace /Java/, "Coffee"
# => 'CoffeeScript is my favorite!'
"foo bar baz".replace /ba./, "foo"
# => 'foo foo baz'
"foo bar baz".replace /ba./g, "foo"
# => 'foo foo foo'
{% endhighlight %}
The second version takes 2 arguments: _pattern_ and _callback function_
{% highlight coffeescript %}
"CoffeeScript is my favorite!".replace /(\w+)/g, (match) ->
match.toUpperCase()
# => 'COFFEESCRIPT IS MY FAVORITE!'
{% endhighlight %}
The callback function is invoked for each match, and the match value is passed as the argument to the callback.
## Discussion
Regular Expressions are a powerful way to match and replace strings.
================================================
FILE: chapters/regular_expressions/searching-for-substrings.md
================================================
---
layout: recipe
title: Searching for Substrings
chapter: Regular Expressions
---
## Problem
You need to search for a substring, and return either the starting position of the match or the matching value itself.
## Solution
There are several ways to accomplish this using regular expressions. Some methods are called on a `RegExp` pattern or object and some are called on `String` objects.
### `RegExp` objects
The first way is to call the `test` method on a `RegExp` pattern or object. The `test` method returns a boolean value:
{% highlight coffeescript %}
match = /sample/.test("Sample text")
# => false
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 with the match information or `null`:
{% highlight coffeescript %}
match = /s(amp)le/i.exec "Sample text"
# => [ 'Sample', 'amp', index: 0, input: 'Sample text' ]
match = /s(amp)le/.exec "Sample text"
# => null
{% endhighlight %}
### `String` objects
The `match` method matches a given string with the `RegExp`. With 'g' flag returns an array containing the matches, without 'g' flag returns just the first match or if no match is found returns `null`.
{% highlight coffeescript %}
"Watch out for the rock!".match(/r?or?/g)
# => [ 'o', 'or', 'ro' ]
"Watch out for the rock!".match(/r?or?/)
# => [ 'o', index: 6, input: 'Watch out for the rock!' ]
"Watch out for the rock!".match(/ror/)
# => null
{% endhighlight %}
The `search` method matches `RegExp` with string and returns the index of the beginning of the match if found, -1 if not.
{% highlight coffeescript %}
"Watch out for the rock!".search /for/
# => 10
"Watch out for the rock!".search /rof/
# => -1
{% endhighlight %}
## Discussion
Regular Expressions are a powerful way to test and match substrings.
================================================
FILE: chapters/strings/capitalizing-words.md
================================================
---
layout: recipe
title: Capitalizing Words
chapter: Strings
---
## Problem
You want to capitalize the first letter of every word in a string.
## Solution
Use the split, map, join pattern: Split the string into words, then use a map to capitalize the first letter and lowercase all other letters of each word before gluing the string back together with join.
{% highlight coffeescript %}
("foo bar baz".split(' ').map (word) -> word[0].toUpperCase() + word[1..-1].toLowerCase()).join ' '
# => 'Foo Bar Baz'
{% endhighlight %}
Or do the same thing using a list comprehension:
{% highlight coffeescript %}
(word[0].toUpperCase() + word[1..-1].toLowerCase() for word in "foo bar baz".split /\s+/).join ' '
# => 'Foo Bar Baz'
{% endhighlight %}
## Discussion
Split, map, join is a common scripting pattern dating back to Perl. This function may benefit from being placed directly onto the String class by [Extending Classes]({{ site.baseurl }}/chapters/objects/extending-classes).
Be aware that two wrinkles can appear in the split, map, join pattern. The first is that the split text works best when it is constant. If the source string has multiple spaces in it, the split will need to take this into account to prevent getting extra, empty words. One way to do this is with a regular expression to split on runs of whitespace instead of a single space:
{% highlight coffeescript %}
("foo bar baz".split(/\s+/).map (word) -> word[0].toUpperCase() + word[1..-1].toLowerCase()).join ' '
# => 'Foo Bar Baz'
{% endhighlight %}
...but this leads us to the second wrinkle: notice that the runs of whitespace are now compressed down to a single character by the join.
Quite often one or both of these wrinkles is acceptable, however, so the split, map, join pattern can be a powerful tool.
================================================
FILE: chapters/strings/finding-substrings.md
================================================
---
layout: recipe
title: Finding Substrings
chapter: Strings
---
## Problem
You need to find the first or last occurrence of a search string within a message.
## Solution
Use Javascript's indexOf() and lastIndexOf() to find the first and last occurrences of a string, respectively.
Syntax: string.indexOf searchstring, start
{% highlight coffeescript %}
message = "This is a test string. This has a repeat or two. This might even have a third."
message.indexOf "This", 0
# => 0
# Modifying the start parameter
message.indexOf "This", 5
# => 23
message.lastIndexOf "This"
# => 49
# Count occurrences of a given string
message.split(" a ").length - 1
# => 3
{% endhighlight %}
================================================
FILE: chapters/strings/generating-a-unique-id.md
================================================
---
layout: recipe
title: Generating a Unique ID
chapter: Strings
---
## Problem
You want to generate a random unique identifier.
## Solution
You can create a Base 36 encoded string from a random number.
{% highlight coffeescript %}
uniqueId = (length=8) ->
id = ""
id += Math.random().toString(36).substr(2) while id.length < length
id.substr 0, length
uniqueId() # => n5yjla3b
uniqueId(2) # => 0d
uniqueId(20) # => ox9eo7rt3ej0pb9kqlke
uniqueId(40) # => xu2vo4xjn4g0t3xr74zmndshrqlivn291d584alj
{% endhighlight %}
## Discussion
There are other possible techniques, but this is relatively performant and flexible.
================================================
FILE: chapters/strings/index.html
================================================
---
layout: chapter
title: Strings
chapter: Strings
---
{% capture url %}/chapters/{{ page.chapter | replace: ' ', '_' | downcase }}{% endcapture %}
{% capture indexurl %}{{ url }}/index.html{% endcapture %}
{% for page in site.pages %}
{% if page.url contains url %}
{% unless page.url == indexurl %}
================================================
FILE: chapters/strings/interpolation.md
================================================
---
layout: recipe
title: String Interpolation
chapter: Strings
---
## Problem
You want to create a string that contains a text representation of a
CoffeeScript Variable.
## Solution
Use CoffeeScript's ruby-like string interpolation instead of
JavaScript's string addition. You must use Double-quoted strings to
allow for interpolation. Single-quoted strings are treated as literals.
Interpolation:
{% highlight coffeescript %}
muppet = "Beeker"
favorite = "My favorite muppet is #{muppet}!"
# => "My favorite muppet is Beeker!"
{% endhighlight %}
{% highlight coffeescript %}
square = (x) -> x * x
message = "The square of 7 is #{square 7}."
# => "The square of 7 is 49."
{% endhighlight %}
## Discussion
CoffeeScript interpolates strings in similar fashion to ruby. Most
expressions are valid inside the `#{...}` interpolation syntax.
CoffeeScript permits multiple expressions inside the interpolation
which can have side effects, but this is discouraged. Only the last
value will be returned.
{% highlight coffeescript %}
# You can do this, but don't. YOU WILL GO MAD.
square = (x) -> x * x
muppet = "Beeker"
message = "The square of 10 is #{muppet='Animal'; square 10}. Oh, and your favorite muppet is now #{muppet}."
# => "The square of 10 is 100. Oh, and your favorite muppet is now Animal."
{% endhighlight %}
================================================
FILE: chapters/strings/lowercasing-a-string.md
================================================
---
layout: recipe
title: Lowercasing a String
chapter: Strings
---
## Problem
You want to lowercase a string.
## Solution
Use JavaScript's String toLowerCase() method:
{% highlight coffeescript %}
"ONE TWO THREE".toLowerCase()
# => 'one two three'
{% endhighlight %}
## Discussion
`toLowerCase()` is a standard JavaScript method. Don't forget the parentheses.
### Syntax Sugar
You can add some Ruby-like syntax sugar with the following shortcut:
{% highlight coffeescript %}
String::downcase = -> @toLowerCase()
"ONE TWO THREE".downcase()
# => 'one two three'
{% endhighlight %}
The snippet above demonstrates a few features of CoffeeScript:
* The double-colon `::` is shorthand for saying `.prototype.`
* The "at" sign `@` is shorthand for saying `this.`
The code above compiles in to the following JavaScript:
{% highlight javascript %}
String.prototype.downcase = function() {
return this.toLowerCase();
};
"ONE TWO THREE".downcase();
{% 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](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/)).
================================================
FILE: chapters/strings/matching-strings.md
================================================
---
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
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]
{% endhighlight %}
## Discussion
You can use either Hirschberg or Wagner–Fischer's algorithm to calculate a Levenshtein distance. This example uses Wagner–Fischer's algorithm.
This version of Levenshtein algorithm is linear in memory, quadratic in time.
str.charAt i is preferred here to str[i] because the latter syntax is not supported by some browsers (e.g. IE7).
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.
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.
================================================
FILE: chapters/strings/repeating.md
================================================
---
layout: recipe
title: Repeating a String
chapter: Strings
---
## Problem
You want to repeat a string.
## Solution
Create an array of n+1 nulls, and then join it with the repetition string as the glue:
{% highlight coffeescript %}
# create a string of 10 foos
Array(11).join 'foo'
# => "foofoofoofoofoofoofoofoofoofoo"
{% endhighlight %}
## Repeat method for Strings
You could also create a method for this in String prototype. It is as simple as that:
{% highlight coffeescript %}
# add repeat method for all strings, that returns string repeated n times
String::repeat = (n) -> Array(n+1).join(this)
{% endhighlight %}
## Discussion
JavaScript lacks a string repeat function, as does CoffeeScript. List comprehensions and maps can be pressed into service here, but in the case of a simple string repeat it's easier to simply build an array of n+1 nulls and then glue them together.
================================================
FILE: chapters/strings/replacing-sub-strings.md
================================================
---
layout: recipe
title: Replacing Sub-Strings Within a String
chapter: Strings
---
## Problem
You want to replace a sub-string with a new sub-string.
## Solution
Split the string using the sub-string you want to remove as a delimiter. Then re-join using the new sub-string as the delimiter.
{% highlight coffeescript %}
"Orange is the new Black".split("Orange").join("Pink")
# => "Pink is the new Black"
"I am so sad. I cannot believe how sad I am today!".split("sad").join("happy")
# => "I am so happy. I cannot believe how happy I am today!"
"I am not a crook.".split("not ").join("")
# => "I am a crook."
{% endhighlight %}
## Discussion
You can also use regexes. If you're matching an exact string, this way is simpler and 10x faster.
If you use regexes, remember that you must escape certain characters.
================================================
FILE: chapters/strings/splitting-a-string.md
================================================
---
layout: recipe
title: Splitting a String
chapter: Strings
---
## Problem
You want to split a string.
## Solution
Use JavaScript's String split() method:
{% highlight coffeescript %}
"foo bar baz".split " "
# => [ 'foo', 'bar', 'baz' ]
{% endhighlight %}
## Discussion
String's split() is a standard JavaScript method. It can be used to split a string on any delimiter, including regular expressions. It also accepts a second parameter that specifies the number of splits to return.
{% highlight coffeescript %}
"foo-bar-baz".split "-"
# => [ 'foo', 'bar', 'baz' ]
{% endhighlight %}
{% highlight coffeescript %}
"foo bar \t baz".split /\s+/
# => [ 'foo', 'bar', 'baz' ]
{% endhighlight %}
{% highlight coffeescript %}
"the sun goes down and I sit on the old broken-down river pier".split " ", 2
# => [ 'the', 'sun' ]
{% endhighlight %}
================================================
FILE: chapters/strings/trimming-whitespace-from-a-string.md
================================================
---
layout: recipe
title: Trimming Whitespace from a String
chapter: Strings
---
## Problem
You want to trim whitespace from a string.
## Solution
Use JavaScript's Regular Expression support to replace whitespace.
To trim leading and trailing whitespace, use the following:
{% highlight coffeescript %}
" padded string ".replace /^\s+|\s+$/g, ""
# => 'padded string'
{% endhighlight %}
To trim only leading whitespace, use the following:
{% highlight coffeescript %}
" padded string ".replace /^\s+/g, ""
# => 'padded string '
{% endhighlight %}
To trim only trailing whitespace, use the following:
{% highlight coffeescript %}
" padded string ".replace /\s+$/g, ""
# => ' padded string'
{% endhighlight %}
## Discussion
Opera, Firefox and Chrome all have a native string prototype `trim` method, and the other browsers could add one as well. For this particular method, I would use the built-in method where possible, otherwise create a polyfill:
{% highlight coffeescript %}
unless String::trim then String::trim = -> @replace /^\s+|\s+$/g, ""
" padded string ".trim()
# => 'padded string'
{% endhighlight %}
### Syntax Sugar
You can add some Ruby-like syntax sugar with the following shortcuts:
{% highlight coffeescript %}
String::strip = -> if String::trim? then @trim() else @replace /^\s+|\s+$/g, ""
String::lstrip = -> @replace /^\s+/g, ""
String::rstrip = -> @replace /\s+$/g, ""
" padded string ".strip()
# => 'padded string'
" padded string ".lstrip()
# => 'padded string '
" padded string ".rstrip()
# => ' padded string'
{% endhighlight %}
For an interesting discussion and benchmarks of JavaScript `trim` performance, see [this blog post](http://blog.stevenlevithan.com/archives/faster-trim-javascript) by Steve Levithan.
================================================
FILE: chapters/strings/uppercasing-a-string.md
================================================
---
layout: recipe
title: Uppercasing a String
chapter: Strings
---
## Problem
You want to uppercase a string.
## Solution
Use JavaScript's String toUpperCase() method:
{% highlight coffeescript %}
"one two three".toUpperCase()
# => 'ONE TWO THREE'
{% endhighlight %}
## Discussion
`toUpperCase()` is a standard JavaScript method. Don't forget the parentheses.
### Syntax Sugar
You can add some Ruby-like syntax sugar with the following shortcut:
{% highlight coffeescript %}
String::upcase = -> @toUpperCase()
"one two three".upcase()
# => 'ONE TWO THREE'
{% endhighlight %}
The snippet above demonstrates a few features of CoffeeScript:
* The double-colon `::` is shorthand for saying `.prototype.`
* The "at" sign `@` is shorthand for saying `this.`
The code above compiles in to the following JavaScript:
{% highlight javascript %}
String.prototype.upcase = function() {
return this.toUpperCase();
};
"one two three".upcase();
{% 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](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/)).
================================================
FILE: chapters/syntax/code_reuse_on_client_and_server.md
================================================
---
layout: recipe
title: Code Reuse on Client and Server
chapter: Syntax
---
## Problem
You have created some functionality in CoffeeScript that you wish to use on the client with a web browser and on the server with Node.js.
## Solution
Export the functionality in the following manner:
{% highlight coffeescript %}
# simpleMath.coffee
# these methods are private
add = (a, b) ->
a + b
subtract = (a, b) ->
a - b
square = (x) ->
x * x
# create a namespace to export our public methods
SimpleMath = exports? and exports or @SimpleMath = {}
# items attached to our namespace are available in Node.js as well as client browsers
class SimpleMath.Calculator
add: add
subtract: subtract
square: square
{% endhighlight %}
## Discussion
In the above example, we create a new namespace called SimpleMath. If `export` is available, our class is exported as a Node.js module. If `export` is *not* available, then SimpleMath is added to the global namespace and available to our web page.
In Node.js, we can include our module using the `require` command.
{% highlight console %}
$ node
> var SimpleMath = require('./simpleMath');
undefined
> var Calc = new SimpleMath.Calculator();
undefined
> console.log("5 + 6 = ", Calc.add(5, 6));
5 + 6 = 11
undefined
>
{% endhighlight %}
In our web page, we can include our module by including it as a script.
{% highlight html %}
SimpleMath Module Example
A SimpleMath Example
{% endhighlight %}
Result:
#A SimpleMath Example
* 5 + 6 = 11
================================================
FILE: chapters/syntax/comparing_ranges.md
================================================
---
layout: recipe
title: Comparing Ranges
chapter: Syntax
---
## Problem
You want to know if a variable is inside a given range.
## Solution
Use CoffeeScript's chained comparison syntax.
{% highlight coffeescript %}
maxDwarfism = 147
minAcromegaly = 213
height = 180
normalHeight = maxDwarfism < height < minAcromegaly
# => true
{% endhighlight %}
## Discussion
This is a nice feature lifted from Python. Instead of writing out the full comparison like
{% highlight coffeescript %}
normalHeight = height > maxDwarfism && height < minAcromegaly
{% endhighlight %}
CoffeeScript allows us to chain the two comparisons together in a form that more closely matches the way a mathematician would write it.
================================================
FILE: chapters/syntax/embedding_javascript.md
================================================
---
layout: recipe
title: Embedding JavaScript
chapter: Syntax
---
## Problem
You want to include some found/pre-written JavaScript code inline with your CoffeeScript.
## Solution
Wrap the JavaScript with backticks:
{% highlight coffeescript %}
`function greet(name) {
return "Hello "+name;
}`
# Back to CoffeeScript
greet "Coffee"
# => "Hello Coffee"
{% endhighlight %}
## Discussion
This is a simple way to integrate small snippets of JavaScript code into your CoffeeScript without converting it over to use CoffeeScript syntax. As shown in the [CoffeeScript Language Reference](http://jashkenas.github.com/coffee-script/#embedded) you can mix the two languages to a certain extent:
{% highlight coffeescript %}
hello = `function (name) {
return "Hello "+name
}`
hello "Coffee"
# => "Hello Coffee"
{% endhighlight %}
Here the `hello` variable is still in CoffeeScript, but is assigned a function written in JavaScript.
================================================
FILE: chapters/syntax/for_loops.md
================================================
---
layout: recipe
title: For Loops
chapter: Syntax
---
## Problem
You need to iterate over an array, object or range with a for loop.
## Solution
{% highlight coffeescript %}
# for(i = 1; i<= 10; i++)
x for x in [1..10]
# => [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]
# To count by 2
# for(i=1; i<= 10; i=i+2)
x for x in [1..10] by 2
# => [ 1, 3, 5, 7, 9 ]
# Perform a simple operation like squaring each item.
x * x for x in [1..10]
# = > [1,4,9,16,25,36,49,64,81,100]
{% endhighlight %}
## Discussion
Comprehensions replace for loops in CoffeeScript, but they simply compile into the traditional javascript equivalent for-loop.
================================================
FILE: chapters/syntax/index.html
================================================
---
layout: chapter
title: Syntax
chapter: Syntax
---
{% capture url %}/chapters/{{ page.chapter | replace: ' ', '_' | downcase }}{% endcapture %}
{% capture indexurl %}{{ url }}/index.html{% endcapture %}
{% for page in site.pages %}
{% if page.url contains url %}
{% unless page.url == indexurl %}
CoffeeScript recipes for the community by the community. Head over to the Contribute page and see what you can do to help out!
================================================
FILE: js/scripts.js
================================================
/*jshint browser: true, devel: true, debug: true */
(function( window, document, undefined ) {
var activePage, position, sidebar,
narrowScreen = ( window.getComputedStyle( document.body, ':after' ).getPropertyValue( 'content' ) === 'narrow' ) ? true : false
// if it's not the index page and not a narrow screen
if ( window.location.pathname.length && !narrowScreen ) {
// get the sidebar
sidebar = document.getElementById( 'sidebar' )
// query the dom for the active page
activePage = document.getElementsByClassName( 'page-active' )
// if an active page was found
if ( activePage.length ) {
// get the offset position and give a padding of 80px
position = activePage[0].offsetTop - 80
// set the scroll position of the sidebar to the new position
sidebar.scrollTop = position
}
}
})( window, document )
================================================
FILE: license.md
================================================
---
layout: default
title: License
---
coffeescript-cookbook.github.io is licensed under the [Creative Commons Attribution 3.0 Unported (CC BY 3.0)](http://creativecommons.org/licenses/by/3.0/) license. By submitting information to this site you agree to grant this license to all users of the site, and that your editing of the authors page constitutes satisfactory attribution.
[LICENSE]({{ site.baseurl }}/LICENSE-CC-BY)
================================================
FILE: recipe-template.md
================================================
---
layout: default
title: Recipe Template
---
## Sample recipe template
Create a new `my-recipe.md` file and use this text as a start.
{% highlight text %}
---
layout: recipe
title: Title of The Recipe
chapter: Chapter Name
---
## Problem
You have a problem.
## Solution
Do this about it.
## Discussion
Here's why.
{% endhighlight %}
================================================
FILE: terms-of-use.md
================================================
---
layout: default
title: Terms of Use
---
================================================
FILE: wanted-recipes.md
================================================
---
layout: default
title: Wanted Recipes
---
# Wanted Recipes
Here's a list of recipes we think we need. Pick one, implement it, and remove it from the page. Alternately, add a quick note here for a recipe you'd like to see so someone else can add it.
In the notes below, "JS" means the recipe is just a simple pass-through to an existing JavaScript method.
## Syntax
* Ensuring variables are closed over # with "do"
## Strings
* HTML methods # JS .sup(), .sub(), .blink(), .link(url), etc. May not exist in your JS implementation!
* substr
{% highlight coffeescript %}
str.substr(x,y) === str[x..x+y-1] === str[x...x+y]
{% endhighlight %}
* substring
{% highlight coffeescript %}
str.substring(x,y) === str.slice(x,y) === str[x..y-1] === str[x...y]
{% endhighlight %}
* Replacing substrings
## Arrays
* Testing every element in an array
{% highlight coffeescript %}
evens = (x for x in [0..10] by 2)
even = (x) -> x % 2 == 0
evens.every even
# => true
{% endhighlight %}
* Detecting presence of matching items in an array
{% highlight coffeescript %}
[1..10].some (x) -> x % 2 == 0 # => true
{% endhighlight %}
## Math
* square root # JS Math.sqrt
* Constants # JS Math.PI, Math.E
* floor, ceil, round # JS Math.floor, Math.ceil, Math.round
* Raising a number to a power # JS Math.pow(x, y)
* Logarithms # Math.log
* Finding the base-n log # Math.log(num) / Math.log(base)
* Exponents # Math.exp
* Check if a credit card is valid (checksum, Luhn algorithm)
## Functions
* Nested functions
{% highlight coffeescript %}
hypotenuse = (a, b) ->
square = (x) -> x * x
Math.sqrt(square(a) + square(b))
console.log hypotenuse 3, 4
# => 5
square 5
# ReferenceError: square is not defined
{% endhighlight %}
* Optional Arguments # use arg? to detect presence: if arg=0, arg? == true
{% highlight coffeescript %}
foo = (a, b=42, c) -> if c? then a*b*c else a*b
[Function]
foo 6
# => 252
foo 1, 2
# => 2
foo 1, 2, 3
# => 6
{% endhighlight %}
## Design patterns
* Creational Patterns
* Abstract Factory
* Prototype
* Structural Patterns
* Adapter
* Composite
* Facade
* Flyweight
* Proxy
* Behavioral Patterns
* Chain of Responsibility
* Iterator
* Mediator
* Observer
* State
* Template Method
* Visitor
## Databases
* Couch access
* MySQL/PostgreSQL access