Perlmazing::Engine - Have your functions load their code and associated modules only when needed, automagically.

SYNOPSIS

This module was written with one main goal in mind: to save time, processing and memory when a module is loaded and it has a lot of functions (exported or not) and a those functions require loading a lot of other modules.

By using this module, you can write your functions in separate files without having to declare any package. Perlmazing::Engine will create empty symbols for each function you write (one per file). Those symbols will be present in your own module just like if they were regular functions - but the code associated with them will be loaded the first time you attempt to use each function. For many heave modules, this can be the answer to faster loading times and, when not all functions are used by a script, also a lot of processing and memory can be saved.

Also, behind the scenes, Perlmazing::Engine manages each function in a separate and unique namespace, but making any other function from your module visible and usable just like if they were all in the same namespace. By doing this, it also maintains your namespace clean, free from anything a specific function imports from other modules just to work itself. Each function can have it's own globals (variables, secondary functions, etc.) without poluting the whole module.

In order to use Perlmazing::Engine, you just do something like the following:

package MyModule;
use Perlmazing::Engine;

# Now your functions are usable, but not loaded until called.

1;

HOW TO USE

So, where do we put functions and their code so Perlmazing::Engine knows what to do? You need to have the following structure for your module files. Assume your module name is MyModule; so you will organize any submodules in the folder ./Submodule, like normal, but you will also have a ./MyModule/Perlmazing folder where your function files will live. You can have an optional ./MyModule/Perlmazing/Precompile folder, where you will place function files that for any reason you want to be compiled at compile time (e.g. functions with prototypes):

.
|-- MyModule.pm
+-- MyModule/
    +-- Perlmazing/
        |-- function_A.pm
        |-- function_B.pm
        +-- Precompile/
            |-- function_C.pm
            |-- function_D.pm

In the previous example, Perlmazing::Engine will create empty symbols for the functions function_A, function_B, function_C and function_D, all of them belonging to the MyModule namespace. If you had a submodule called MyModule::Clients and wanted to use Perlmazing::Engine there too, then that submodule would use its own folder at ./MyModule/Clients/Perlmazing. It would then look like this:

.
|-- MyModule.pm
+-- MyModule/
    |-- Clients.pm
    +-- Clients/
    |   +-- Perlmazing
    |       |-- function_E.pm
    |       |-- function_F.pm
    +-- Perlmazing/
        |-- function_A.pm
        |-- function_B.pm
        +-- Precompile/
            |-- function_C.pm
            |-- function_D.pm

MyModule::Clients is now able to use the functions function_E and function_F by just calling use Perlmazing::Engine.

HOW FUNCTIONS SHOULD BE WRITTEN

Besides residing on its own file in their respective Perlmazing folder, and having a file name that is their exact actual function name, they also have one particularity that most be respected: the function name inside the file will always be main. This has several reasons, being one of the most important ones that you can import your own module and if that module exports functions by default, and one of those functions happens to be the one you are writting in this file, then having the same exact name would cause a conflict.

There are also two types of functions you can write, in terms of behavior and this is something comming from Perlmazing::Engine. Basically, you get the regular type and the Listable type. The regular type is simply any kind of subroutine, and it can simply do whatever you code it to do.

REGULAR FUNCTIONS

The following is an example of a simple function. Let's say that function name is "say_hello()", so it will live in the file ./MyModule/Perlmazing/say_hello.pm and will have the following content:

use strict;
use warnings;
# use any other module you need here for this specific function to work

sub main {
    print "Hello there!\n";
}

1;

LISTABLE FUNCTIONS

Listable functions are all meant to follow this behavior:

# Assume 'my_sub' is a function of the type Listable:

# Calling my_sub on an array will directly affect elements of @array:

my_sub @array;

# Calling my_sub on a list will *attempt* to directly affect the
# elements of that list, failing on 'read only'/'constant' elements
# like the elements in the following list:

my_sub (1, 2, 3, 4, 5, 'string element');

# Calling my_sub on an array or a list BUT with an assignment,
# will *not* affect the original array or list, but assign an
# affected copy:

my @array_A = my_sub @array;
my @array_B = my_sub (1, 2, 3, 4, 5, 'string_element');

# Listable functions can be chained to achieve both behaviors
# (assignment or direct effect) on a single call. Assume
# 'my_sub2', 'my_sub3' and 'my_sub4' are also Listable functions:

my_sub my_sub1 my_sub2 my_sub3 my_sub4 @array;
my @array_C = my_sub my_sub1 my_sub2 my_sub3 my_sub4 (1, 2, 3, 4, 5, 'string element');

# When a Listable function is assigned in scalar context, then only the
# first element is assigned, not a list/array count.

my $scalar = my_sub @array; # $scalar contains the first element of the resulting list

When writting a listable function, you need to do two things: first, make that function listable by including in its <@ISA> the namespace Perlmazing::Listable. Second, you should always deal directly with the argument $_[0] and not a copy of it. This means you should not do something like my ($arg1, $arg2) = @_. You will only deal with $_[0] because Perlmazing::Engine will always pass only one argument to Perlmazing::Listable functions and expect that function to directly affect that argument. Then Perlmazing::Engine will be the one deciding what to do with that result, based on the context and arguments that function was called with.

The following is an example taken from the function escape_uri from the Perlmazing module. Look at how simple it is:

use Perlmazing;
use URI::Escape;
our @ISA = qw(Perlmazing::Listable);

sub main {
    $_[0] = uri_escape($_[0]) if defined $_[0];
}

1;

That function will have all the behavior previously described for Listable functions, but you don't need to think of that behavior here, Perlmazing::Engine will do that for you and you will only work with $_[0].

EXPORTS

Perlmazing::Engine doesn't export anything by default. In fact, so far none of its functions or methods are meant to be imported. If you are wondering about how to export functions from your own module (even if they work through Perlmazing::Engine), then you will do so exactly as you would if you weren't using this module (e.g. using Exporter or your favorite export module/method).

METHODS

The following is a list of methods you can call from Perlmazing::Engine:

found_symbols

my @symbols = Perlmazing::Engine->found_symbols($optional_namespace)

This method will return a list with all the symbols Perlmazing::Engine found for a specific package/namespace. If you don't provide any arguments, then the current namespace will be used. The following is an example of it being used to export every function from your module into its caller:

use strict;
use warnings;
use Perlmazing::Engine;
require Exporter;

our @EXPORT = Perlmazing::Engine->found_symbols;

# Or, you could do that with @EXPORT_OK just to make them available for export.

loaded_symbols

my @symbols = Perlmazing::Engine->loaded_symbols($optional_namespace)

This method will return a list of the symbols for which its actual code has been already loaded.

preload

Perlmazing::Engine->preload(@list_of_symbols_to_preload)

This method will load (completely, including their respective code) all of the symbols passed as argument. This is useful then you know you will need these symbols loaded from the begining, or maybe at compile time, for any reasons you may have.

precompile

Perlmazing::Engine->precompile

This method is similar to preload, but while preload works with any symbol name passed as argument, precompile works with the symbols found in the precompile folder described previously.

AUTHOR

Francisco Zarabozo, <zarabozo at cpan.org>

BUGS

Please report any bugs or feature requests to bug-perlmazing at rt.cpan.org, or through the web interface at http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Perlmazing. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.

SUPPORT

You can find documentation for this module with the perldoc command.

perldoc Perlmazing::Engine

You can also look for information at:

LICENSE AND COPYRIGHT

Copyright 2015 Francisco Zarabozo.

This program is free software; you can redistribute it and/or modify it under the terms of either: the GNU General Public License as published by the Free Software Foundation; or the Artistic License.

See http://dev.perl.org/licenses/ for more information.

1 POD Error

The following errors were encountered while parsing the POD:

Around line 214:

=pod directives shouldn't be over one line long! Ignoring all 2 lines of content