Provides pattern-based mutation for MooTools classes. Works with MooTools 1.3.
In the current version of MooTools, mutators are key-based: a particular key, such as Extends or Implements, is mapped directly to a mutator function in the Class.Mutators object. This limits mutators to a single invocation per class, which is totally acceptable though stiff.
Development versions of MooTools 2.0, however, introduced the concept of pattern-based mutators. Instead of mapping keys directly to mutator functions, the Class implementation of MooTools 2.0 checks the keys of a declaration against a set of patterns mutators. This makes it possible to apply a single mutator to several items in the declaration, and enables more idiomatic declarations.
Unfortunately, pattern mutators weren't included into 1.3. This extension, however, changes that.
The best way to understand pattern mutators is through an example. Let's say we have the following custom mutator:
Class.Mutators.Protected = function(items){
for (var fn in items) {
if (items[fn] instanceof Function) items[fn].protect();
}
this.implement(items);
};
This is a simple mutator that enables us to set protected methods in our class declarations. To use it, we have to define a Protected key in our declaration, like so:
var MyClass = new Class({
Protected: {
hi: function(){
console.log('Hi Universe!');
}
},
hello: function(){
console.log('Hello World!');
}
});
var inst = new MyClass();
inst.hello(); // 'Hello World!'
inst.hi(); // Throws an error: 'The method "hi" cannot be called.'
We had to define a separate Protected key in this class declaration because mutators are mapped using the keys of a declaration. In this case, our Protected key is mapped to the Class.Mutators.Protected mutator function.
Pattern-based mutators, on the other hand, aren't mapped directly using keys. Instead, a pattern mutator defines a pattern using regular expressions to determine where it should be applied. Here's a pattern-based equivalent of our Protected mutator:
Class.defineMutator(/^protected\s(\w+)/, function(fn, name){
this.implement(name, fn.protect());
});
This mutator has a pattern that states it should be applied to any key in a class declaration that start with protected . To use it, we simply have to change our keys:
var MyClass = new Class({
'protected hi': function(){
console.log('Hi Universe!');
},
hello: function(){
console.log('Hello World!');
}
});
var inst = new MyClass();
inst.hello(); // 'Hello World!'
inst.hi(); // Throws an error: 'The method "hi" cannot be called.'
Instead of creating a separate Protected key in our class declaration, we simply added a protected qualifier at the start of the method name. The effects, though, are the same as our previous declaration.
This extension provides a function, Class.defineMutator, that can be used to define both key-based and pattern-based mutators
Class.defineMutator(matcher, fn);
matcher- (string) or (regexp) The matcher that will be checked against a class declaration. If you provide a string value, the mutator will be a key-based mutator; if you provide a regular expression value, the mutator will be a pattern-based mutator.fn- (function) - The mutator function that will be invoked for the matching properties in a class declaration. This function will always be invoked with itsthisvalue bound to the current class.
Syntax:
fn(value [, match1, match2, ..., matchN])
Arguments:
value- (mixed) The value of the particular property in the class declaration that matches the mutator criteria.matchN- (mixed) For pattern mutators, the remaining arguments after the firstvalueargument will be the captured matches from the mutator's regular expression.
- This extension wraps the default
Class.prototype.implementmethod in order to add the pattern-based mutator check. Internally, though, it still uses the defaultimplementmethod in order to add the members to the class'prototype. The defaultimplementmethod is reimplemented asdefine. - Pattern mutators are tested in reverse: the last mutator declared will be the first one tested. This is due to the use of a reverse
whileloop to speed-up the matching process. - Pattern mutators take precedence over key-based mutators, and a pattern mutator could be applied together with a key-based mutator in some cases.
- Several mutators can be used in a single key as long as the mutators use flexible regexp patterns and always invoke
implementmethod.
Mark "Keeto" Obcena <keetology.com>
Copyright 2010, MIT-style License
Original pattern-based mutator idea and code for the protected and linked mutators from Valerio Proietti via MooTools 2.0.