Monday, April 02, 2012

This example assumes that you have a Github account. If you don't have one, you
can get one at (suprise!) Github. It also assumes that
you have installed Node and
npm. It will also simplify your life to have the github gem installed

Create the basic structure

OK, now I have an initialized repository and I need something to put in
it. I like Readme Driven Development and, in that spirit, let's create a Readme.

# Create a Readme file with my favorite editor
$ vi Readme.md
$ cat Readme.md
# Sleep Sort
`sleep-sort` works by creating a task for every number to be sorted. The task
will "sleep" n number of milliseconds and then push the number onto an array.
When all tasks are done, the array is returned sorted.# Add all files to the repo
$ git add .# Commit
$ git commit -m 'Added Readme'

I have setup a local repository and committed our Readme. Now, I need to
create our remote repository on Github. With the Github gem, this is trivial.

OK, the directories exists and the files exist, it's time to make the module. To
do this I need to create a package.json file that contains meta-information
about the module. An easy way to do this is by using npm init.

npm init guesses some of the information, so that I don't have to enter it
myself. When the process is done I have a package.json file in the root
directory of our project, lets add it to git and commit it.

$ git add package.json
$ git commit -m 'Initial package.json'

Note that I added lib/main.js as the main file. This will be the file that is
required when Node requires the module later on. I also added the test script
mocha test/*.js, this script can be invoked by running npm test.

But, in order for this to work, I need to add
mocha as a development dependency in
package.json. And while I am at it, I will also add
should.js as a dependency. should.js
provides should-style assertions.

//package.json{..."devDependencies":{// Use any version"mocha":"","should":""}}

If I run this, npm test I get an error since I haven't implemented a
module in lib/main.js. Time to do that. Since I am only going to be exporting
a single function, sleepsort, from this module I will export it via module.exports, instead of exports.sleepsort.

functionsleepsort(){return[];}
module.exports = sleepsort;

The above code gets the first test passing. Notice that I required the function
directly with require('sleepsort'), in the test above, this works because of
the above mentioned export method.

1. Sign in to (or sign up with) Travis with my Github account

Find my repository, sleep-sort, and turn it on. This will turn on the
Travis commit hook on Github, and it will run my tests, every time I
push to Github. Travis will run the command I specified in package.json under
the scripts/test entry, by running npm test.

3. Add a .travis.yml

Create a .travis.yml, like this.

language: node_js
node_js:-0.6-0.7

I'm telling Travis to run the tests with both version 0.6 (stable) and 0.7
(unstable). Then commit this file, and push it to Github.

The Rest of the Code

That was a lot of work for a function that is only able to sort an empty
array. And, there is something fishy going on. That function I implemented
seems very synchronous, isn't Node supposed to be asynchronous?

Well, gosh! Let me fix that right away.

First I change the test. Since the code now is going to be asynchronous I
will take advantage of some nifty features of mocha. If I give the
callback function of it an argument done, mocha will inject a function that
I can call when the test is done. Like this:

describe('with an empty array argument',function(){it('calls the callback with an empty array',function(done){var result =sleepsort([],function(result){
result.should.eql([]);done();});});});

If I hadn't called done, mocha would timeout and the test would be marked as a
failure. Simple, yet powerful. With a new failing test, I update the actual
code.

Take an extra look at appendResult. It's a function that creates another
function and returns it. The created function is the function that will be
called when the timeout fires.

Now I have a function that sorts single element arrays too. Let's see if it can
sort more than that. One more test.

describe('with an unsorted two element array',function(){it('calls the callback with a sorted two element array',function(done){var result =sleepsort([2,1],function(result){
result.should.eql([1,2]);done();});});});

Our test doesn't pass, I need to make sure the callback is only called when
the result is complete. How do I know that it is complete? I know that if the
array of the result is the same length as the input array. Here is the final
function.