📄 attribute::handlers.3
字号:
the line number in this file..PPLikewise, declaring any variables with the \f(CW\*(C`:Loud\*(C'\fR attribute within thepackage:.PP.Vb 1\& package LoudDecl;\&\& my $foo :Loud;\& my @foo :Loud;\& my %foo :Loud;.Ve.PPwill 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)..PPThe package name argument will typically be the name of the class intowhich the subroutine was declared, but it may also be the name of a derivedclass (since handlers are inherited)..PPIf 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 thestring \f(CW\*(AqLEXICAL\*(Aq\fR in that case. Likewise, ascribing an attribute toan anonymous subroutine results in a symbol table argument of \f(CW\*(AqANON\*(Aq\fR..PPThe data argument passes in the value (if any) associated with theattribute. For example, if \f(CW&foo\fR had been declared:.PP.Vb 1\& sub foo :Loud("turn it up to 11, man!") {...}.Ve.PPthen a reference to an array containing the string\&\f(CW"turn it up to 11, man!"\fR would be passed as the last argument..PPAttribute::Handlers makes strenuous efforts to convertthe data argument (\f(CW$_[4]\fR) to a useable form before passing it tothe handler (but see \*(L"Non-interpretive attribute handlers\*(R").If those efforts succeed, the interpreted data is passed in an arrayreference; 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/my, ears, are, bleeding/) {...}\& sub foo :Loud(till,ears,are,bleeding) {...}.Ve.PPcauses it to pass \f(CW\*(C`[\*(Aqtill\*(Aq,\*(Aqears\*(Aq,\*(Aqare\*(Aq,\*(Aqbleeding\*(Aq]\*(C'\fR as the handler'sdata argument. While:.PP.Vb 1\& sub foo :Loud([\*(Aqtill\*(Aq,\*(Aqears\*(Aq,\*(Aqare\*(Aq,\*(Aqbleeding\*(Aq]) {...}.Ve.PPcauses it to pass \f(CW\*(C`[ [\*(Aqtill\*(Aq,\*(Aqears\*(Aq,\*(Aqare\*(Aq,\*(Aqbleeding\*(Aq] ]\*(C'\fR; the arrayreference specified in the data being passed inside the standardarray reference indicating successful interpretation..PPHowever, if the data can't be parsed as valid Perl, thenit 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.PPcause 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 thedata argument..PPIf no value is associated with the attribute, \f(CW\*(C`undef\*(C'\fR is passed..Sh "Typed lexicals".IX Subsection "Typed lexicals"Regardless of the package in which it is declared, if a lexical variable isascribed an attribute, the handler that is invoked is the one belonging tothe 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.PPcauses the LoudDecl::Loud handler to be invoked (even if OtherClass alsodefines a handler for \f(CW\*(C`:Loud\*(C'\fR attributes)..Sh "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 isgiven 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.PPcreates 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.PPYou 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.PPYou can also explicitly indicate that a single handler is meant to beused 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(CW\*(C`ATTR(ANY)\*(C'\fR is a synonym for \f(CW\*(C`:ATTR\*(C'\fR)..Sh "Non-interpretive attribute handlers".IX Subsection "Non-interpretive attribute handlers"Occasionally the strenuous efforts Attribute::Handlers makes to convertthe data argument (\f(CW$_[4]\fR) to a useable form before passing it tothe handler get in the way..PPYou can turn off that eagerness-to-help by declaringan 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.PPThen the handler makes absolutely no attempt to interpret the data itreceives and simply passes it as a string:.PP.Vb 1\& my $power : Raw(1..100); # handlers receives "1..100".Ve.Sh "Phase-specific attribute handlers".IX Subsection "Phase-specific attribute handlers"By default, attribute handlers are called at the end of the compilationphase (in a \f(CW\*(C`CHECK\*(C'\fR block). This seems to be optimal in most cases becausemost things that can be defined are defined by that point but nothing hasbeen executed..PPHowever, it is possible to set up attribute handlers that are called atother points in the program's compilation or execution, by explicitlystating the phase (or phases) in which you wish the attribute handler tobe 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.PPAs the last example indicates, a handler may be set up to be (re)called intwo or more phases. The phase name is passed as the handler's final argument..PPNote that attribute handlers that are scheduled for the \f(CW\*(C`BEGIN\*(C'\fR phaseare handled as soon as the attribute is detected (i.e. before anysubsequently defined \f(CW\*(C`BEGIN\*(C'\fR blocks are executed)..ie n .Sh "Attributes as ""tie"" interfaces".el .Sh "Attributes as \f(CWtie\fP interfaces".IX Subsection "Attributes as tie interfaces"Attributes make an excellent and intuitive interface through which to tievariables. 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.PPNote 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\fRwill consist of a single array reference; otherwise, it will consist of thesingle argument directly. Since Tie::Cycle requires its cycling values tobe passed as an array reference, this means that we need to wrapnon-array-reference arguments in an array constructor:.PP.Vb 1\& $data = [ $data ] unless ref $data eq \*(AqARRAY\*(Aq;.Ve.PPTypically, however, things are the other way around: the tieable class expectsits 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.PPThis software pattern is so widely applicable that Attribute::Handlersprovides 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.PPNote 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 inthe original Tie::Cycle example at the start of this section)..PPThe argument after \f(CW\*(Aqautotie\*(Aq\fR is a reference to a hash in which each key isthe name of an attribute to be created, and each value is the class to whichvariables ascribed that attribute should be tied..PPNote that there is no longer any need to import the Tie::Cycle module \*(--Attribute::Handlers takes care of that automagically. You can even passarguments to the module's \f(CW\*(C`import\*(C'\fR subroutine, by appending them to theclass name. For example:.PP.Vb 2\& use Attribute::Handlers\& autotie => { Dir => \*(AqTie::Dir qw(DIR_UNLINK)\*(Aq };.Ve.PP
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -