Beefy Boxes and Bandwidth Generously Provided by pair Networks
Think about Loose Coupling

Right place to put common execute code in App::Cmd

by McA (Priest)
on Dec 10, 2012 at 14:49 UTC ( #1008107=perlquestion: print w/replies, xml ) Need Help??
McA has asked for the wisdom of the Perl Monks concerning the following question:

Hi all,

I do have a problem with App::Cmd at the moment. I don't know where the right place is to execute code which is common to all commands.

In all commands I want to execute some common code without explicitly calling it in the command's execute method. And I want that validate_args is run before.

Hints and ideas welcome.

Best regards

Replies are listed 'Best First'.
Re: Right place to put common execute code in App::Cmd
by tobyink (Abbot) on Dec 10, 2012 at 14:59 UTC

    This is the kind of place where aspect-oriented programming is awesome. If you're using Moose, Moo or another OO library that supports method modifiers, then it's probably just a matter of creating a role with a before execute method modifier and then applying it to all your command classes.

    Otherwise, if you have a base class for all your command classes, you could try creating a method called before_execute and then manually modifying all your execute methods to call $_[0]->before_execute at the start.

    perl -E'sub Monkey::do{say$_,for@_,do{($monkey=[caller(0)]->[3])=~s{::}{ }and$monkey}}"Monkey say"->Monkey::do'

      Hi tobyink,

      thank you for answering that fast. I have to admit that I hoped it. ;-) (a ++ for that)

      The first suggestion is not an option for me right now. The second approach is which I'm doing right now. But I wanted to avoid the call of before_execute in every execute method. I really hoped that there is another callback which I haven't found.

      Once again. Thank you.

      Best regards

        "I really hoped that there is another callback which I haven't found."

        The relevant code is App::Cmd::execute_command. As you can see, nothing happens between validate_args and execute that you could possibly hook onto.

        One alternative approach could be to subclass App::Cmd, overriding that method with your own implementation that adds extra hooks between validate_args and execute:

        { package My::App::Cmd; use base 'App::Cmd'; sub execute_command { my ($self, $cmd, $opt, @args) = @_; local our $active_cmd = $cmd; $cmd->validate_args($opt, \@args); $cmd->before_execute($opt, \@args); $cmd->execute($opt, \@args); } }

        Then use My::App::Cmd instead of App::Cmd.

        perl -E'sub Monkey::do{say$_,for@_,do{($monkey=[caller(0)]->[3])=~s{::}{ }and$monkey}}"Monkey say"->Monkey::do'

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1008107]
Approved by moritz
Front-paged by davido
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others taking refuge in the Monastery: (7)
As of 2017-06-23 22:31 GMT
Find Nodes?
    Voting Booth?
    How many monitors do you use while coding?

    Results (555 votes). Check out past polls.