home | O'Reilly's CD bookshelfs | FreeBSD | Linux | Cisco | Cisco Exam    

Book HomeJava and XSLTSearch this book

8.2. Attribute::Handlers

Implements a simpler definition of attribute handlers. When inherited by a package, Attribute::Handlers allows that package's class to define handler subroutines for specific attributes. When inherited by a package, these handlers will be called by the same names as the original attribute-handling subroutines. Attribute handlers will be called at one of the following compilation phases: BEGIN, CHECK, INIT, or END blocks. Note that Attribute::Handlers is shipped with the Perl source kit as of Version 5.8.

Handlers are defined as subroutines and named as the desired attribute. In the following example, the attribute is :ATTR, which lives in a subroutine that's called Nate1() in the HandlerBing class:

package HandlerBing;
use Attribute::Handlers;
sub Nate1 :ATTR {
    my(@attrs) = @_; # We simply want to test by dumping the attributes
    print "attributes: \n", 
       join("\n", @attrs), "\n";
 # true.

This stub for the HandlerBing class creates a handler for the attribute :Nate1. When you want to use this handler while within HandlerBing, you can do the following:

sub Nate2 :Nate1 {
    my (@stuff) = @_;
        print STDERR "in Nate2 ", join("\n", @stuff), "\n";

When you call Nate2, it invokes the Nate1 handler and passes the following elements into the @_ array:

The name of the package in which the handler was declared

A reference to the symbol table entry (a typeglob) that contains the subroutine

A reference to the subroutine

The name of the attribute itself

Any data associated with that attribute

The name of the compilation phase in which the handler was invoked

The same holds true for declaring any variables with the :Nate1 attribute within HandlerBing:

my $monica :Nate1;
my $phoebe :Nate1;

Attribute::Handlers also supports typed lexicals. This is a nice feature, since you can invoke a handler from a package that defines another one from whatever package you're in (or writing!). For example:

package MustNotSeeTV;
 my HandlerBring $whatever : Nate1;
 # true

You can apply handlers only by type, if you wish. You can do this by passing a built-in type to :ATTR:

package ReRun;
 sub Tiresome :ATTR(HASH) { print "your reruns have become tiresome\n"; }
 # true

In the above code, Tiresome is an attribute handler that applies only to HASH es. And certainly, you can declare separate handlers (of the same names) for the other types.

If you have problems passing certain data to a handler, such as now..later or laugh@you, you can use the RAWDATA type to pass this data cleanly:

sub RawLikeSushi : ATTR(RAWDATA) { ... do something ... }

Attribute::Handlers implements the following diagnostics (from the Attribute::Handlers manpage):

Bad attribute type: ATTR(%s)
An attribute handler was specified with an :ATTR(ref_type), but the type of referent it was defined to handle wasn't one of the five permitted: SCALAR, ARRAY, HASH, CODE, or ANY.

Attribute handler %s doesn't handle %s attributes
A handler for attributes of the specified name was defined, but not for the specified type of declaration. Typically encountered when trying to apply a VAR attribute handler to a subroutine, or a SCALAR attribute handler to another type of variable.

Declaration of %s attribute in %s package may clash with future reserved word
A handler for an attribute with an all-lowercase name was declared. An attribute with an all-lowercase name might mean something to Perl itself someday, even though most don't yet. Use a mixed-case attribute name instead.

Can't have two ATTR specifiers on one subroutine
You just can't, okay? Instead, put all the specifications together, separated by commas in a single ATTR(specifications).

Can't autotie a %s
You can declare autoties only for types SCALAR, ARRAY, and HASH. They're the only things (apart from typeglobs, which are not declarable) that Perl can tie.

Internal error: %s symbol went missing
Something is rotten in the state of the program. An attributed subroutine ceased to exist between the point where it was declared and the point where its attribute handler(s) would have been called.

Won't be able to apply an END handler
You tried to define an END handler for an attribute that is applied to a lexical variable. Since the variable may not be available during END, this will fail.

Library Navigation Links

Copyright © 2002 O'Reilly & Associates. All rights reserved.