Modulino: both script and module in Perl

In the Python world it is quite straight forward to make files work either as executables or as modules.
In Perl it is a bit strange, but doable.

brian d foy has written a number of articles about Modulinos,
but in nutshell a Modulino is a Perl file that can act both as an executable (a script that you would invoke directly)
or as a module (Something you load into memory and expect to execute code only when you call one of its functions or
methods).

The way to implement this in Perl is to put every executable code inside function and leave only the following statement in the main body of your code:

main() if not caller();

assuming you have a function called main that implements the behavior you'd want to see when the file is
executed as a stand-alone script.

Here is an example to demonstrate the concept:

examples/modulino.pm

use strict;
use warnings;
use 5.010;
main() if not caller();
sub main {
say "Hello from main() of modulino.pl";
}
1;

If we run it as a script we will have the following output:

$ perl modulino.pm
Hello from main() of modulino.pl

If we load it as a module, it will generate no output:

$ perl -Mmodulino -e1

that's because it will not execute the main() function.

However, we can use its functions:

$ perl -Mmodulino -e"main()"
Hello from main() of modulino.pl

We can also use it inside another script:

examples/modulino_user.pl

use strict;
use warnings;
use 5.010;
use modulino;
main()

$ perl modulino_user.pl
Hello from main() of modulino.pl

What is this caller ?

To quote from its documentation:

The caller function of Perl returns the context of the current pure perl subroutine call.
In scalar context, returns the caller's package name if there is a caller
(that is, if we're in a subroutine or "eval" or "require") and the undefined value otherwise.

In other words, when we execute the file directly caller returns undef, but when
we load it with a use statement (which is just a wrapper around require) then
it will have some value other than undef. Something true.

The caller function has other uses as well, but for our purposes this is what we need to know about it.

Modulino with print

In case you'd like to look at another example to see how this works check out this one:

examples/modulino_with_print.pm

use strict;
use warnings;
use 5.010;
say "Hello from the body of modulino.pl";
main() if not caller();
sub main {
say "Hello from main() of modulino.pl";
}
1;

Here we have an extra print-statement in the main body of the file.

When executing directly we see both lines:

$ perl modulino_with_print.pm
Hello from the body of modulino.pl
Hello from main() of modulino.pl

When loaded as a module, only the one in the body of the file is executed.

$ perl -Mmodulino_with_print -e1
Hello from the body of modulino.pl

BTW, that's one of the reasons it is not recommended to put any code outside of functions. Especially not in modules.

Modulino in a package

To show yet another case, here we can see that we can use the same trick in a namespace as well:

examples/MyModulino.pm

package MyModulino;
use 5.010;
use strict;
use warnings;
hi() if not caller();
sub hi {
say "Hello from main() of modulino.pl";
}
1;

In this case we have our code inside a package.
This is how the output looks like if we try to run it directly:

$ perl MyModulino.pm
Hello from main() of modulino.pl

We can create a script using the module:

examples/use_my_modulino.pl

use 5.010;
use strict;
use warnings;
use MyModulino;
say "before";
MyModulino::hi();
say "after";

And this is its output if we run the script:

$ perl use_my_modulino.pl
before
Hello from main() of modulino.pl
after

If we did not call MyModulino::hi(); we would only see the "before" and "after" lines.