=head1 NAME

B<Evented::API::Module> - represents a module for use with
L<Evented::API::Engine>.

=head1 SYNOPSIS

    # Module metadata
    #
    # @name:        'My::Module'
    # @package:     'M::My::Module'
    # @description:
    #
    # @depends.modules+ 'Some::Other'
    # @depends.modules+ 'Another::Yet'
    #
    # @author.name:     'Mitchell Cooper'
    # @author.website:  'https://github.com/cooper'
    #
    package M::My::Module;
    
    use warnings;
    use strict;
    use 5.010;
    
    # Auto-exported variables
    our ($api, $mod);
    
    # Default initializer
    sub init {
        say 'Loading ', $mod->name;
        
        # indicates load success
        return 1;
    }
    
    # Default deinitializer
    sub void {
        say 'Bye!';
        
        # indicates unload success
        return 1;
    }
    
    # Package must return module object
    $mod;

=head1 DESCRIPTION

=head2 Module directory structure

Modules must be placed within one of the search directories specified in the
L<Evented:API::Engine> C<mod_inc> consturctor option or the C<dirs> option
of C<< ->load_module >> and similar Engine methods.

A module in its simplest form is a directory with the C<.module> extension
and a single C<.pm> file of the same name. Double-colon namespace separators
are condensed to directories, as with normal Perl packages. For instance, a
module called My::Backend's main package file could be located at either of the
following:

    $SEARCH_DIR/My/Backend.module/Backend.pm
    $SEARCH_DIR/My/Backend/Backend.module/Backend.pm

The directory with the C<.module> extension is called the module directory. In
addition to the Perl package file, it can house other data associated with the
module, such as JSON-encoded metadata, submodules, and documentation.

    $MODULE_DIR/Backend.pm              # package file
    $MODULE_DIR/Backend.json            # metadata file
    $MODULE_DIR/Backend.md              # documentation
    $MODULE_DIR/More.module/More.pm     # submodule package
    $MODULE_DIR/More.module/More.json   # submodule metadata
    
=head2 Module metadata

Module metadata is extracted from comments in primary package file.

Metadata is written to a C<.json> file within the module directory
(when developer mode is enabled). These metadata files should be included in
distributions, as they contains version and author information.

B<Syntax> for metadata comments is as follows:

    # @normal:      "A normal option with a Perl-encoded value"
    # @boolean      # a boolean option!
    # @list+        'A value to add to a list'
    # @list+        'Another value to add to the list'
    
B<Supported options>

    # @name:                'Some::Module'              # module name
    # @package:             'M::Some::Module'           # main package
    # @package+             'M::Some::Module::Blah'     # additional packages
    # @version:             '1.01'                      # module version
    # @depends.modules+     'Some::Mod::Dependency'     # module dependencies
    # @depends.modules+     'A::B', 'C::D'              # additional dependencies
    # @depends.bases+       'Some::Base::Dependency'    # base dependencies
    # @author.name:         'John Doe'                  # author name
    # @author.website:      'http://john.example.com'   # author URL
    # @no_bless                                         # don't bless
    # @preserve_sym                                     # don't erase symbols
    
These, I feel, require additional explanation:

=over

=item *

B<@version> - this obviously is a numerical module version. I'm mentioning it
here to tell you that you probably shouldn't bother using it, as the API Engine
offers automatic versioning (with developer mode enabled) if you simply omit
this option.

=item *

B<@depends.bases> - like C<@depends.modules>, except the C<Base::> prefix is
added. bases are modules which don't really offer any functionality on their
own but provide APIs for other modules to use.

=item *

B<@no_bless> - if true, the module object will not be blessed to the module's
primary package (which is the default behavior). this might be useful if your
module contains names conflicting with API Engine or uses autoloading.

=item *

B<@preserve_sym> - if true, the packages associated with the module will not be
deleted from the symbol table upon unload. this is worse for memory, but it
may be necessary for the "guts" of your program, particularly those parts which
deal with the loading and unloading of modules themselves.

=back

=head1 METHODS

=head2 $mod->name

B<Returns> module full name.

=head2 $mod->package

B<Returns> module's primary Perl package name.

=head2 $mod->api

B<Returns> associated L<API Engine | Evented::API::Engine>.

=head2 $mod->parent

B<Returns> parent module, if this is a submodule.

=head2 $mod->submodules

B<Returns> list of loaded submodules objects.

=head2 $mod->Log($msg)

Used for logging associated with module. Use L<API Engine | Evented:API::Engine>
C<< ->Log() >> for messages not associated with a specific module.

B<Parameters>

=over

=item *

B<$msg> - text to log.

=back

=head2 $mod->get_symbol($sym)

Fetches the value of a symbol in module's main package.

B<Parameters>

=over

=item *

B<$sym> - string symbol; such as C<@list>, C<%hash>, or C<$scalar>.

=back

B<Returns>

The data in its native type (NOT a reference), or the zero value for that type
if no symbol table entry exists.

=head2 $mod->load_submodule($submod_name)

Loads a submodule.

This is generally used within the module initializer.

B<Parameters>

=over

=item *

B<$submod_name> - name of the submodule, without the parent module name prefix.
for instance if the full submodule name is C<My::Module::Sub>, this is simply
C<Sub>.

=back

B<Returns>

Submodule object on success, false otherwise.

=head2 $mod->unload_submodule($submod)

Unloads a submodule.

You do not have to call this in the parent module deinitializer. Only use this
method if you want to dynamically unload a submodule for some reason without
unloading the parent module.

B<Parameters>

=over

=item *

B<$submod> - submodule object or name, without the parent module name prefix.
for instance if the full submodule name is C<My::Module::Sub>, this is simply
C<Sub>.

=back

=head2 $mod->add_companion_submodule($mod_name, $submod_name)

Registers a submodule (provided by this module) as a companion of another
top-level module.

Companion submodules are submodules which are automatically loaded and unloaded
as needed in conjunction with other top-level modules.

This is generally called from within the parent module initializer.

B<Parameters>

=over

=item *

B<$mod_name> - name of another top-level module to register the submodule as
a companion.

=item *

B<$submod_name> - name of the submodule to register a companion, without the
parent module name prefix. for instance if the full submodule name is
C<My::Module::Sub>, this is simply C<Sub>.

=back

=head2 $mod->store($key, $value)

Stores a piece of data associated with module.

B<Parameters>

=over

=item *

B<$key> - name for fetching data later.

=item *

B<$value> - value to store.

=back

=head2 $mod->retrieve($key, $default_value)

Retrieves a piece of data associated with module.

B<Parameters>

=over

=item *

B<$key> - name associated with data to fetch.

=back

B<Returns>

Fetched data, undef if not found.

=head2 $mod->list_store_add($key, $value)

Adds an entry to a list of data associated with module.

=over

=item *

B<$key> - name for fetching data later.

=item *

B<$value> - value to add.

=back

=head2 $mod->list_store_remove_matches($key, $code, $max)

Removes entries satisfying a code from a list of data associated with module.

B<Parameters>

=over

=item *

B<$key> - name of list.

=item *

B<$code> - code reference passed each entry which should return true for
matches.

=item *

B<$max> - I<optional>, maximum number of entries to remove.

=back

B<Returns>

Number of items removed, false if none matched.

=head2 $mod->list_store_items($key)

Fetches all values in a list associated with module.

=over

=item *

B<$key> - name of the list to retrieve.

=back

B<Returns>

List of fetch values, or empty list if none were found.

=head2 $mod->dependencies

B<Returns> top-level module dependencies.

=head2 $mod->companions

For companion submodules,
B<Returns> modules that this submodule depends on.

=head2 $mod->dependents

B<Returns> top-level modules that depend on this module.

=head2 $mod->dependent_companions

B<Returns> companion submodules that depend on this module.

