Beefy Boxes and Bandwidth Generously Provided by pair Networks
more useful options
 
PerlMonks  

Core module: Attribute::Handlers behaviour

by enigma (Novice)
on Oct 20, 2012 at 06:24 UTC ( #1000101=perlquestion: print w/ replies, xml ) Need Help??
enigma has asked for the wisdom of the Perl Monks concerning the following question:

Hello perlmonks,

Aim: To start tracing of the module flow in my project once execution started based on user choice.

Description: When user wants to see the trace of the module file he/she enable the traceing just by setting the trace parameter to TRUE in project configuration file (before starting the execution).

Solution: Tried Core module: use Attribute::Handlers;

Flow: Once the execution started it first check the trace parameter value and if it is TRUE then it reads the module file and changes the subroutine with sub foo: TRACE {...} and adds the Core module "Attribute::Handlers" as shown above.

Once the new module is generated, then we try to load it dynamically - eval "use module_name;";

Result: module_name module gets loaded successfully and i can call its subroutines, but those subroutines shows normal behaviour i.e. it is not using sub TRACE: ATTR {...} present in the module.

Validated: I tried to load the new modifiled module using static loading,like ... use module_name; It is loading successfully and using the TRACE sub for ATTR.

I need your help here to understand this behaviour change in core module when using with eval i.e. loading dynamically. Please let me know how i can make it correct without changing the design of the code.

Thanks.

Comment on Core module: Attribute::Handlers behaviour
Select or Download Code
Re: Core module: Attribute::Handlers behaviour
by Anonymous Monk on Oct 20, 2012 at 06:34 UTC

    use constant, don't use attributes to control tracing

    Also, post an example of what you're talking about

      Thanks for quick response.

      In my openion use constant; is a good solution for debug/info/error msgs. But if we are talking about tracing ...

      it is like in log file ...

      [<date_time>] TRACE: entering sub for ... [<date_time>] TRACE: parameters passed ... [<date_time>] TRACE: exiting sub for ...

      as core module add attribute features during compilation only, there is less performance issue...less cluttering in your code. as compared to explicitly writing entry/exit for each module.

        Sounds like a cool and effective use of attributes to me. But still, you are more likely to get help with the problem if you supply code people can try.


        With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.

        RIP Neil Armstrong

Re: Core module: Attribute::Handlers behaviour
by moritz (Cardinal) on Oct 20, 2012 at 07:11 UTC
    As a clarification, if you write
    use Attribute::Handlers; sub TRACE :ATTR(CODE) { ... }

    Then your sub TRACE will be called once if you write

    sub mysub :TRACE { }

    but it will not be called for each call of mysub.

    So to achieve what you want, you have to write your TRACE function in a way that, if the appropriate configuration option is set, it wraps the function in a way that makes the tracing happen. Maybe Hook::LexWrap can be helpful for that purpose.

Re: Core module: Attribute::Handlers behaviour
by tobyink (Abbot) on Oct 20, 2012 at 13:58 UTC

    Perl attributes are typically handled at CHECK time - between compile time (BEGIN) and INIT time, and way before run time. Your eval happens at run time, so too late to effect attribute processing.

    It is in fact possible to alter when processing happens for particular attributes, but it needs to be one of the compilation phases (BEGIN, CHECK, INIT or END), and not runtime.

    * * *

    As it happens I've been working on some aspect-oriented programming stuff for Moose that might be just what you need.

    { package User; use Moose; has name => (is => 'ro', isa => 'Str'); sub login { my $self = shift; print $self->name, " is logged in\n"; } } { package Tracing; use MooseX::Aspect; my $aspect = __PACKAGE__; sub log_msg { my $class = shift; print STDERR "TRACE: $_\n" for @_; } apply_to 'User' => role { before login => sub { my $self = shift; $aspect->log_msg($self->name . " attempted to log in"); }; }; } # try setting tracing to 0 :-) my $config = { tracing => 1 }; if ($config->{tracing}) { Tracing->setup; } my $bob = User->new( name => 'Bob' ); $bob->login;

    Packages of interest: Moose, MooseX::Aspect, Sub::Talisman and MooseX::ModifyTaggedMethods.

    MooseX::Aspect is still at a very early stage of development, and bugs abound. But I think it shows quite a bit of promise for doing this sort of thing.

    perl -E'sub Monkey::do{say$_,for@_,do{($monkey=[caller(0)]->[3])=~s{::}{ }and$monkey}}"Monkey say"->Monkey::do'
      Perl attributes are typically handled at CHECK time - between compile time (BEGIN) and INIT time, and way before run time. Your eval happens at run time, so too late to effect attribute processing.

      Hm. That doesn't ring true.

      Just because it is the main scripts runtime, doesn't prevent the eval use'd script from having its own BEGIN & END times. After all, it still has to be compiled.

      Given junk.pm:

      package junk; sub BEGIN { printf "Hi from %s BEGIN\n", __PACKAGE__ } sub CHECK { printf "Hi from %s CHECK\n", __PACKAGE__ } sub INIT { printf "Hi from %s INIT\n", __PACKAGE__ } sub END { printf "Hi from %s END\n", __PACKAGE__ } 1;

      This script that eval's it into being:

      #! perl -slw use strict; print "Main runtime: About to eval use junk"; <STDIN>; eval "use junk"; print "Main runtime: Just eval'd use junk"; <STDIN>;

      I get:

      C:\test>junk Main runtime: About to eval use junk Hi from junk BEGIN Too late to run CHECK block at junk.pm line 4, <STDIN> line 1. Too late to run INIT block at junk.pm line 5, <STDIN> line 1. Main runtime: Just eval'd use junk Hi from junk END

      So, if the attribute handling can be done at BEGIN time, then it is quite simple to wrap the attributed function over in a wrapper that did the tracing,

      Tweak junk.pm above to be::

      package junk; use Attribute::Handlers; no warnings 'redefine'; sub TRACE : ATTR(CODE,BEGIN) { my ($pkg, $sym, $ref, $attr, $data, $phase, $file, $line) = @_; *{ $sym } = sub { warn "$file($line) called with [@_]\n"; my( @rc )= &$ref; warn "$file($line): returning [ @rc ]\n"; } } sub doStuff :TRACE { print "junk::doStuff says hi"; } 1;

      And main to be:

      #! perl -slw use strict; print "Main runtime: About to eval use junk"; <STDIN>; eval "use junk"; print "Main runtime: Just eval'd use junk; calling doStuff()"; <STDIN> +; junk::doStuff( 1..10 );

      And you get:

      C:\test>junk Main runtime: About to eval use junk Main runtime: Just eval'd use junk; calling doStuff() junk.pm(16) called with [1 2 3 4 5 6 7 8 9 10] junk::doStuff says hi junk.pm(16): returning [ 1 ]

      which is kind of cool. (Shame the function name isn't provided to the attribute handler.)

      It'd be better if installing the TRACE attr into UNIVERSAL would then apply the wrappers to runtime loaded modules; and better yet if you you could use a "trace handler" package once in main and have it apply itself everywhere.


      With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      "Science is about questioning the status quo. Questioning authority".
      In the absence of evidence, opinion is indistinguishable from prejudice.

      RIP Neil Armstrong

      @_

        "Just because it is the main scripts runtime, doesn't prevent the eval use'd script from having its own BEGIN & END times. After all, it still has to be compiled."

        Naturally. But it was my reading of the OP that he wanted to be able to apply the attributes defined in the eval-use'd script to subs defined in its caller, which would have already finished compiling. Of course, I may have misinterpreted.

        "Shame the function name isn't provided to the attribute handler."

        That's why god invented Sub::Identify ;-)

        1066 and all that
Re: Core module: Attribute::Handlers behaviour
by enigma (Novice) on Oct 21, 2012 at 10:11 UTC

    Hello PerlMonks,

    I understand the trick "BrowserUk" has suggested. I tried to implement the same as below but it is always giving me error as

    Can't locate object method "new" via package "Module"

    Module.pm

    package Module; use Attribute::Handlers; sub TRACE :ATTR(CODE,BEGIN) { my ($pkg, $sym, $ref, $attr, $data, $phase, $file, $line) = @_; *{ $sym } = sub { warn "$file($line) called with [@_]\n"; my( @rc )= &$ref; warn "$file($line): returning [ @rc ]\n"; } } sub new :TRACE{ my $instance = shift; my $class = ref($instance) || $instance; my $self = {}; return bless($self, $class); } 1;

    Test.pl

    #!/usr/local/bin/perl my $module_to_load = 'Module'; eval "use $module_to_load;"; # Create object my $obj = Module->new(); print "CLASS: " . ref($obj) ."\n";

    When i'm changing the execution phase in ATTR to INIT,CHECK - module gets compiled successfully but ATTR TRACE is not called. And when i change the phase to BEGIN, I'm getting the above error message.

    I need your help to understand why my Test.pl is not able to find "new()" method in Module.pm when Attribute::Handers are called at BEGIN phase.

    Thanks

      I don't get that, even though your module doesn't return an object ( compared to Attribute::Constructor ), trace gets called if the phase is BEGIN

      $ perl -le " eval qq/use Junk;/; print Junk->new " Junk.pm(22) called with [Junk] Junk.pm(22): returning [ Junk=HASH(0x3f8d1c) ] 1 $ cat Junk.pm package Junk; use Attribute::Handlers; #~ sub TRACE :ATTR(CODE,CHECK) { #~ sub TRACE :ATTR(CODE,INIT,CHECK) { #~ sub TRACE :ATTR(CODE,INIT) { sub TRACE :ATTR(CODE,BEGIN) { #~ sub TRACE :ATTR(CODE) { my ($pkg, $sym, $ref, $attr, $data, $phase, $file, $line) = @_; *{ $sym } = sub { warn "$file($line) called with [@_]\n"; my( @rc )= &$ref; warn "$file($line): returning [ @rc ]\n"; } } sub new :TRACE { my $instance = shift; my $class = ref($instance) || $instance; my $self = {}; return bless($self, $class); } 1;
Re: Core module: Attribute::Handlers behaviour
by enigma (Novice) on Oct 21, 2012 at 11:43 UTC

    Even I'm not getting, why it is not working for "Test 4" ...

    Module.pm

    package Module; use strict; use warnings; use Attribute::Handlers; #sub TRACE :ATTR(CODE) { # Test 1 #sub TRACE :ATTR(CODE,INIT) { # Test 2 #sub TRACE :ATTR(CODE,CHECK) { # Test 3 sub TRACE :ATTR(CODE,BEGIN) { # Test 4 my ($pkg, $sym, $ref, $attr, $data, $phase, $file, $line) = @_; *{ $sym } = sub { warn "$file($line) called with [@_]\n"; my( @rc )= &$ref; warn "$file($line): returning [ @rc ]\n"; } } sub new :TRACE{ my $instance = shift; my $class = ref($instance) || $instance; my $self = {}; return bless($self, $class); } END { } 1; __END__

    Test.pl

    #!/usr/local/bin/perl use strict; use warnings; my $module_to_load = 'Module'; eval "use $module_to_load;"; # Create object my $obj = Module->new(); print "REF: " . ref($obj) ."\n";

    Results: Test 1: Code compiles and executes, but without ATTR support.

    Test 2: Code compiles and executes, but without ATTR support.

    Test 3: Code compiles and executes, but without ATTR support.

    Test 4: Code throws and error msg as - Can't locate object method "new" via package "Module" at ./Test.pl line 10.

    perl version: This is perl, v5.8.5 built for i386-linux-thread-multi

    OS version: Linux <host> 2.6.9-67.EL #1 Wed Nov 7 13:41:13 EST 2007 i686 i686 i386 GNU/Linux

    Thanks

Re: Core module: Attribute::Handlers behaviour
by enigma (Novice) on Oct 21, 2012 at 12:36 UTC

    There was two issues that I have found.

    1. I need to use ...no strict 'refs';

    2. Dump of args passed to ATTR is -

    $VAR1 = 'Module'; $VAR2 = 'ANON'; $VAR3 = sub { "DUMMY" }; $VAR4 = 'TRACE'; $VAR5 = undef; $VAR6 = 'BEGIN';

    ...

    Why it is taking "new()" as anonymous subroutine?

    I think because of this only *{$_[1]} is not getting replaced with other sub... Please advise

    Thanks

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1000101]
Approved by moritz
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others rifling through the Monastery: (7)
As of 2014-12-27 13:09 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    Is guessing a good strategy for surviving in the IT business?





    Results (177 votes), past polls