|Think about Loose Coupling|
Technique for executable modulesby tlhackque (Beadle)
|on Feb 04, 2019 at 15:31 UTC||Need Help??|
Over the years, I've seen a number of techniques used to enable a Perl module to have a dual-life as as a command. These range from commented out mainline code (used for testing) to requiring the command line user to invoke a 'run' function. And include invoking 'caller' to guess the mode, inspecting $0, or even '$Pkg::FooMode='module'; require Pkg::Foo;'.
None has seemed entirely satisfactory: there always seem to be either functional or esthetic compromises. Often with some burden on the end user(s) as well as the author.
Here is a technique that, with minimal one-time setup, hides the ugliness from all users, yet has minimal impact on the developer.
Assume that your script is to be installed in /opt/sbin, and that your Perl library includes /usr/lib/perl5/site_perl/5.99.0/.
Your script looks like:
And the installation looks like:
This allows the user to treat the module as an ordinary command - no CamelCase name, 'funny' .pm extension, or '-e run()' to remember (or wrap in another script). No worries for the module author about strange ways it might be loaded, forgetting to shut off test code before release, or having 'shift' default to '@_' instead of '@ARGV'. (S)he can, of course, still provide a 'run' function if desired, but it's not required. And of course, lazy loading the command-only modules reduces the dual-life expense when used as a pure module.
There is no unusual magic about the locations chosen for this explanation: the .pm symlink goes in the library where 'use' & 'require' can find it, and the executable goes in PATH. Of course, you can invert the direction of the symlink if you think of the module as primary and the executable as secondary. TMTOWTDI; tastes vary. Note that File::Spec->abs2rel is a convenient way to generate the symlink in an installation script. You do want to use a relative target in case the file is on a mountpoint.