diff options
Diffstat (limited to 'upstream/mageia-cauldron/man3pm/Attribute::Handlers.3pm')
-rw-r--r-- | upstream/mageia-cauldron/man3pm/Attribute::Handlers.3pm | 758 |
1 files changed, 758 insertions, 0 deletions
diff --git a/upstream/mageia-cauldron/man3pm/Attribute::Handlers.3pm b/upstream/mageia-cauldron/man3pm/Attribute::Handlers.3pm new file mode 100644 index 00000000..eb46aece --- /dev/null +++ b/upstream/mageia-cauldron/man3pm/Attribute::Handlers.3pm @@ -0,0 +1,758 @@ +.\" -*- mode: troff; coding: utf-8 -*- +.\" Automatically generated by Pod::Man 5.01 (Pod::Simple 3.43) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" \*(C` and \*(C' are quotes in nroff, nothing in troff, for use with C<>. +.ie n \{\ +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds C` +. ds C' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is >0, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.\" +.\" Avoid warning from groff about undefined register 'F'. +.de IX +.. +.nr rF 0 +.if \n(.g .if rF .nr rF 1 +.if (\n(rF:(\n(.g==0)) \{\ +. if \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. if !\nF==2 \{\ +. nr % 0 +. nr F 2 +. \} +. \} +.\} +.rr rF +.\" ======================================================================== +.\" +.IX Title "Attribute::Handlers 3pm" +.TH Attribute::Handlers 3pm 2023-11-28 "perl v5.38.2" "Perl Programmers Reference Guide" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH NAME +Attribute::Handlers \- Simpler definition of attribute handlers +.SH VERSION +.IX Header "VERSION" +This document describes version 1.03 of Attribute::Handlers. +.SH SYNOPSIS +.IX Header "SYNOPSIS" +.Vb 4 +\& package MyClass; +\& require 5.006; +\& use Attribute::Handlers; +\& no warnings \*(Aqredefine\*(Aq; +\& +\& +\& sub Good : ATTR(SCALAR) { +\& my ($package, $symbol, $referent, $attr, $data) = @_; +\& +\& # Invoked for any scalar variable with a :Good attribute, +\& # provided the variable was declared in MyClass (or +\& # a derived class) or typed to MyClass. +\& +\& # Do whatever to $referent here (executed in CHECK phase). +\& ... +\& } +\& +\& sub Bad : ATTR(SCALAR) { +\& # Invoked for any scalar variable with a :Bad attribute, +\& # provided the variable was declared in MyClass (or +\& # a derived class) or typed to MyClass. +\& ... +\& } +\& +\& sub Good : ATTR(ARRAY) { +\& # Invoked for any array variable with a :Good attribute, +\& # provided the variable was declared in MyClass (or +\& # a derived class) or typed to MyClass. +\& ... +\& } +\& +\& sub Good : ATTR(HASH) { +\& # Invoked for any hash variable with a :Good attribute, +\& # provided the variable was declared in MyClass (or +\& # a derived class) or typed to MyClass. +\& ... +\& } +\& +\& sub Ugly : ATTR(CODE) { +\& # Invoked for any subroutine declared in MyClass (or a +\& # derived class) with an :Ugly attribute. +\& ... +\& } +\& +\& sub Omni : ATTR { +\& # Invoked for any scalar, array, hash, or subroutine +\& # with an :Omni attribute, provided the variable or +\& # subroutine was declared in MyClass (or a derived class) +\& # or the variable was typed to MyClass. +\& # Use ref($_[2]) to determine what kind of referent it was. +\& ... +\& } +\& +\& +\& use Attribute::Handlers autotie => { Cycle => Tie::Cycle }; +\& +\& my $next : Cycle([\*(AqA\*(Aq..\*(AqZ\*(Aq]); +.Ve +.SH DESCRIPTION +.IX Header "DESCRIPTION" +This module, when inherited by a package, allows that package's class to +define attribute handler subroutines for specific attributes. Variables +and subroutines subsequently defined in that 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 \f(CW\*(C`BEGIN\*(C'\fR, \f(CW\*(C`CHECK\*(C'\fR, \f(CW\*(C`INIT\*(C'\fR, or \f(CW\*(C`END\*(C'\fR +block). (\f(CW\*(C`UNITCHECK\*(C'\fR blocks don't correspond to a global compilation +phase, so they can't be specified here.) +.PP +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 \f(CW\*(C`:ATTR\*(C'\fR. For example: +.PP +.Vb 2 +\& package LoudDecl; +\& use Attribute::Handlers; +\& +\& 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)\en", +\& "in phase $phase\en", +\& "in file $filename at line $linenum\en"; +\& } +.Ve +.PP +This creates a handler for the attribute \f(CW\*(C`:Loud\*(C'\fR in the class LoudDecl. +Thereafter, any subroutine declared with a \f(CW\*(C`:Loud\*(C'\fR attribute in the class +LoudDecl: +.PP +.Vb 1 +\& package LoudDecl; +\& +\& sub foo: Loud {...} +.Ve +.PP +causes the above handler to be invoked, and passed: +.IP [0] 4 +.IX Item "[0]" +the name of the package into which it was declared; +.IP [1] 4 +.IX Item "[1]" +a reference to the symbol table entry (typeglob) containing the subroutine; +.IP [2] 4 +.IX Item "[2]" +a reference to the subroutine; +.IP [3] 4 +.IX Item "[3]" +the name of the attribute; +.IP [4] 4 +.IX Item "[4]" +any data associated with that attribute; +.IP [5] 4 +.IX Item "[5]" +the name of the phase in which the handler is being invoked; +.IP [6] 4 +.IX Item "[6]" +the filename in which the handler is being invoked; +.IP [7] 4 +.IX Item "[7]" +the line number in this file. +.PP +Likewise, declaring any variables with the \f(CW\*(C`:Loud\*(C'\fR attribute within the +package: +.PP +.Vb 1 +\& package LoudDecl; +\& +\& my $foo :Loud; +\& my @foo :Loud; +\& my %foo :Loud; +.Ve +.PP +will cause the handler to be called with a similar argument list (except, +of course, that \f(CW$_[2]\fR will be a reference to the variable). +.PP +The package name argument will typically be the name of the class into +which the subroutine was declared, but it may also be the name of a derived +class (since handlers are inherited). +.PP +If a lexical variable is given an attribute, there is no symbol table to +which it belongs, so the symbol table argument (\f(CW$_[1]\fR) is set to the +string \f(CW\*(AqLEXICAL\*(Aq\fR in that case. Likewise, ascribing an attribute to +an anonymous subroutine results in a symbol table argument of \f(CW\*(AqANON\*(Aq\fR. +.PP +The data argument passes in the value (if any) associated with the +attribute. For example, if \f(CW&foo\fR had been declared: +.PP +.Vb 1 +\& sub foo :Loud("turn it up to 11, man!") {...} +.Ve +.PP +then a reference to an array containing the string +\&\f(CW"turn it up to 11, man!"\fR would be passed as the last argument. +.PP +Attribute::Handlers makes strenuous efforts to convert +the data argument (\f(CW$_[4]\fR) to a usable form before passing it to +the handler (but see "Non-interpretive attribute handlers"). +If those efforts succeed, the interpreted data is passed in an array +reference; if they fail, the raw data is passed as a string. +For example, all of these: +.PP +.Vb 4 +\& sub foo :Loud(till=>ears=>are=>bleeding) {...} +\& sub foo :Loud(qw/till ears are bleeding/) {...} +\& sub foo :Loud(qw/till, ears, are, bleeding/) {...} +\& sub foo :Loud(till,ears,are,bleeding) {...} +.Ve +.PP +causes it to pass \f(CW\*(C`[\*(Aqtill\*(Aq,\*(Aqears\*(Aq,\*(Aqare\*(Aq,\*(Aqbleeding\*(Aq]\*(C'\fR as the handler's +data argument. While: +.PP +.Vb 1 +\& sub foo :Loud([\*(Aqtill\*(Aq,\*(Aqears\*(Aq,\*(Aqare\*(Aq,\*(Aqbleeding\*(Aq]) {...} +.Ve +.PP +causes it to pass \f(CW\*(C`[ [\*(Aqtill\*(Aq,\*(Aqears\*(Aq,\*(Aqare\*(Aq,\*(Aqbleeding\*(Aq] ]\*(C'\fR; the array +reference specified in the data being passed inside the standard +array reference indicating successful interpretation. +.PP +However, if the data can't be parsed as valid Perl, then +it is passed as an uninterpreted string. For example: +.PP +.Vb 2 +\& sub foo :Loud(my,ears,are,bleeding) {...} +\& sub foo :Loud(qw/my ears are bleeding) {...} +.Ve +.PP +cause the strings \f(CW\*(Aqmy,ears,are,bleeding\*(Aq\fR and +\&\f(CW\*(Aqqw/my ears are bleeding\*(Aq\fR respectively to be passed as the +data argument. +.PP +If no value is associated with the attribute, \f(CW\*(C`undef\*(C'\fR is passed. +.SS "Typed lexicals" +.IX Subsection "Typed lexicals" +Regardless of the package in which it is declared, if a lexical variable is +ascribed an attribute, the handler that is invoked is the one belonging to +the package to which it is typed. For example, the following declarations: +.PP +.Vb 1 +\& package OtherClass; +\& +\& my LoudDecl $loudobj : Loud; +\& my LoudDecl @loudobjs : Loud; +\& my LoudDecl %loudobjex : Loud; +.Ve +.PP +causes the LoudDecl::Loud handler to be invoked (even if OtherClass also +defines a handler for \f(CW\*(C`:Loud\*(C'\fR attributes). +.SS "Type-specific attribute handlers" +.IX Subsection "Type-specific attribute handlers" +If an attribute handler is declared and the \f(CW\*(C`:ATTR\*(C'\fR specifier is +given the name of a built-in type (\f(CW\*(C`SCALAR\*(C'\fR, \f(CW\*(C`ARRAY\*(C'\fR, \f(CW\*(C`HASH\*(C'\fR, or \f(CW\*(C`CODE\*(C'\fR), +the handler is only applied to declarations of that type. For example, +the following definition: +.PP +.Vb 1 +\& package LoudDecl; +\& +\& sub RealLoud :ATTR(SCALAR) { print "Yeeeeow!" } +.Ve +.PP +creates an attribute handler that applies only to scalars: +.PP +.Vb 2 +\& package Painful; +\& use base LoudDecl; +\& +\& my $metal : RealLoud; # invokes &LoudDecl::RealLoud +\& my @metal : RealLoud; # error: unknown attribute +\& my %metal : RealLoud; # error: unknown attribute +\& sub metal : RealLoud {...} # error: unknown attribute +.Ve +.PP +You can, of course, declare separate handlers for these types as well +(but you'll need to specify \f(CW\*(C`no warnings \*(Aqredefine\*(Aq\*(C'\fR to do it quietly): +.PP +.Vb 3 +\& package LoudDecl; +\& use Attribute::Handlers; +\& no warnings \*(Aqredefine\*(Aq; +\& +\& sub RealLoud :ATTR(SCALAR) { print "Yeeeeow!" } +\& sub RealLoud :ATTR(ARRAY) { print "Urrrrrrrrrr!" } +\& sub RealLoud :ATTR(HASH) { print "Arrrrrgggghhhhhh!" } +\& sub RealLoud :ATTR(CODE) { croak "Real loud sub torpedoed" } +.Ve +.PP +You can also explicitly indicate that a single handler is meant to be +used for all types of referents like so: +.PP +.Vb 2 +\& package LoudDecl; +\& use Attribute::Handlers; +\& +\& sub SeriousLoud :ATTR(ANY) { warn "Hearing loss imminent" } +.Ve +.PP +(I.e. \f(CWATTR(ANY)\fR is a synonym for \f(CW\*(C`:ATTR\*(C'\fR). +.SS "Non-interpretive attribute handlers" +.IX Subsection "Non-interpretive attribute handlers" +Occasionally the strenuous efforts Attribute::Handlers makes to convert +the data argument (\f(CW$_[4]\fR) to a usable form before passing it to +the handler get in the way. +.PP +You can turn off that eagerness-to-help by declaring +an attribute handler with the keyword \f(CW\*(C`RAWDATA\*(C'\fR. For example: +.PP +.Vb 3 +\& sub Raw : ATTR(RAWDATA) {...} +\& sub Nekkid : ATTR(SCALAR,RAWDATA) {...} +\& sub Au::Naturale : ATTR(RAWDATA,ANY) {...} +.Ve +.PP +Then the handler makes absolutely no attempt to interpret the data it +receives and simply passes it as a string: +.PP +.Vb 1 +\& my $power : Raw(1..100); # handlers receives "1..100" +.Ve +.SS "Phase-specific attribute handlers" +.IX Subsection "Phase-specific attribute handlers" +By default, attribute handlers are called at the end of the compilation +phase (in a \f(CW\*(C`CHECK\*(C'\fR block). This seems to be optimal in most cases because +most things that can be defined are defined by that point but nothing has +been executed. +.PP +However, it is possible to set up attribute handlers that are called at +other points in the program's compilation or execution, by explicitly +stating the phase (or phases) in which you wish the attribute handler to +be called. For example: +.PP +.Vb 5 +\& sub Early :ATTR(SCALAR,BEGIN) {...} +\& sub Normal :ATTR(SCALAR,CHECK) {...} +\& sub Late :ATTR(SCALAR,INIT) {...} +\& sub Final :ATTR(SCALAR,END) {...} +\& sub Bookends :ATTR(SCALAR,BEGIN,END) {...} +.Ve +.PP +As the last example indicates, a handler may be set up to be (re)called in +two or more phases. The phase name is passed as the handler's final argument. +.PP +Note that attribute handlers that are scheduled for the \f(CW\*(C`BEGIN\*(C'\fR phase +are handled as soon as the attribute is detected (i.e. before any +subsequently defined \f(CW\*(C`BEGIN\*(C'\fR blocks are executed). +.ie n .SS "Attributes as ""tie"" interfaces" +.el .SS "Attributes as \f(CWtie\fP interfaces" +.IX Subsection "Attributes as tie interfaces" +Attributes make an excellent and intuitive interface through which to tie +variables. For example: +.PP +.Vb 2 +\& use Attribute::Handlers; +\& use Tie::Cycle; +\& +\& sub UNIVERSAL::Cycle : ATTR(SCALAR) { +\& my ($package, $symbol, $referent, $attr, $data, $phase) = @_; +\& $data = [ $data ] unless ref $data eq \*(AqARRAY\*(Aq; +\& tie $$referent, \*(AqTie::Cycle\*(Aq, $data; +\& } +\& +\& # and thereafter... +\& +\& package main; +\& +\& my $next : Cycle(\*(AqA\*(Aq..\*(AqZ\*(Aq); # $next is now a tied variable +\& +\& while (<>) { +\& print $next; +\& } +.Ve +.PP +Note that, because the \f(CW\*(C`Cycle\*(C'\fR attribute receives its arguments in the +\&\f(CW$data\fR variable, if the attribute is given a list of arguments, \f(CW$data\fR +will consist of a single array reference; otherwise, it will consist of the +single argument directly. Since Tie::Cycle requires its cycling values to +be passed as an array reference, this means that we need to wrap +non-array-reference arguments in an array constructor: +.PP +.Vb 1 +\& $data = [ $data ] unless ref $data eq \*(AqARRAY\*(Aq; +.Ve +.PP +Typically, however, things are the other way around: the tieable class expects +its arguments as a flattened list, so the attribute looks like: +.PP +.Vb 5 +\& sub UNIVERSAL::Cycle : ATTR(SCALAR) { +\& my ($package, $symbol, $referent, $attr, $data, $phase) = @_; +\& my @data = ref $data eq \*(AqARRAY\*(Aq ? @$data : $data; +\& tie $$referent, \*(AqTie::Whatever\*(Aq, @data; +\& } +.Ve +.PP +This software pattern is so widely applicable that Attribute::Handlers +provides a way to automate it: specifying \f(CW\*(Aqautotie\*(Aq\fR in the +\&\f(CW\*(C`use Attribute::Handlers\*(C'\fR statement. So, the cycling example, +could also be written: +.PP +.Vb 1 +\& use Attribute::Handlers autotie => { Cycle => \*(AqTie::Cycle\*(Aq }; +\& +\& # and thereafter... +\& +\& package main; +\& +\& my $next : Cycle([\*(AqA\*(Aq..\*(AqZ\*(Aq]); # $next is now a tied variable +\& +\& while (<>) { +\& print $next; +\& } +.Ve +.PP +Note that we now have to pass the cycling values as an array reference, +since the \f(CW\*(C`autotie\*(C'\fR mechanism passes \f(CW\*(C`tie\*(C'\fR a list of arguments as a list +(as in the Tie::Whatever example), \fInot\fR as an array reference (as in +the original Tie::Cycle example at the start of this section). +.PP +The argument after \f(CW\*(Aqautotie\*(Aq\fR is a reference to a hash in which each key is +the name of an attribute to be created, and each value is the class to which +variables ascribed that attribute should be tied. +.PP +Note that there is no longer any need to import the Tie::Cycle module \-\- +Attribute::Handlers takes care of that automagically. You can even pass +arguments to the module's \f(CW\*(C`import\*(C'\fR subroutine, by appending them to the +class name. For example: +.PP +.Vb 2 +\& use Attribute::Handlers +\& autotie => { Dir => \*(AqTie::Dir qw(DIR_UNLINK)\*(Aq }; +.Ve +.PP +If the attribute name is unqualified, the attribute is installed in the +current package. Otherwise it is installed in the qualifier's package: +.PP +.Vb 1 +\& package Here; +\& +\& use Attribute::Handlers autotie => { +\& Other::Good => Tie::SecureHash, # tie attr installed in Other:: +\& Bad => Tie::Taxes, # tie attr installed in Here:: +\& UNIVERSAL::Ugly => Software::Patent # tie attr installed everywhere +\& }; +.Ve +.PP +Autoties are most commonly used in the module to which they actually tie, +and need to export their attributes to any module that calls them. To +facilitate this, Attribute::Handlers recognizes a special "pseudo-class" \-\- +\&\f(CW\*(C`_\|_CALLER_\|_\*(C'\fR, which may be specified as the qualifier of an attribute: +.PP +.Vb 1 +\& package Tie::Me::Kangaroo::Down::Sport; +\& +\& use Attribute::Handlers autotie => +\& { \*(Aq_\|_CALLER_\|_::Roo\*(Aq => _\|_PACKAGE_\|_ }; +.Ve +.PP +This causes Attribute::Handlers to define the \f(CW\*(C`Roo\*(C'\fR attribute in the package +that imports the Tie::Me::Kangaroo::Down::Sport module. +.PP +Note that it is important to quote the _\|_CALLER_\|_::Roo identifier because +a bug in perl 5.8 will refuse to parse it and cause an unknown error. +.PP +\fIPassing the tied object to \fR\f(CI\*(C`tie\*(C'\fR +.IX Subsection "Passing the tied object to tie" +.PP +Occasionally it is important to pass a reference to the object being tied +to the TIESCALAR, TIEHASH, etc. that ties it. +.PP +The \f(CW\*(C`autotie\*(C'\fR mechanism supports this too. The following code: +.PP +.Vb 2 +\& use Attribute::Handlers autotieref => { Selfish => Tie::Selfish }; +\& my $var : Selfish(@args); +.Ve +.PP +has the same effect as: +.PP +.Vb 1 +\& tie my $var, \*(AqTie::Selfish\*(Aq, @args; +.Ve +.PP +But when \f(CW"autotieref"\fR is used instead of \f(CW"autotie"\fR: +.PP +.Vb 2 +\& use Attribute::Handlers autotieref => { Selfish => Tie::Selfish }; +\& my $var : Selfish(@args); +.Ve +.PP +the effect is to pass the \f(CW\*(C`tie\*(C'\fR call an extra reference to the variable +being tied: +.PP +.Vb 1 +\& tie my $var, \*(AqTie::Selfish\*(Aq, \e$var, @args; +.Ve +.SH EXAMPLES +.IX Header "EXAMPLES" +If the class shown in "SYNOPSIS" were placed in the MyClass.pm +module, then the following code: +.PP +.Vb 2 +\& package main; +\& use MyClass; +\& +\& my MyClass $slr :Good :Bad(1**1\-1) :Omni(\-vorous); +\& +\& package SomeOtherClass; +\& use base MyClass; +\& +\& sub tent { \*(Aqacle\*(Aq } +\& +\& sub fn :Ugly(sister) :Omni(\*(Aqpo\*(Aq,tent()) {...} +\& my @arr :Good :Omni(s/cie/nt/); +\& my %hsh :Good(q/bye/) :Omni(q/bus/); +.Ve +.PP +would cause the following handlers to be invoked: +.PP +.Vb 1 +\& # my MyClass $slr :Good :Bad(1**1\-1) :Omni(\-vorous); +\& +\& MyClass::Good:ATTR(SCALAR)( \*(AqMyClass\*(Aq, # class +\& \*(AqLEXICAL\*(Aq, # no typeglob +\& \e$slr, # referent +\& \*(AqGood\*(Aq, # attr name +\& undef # no attr data +\& \*(AqCHECK\*(Aq, # compiler phase +\& ); +\& +\& MyClass::Bad:ATTR(SCALAR)( \*(AqMyClass\*(Aq, # class +\& \*(AqLEXICAL\*(Aq, # no typeglob +\& \e$slr, # referent +\& \*(AqBad\*(Aq, # attr name +\& 0 # eval\*(Aqd attr data +\& \*(AqCHECK\*(Aq, # compiler phase +\& ); +\& +\& MyClass::Omni:ATTR(SCALAR)( \*(AqMyClass\*(Aq, # class +\& \*(AqLEXICAL\*(Aq, # no typeglob +\& \e$slr, # referent +\& \*(AqOmni\*(Aq, # attr name +\& \*(Aq\-vorous\*(Aq # eval\*(Aqd attr data +\& \*(AqCHECK\*(Aq, # compiler phase +\& ); +\& +\& +\& # sub fn :Ugly(sister) :Omni(\*(Aqpo\*(Aq,tent()) {...} +\& +\& MyClass::UGLY:ATTR(CODE)( \*(AqSomeOtherClass\*(Aq, # class +\& \e*SomeOtherClass::fn, # typeglob +\& \e&SomeOtherClass::fn, # referent +\& \*(AqUgly\*(Aq, # attr name +\& \*(Aqsister\*(Aq # eval\*(Aqd attr data +\& \*(AqCHECK\*(Aq, # compiler phase +\& ); +\& +\& MyClass::Omni:ATTR(CODE)( \*(AqSomeOtherClass\*(Aq, # class +\& \e*SomeOtherClass::fn, # typeglob +\& \e&SomeOtherClass::fn, # referent +\& \*(AqOmni\*(Aq, # attr name +\& [\*(Aqpo\*(Aq,\*(Aqacle\*(Aq] # eval\*(Aqd attr data +\& \*(AqCHECK\*(Aq, # compiler phase +\& ); +\& +\& +\& # my @arr :Good :Omni(s/cie/nt/); +\& +\& MyClass::Good:ATTR(ARRAY)( \*(AqSomeOtherClass\*(Aq, # class +\& \*(AqLEXICAL\*(Aq, # no typeglob +\& \e@arr, # referent +\& \*(AqGood\*(Aq, # attr name +\& undef # no attr data +\& \*(AqCHECK\*(Aq, # compiler phase +\& ); +\& +\& MyClass::Omni:ATTR(ARRAY)( \*(AqSomeOtherClass\*(Aq, # class +\& \*(AqLEXICAL\*(Aq, # no typeglob +\& \e@arr, # referent +\& \*(AqOmni\*(Aq, # attr name +\& "" # eval\*(Aqd attr data +\& \*(AqCHECK\*(Aq, # compiler phase +\& ); +\& +\& +\& # my %hsh :Good(q/bye) :Omni(q/bus/); +\& +\& MyClass::Good:ATTR(HASH)( \*(AqSomeOtherClass\*(Aq, # class +\& \*(AqLEXICAL\*(Aq, # no typeglob +\& \e%hsh, # referent +\& \*(AqGood\*(Aq, # attr name +\& \*(Aqq/bye\*(Aq # raw attr data +\& \*(AqCHECK\*(Aq, # compiler phase +\& ); +\& +\& MyClass::Omni:ATTR(HASH)( \*(AqSomeOtherClass\*(Aq, # class +\& \*(AqLEXICAL\*(Aq, # no typeglob +\& \e%hsh, # referent +\& \*(AqOmni\*(Aq, # attr name +\& \*(Aqbus\*(Aq # eval\*(Aqd attr data +\& \*(AqCHECK\*(Aq, # compiler phase +\& ); +.Ve +.PP +Installing handlers into UNIVERSAL, makes them...err..universal. +For example: +.PP +.Vb 2 +\& package Descriptions; +\& use Attribute::Handlers; +\& +\& my %name; +\& sub name { return $name{$_[2]}||*{$_[1]}{NAME} } +\& +\& sub UNIVERSAL::Name :ATTR { +\& $name{$_[2]} = $_[4]; +\& } +\& +\& sub UNIVERSAL::Purpose :ATTR { +\& print STDERR "Purpose of ", &name, " is $_[4]\en"; +\& } +\& +\& sub UNIVERSAL::Unit :ATTR { +\& print STDERR &name, " measured in $_[4]\en"; +\& } +.Ve +.PP +Let's you write: +.PP +.Vb 1 +\& use Descriptions; +\& +\& my $capacity : Name(capacity) +\& : Purpose(to store max storage capacity for files) +\& : Unit(Gb); +\& +\& +\& package Other; +\& +\& sub foo : Purpose(to foo all data before barring it) { } +\& +\& # etc. +.Ve +.SH "UTILITY FUNCTIONS" +.IX Header "UTILITY FUNCTIONS" +This module offers a single utility function, \f(CWfindsym()\fR. +.IP findsym 4 +.IX Item "findsym" +.Vb 1 +\& my $symbol = Attribute::Handlers::findsym($package, $referent); +.Ve +.Sp +The function looks in the symbol table of \f(CW$package\fR for the typeglob for +\&\f(CW$referent\fR, which is a reference to a variable or subroutine (SCALAR, ARRAY, +HASH, or CODE). If it finds the typeglob, it returns it. Otherwise, it returns +undef. Note that \f(CW\*(C`findsym\*(C'\fR memoizes the typeglobs it has previously +successfully found, so subsequent calls with the same arguments should be +much faster. +.SH DIAGNOSTICS +.IX Header "DIAGNOSTICS" +.ie n .IP """Bad attribute type: ATTR(%s)""" 4 +.el .IP "\f(CWBad attribute type: ATTR(%s)\fR" 4 +.IX Item "Bad attribute type: ATTR(%s)" +An attribute handler was specified with an \f(CW:ATTR(\fR\f(CIref_type\fR\f(CW)\fR, but the +type of referent it was defined to handle wasn't one of the five permitted: +\&\f(CW\*(C`SCALAR\*(C'\fR, \f(CW\*(C`ARRAY\*(C'\fR, \f(CW\*(C`HASH\*(C'\fR, \f(CW\*(C`CODE\*(C'\fR, or \f(CW\*(C`ANY\*(C'\fR. +.ie n .IP """Attribute handler %s doesn\*(Aqt handle %s attributes""" 4 +.el .IP "\f(CWAttribute handler %s doesn\*(Aqt handle %s attributes\fR" 4 +.IX Item "Attribute handler %s doesnt handle %s attributes" +A handler for attributes of the specified name \fIwas\fR defined, but not +for the specified type of declaration. Typically encountered when trying +to apply a \f(CW\*(C`VAR\*(C'\fR attribute handler to a subroutine, or a \f(CW\*(C`SCALAR\*(C'\fR +attribute handler to some other type of variable. +.ie n .IP """Declaration of %s attribute in package %s may clash with future reserved word""" 4 +.el .IP "\f(CWDeclaration of %s attribute in package %s may clash with future reserved word\fR" 4 +.IX Item "Declaration of %s attribute in package %s may clash with future reserved word" +A handler for an attributes with an all-lowercase name was declared. An +attribute with an all-lowercase name might have a meaning to Perl +itself some day, even though most don't yet. Use a mixed-case attribute +name, instead. +.ie n .IP """Can\*(Aqt have two ATTR specifiers on one subroutine""" 4 +.el .IP "\f(CWCan\*(Aqt have two ATTR specifiers on one subroutine\fR" 4 +.IX Item "Cant have two ATTR specifiers on one subroutine" +You just can't, okay? +Instead, put all the specifications together with commas between them +in a single \f(CWATTR(\fR\f(CIspecification\fR\f(CW)\fR. +.ie n .IP """Can\*(Aqt autotie a %s""" 4 +.el .IP "\f(CWCan\*(Aqt autotie a %s\fR" 4 +.IX Item "Cant autotie a %s" +You can only declare autoties for types \f(CW"SCALAR"\fR, \f(CW"ARRAY"\fR, and +\&\f(CW"HASH"\fR. They're the only things (apart from typeglobs \-\- which are +not declarable) that Perl can tie. +.ie n .IP """Internal error: %s symbol went missing""" 4 +.el .IP "\f(CWInternal error: %s symbol went missing\fR" 4 +.IX Item "Internal error: %s symbol went missing" +Something is rotten in the state of the program. An attributed +subroutine ceased to exist between the point it was declared and the point +at which its attribute handler(s) would have been called. +.ie n .IP """Won\*(Aqt be able to apply END handler""" 4 +.el .IP "\f(CWWon\*(Aqt be able to apply END handler\fR" 4 +.IX Item "Wont be able to apply END handler" +You have defined an END handler for an attribute that is being applied +to a lexical variable. Since the variable may not be available during END +this won't happen. +.SH AUTHOR +.IX Header "AUTHOR" +Damian Conway (damian@conway.org). The maintainer of this module is now Rafael +Garcia-Suarez (rgarciasuarez@gmail.com). +.PP +Maintainer of the CPAN release is Steffen Mueller (smueller@cpan.org). +Contact him with technical difficulties with respect to the packaging of the +CPAN module. +.SH BUGS +.IX Header "BUGS" +There are undoubtedly serious bugs lurking somewhere in code this funky :\-) +Bug reports and other feedback are most welcome. +.SH "COPYRIGHT AND LICENSE" +.IX Header "COPYRIGHT AND LICENSE" +.Vb 3 +\& Copyright (c) 2001\-2014, Damian Conway. All Rights Reserved. +\& This module is free software. It may be used, redistributed +\& and/or modified under the same terms as Perl itself. +.Ve |