Modifying existing classes and modules

Just like in Ruby, classes and modules are open for modification at any time, so you can add and change methods in existing classes. All classes and modules in jsclass have some special methods for modifying the methods they contain. The following is written to apply to modifying classes, but it applies equally to modifying modules—classes are just modules that can be instantiated.

The first of these methods is called define(). This adds a single named method to the class/module. If you’re modifying a class, the method instantly becomes available in instances of the class, and in its subclasses.

Animal.define('sleep', function() {
    return this.name + ' is sleeping';
});

rex.sleep()
// -> "Rex is sleeping"

Note that if the class already has a method with the same name as the one you’re defining, the old method will be overwritten. Methods in parent classes and in mixins can be accessed using callSuper().

If you want to create aliases for methods that already exist, use the alias() method. The new alias goes on the left-hand-side, the existing method name on the right.

Animal.alias({
    talk:   'speak',
    rest:   'sleep'
});

The other option available to you is to use include(). This method has a couple of roles; if you supply a Module, the module is mixed into the class and becomes part of its inheritance tree. If you supply any other type of object, the methods from the object are copied into the class itself, overwriting any pre-existing methods with similar names.

// Replace Dog's speak method  (#1)
Dog.include({
    speak: function(stuff) {
        return this.callSuper('lots of ' + stuff) + '!';
    }
});

rex.speak('cats')
// -> "My name is Rex and I like lots of cats!" 

// Mix in a module, altering the class's ancestry
// callSuper() in Dog#speak will now call this method
var Speaker = new Module({
    speak: function(stuff) {
        return 'I can talk about ' + stuff + '!';
    }
});

Dog.include(Speaker);
rex.speak('cats')
// -> "I can talk about lots of cats!!"

Notice how including Speaker does not overwrite the speak method in the Dog class (marked #1 above). That method is defined in Dog and will persist until overwritten directly in the Dog class. Speaker merely injects another method called speak into the inheritance chain for the Dog class. For more information, refer to the explanation of Ruby’s method lookup algorithm.