Mark Needham

Thoughts on Software Development

Learning node.js: Step

with 5 comments

I’ve been playing around with node.js to generate some graphs from our git repository which effectively meant chaining together a bunch of shell commands to give me the repository data in the format I wanted.

I was able to do this by making use of child_process which comes with the core library.

The first version looked like this:

var exec = require('child_process').exec, _ = require("underscore");
...
function parseCommitsFromRepository(fn) {
  var gitRepository = "/tmp/core";
  var gitPlayArea = "/tmp/" + new Date().getTime();
 
  exec('cd ' + gitRepository + ' && git reset HEAD', function() {
    exec('git clone ' + gitRepository + ' ' + gitPlayArea, function() {
      exec('cd ' + gitPlayArea + ' && git log --pretty=format:"%H | %ad | %s%d" --date=raw', function(blank, gitEntries) {
        var commits = _(gitEntries.split("\n")).chain()
                        .filter(function(item) { return item != ""; })
                        .map(function(item) { return item.split("|") })
                        .filter(function(theSplit) { return theSplit !== undefined && theSplit[1] !== undefined && theSplit[2] !== undefined; })
                        .map(function(theSplit) {  
                          var date = new Date(theSplit[1].trim().split(" ")[0]*1000);
                          return {message: theSplit[2].trim(), date: date.toDateString(), time : date.toTimeString()}; })
                        .value();			
        fn(commits);
      });		
    });
  });
}

node.js has an asynchronous programming model so the majority of the time we have to pass callbacks to other functions which get called when the asynchronous computation has completed.

In this case there’s an order dependency in the parseCommitsFromRepository function such that we need to nest the second call to exec inside the callback from the first call.

i.e. we don’t want to get the log of the repository before we’ve cloned the repository to the location that we’re trying to get that log from.

As you create more and more order dependencies between asynchronous functions the nesting becomes greater and the code moves more and more to the right hand side of the screen.

I came across the Step library which allows you to stack up functions and have the results from each one get passed on to the next.

I decided to try it in my code and it ended up looking like this:

function parseCommitsFromRepository(fn) {	
  var gitRepository = "/tmp/core";
  var gitPlayArea = "/tmp/" + new Date().getTime();	
  Step(
    function getRepositoryUpToDate() { exec('cd ' + gitRepository + ' && git reset HEAD', this); },
    function cloneRepository()       { exec('git clone ' + gitRepository + ' ' + gitPlayArea, this); },
    function getGitEntries()         { exec('cd ' + gitPlayArea + ' && git log --pretty=format:"%H | %ad | %s%d" --date=raw', this); },
    function handleResponse(blank, gitEntries) {
      var commits = _(gitEntries.split("\n")).chain()
                      .filter(function(item) { return item != ""; })
                      .map(function(item) { return item.split("|") })
                      .filter(function(theSplit) { return theSplit !== undefined && theSplit[1] !== undefined && theSplit[2] !== undefined; })
                      .map(function(theSplit) {  
                        var date = new Date(theSplit[1].trim().split(" ")[0]*1000);
                        return {message: theSplit[2].trim(), date: date.toDateString(), time : date.toTimeString()}; })
                      .value();			
      fn(commits);
    }
  );	
}

An interesting side effect of using this approach is that we can describe what each exec call is doing in the name of the function that executes it.

Another neat thing about this library is that I can easily wrap those functions inside a logging function if I want to see on the console where the process has got up to:

function log(message, fn) {
  return function logMe() {
    console.log(new Date().toString() + ": " + message);
     fn.apply(this, arguments);
  }
}
function parseCommitsFromRepository(fn) {	
  var gitRepository = "/tmp/core";
  var gitPlayArea = "/tmp/" + new Date().getTime();	
  Step(
    log("Resetting repository", function getRepositoryUpToDate() { exec('cd ' + gitRepository + ' && git reset HEAD', this); }),
    log("Cloning repository", function cloneRepository()         { exec('git clone ' + gitRepository + ' ' + gitPlayArea, this); }),
    log("Getting log", function getGitEntries()                  { exec('cd ' + gitPlayArea + ' && git log --pretty=format:"%H | %ad | %s%d" --date=raw', this); }),
    log("Processing log", function handleResponse(blank, gitEntries) {
      var commits = _(gitEntries.split("\n")).chain()
                      .filter(function(item) { return item != ""; })
                      .map(function(item) { return item.split("|") })
                      .filter(function(theSplit) { return theSplit !== undefined && theSplit[1] !== undefined && theSplit[2] !== undefined; })
                      .map(function(theSplit) {  
                        var date = new Date(theSplit[1].trim().split(" ")[0]*1000);
                        return {message: theSplit[2].trim(), date: date.toDateString(), time : date.toTimeString()}; })
                      .value();			
      fn(commits);
    })
  );	
}

I then get this output when executing the function:

Sun Sep 11 2011 23:33:09 GMT+0100 (BST): Resetting repository
Sun Sep 11 2011 23:33:11 GMT+0100 (BST): Cloning repository
Sun Sep 11 2011 23:33:24 GMT+0100 (BST): Getting log
Sun Sep 11 2011 23:33:24 GMT+0100 (BST): Processing log

There are more cool ways to use the Step library on the github page – what I’ve described here is only a very simple use case.

Be Sociable, Share!

Written by Mark Needham

September 11th, 2011 at 10:37 pm

Posted in Javascript

Tagged with ,

  • Nice! I no longer have to buy that 15″ laptop just to keep my js all visible on a single screen at once!

  • I absolutely LOVE Step. I’ve been writing node.js code since December and you couldn’t force me to code node.js without Step. There are a large number of so called ‘control flow’ modules for node.js, but for me, Step is by far the best. Your blog post here shows a good example of how it makes things better 🙂

  • yan

    fake cartier watchesKeep an eye on these kinds of watches with day and date thins whilst your watch assists that it is deliver the results and type. In addition to except if any mater with lifestyle as well as dying, don’t simply advertise a person enjoy lacking the knowledge of the assessment valuation on this. You may also morph it into a treasure portion to get having proper best swiss rolex replicas security plus care, it will stick with family members by means of decades.Whenever you visit the particular recognition that purchasing panerai swiss replica an eye fixed is much more than simply a matter of style, you’ll discover that imitation patek philippe essential to master all that you can regarding the making of watches and thepanies that exist watch bands leather on the market.Mid priced watches like the versions via Label Heuer wristwatches and also other machines are priceding from pertaining to $1,Thousand or more. These pieces will give you more when ites to difficulties best replica watches for sale in addition to functionality and will frequently be a little more special. Below I am going to summarize many of fake watches cartier the most essential facts would like to consider, when looking for an ideal mid priced wrist watch.The replica watches iwc actual action style is but one thing that can help determine value. Different watches costs three hundred dollars $1,1000 lady datejust and up may possess a hardware movement or maybe at the minimum some sort of movement that is high quality replica breitling watches known as “super quartz”.A swiss cartier replica super quartz movement could be accurate to be able to in just 5 various seconds every year, which is quite appropriate.Mechanised actionsprise several tineponents luxury swiss watches and many designs are generally fretting hand set up. Most of these watches is often hand ended as well as automatic rotating, which usually just means that they’re wound by luminor power reserve the action of this wrist. A benefit to some mechanised look at replica cartier watches is it is likely to work for a life long, nevertheless the down side for a lot of may be the increased swiss iwc replica routine maintenance they need.Related articles: http://www.selfwatches.com http://www.cornwatches.com.

  • suman wang

    Hanging out at a lower popularity rank on the replica watches most favorite list,the fake Vacheron Constantin watches are still among the most wanted brands and I think they will be in the top 10 fake watches brands for a long time. Vacheron Constantin replica watches are definitely among the classic fake watches that you know will have a place in tag heuer fake watches people’s preferences iwc replica watches no matter what. And for a good reason I’d add. Vacheron Constantin have some really unique,classy and cartier replica watches good looking extremely expensive watches that a regular guy like you and me could never ever touch so we’re looking after the good quality replica Vacheron watches that can satisfy our needs. This is one replica watches of those good lookers that has a good grip and feel on the wrist.Dial has a good pattern though it’s missing the 6 o’clock square small seconds hand. I’ve seen some of patek philippe replica watches those babies that have it but I felt more comfortable with getting this one for quality reasons. Markers,numbers,and the Vacheron logo are properly done. The most important and unique two features of this watch are the omega replica watches shape of the case which fake watches is rose gold plated and looks just like the original and the domed square scratch-proof crystal that falls so well fake watches on top of the case matching the original very well. Small crown bares the Vacheron Constantin logo and comes out easily. Setting the time on this Japanese Quartz (battery run) movement is very breitling replica watches simple and as you can see the hack mechanism hublot replica watches comes on when the crown is pulled out. I like the crocodile imitation leather band as well because it’s good quality,proper width and has a good grip on the wrist.

  • suman wang

    Elie Saab has always been our dress brand often mentioned,because it really is ideal for a variety of elegant dress dinner parties,Elie Saab generous sketched dresses to wear to a wedding out beautifully lavish costumes feast,sway with sparkling stars,dazzling fashion at the same time to bring everyone also let Elie maternity wedding dress Saab woman incarnation of the most beautiful elf princess kingdom .Elie Saab is a concern in recent years by the Lebanese international fashion maternity wedding dresses,his design was the favorite of Hollywood stars,including Halle Berry,Catherine Zeta-Jones and Elizabeth Hurley,also including the royal family,such as the Middle East Queen Rania of Jordan and so cheap wedding dress on . Recently,Elie Saab released girls party dresses its 2013 early spring vacation series of new women . This series includes both women’s Elie Saab ‘s most famous luxury noble,elegant and charming evening bridal dresses dress also includes a stylish and comfortable,minimalist capable wear so dizzying.Elie Saab 2013 early spring vacation series,the most part is still the color short prom dresses of the dress,which is to be expected . Two of which Notably,the first black knit dress skirt,tulle shoulder treatment is very special;second was followed by ultra- tight money,inlaid with sparkling sequins lace fabric,not remove the attention to the eyes casual wedding dresses of a woman .As far as gadgets go,you can attempt various combinations bridal gown but the rule is designed for formal outfits to wear considerably more subtle pieces of jewelry along with accessories.Reliable color heels silver precious metal simple jewelry perfect for dressed wedding gown up outfits having dresses.