MethodChain
MethodChain
provides a mechanism for storing a sequence of method calls
and then executing that sequence on any object you like.
// In the browser JS.require('JS.MethodChain', function(MethodChain) { ... }); // In CommonJS var MethodChain = require('jsclass/src/method_chain').MethodChain;
Here’s a quick example:
var chain = new MethodChain(); chain.map(function(s) { return s.toUpperCase() }) .join(', ') .replace(/[aeiou]/ig, '_'); chain.__exec__(['foo', 'bar']) // -> "F__, B_R"
Here, we create a new MethodChain
object called chain
. We then call three
methods on it, map()
, join()
and replace()
. chain
remembers the names
of these methods and the arguments you used, then calls the stored chain on
any object you pass to its __exec__()
method.
If you call further methods on chain
, they get added to the list:
chain.split(/_+/); chain.__exec__(['foo', 'bar']) // -> ["F", ", B", "R"]
How it works
When you call a method like map()
on a MethodChain
instance, the instance
stores the name of the method and any arguments you pass to it. All of chain
’s
methods return chain
again, allowing you to chain methods together as shown
above.
Any method you want to store in a chain has to exist in MethodChain
’s list
of method names in advance (my kingdom for a method_missing
feature in
JavaScript!), or you will get an error. MethodChain
comes with over 300
method names in place from the JavaScript core API to get you started. If you
find that a method is missing, you can add it like so:
// Add all methods from a class or object MethodChain.addMethods(jQuery); // Add methods by name MethodChain.addMethods(['methodName1', 'someOtherMethod']);
All MethodChain
instances will then have the methods you’ve added.
There are a few reserved methods on MethodChain
objects that you cannot use
for chaining:
__()
– two underscores – more on this in a second____()
– four underscores, used for storing method calls__exec__()
– executes the stored chain against its argumenttoFunction()
– returns a function that executes the chain when called
Changing scope using __()
All chains have a method called __()
(that’s two underscores) that you can
use to change the scope of the chain. By default, each method in the chain is
called on the return value of the previous method, but __()
lets you insert
objects into the chain so that subsequent methods get called on said object.
__()
also lets you insert anonymous functions into the chain. Within each
function, this
refers to the return value of the previous method. Putting
all this together, you could do:
var chain = new MethodChain(); chain.__(document).getElementsByTagName('p') .__(function() { console.log(this) });
When we execute chain
, the net effect is the same as:
console.log(document.getElementsByTagName('p'));
If you insert a function into the chain, its return value will be used as the receiving object for the next method call in the chain.
toFunction()
The toFunction
method returns a function that executes the chain against its
argument. For example, taking the first chain we created at the top of this
page:
var func = chain.toFunction(); func(['foo', 'bar']) // -> "F__, B_R"
The wait()
method
MethodChain
adds a method called wait()
as an instance method and a class
method to all classes and objects created with jsclass
. This method allows
you to delay execution of a chain against an object for a given about of time.
var Fiddle = new Class({ initialize: function(quantity) { this.size = quantity; }, proclaim: function(thing) { console.log('I have ' + this.size + ' ' + thing + 's!'); } }); var fid = new Fiddle(99); // Call proclaim() after 5 seconds // prints "I have 99 problems!" fid.wait(5).proclaim('problem');
Further reading
For some background and further usage examples, refer to the articles on
ChainCollector
on my blog. ChainCollector
is the name I originally gave the MethodChain
class.