Reputation: 877
I am creating a set of small Perl programs which will be run like a CLI. I want all of them to share some features, eg. same input/output format (probably JSON). I also want each component to be black-box testable with mock arguments. This is what I have so far:
A number of modules actionA.pm
, actionB.pm
... actionZZZ.pm
, one for each component/operation. All of them will use Moose
and should have a sub run {...}
which will receive a data hasref/object with the operation's input parameters, and any handle (database, filesystem, whatever) they need to use, and return a data hashref/object with the operation's output parameters.
A Moose role which requires 'run'
and is consumed by every actionX.pm
module, forcing them to implement run
.
Additional Moose roles and/or superclasses for certain subsets of the actionX.pm
modules, so they can consume them to specify wether they need their run
method to be provided with a database handler, a filesystem handler, etc.
A common Moose superclass (don't know if this really needs to be either Moose nor a superclass, just want this to be a fairly simple one-liner on each actionX.pm
), let's call it abstractAction.pm
, for all of the actionX.pm
classes, which converts them into some sort of Modulino (see below).
What I want to achieve with this is that, when I run perl actionX.pm arguments
from command line, some code in abstractAction.pm
will:
Read JSON/whatever from @ARGV
and convert it to Perl data structures.
This part is not clear: know that it was called from/as actionX
, so it knows that if actionX
consumes role needDB
, it will need to get a database handler to pass it to run
, etc.
Call actionX->run()
passing the data object and any handler obtained at step 2.
I tried using both run()
and __PACKAGE__->run()
in abstractAction.pm
, but it calls the superclass method, not the child's. Is there any way I can know the child's package name from the parent? That doesn't even sound good. Is there a better way to do what I am trying to achieve?
I know I could simply do perl abstractAction.pm actionX arguments
instead of perl actionX.pm arguments
and call it a day, but I'd rather not.
Upvotes: 0
Views: 112
Reputation: 385897
Fundamentally, you'll need to call run
as a method, using the name of the child class (if it's a class method) or an object of the child class (if it's an instance method) as the invocant.
Calling run
as a class method:
ActionX->run(...)
Calling run
as an instance method:
ActionX->new(...)->run(...)
The other issue is that you're executing a .pm
file, which leads to problems. Load modules, don't execute them. For example,
#!/usr/bin/perl
use strict;
use warnings;
my $action = shift(@ARGV)
or die("usage\n");
$action =~ /^\w+\z/
or die("Bad action\n");
my $pkg = $action; # Or: my $pkg = "...::" . $action;
my $module =~ s{::}{/}g . '.pm';
require $module;
$pkg->new(@ARGV)->run();
If the script is named action
, then you can do
action ActionX parameters
Upvotes: 1