You are right, the documentation is not very clear in this area, especially since attributes are not so complicated. If you define a subroutine attribute, like this:
sub some_method :Foo { }
Perl will while compiling your program (this is important) look for the magic sub MODIFY_CODE_ATTRIBUTES
in the current package or any of its parent classes. This will be called with the name of the current package, a reference to your subroutine, and a list of the attributes defined for this subroutine. If this handler does not exist, compilation will fail.
What you do in this handler is entirely up to you. Yes, that's right. No hidden magic whatsoever. If you want to signal an error, returning the name of the offending attributes will cause the compilation to fail with an "invalid attribute" message.
There is another handler called FETCH_CODE_ATTRIBUTES
that will be called whenever someone says
use attributes;
my @attrs = attributes::get(\&some_method);
This handler gets passed the package name and subroutine reference, and is supposed to return a list of the subroutine's attributes (though what you really do is again up to you).
Here is an example to enable simple "tagging" of methods with arbitrary attributes, which you can query later:
package MyClass;
use Scalar::Util qw( refaddr );
my %attrs; # package variable to store attribute lists by coderef address
sub MODIFY_CODE_ATTRIBUTES {
my ($package, $subref, @attrs) = @_;
$attrs{ refaddr $subref } = \@attrs;
return;
}
sub FETCH_CODE_ATTRIBUTES {
my ($package, $subref) = @_;
my $attrs = $attrs{ refaddr $subref };
return @$attrs;
}
1;
Now, in MyClass and all its subclasses, you can use arbitrary attributes, and query them using attributes::get()
:
package SomeClass;
use base 'MyClass';
use attributes;
# set attributes
sub hello :Foo :Bar { }
# query attributes
print "hello() in SomeClass has attributes: ",
join ', ', attributes::get(SomeClass->can('hello'));
1;
__END__
hello() in SomeClass has attributes: Foo, Bar
In summary, attributes don't do very much which on the other hand makes them very flexible: You can use them as real "attributes" (as shown in this example), implement something like decorators (see Sinan's answer), or for your own devious purposes.