JS.Class 2.1.5 supports Node, Narwhal and more

While there’s much work going on towards what will probably be JS.Class 3.0, the 2.1.x series is benefiting from some of the goodness being added upstream. I’ve just pushed out a new release that gets the package manager and all the libraries to work under CommonJS, specifically targeting Node.js and Narwhal for now.

I’ve had to make one tiny API change to avoid conflicting with the CommonJS API, so require() is now JS.require() and works just like it did before. To get your packages to work under CommonJS platforms, you don’t need to mess around with the exports object, you just need to remember this one rule:

If you want JS.Packages to find your object, do not declare it with var.

I’ll elaborate on this in a future post, but for now just remember that JS.Packages can only work with globally accessible objects, and using the var keyword (even outside a function) under CommonJS only makes the variable visible in the current file. If you stick to this rule and don’t use the exports object, you’ll have code that JS.Packages can run in any environment.

So, to get started using JS.Class on Node, just do what you’ve always done:

JSCLASS_PATH = './path/to/js.class';
require(JSCLASS_PATH + '/loader');

JS.require('JS.SortedSet', function() {
    var set = new JS.SortedSet([3,8,5,9]);
    require('sys').puts(set.count());
});

Note that the require() function is now called JS.require() in order to avoid conflicts with the CommonJS API. I thought about renaming it since I don’t like the fact that putting in the JS namespace makes it look like it can only load parts of JS.Class, but I honestly couldn’t think of a better name for it. Just remember you can load any library you like with it.

As usual, you can download JS.Class from its website.

JS.Class 2.1: an improved package manager, proper hashes, and lots of Ruby 1.9 goodness

Having managed to go the weekend without making any more fiddly changes to it, I’m finally pushing JS.Class 2.1 out of its Git repo and into the real world. The major updates in this release are a Hash implementation, a much-improved package manager that runs on server-side platforms, and lots of updates taken from Ruby 1.9. The full summary:

  • New libraries: ConstantScope, Hash and HashSet, a much faster Set implementation.
  • The package manager has been improved with a new API, parallel downloading of files, and support for server-side environments such as SpiderMonkey, Rhino and V8. It also supports user-defined loader functions for transparent integration with Google and Yahoo!’s packaging systems.
  • The Enumerable module has been updated with plenty of methods from Ruby 1.9, and now supports enumerators, and Symbol#to_proc-like functionality whereby a string, MethodChain or any object that implements toFunction() can be used as an iterator.
  • The core object methods now live in Kernel, and we’ve added new methods: tap(), equals(), hash() and enumFor().
  • The double inclusion problem is now fixed; no current Ruby implementation seems to support this properly.
  • Ancestor and method lookups are now cached so callSuper runs about twice as fast.
  • Classes can be named to generate displayName on methods for
    use with the WebKit debugger.

You can download it from the website, and you’ll no doubt be pleased to know I finally compiled a changelog for the project and will be including it with releases from now on.

Urgent bug fix release for JS.Class 1.6

Quick announcement: if you’re still running JS.Class 1.6, you’ll want to upgrade to the just-released 1.6.3 release which fixes a major bug introduced by Safari 4. This browser makes Function#prototype non-enumerable until it is overwritten by the user. This caused a check in JS.Class to fail, causing classes to become their own parents and cause stack overflows. Head over to the JS.Class website to download the latest version.

Where did all my code go? Using Ojay chains to express yourself clearly

I’ve been putting together a presentation to be given internally at work on what Ojay is and why we’re doing it. It occurred to me that I’ve not spoken very much about it here, hoping the documentation and examples would speak for themselves. So, today I’m going to go through how to take an animation sequence that would be really complicated in YUI and make it so simple that you’ll never want to write another callback function again.

The really core thing about Ojay’s chaining API is that each function that does something asynchronous (like an animation, or an HTTP request) returns a MethodChain object, which is essentially a magic object that remembers methods called on it so they can be replayed later. This allows you to construct complex instruction sequences with far fewer (sometimes none!) nested callback functions.

For today’s example, let’s assume you want to do the following. You have an element called trigger and another called logo. When you click the trigger, you want the logo to move around the edges of square. During the animation, the logo should pause for half a second at each corner. So, your starting point might be:

<div id="trigger"></div>
<div id="logo"></div>

<script type="text/javascript">
    YAHOO.util.Dom.setStyle('logo', 'position', 'absolute');
    YAHOO.util.Dom.setStyle('logo', 'left', '200px');
    YAHOO.util.Dom.setStyle('logo', 'top', '200px');

    var points = [[400,200], [400,400], [200,400], [200,200]];
</script>

The question is, how are you going to implement the animation sequence? In this example, I’m going to show how this case can be simplified using loops, but other sequences of events don’t lend themselves to this simplification. My hope is to show that Ojay scales to very complicated asynchronous sequences without making your head (or your typing fingers) hurt.

Let’s try a really dumb implementation. And, remember that this is only dumb because this case lends itself easily to looping. With more complex effect combinations you won’t be so lucky. The dumb implementation is to simply list all the animations by hand, chaining them together using onComplete callbacks. We use setTimeout() to handle the pauses.

YAHOO.util.Event.addListener('trigger', 'click', function() {
    var anim = new YAHOO.util.Anim('logo', {
        left:   {to: points[0][0]},
        top:    {to: points[0][1]}
    }, 0.7);
    anim.onComplete.subscribe(function() {
        setTimeout(function() {
            var anim = new YAHOO.util.Anim('logo', {
                left:   {to: points[1][0]},
                top:    {to: points[1][1]}
            }, 0.7);
            anim.onComplete.subscribe(function() {
                setTimeout(function() {
                    var anim = new YAHOO.util.Anim('logo', {
                        left:   {to: points[2][0]},
                        top:    {to: points[2][1]}
                    }, 0.7);
                    anim.onComplete.subscribe(function() {
                        setTimeout(function() {
                            var anim = new YAHOO.util.Anim('logo'
                            , { left:   {to: points[3][0]},
                                top:    {to: points[3][1]}
                            }, 0.7);
                            anim.animate();
                        }, 500);
                    });
                    anim.animate();
                }, 500);
            });
            anim.animate();
        }, 500);
    });
    anim.animate();
});

There are several things wrong with this, aside from the fact that it just looks wrong because of all the repetition. First up, it doesn’t tell a story, at least not one that’s easy to follow. Instead of flowing down the page, it flows outwards in this nested structure, so that pause intervals are specified nowhere near where the pause actually happens in the sequence. Similarly, the call to initiate each animation is miles away from the code that runs after the animation. To follow the story, you have skip up and down the text. You can make this easier by specifying each callback externally and chaining them afterwards; the event handler will tell a better story but the chain will probably be even harder to follow.

So, let’s try a more digestable approach by turning this into a loop. If this really didn’t lend itself to looping, then we’d be stuck with the above code, but we can make this case shorter so let’s have a go. We’ll make a loop that kicks off the four stages of the animation, but we don’t want all of them to run at once so we’ll delay each stage by an appropriate amount such that the whole effect works properly.

YAHOO.util.Event.addListener('trigger', 'click', function() {
    for (var i = 0, n = points.length; i < n; i++) {
        (function(x) {
            setTimeout(function() {
                var anim = new YAHOO.util.Anim('logo', {
                    left:   {to: points[x][0]},
                    top:    {to: points[x][1]}
                }, 0.7);
                anim.animate();
            }, (700 + 500) * x);
        })(i);
    }
});

This is just about the shortest way I managed to write this code using YUI. It perhaps looks nicer than the first example, but it’s broken in a pretty fundamental way: it works sort of ‘by accident’ in that you happen to have timed everything just right so that it does what you expect. You’ve not actually chained the animations together using callbacks, so each one runs regardless of whether the one before it has actually finished. This is especially important if there are other side effects of the animation running, if other actions need to occur at the same time. If one step fails, the next step will still run. There are some other issues, like that funny-looking closure to make sure the correct step runs, and the whole thing isn’t that readable really.

So, you need to chain the steps together properly. We can still do this using a loop by building an array of animations, and when each one finishes it shifts the next animation off the stack and runs it:

YAHOO.util.Event.addListener('trigger', 'click', function() {
    var anim, anims = [];
    for (var i = 0, n = points.length; i < n; i++) {
        anim = new YAHOO.util.Anim('logo', {
            left:   {to: points[i][0]},
            top:    {to: points[i][1]}
        }, 0.7);
        anim.onComplete.subscribe(function() {
            var nextAnim = anims.shift();
            if (!nextAnim) return;
            setTimeout(function() {
                nextAnim.animate();
            }, 500);
        });
        anims.push(anim);
    }
    anims.shift().animate();
});

This has made the code longer, but at least it’s robust now: the start of each animation is properly synchronized with the end of the previous one. This is the shortest robust implementation that I could find in YUI and Plain Old JavaScript. It might be called elegant but I’m not sure it’s that much easier to follow than the first huge example. At least it’s explicit about the fact that animations are chained, which makes it better than the previous snippet.

Now, let’s use Ojay to translate our ‘dumb’ example from above:

$('#trigger').on('click')
    ._('#logo')
    .animate({
        left:   {to: points[0][0]},
        top:    {to: points[0][1]}
    }, 0.7)
    .wait(0.5)
    .animate({
        left:   {to: points[1][0]},
        top:    {to: points[1][1]}
    }, 0.7)
    .wait(0.5)
    .animate({
        left:   {to: points[2][0]},
        top:    {to: points[2][1]}
    }, 0.7)
    .wait(0.5)
    .animate({
        left:   {to: points[3][0]},
        top:    {to: points[3][1]}
    }, 0.7)
    .wait(0.5);

I don’t expect I’ll meet much opposition if I suggest that this is incredibly readable. There is no cruft aside from the punctuation required to make JavaScript parse the code correctly. It tells a nice linear story, where each stage and parameter is mentioned in the order the sequence actually takes place. There is no nesting — one mantra I have in my mind pretty often is a snippet from ‘Why Why Functional Programming Matters Matters‘: “there’s nothing inherently nested about what we’re trying to do”. And, it’s actually shorter than the final YUI attempt above (both with whitespace removed).

And if you feel like going super-minimal, Ojay includes the JavaScript 1.8 Array#reduce() function that makes shrinking the chain really simple:

$('#trigger').on('click', function() {
    points.reduce(function(chain, point) {
        return chain.animate({
            left:   {to: point[0]},
            top:    {to: point[1]}
        }, 0.7).wait(0.5);
    }, $('#logo'));
});

Back to my assertion that Ojay scales better than other libraries to complex sequences. This example was fairly contrived, mostly for sake of focusing on the code rather than the application. I could just as well have illustrated all this with this example: when we click a button, fade in a ‘loading’ indicator, make a search request to the server, print the result to the page and fade out the loading indicator. This would be an irreducible pile of nested callbacks in YUI, and indeed in Prototype or jQuery. In Ojay:

var getSearchTerm = function() {
    return $('#q').node.value;
};

$('#search').on('click')
    ._('#loading').animate({opacity: {to: 1}}, 0.3)
    ._($.HTTP).GET('/search', {q: getSearchTerm})
    .insertInto('#results')
    ._('#loading').animate({opacity: {to: 0}}, 0.3);

Notice how $.HTTP.GET can take functions as query parameters: the getSearchTerm function returns the value of an input field at the time the event fires. The equivalent YUI code, just for completeness:

YAHOO.util.Event.addListener('search', 'click', function() {
    var anim = new YAHOO.util.Anim('loading', {
        opacity:  {to: 1}
    }, 0.3);
    anim.onComplete.subscribe(function() {
        var term = YAHOO.util.Dom.get('q').value;
        YAHOO.util.Connect.asyncRequest('GET',
            '/search?q=' + term, {
            success: function(response) {
                YAHOO.util.Dom.get('results').innerHTML =
                        response.responseText;
                var anim = new YAHOO.util.Anim('loader', {
                    opacity:  {to: 0}
                }, 0.3);
                anim.animate();
            }
        });
    });
    anim.animate();
});

This is basically what I mean when I say that Ojay scales: it doesn’t get confusing when you add more and more async behaviour. In fact, Ojay code doesn’t really get more complicated at all in the sense that YUI does; it might get bigger, but it remains easy to understand.

JS.Class 1.5 is now out

Hot on the heels of Ojay comes a new release of JS.Class, my Ruby-inspired JavaScript library for class-based OOP. Ojay is itself based on JS.Class, and has influenced the design of some of its new features. There has been one small change to the 1.0 API, and a stack of additional modules added in; it’s not really a 1.1 release or a 2.0 release, hence 1.5.

The one change to the 1.0 API is that _super is now called callSuper. Ojay uses a compression strategy that obfuscates ‘private’ variables (this will be in the next PackR release, as and when Packer 3.1 comes out). You do need to be very careful when doing this, though, so I figured I should make super not look like a private variable just in case.

Now, onto the new stuff. This release adds tons of new features to play with, namely:

  • Implementations of several design patterns in such a way that minimises how much repetitive boilerplate you need to write to use them. (I’m becoming more and more convinced that repetition is one of the largest and most easily removable causes of software bugs.) Patterns include decorator, virtual proxy, observer and command.
  • Versions of Ruby’s Comparable, Enumerable and Observable modules.
  • Linked lists. They’re like arrays, but much better suited to removal, shift operations and reordering.
  • MethodChain, formerly known as ChainCollector. This module on its own is responsible for some of Ojay’s key features.

So, what are you waiting for? Go and download it and tell me what you think.

Announcing Ojay, the nice way to use YUI

I’ve been wanting to talk about this project for weeks if not months, and now I finally can. the OTHER media (the web shop I work for) is open-sourcing Ojay, a project I’ve been developing on-and-off since I started at the company back in October. It’s a wrapper for the core DOM, event, animation and Ajax modules in YUI, providing a very concise, expressive API to what is, truth be told, a finely crafted library with a verbose, repetitive API.

The project started out as a replacement for DED|Chain, which we’d been using for a while but has not kept pace with the changes in YUI. When I started at this job, I’d been using Prototype for a year, and jQuery a little before that and was somewhat surprised at the amount of work I had to do to build anything with YUI. It does a sterling job of smoothing over browser inconsistencies and has some really nice features, they’re just not very nice to use. Ojay evolved out of my desire to get back the expressiveness I’d enjoyed with other libraries, while keeping access to YUI’s feature set.

To me, expressiveness is not just ‘syntactic sugar’, a tool to help you type fewer lines of code. It’s a core factor in how maintainable and well-designed your codebase is. We have a team made up of Java devs, a few Ruby enthusiasts and a couple of JavaScripters, and it’s crucially important to us that anyone can look at a piece of code and figure out what it does. Code should tell a story. Allow me to quote Reg Braithwaite:

One problem with the for loop is that it can only handle one loop at a time. We have to nest loops to work with two lists at once. This is patently wrong: there’s nothing inherently nested about what we’re trying to do. We can demonstrate this easily: try calling a colleague on the telephone and explaining what we want as succinctly as possible. Do you say “We want a loop inside a loop and inside of that an if, and…”?

No, we say, “We want to count the number of employees that have been with the company longer than their departments have existed.” There’s no discussion of nesting.

… The difference is more than just semantics, or counting characters, or the alleged pleasure of fooling around with closures. …

We have an example of the “Telephone Test:” when code very closely resembles how you would explain your solution over the telephone, we often say it is “very high level.” The usual case is that such code expresses a lot more what and a lot less how. The concern of what has been very clearly separated from the concern of how: you can’t even see the how if you don’t go looking for it. In general, we think this is a good thing.

And so it is with Ojay. Take this example from the documentation site:

$('a#run-this-code').on('click', $.stopEvent)
    .setContent('Running...')
    ._('#example').animate({
        height:     {to: 0},
        opacity:    {from: 1, to: 0}
    }, 0.5)
    ._($.HTTP).GET('/service/hello.html')
    .insertInto('#example')
    ._('#example').animate({
        height:     {to: 80},
        opacity:    {from: 0, to: 1}
    }, 0.7);

It says what you want to happen, with very little how. There are at least three pieces of asynchronous behaviour in this code: we want the code to fire when a certain link is clicked, then when the first animation is over we want to request some data from the server, then when the data arrives we want to insert it into the document and perform another animation. The usual way to handle asynchronous behaviour is using callback functions, but I’ve not used the word function but once in the above example. That would involve nesting things, and — hey, you guessed — there’s nothing inherently nested about what we’re trying to do. What we’re trying to do is carry out a list of instructions: wait for an event, then animate something, then make an Ajax request. And that’s exactly what the code looks like. I’m willing to bet that, with no knowledge of Ojay itself, most programmers with a passing familiarity with client-side scripting could guess what the above code does.

Update, in response to some comments on Ajaxian… The alternative way to write the above would be:

$('a#run-this-code').on('click', function(link, e) {
    e.stopEvent();
    link.setContent('Running...');
    var example = $('#example');
    example.animate({
        height:     {to: 0},
        opacity:    {from: 1, to: 0}
    }, 0.5, {
        after: function() {
            $.HTTP.GET('/service/hello.html', {}, {
                onSuccess: function(transport) {
                    example.setContent(transport.responseText);
                    example.animate({
                        height:     {to: 80},
                        opacity:    {from: 0, to: 1}
                    }, 0.7);
                }
            })
        }
    });
});

The point being that Ojay’s chaining mechanism handles asynchronous behaviour for you, rather than synchronously calling methods on the same base object. This approach means that, as well as being shorter and easier to follow, it’s much easier to change and debug: if you want to remove one of the asynchronous steps in the sequence, you only need to modify code in one place, rather than two or more as you would in the second example. (End update)

This is exactly the sort of stuff I’ve been alluding to when talking about ChainCollector. (It’s now called MethodChain, and will be part of the next release of JS.Class, which Ojay itself is based on.) Ojay uses this technique extensively to let you handle asynchronous coding as if it were synchronous, so that your code more clearly expresses what you’re trying to do. One particularly expressive part of the library is its HTML module:

Ojay.HTML.ul({id: 'list'}, function(HTML) {
    HTML.li('Item one');
    HTML.li('Item two');
    ['Cats', 'Dogs', 'Pets'].forEach(HTML.method('li'));
})

// -> <ul id="list">
          <li>Item one</li>
          <li>Item two</li>
          <li>Cats</li>
          <li>Dogs</li>
          <li>Pets</li>
      </ul>

Yes, people have done this sort of thing before, but I knew it could be made even cleaner. Most of Ojay is essentially an attempt to push JavaScript as far as I can, to make it get out of the way and let me say what I mean.

One other major area of frustration we’ve paved over with Ojay is YAHOO.util.History. It’s a great tool, but it encourages bad design, or at least makes good design fairly tricky. Ojay includes a wrapper for YAHOO.util.History that distills it down to one function call:

$.History.manage(myObject, 'itsName');

myObject has to implement a couple of special methods for this to work, but it’s not that hard and it will improve the design of your code: the concern of having an object know its state has been separated from the concern of getting the browser to remember that state. Your object will work with or without history management — it can just be bolted on as and when you feel like it.

That’s really all I wanted to say about it for now. Chances are I’ll be demonstrating some example code here, and digging into Ojay’s innards a little along the way. For now, I’d be thrilled if you’d download Ojay and give it a whirl. Our code is hosted on Google Code, and we have a mailing list should you want to get in touch.

Using ChainCollector to respond to Ajax calls

Saq made a couple of comments on my ChainCollector article about how to queue up functions to respond to Ajax calls, and whether I could write something up to shed a bit of light on how this might be done. Today, I’m going to implement some methods that allow to GET from/POST to a URL, then do some basic things with the response using very sentence-like code. Specifically, I’m going to end up with:

Ajax.GET('/api').then.insertInto('#blog-excerpt').and.evalScripts()

(I hope you’re starting to see why I wrote ChainCollector: code clarity is something that’s very important to me, especially when you’re working in a team that covers the whole web software stack and many of them don’t know JavaScript.) I’m not sure if this exactly answers Saq’s problem, but I hope it will illustrate how you might begin using ChainCollector to solve issues like this.

Okay, the first thing we’re going to need is a new class that provides us with methods to use in the chain above. Let’s call it ChainableRequest. I’m using Prototype today, but hopefully non-Prototype users will be able to follow along.

Ajax.ChainableRequest = Class.create();

Object.extend(Ajax.ChainableRequest.prototype, {
  initialize: function(verb, url) {
    this.chain = new ChainCollector(this);
    this.request = new Ajax.Request(url, {
      method: verb,
      onComplete: function(transport) {
        this.response = transport;
        this.chain.fire(this);
      }.bind(this)
    });
  }
});

This class takes two arguments to initialize its instances: an HTTP verb (GET or POST) and a URL. It sets up a new ChainCollector (which will inherit any methods we add to ChainableRequest) and sets off an Ajax request to the URL. It registers a callback that tells the request to fire the chain when the request completes.

So, onto the methods that we want to add to the chain. We need a method that inserts the response into some elements on the page. I want this method to accept a CSS selector, an element reference, or an array of element references. For each element found, it strips any scripts out of the response and inserts the remainder into the element. Note how each method returns the ChainableRequest object for chaining purposes.

Object.extend(Ajax.ChainableRequest.prototype, {
  insertInto: function(elements) {
    if (!this.response) return this;
    if (typeof elements == 'string') elements = $$(elements);
    if (!(elements instanceof Array)) elements = [elements];
    elements.each(function(element) {
      element.innerHTML = this.response.responseText.stripScripts();
    }.bind(this));
    return this;
  }
});

And, we need a method to evaluate the scripts in the response. You’ll see that Prototype uses a setTimeout in some cases to do this, in case the document hasn’t finished updating the DOM in response to an innerHTML change.

Object.extend(Ajax.ChainableRequest.prototype, {
  evalScripts: function() {
    if (!this.response) return this;
    setTimeout(function() {
      this.response.responseText.evalScripts();
    }.bind(this), 10);
    return this;
  }
});

The final piece of the puzzle is to create methods for any HTTP verbs you want to use. Note that I’m using capitals because that’s the convention with HTTP verbs, and also because you might want to go on an implement PUT and DELETE (supported by YUI), and delete is a reserved word in JavaScript. Each verb method should create a new ChainableRequest, then return its chain property so you can chain methods into the onComplete callback.

$w('GET POST').each(function(verb) {
  Ajax[verb] = function(url) {
    var req = new Ajax.ChainableRequest(verb, url);
    return req.chain;
  };
});

// Remember to add the required methods to ChainCollector
ChainCollector.addMethods(Ajax.ChainableRequest);

And that just about wraps it up in terms of getting our initial code sentence working. You’d probably want something a lot more flexible than this in real life, but this covers some common uses for Ajax calls that can easily be turned into sentence structures. You can download the ChainableRequest JavaScript class to save yourself copy-pasting all the code from this article.

Asynchronous function chaining in JavaScript

Update, 25 February 2008: This class is now available as part of JS.Class (it’s called MethodChain now). It also forms a key part of Ojay, an expressive wrapper for YUI.

Update, 12 Dec 2007: Another implementation change. A blank ChainCollector instance now has the following properties: then, and, ____ (formerly __enqueue) and fire. The method queue and base object are private variables, and addMethods is a static method. I’m trying to make it as flexible as possible, i.e. it should have the fewest possible named properties but still allow you to extend it to your needs. Also, you now add methods to ChainCollector‘s prototype rather than to instances as this is much faster.

Update, 9 Dec 2007: I’ve modified the implementation of ChainCollector so it has fewer methods in its prototype, thus fewer chances of name collisions. It no longer has initialize, __addMethods or __enqueue methods — these are now ‘private’ methods created using the module pattern.

For this post, I’m going to be using jQuery, because it’s the closest well-known thing to the library I’m currently working on at my new job. (It’s a wrapper for YUI with lots of syntax niceties.)

Programming asynchronous actions is a pain in the head. Why can’t I do setTimeout($('#myNode').hide, 2000)? I need to bind the hide function to the $('#myNode') object for starters, and jQuery doesn’t give you a bind method, and besides, binding and execution scope gives lots of JavaScript novices a headache. Wouldn’t this be nice:

$('#myNode').wait(2).then.hide();

Over the weekend, I was trying to figure out a general purpose way of adding asynchronous behaviour like this, so I could use it with event handlers, Ajax calls, post-animation callbacks etc. My inspiration came from Methodphitamine (site unavailable, try the Google cache).

I won’t bore any non-Rubyists with the details, but the idea is quite simple: create an object with no predefined methods, which accepts any method call and adds the name of the method and its arguments to a queue. This queue can be turned into a function and called on whatever object you want at a later time. Unfortunately, JavaScript has no analogue for Ruby’s method_missing, which means if you want such an object in JavaScript, you need to predefine every method name you might want to use. Big pain.

But, you can get something quite usable if you’re implementing an interface (like jQuery’s) that allows chaining. You can pass some object to the constructor for your magical queue-collecting object, and have it implement copies of all the object’s methods. If you need methods from other objects, you can pass those in too.

An example, implementing my wait suggestion from above:

jQuery.fn.wait = function(time) {
  var collector = new ChainCollector(), self = this;
  // Deal with scoping issues...
  var fire = function() { collector.fire(self); };
  setTimeout(fire, Number(time) * 1000);
  return collector;
};

// Then extend ChainCollector with all jQuery's methods
ChainCollector.addMethods(jQuery);

With this defined (and ChainCollector, code to follow), you can do this:

$('#jq-header').wait(2).then.hide('slow')

Grab all the code from this post and go try that out on the jQuery home page. Nice, no? I’m using this technique for writing concise, extensible event handlers at the moment, and it’s very nice indeed. You can even chain multiple wait calls into the same statement:

$('#jq-header').wait(2).then.hide('slow').wait(3).then.show('fast')

Anyway, now that I’ve got you all fired up about this, here’s the magic that makes it all possible:

var ChainCollector = function(base) {
    var CLASS = arguments.callee;
    
    this.then = this.and = this;
    var queue = [], baseObject = base || {};
    
    this.____ = function(method, args) {
        queue.push({func: method, args: args});
    };
    
    this.fire = function(base) {
        var object = base || baseObject, method, property;
        for (var i = 0, n = queue.length; i < n; i++) {
            method = queue[i];
            if (object instanceof CLASS) {
                object.____(method.func, method.args);
                continue;
            }
            property = object[method.func];
            object = (typeof property == 'function')
                    ? property.apply(object, method.args)
                    : property;
        }
        return object;
    };
};

ChainCollector.addMethods = function(object) {
    var methods = [], property, i, n, name;
    var self = this.prototype;
    
    var reservedNames = [], blank = new this();
    for (property in blank) reservedNames.push(property);
    var re = new RegExp('^(?:' + reservedNames.join('|') + ')$');
    
    for (property in object) {
        if (Number(property) != property)
            methods.push(property);
    }
    if (object instanceof Array) {
        for (i = 0, n = object.length; i < n; i++) {
            if (typeof object[i] == 'string')
                methods.push(object[i]);
        }
    }
    for (i = 0, n = methods.length ; i < n; i++)
        (function(name) {
            if (re.test(name)) return;
            self[name] = function() {
                this.____(name, arguments);
                return this;
            };
        })(methods[i]);
    
    if (object.prototype)
        this.addMethods(object.prototype);
};

I’d love to know what uses people find for this.