Hooks

Module, Class, and Objectimplement several callback methods, or hooks. These methods are not defined by default, but if you define them for a module, class, or object, then they will be invoked when certain events occur. This gives you an opportunity to extend Ruby’s behavior when classes are subclassed, when modules are included, or when methods are defined. Hook methods (except for some deprecated ones not described here) have names that end in “ed.”

When a new class is defined, Ruby invokes the class method inherited on the superclass of the new class, passing the new class object as the argument. This allows classes to add behavior to or enforce constraints on their descendants. Recall that class methods are inherited, so that the an inherited method will be invoked if it is defined by any of the ancestors of the new class. Define Object.inherited to receive notification of all new classes that are defined:

def Object.inherited(c)
  puts "class #{c} < #{self}"
end

When a module is included into a class or into another module, the included class method of the included module is invoked with the class or module object into which it was included as an argument. This gives the included module an opportunity to augment or alter the class in whatever way it wants—it effectively allows a module to define its own meaning for include. In addition to adding methods to the class into which it is included, a module with an included method might also alter the existing methods of that class, for example:

module Final             # A class that includes Final can't be subclassed
  def self.included(c)   # When included in class c
    c.instance_eval do   # Define a class method of c
      def inherited(sub) # To detect subclasses
        raise Exception, # And abort with an exception
              "Attempt to create subclass #{sub} of Final class #{self}"
      end
    end
  end
end

Similarly, if a module defines a class method named extended, that method will be invoked any time the module is used to extend an object (with Object.extend). The argument to the extended method will be the object that was extended, of course, and the extended method can take whatever actions it wants on that object.

In addition to hooks for tracking classes and the modules they include, there are also hooks for tracking the methods of classes and modules and the singleton methods of arbitrary objects. Define a class method named method_added for any class or module and it will be invoked when an instance method is defined for that class or module:

def String.method_added(name) 
  puts "New instance method #{name} added to String"
end

Note that the method_added class method is inherited by subclasses of the class on which it is defined. But no class argument is passed to the hook, so there is no way to tell whether the named method was added to the class that defines method_added or whether it was added to a subclass of that class. A workaround for this problem is to define an inherited hook on any class that defines a method_added hook. The inherited method can then define a method_added method for each subclass.

When a singleton method is defined for any object, the method singleton_method_added is invoked on that object, passing the name of the new method. Remember that for classes, singleton methods are class methods:

def String.singleton_method_added(name)
  puts "New class method #{name} added to String"
end

Interestingly, Ruby invokes this singleton_method_added hook when the hook method itself is first defined. Here is another use of the hook. In this case, singleton_method_added is defined as an instance method of any class that includes a module. It is notified of any singleton methods added to instances of that class:

# Including this module in a class prevents instances of that class
# from having singleton methods added to them. Any singleton methods added
# are immediately removed again.
module Strict
  def singleton_method_added(name)
    STDERR.puts "Warning: singleton #{name} added to a Strict object"
    eigenclass = class << self; self; end
    eigenclass.class_eval { remove_method name }
  end
end

In addition to method_added and singleton_method_added, there are hooks for tracking when instance methods and singleton methods are removed or undefined. When an instance method is removed or undefined on a class or module, the class methods method_removed and method_undefined are invoked on that module. When a singleton method is removed or undefined on an object, the methods singleton_method_removed and singleton_method_undefined are invoked on that object.

Finally, note that the method_missing and const_missing methods documented elsewhere in this chapter also behave like hook methods.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.189.188.238