Attribute-Handlers-Clean
view release on metacpan or search on metacpan
lib/Attribute/Handlers/Clean.pm view on Meta::CPAN
sub other : Omni {
# ...
}
=head1 DESCRIPTION
This module is heavily based on the excellent L<Attribute::Handlers>. Around 90% of the code
and documentation is exactly the same. The big difference is that, while L<Attribute::Handlers>
relies on defining things in the L<UNIVERSAL> namespace, this module does not. Still,
this module make it easier and more intuitive to define custom attributes that will
work on your classes and subclasses.
The problem with altering L<UNIVERSAL> is that ALL other classes loaded in Perl can
be affected by this pollution. It might even break things when their functionality
relies on basic calls like C<package->can('...')>. Still, L<Attribute::Handlers> is
an excellent idea an implementation, but we can get away with it without polluting
L<UNIVERSAL> by polluting only the classes using L<Attribute::Handlers::Clean> (which
doesn't really create a problem, since putting things in L<UNIVERSAL> was already
doing that, but for everything and everyone).
I decided to work on this adaptation in a new namespace because L<Attribute::Handlers>
specifically instructs to create subroutines with attributes under the L<UNIVERSAL>
namespace. Changing this behavior directly in L<Attribute::Handlers> would
probably break a lot of modules that rely on this already. So, creating
L<Attribute::Handlers::Clean> seemed like the best option.
This module, when used via C<use>, automatically makes the caller a subclass,
without the need to specify it in its own C<@ISA>. The only case where you
will need to manually add it to your C<@ISA>, is then you declare C<@ISA>
in your class with specific values.
This will also cause an automatic reaction on other modules calling yours,
making your attribute definitions available to all callers and sub-callers
without having to declare them as part of L<UNIVERSAL>.
If your class C<use>s C<Attribute::Handlers::Clean> but needs to define
its own C<import> method, then all you need to do to ensure the right
behavior is adding a call to C<Attribute::Handlers::Clean->import> in your
own C<import> mehod. For example:
package MyClass;
use Attribute::Handlers::Clean;
sub import {
# Some custom stuff you need to do here that
# drove you to define your own import method
Attribute::Handlers::Clean->import; # <- That's it.
}
That will allow any other classes calling C<MyClass> to have the necessary
definitions for your attributes to work there too. You can do this same
thing in your calling subclasses if you need the callers of those subclasses
to also have your custom attributes available there. This is only necessary
when you define your own C<import> method. Otherwise, it should happen
automatically.
Variables and subroutines subsequently defined in your package, or in packages
derived from that package may be given attributes with the same names as
the attribute handler subroutines, which will then be called in one of
the compilation phases (i.e. in a C<BEGIN>, C<CHECK>, C<INIT>, or C<END>
block). (C<UNITCHECK> blocks don't correspond to a global compilation
phase, so they can't be specified here.)
To create a handler, define it as a subroutine with the same name as
the desired attribute, and declare the subroutine itself with the
attribute C<:ATTR>. For example:
package LoudDecl;
use Attribute::Handlers::Clean;
sub Loud :ATTR {
my ($package, $symbol, $referent, $attr, $data, $phase, $filename, $linenum) = @_;
print STDERR
ref($referent), " ",
*{$symbol}{NAME}, " ",
"($referent) ", "was just declared ",
"and ascribed the ${attr} attribute ",
"with data ($data)\n",
"in phase $phase\n",
"in file $filename at line $linenum\n";
}
This creates a handler for the attribute C<:Loud> in the class LoudDecl.
Thereafter, any subroutine declared with a C<:Loud> attribute in the class
LoudDecl:
package LoudDecl;
sub foo : Loud {...}
...or, in another class calling LoudDecl via C<use>:
package MyOtherClass;
use LoudDecl;
sub bar : Loud {...}
causes the above handler to be invoked, and passed:
=over
=item [0]
the name of the package into which it was declared;
=item [1]
a reference to the symbol table entry (typeglob) containing the subroutine;
=item [2]
a reference to the subroutine;
=item [3]
the name of the attribute;
=item [4]
any data associated with that attribute;
( run in 1.160 second using v1.01-cache-2.11-cpan-5735350b133 )