Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things
 
PerlMonks  

comment on

( [id://3333]=superdoc: print w/replies, xml ) Need Help??
I don't think so, not in a general way.According to the Perl documentation on attributes, attribute::get calls a per-package routine FETCH_CODE_ATTRIBUTES to get code attributes for that package. As near as I can tell looking at the source code for Attribute::Handlers, this function is never defined when it processes the BEGIN, CHECK, etc blocks for each package. Hence, attribute::get has no way of knowing about the attributes you defined via Attribute::Handlers.

You could, of course, define the function yourself, except that you would have to patch the module code, hardly "easy". Attribute::Handlers stores all of its attribute definitions in a private-to-package my variable @aDeclarations. There is no way to get at this data except by working within the package itself, i.e. patching it.

You could explicitly push the attributes into your own array each time you define a routine, as shmem suggests, but then you have to define to your team (or the coder that comes after you) that this is the "pattern" for how we define these functions and either write it down somewhere (will anyone read it?) or make it part of team memory (how?). That isn't always reliable - someone is bound to forget, leading to hard to track down bugs. So it is difficult in a different way.

There is another important reason for encapsulating your handling of attributes in a module rather than explicitly defining a FETCH routine in each package. The interface for attribute handling, including the FETCH method is, to quote the perldocs:

WARNING: the mechanisms described here are still experimental. Do not rely on the current implementation.

Personally, I prefer solutions where the structure itself prevents human error and minimizes the impact of interface change, so I would go for a solution that encapsulates how Perl comes to understand your handlers exist and lets you define nothing other than attribute functionality in your attribute handlers. It turns out it is pretty easy and short (about 20-25 lines), if you make use of the current interface. That interface did not exist when Attribute::Handlers was first written in 2001, which is part of the reason it is so much longer.

First I would define a small module, let's call it Monks::AttributeDispatcher, to replace mod:://Attribute::Handlers. This module's use statement would accept a dispatch table as the parameters for its use clause and would manufacture the calling package's FETCH_CODE_ATTRIBUTES and MODIFY_CODE ATTRIBUTES methods. The code that used the module would look like this:

use strict; use warnings; #here's where you set up your attribute handlers use Monks::AttributeDispatcher Loud => sub { print "NOISY\n"; } , Boom => sub { print "BOOM\n"; } ; #here's where you show off your handlers sub foo: Loud method { print 1; } sub bar : Loud Boom method { print "pling.\n"; } print "Attributes: "; print join ', ', attributes::get(\&bar); print "\n";

The Monks::AttributeDispatcher module would look like this:

use strict; use warnings; package Monks::AttributeDispatcher; sub import { my $sPackage = shift @_; my %hDispatch = ( @_ ); print "caller=$caller dispatch=<@{[ %hDispatch ]}>\n"; my $sFetch = "${caller}::FETCH_CODE_ATTRIBUTES"; *{$sFetch} = sub { return keys %hDispatch; }; my $sModify = "${caller}::MODIFY_CODE_ATTRIBUTES"; *{$sModify} = sub { my $sPackage = shift @_; my $crSub = shift @_; foreach my $sAttribute (@_) { my $crAttribute = $hDispatch{$sAttribute}; #print STDERR "attribute=<$sAttribute> sub=<$crAttribute>\n"; &$crAttribute($sPackage, $crSub, $sAttribute) if defined($crAttribute); } return (); #indicate all attributes were handled } } return 1;

Note 1:Your handler gets three parameters: the name of the package where the subroutine is defined, the code reference of the subroutine, and the name of the attribute. This permits you to write context aware handlers, should you wish.

Note 2: If your subroutines are too complex to define in-line (or you want two attributes to share the same handler) you can always define the handler subroutines in a BEGIN {} block before your use Monks::Dispatcher statement.

The following code illustrates both notes 1&2:

use strict; use warnings; BEGIN { sub makeNoise { my ($sPackage, $crSub, $sAttribute) = @_; print "NOISY $sAttribute\n"; } } use Monks::AttributeDispatcher Lion => \&makeNoise , Tiger => \&makeNoise , Bear => \&makeNoise , Boom => sub { print "BOOM\n"; } ; sub foo: Boom { print 1; } sub bar : Lion Tiger Bear Boom { print "pling.\n"; }

Caveat 1: This version assumes you only care about subroutine attributes handlers since that was all you mentioned in your post. It would be relatively easy to modify it to have it emulate Attribute::Handlers's ability to selectively apply handlers to more than one type of object (SCALAR, CODE, etc). I would (a) replace the value of each hash element with a 2-element array reference indicate type and code reference. (b) revise the module to make use of that information. There are separate FETCH and MODIFY methods for each type of reference.

Caveat 2: I've been playing around with this some more and the one thing I can't seem to make Monks::AttributeDispatcher do is replace definition of function foo(...) with something else (I can,however, generate new functions that call foo(...).). Attribute::Handlers can do this easily because it gets the *name* of the subroutine rather than a code reference. MODIFY_CODE_ATTRIBUTES only gets the code reference. If there is a Perl trick to work around this, it is missing from my bag-o-tricks. If this is important to you and there is no work around, it looks to me like your only "non-intrusive" choice would be to patch Attribute::Handlers so that it generates the FETCH method.

Best, beth

Update: posted at the same time as shmem, added discussion of shmem's post.

Update 2: Added question about why using Attribute::Handlers.

Update 2:posted alternate to Attribute::Handlers - it is not nice to suggest one should make a patch without showing how.

Update 3:added second caveat.


In reply to Re: Support for attributes:get in Attribute::Handlers? by ELISHEVA
in thread Support for attributes:get in Attribute::Handlers? by Thilosophy

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post; it's "PerlMonks-approved HTML":



  • Are you posting in the right place? Check out Where do I post X? to know for sure.
  • Posts may use any of the Perl Monks Approved HTML tags. Currently these include the following:
    <code> <a> <b> <big> <blockquote> <br /> <dd> <dl> <dt> <em> <font> <h1> <h2> <h3> <h4> <h5> <h6> <hr /> <i> <li> <nbsp> <ol> <p> <small> <strike> <strong> <sub> <sup> <table> <td> <th> <tr> <tt> <u> <ul>
  • Snippets of code should be wrapped in <code> tags not <pre> tags. In fact, <pre> tags should generally be avoided. If they must be used, extreme care should be taken to ensure that their contents do not have long lines (<70 chars), in order to prevent horizontal scrolling (and possible janitor intervention).
  • Want more info? How to link or How to display code and escape characters are good places to start.
Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others having an uproarious good time at the Monastery: (5)
As of 2024-03-29 12:33 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found