Beefy Boxes and Bandwidth Generously Provided by pair Networks
Do you know where your variables are?
 
PerlMonks  

Calling an intermediate method

by trizen (Friar)
on Dec 18, 2013 at 23:28 UTC ( #1067740=perlquestion: print w/ replies, xml ) Need Help??
trizen has asked for the wisdom of the Perl Monks concerning the following question:

Hello,

Is it possible to, automatically, call some other method before calling the final method?

package Foo { sub new { bless [] }; sub msg { print "On my way to '%s'\n"; # name of the final method is op +tional } sub Berlin { print "I'm in Berlin!\n"; } sub Paris { print "I'm in Paris!\n"; } }; my $obj = Foo->new; $obj->Berlin(); # should go first in msg(), then in Berlin()

Thanks

Comment on Calling an intermediate method
Download Code
Re: Calling an intermediate method
by tobyink (Abbot) on Dec 18, 2013 at 23:45 UTC

    Not quite sure what you mean. Maybe like this?

    package Foo { sub new { bless [] }; sub msg { my $self = shift; printf "On my way to '%s'\n", @_; } sub Berlin { my $self = shift; $self->msg('Berlin'); print "I'm in Berlin!\n"; } sub Paris { my $self = shift; $self->msg('Paris'); print "I'm in Paris!\n"; } }; my $obj = Foo->new; $obj->Berlin();

    Or maybe you mean like this?

    package Foo { sub new { bless [] }; sub msg { my $self = shift; printf "On my way to '%s'\n", @_; } sub Berlin { my $self = shift; print "I'm in Berlin!\n"; } sub Paris { my $self = shift; print "I'm in Paris!\n"; } }; use Class::Method::Modifiers qw( install_modifier ); for my $city (qw/ Paris Berlin /) { install_modifier "Foo", before => $city => sub { my $self = shift; $self->msg($city); }; } my $obj = Foo->new; $obj->Berlin();
    use Moops; class Cow :rw { has name => (default => 'Ermintrude') }; say Cow->new->name

      Thank you very much. Class::Method::Modifiers does exactly what I want, but the bad thing is that you must know all the method names. I worked around this issue by using the special hash %PackageName::, but I really don't like this ugly fix. I looked briefly in the documentation of overload, but there doesn't seem to be any way to overload the method caller. Maybe, will come some day...

      use 5.014; package Foo { sub new { bless [] } use Class::Method::Modifiers qw(before); foreach my $method (keys %Foo::) { next if $method =~ /^(_|(?:BEGIN|new|before)\z)/; before $method => sub { my ($self) = @_; print "** Preparing...\n"; push @{$self}, 'money'; print "** Ready to continue...\n"; }; } sub Berlin { my $self = shift; print "> I'm in Berlin!\n"; } sub Paris { my $self = shift; print "> I'm in Paris!\n"; } }; my $obj = Foo->new; $obj->Berlin(); say "# Self contains: @{$obj}";

        Sub attributes provide a fairly nice alternative...

        use 5.014; package Foo { sub new { bless [] } use Attribute::Handlers; use Class::Method::Modifiers qw(before); sub City :ATTR { my $method = substr *{$_[1]}, 1; before $method => sub { my ($self) = @_; print "** Preparing...\n"; push @{$self}, 'money'; print "** Ready to continue...\n"; }; } sub Berlin :City { my $self = shift; print "> I'm in Berlin!\n"; } sub Paris :City { my $self = shift; print "> I'm in Paris!\n"; } }; my $obj = Foo->new; $obj->Berlin(); say "# Self contains: @{$obj}";
        use Moops; class Cow :rw { has name => (default => 'Ermintrude') }; say Cow->new->name
Re: Calling an intermediate method
by choroba (Abbot) on Dec 18, 2013 at 23:51 UTC
    You can use the before modifier, which comes with Moo and Moose:
    #!/usr/bin/perl use warnings; use strict; package Foo { use Moo; sub msg { printf "On my way to '%s'\n", shift; } sub Berlin { print "I'm in Berlin!\n"; } sub Paris { print "I'm in Paris!\n"; } for my $city (qw( Berlin Paris )) { before $city => sub { msg($city) }; } }; my $obj = Foo->new; $obj->Berlin(); # should go first in msg(), then in Berlin()
    لսႽ ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ
Re: Calling an intermediate method
by sundialsvc4 (Abbot) on Dec 19, 2013 at 00:27 UTC

    As far as I am aware, the only way to do this is to have the called-class (explicitly) invoke its superclass.   (Or, in the case at bar, both the Berlin and the Paris methods would have to explicitly call msg(), and if there were more than half-a-dozen of these I’d be declaring another class.)

    As far as I am aware, the (“unadorned” ...) Perl language does not provide for any sort of “implicit wrappers.”

Re: Calling an intermediate method
by AnomalousMonk (Abbot) on Dec 19, 2013 at 18:59 UTC

    The approaches of tobyink and choroba sound like they are what you want (and they're certainly more sophisticated than my approach), but would the following be useful?

    >perl -wMstrict -e "use 5.014; ;; package Foo { ;; sub new { bless [] }; ;; sub msg { my $self = shift; my ($destination) = @_; printf qq{On my way to '%s'. }, $destination; my $coderef = $self->can($destination); return print qq{Cannot get there. \n} unless $coderef; $self->$coderef($destination); } ;; sub Berlin { my $self = shift; print qq{I am in $_[0]! \n}; } ;; sub Paris { my $self = shift; print qq{Arrived in $_[0]! \n}; } ;; } ;; my $obj = Foo->new; $obj->msg('Berlin'); $obj->msg('Paris'); $obj->msg('London'); " On my way to 'Berlin'. I am in Berlin! On my way to 'Paris'. Arrived in Paris! On my way to 'London'. Cannot get there.

    Update: See perlobj, perltoot, perltooc for info on can(). (Update: perltoot and perltooc exist for Perl 5.14, but have been superceded for 5.18. So you're on your own...)

Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others chilling in the Monastery: (9)
As of 2014-10-21 17:58 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    For retirement, I am banking on:










    Results (106 votes), past polls