NAME

My::Module::Build - Helper for releasing my (DOMQ's) code to CPAN

SYNOPSIS

This module works mostly like Module::Build with a few differences highlighted below. Put this in Build.PL:

use strict;
use warnings;

## Replace
# use Module::Build;
## with
use FindBin; use lib "$FindBin::Bin/inc";
use My::Module::Build;

## Replace
# my $builder = Module::Build->new(
## With
my $builder = My::Module::Build->new(
   ## ... Use ordinary Module::Build arguments here ...
   build_requires =>    {
         'Acme::Pony'    => 0,
         My::Module::Build->requires_for_build(),
   },
   add_to_no_index => { namespace => [ "My::Private::Stuff" ] },
);

## The remainder of the script works like with stock Module::Build

DESCRIPTION

DOMQ is a guy who releases CPAN packages from time to time - you are probably frobbing into one of them right now.

This module is a subclass to Module::Build by Ken Williams, and a helper that supports DOMQ's coding style for Perl modules so as to facilitate relasing my code to the world.

How to use My::Module::Build for a new CPAN package

This part of the documentation is probably only useful to myself, but hey, you never know - Feel free to share and enjoy!

  1. If not already done, prepare a skeletal CPAN module that uses Module::Build as its build support class. Module::Starter and its companion command module-starter(1) is highly recommended for this purpose, e.g.

    module-starter --mb --module=Main::Screen::Turn::On \
      --author='Dominique Quatravaux' --email='domq@cpan.org' --force
  2. create an inc/ subdirectory at the CPAN module's top level and drop this file there. (While you are there, you could put the rest of the My:: stuff along with it, and the t/maintainer/ test cases - see "SEE ALSO".)

  3. Amend the Build.PL as highlighted in the "SYNOPSIS".

  4. VERY IMPORTANT! Arrange for My::Module::Build and friends to not be indexed on the CPAN, lest the Perl deities' wrath fall upon you. This is done by adding the following lines to the META.yml file:

    no_index:
      directory:
        - examples
        - inc
        - t

    (indentation is meaningful - "no_index:" must start at the very first column and the indenting quantum is exactly 2 spaces, no tabs allowed)

    If you prefer the META.yml file to be built automatically, do a

    ./Build manifest
    ./Build distmeta

    and the aforementioned no_index exclusions will be set up automatically (but please double-check nevertheless).

Coding Style and Practices supported by this module

No, I don't want to go into silly regulations regarding whether I should start a new line before the opening bracket in a sub declaration. This would be coding syntax, or coding grammar. The stuff here is about style, and only the subset thereof that is somehow under control of the CPAN build process.

Unit tests

A large fraction of the unit tests are written as perlmodlib-style __END__ documents attached directly to the module to test. See My::Tests::Below for details. My::Module::Build removes the test footer at build time so as not to waste any resources on the install target platform.

Extended test action

The ./Build test action allows one to specify a list of individual test scripts to run, in a less cumbersome fashion than straight Module::Build:

./Build test t/sometest.t lib/Foo/Bar.pm

For the developper's comfort, if only one test is specified in this way, ACTION_test assumes that verbose mode is wanted (see "test" in Module::Build). This DWIM can be reversed on the command line:

./Build test verbose=0 t/sometest.t

In the case of running a single test, ACTION_test also automatically detects that we are running under Emacs' perldb mode and runs the required test script under the Perl debugger. Running a particular test under Emacs perldb is therefore as simple as typing:

M-x perldb <RET> /path/to/CPAN/module/Build test MyModule.pm

If a relative path is passed (as shown), it is interpreted relative to the current directory set by Emacs (which, except under very bizarre conditions, will be the directory of the file currently being edited). The verbose above applies here by default, conveniently causing the test script to run in verbose mode in the debugger.

Like the original "test" in Module::Build, ./Build test accepts supplemental key=value command line switches, as exemplified above with verbose. Additional switches are provided by My::Module::Build:

use_blib=0

Load modules from the source directory (e.g. lib) instead of the build directories (e.g. blib/lib and blib/arch). I use this to debug Inline::C code in a tight tweak-run-tweak-run loop, a situation in which the MD5-on-C-code feature of Inline saves a lot of rebuilds.

REFERENCE

Constructors and Class Methods

new(%named_options)

Overloaded from parent class in order to call "check_maintainer_dependencies" if "maintainer_mode_enabled" is true. Also sets the recursive_test_files property to true by default (see "test_files" in Module::Build), since I like to store maintainer-only tests in t/maintainer (as documented in "find_test_files").

In addition to the %named_options documented in "new" in Module::Build, My::Module::Build provides support for the following switches:

add_to_no_index => $data_structure

Appends the aforementioned directories and/or namespaces to the list that "ACTION_distmeta" stores in META.yml. Useful to hide some of the Perl modules from the CPAN index.

requires_for_build()

Returns a list of packages that are required by My::Module::Build itself, and should therefore be appended to the build_requires hash as shown in "SYNOPSIS".

Methods that can be called from inside Build.PL

maintainer_mode_enabled()

Returns true iff we are running "./Build.PL" or "./Build" off a revision control system of some kind. Returns false in all other situations, especially if we are running on an untarred package downloaded from CPAN.

check_maintainer_dependencies()

Checks that the modules required for modifying the CPAN package are installed on the target system, and displays a friendly, non-fatal message otherwise. This method is automatically run from "new" if appropriate (that is, if "maintainer_mode_enabled" is true).

show_warning($message)

Displays a multi-line message $message to the user, and prompts him/her to "Press RETURN to continue".

show_fatal_error($message)

Like "show_warning", but throws an exception after displaying $message.

use_blib()
use_blib($boolean)

Returns false if the user specified use_blib=0 on the command line, and true otherwise. See "Extended test action" for details. The form with a parameter allows one to set the value that will subsequently be returned by use_blib, thereby overriding the command line.

Dependent Option Graph

This API is a wrapper around "prompt" in Module::Build, "get_options" in Module::Build and "notes" in Module::Build to streamline the programming of optional features into a ./Build.PL script. Here is a short synopsis for this feature:

my $class = My::Module::Build->subclass(code => <<'CODE');

sub install_everything: Config_Option {
    question => "Install everything",
    default => 1;
}

sub install_module_foo: Config_Option(type="boolean") {
    my $build = shift;
    return (default => 1) # Don't even bother asking the question
       if $build->option_value("install_everything");
    question => "Install module foo",
    default => 0;
}

CODE

my $builder = $class->new(...) # See SYNOPSIS

Options can then be fed from the command line (e.g. ./Build.PL --gender=f) or by answering the questions interactively on the terminal. My::Module::Build will ask the questions at "new" time, in the correct order if they depend on each other (as shown in the example), detect circular dependencies, and die if a mandatory question does not get an appropriate answer.

Syntax

As shown above, options are methods in a subclass to My::Module::Build with a subroutine attribute of the form Config_Option(key1=value1, ...). Right now the following keys are defined:

type

The datatype of this option, either as a word (e.g. "boolean", "integer" or "string") or as a GetOpt::Long qualifier (e.g. "!", "=s" or "=i").

The default is to guess from the name of the option: "install_foo" and "enable_bar" are supposed to be booleans, "baz_port" an integer, and everything else a string.

The name of the method is the internal key for the corresponding option (e.g. for "option_value"). It is also the name of the corresponding command-line switch, except that all underscores are converted to dashes.

The method shall return a (key, value) "flat hash" with the following keys recognized:

question

The question to ask, as text. A question mark is appended automatically for convenience if there isn't already one. If no question is set, My::Module::Build will not ask anything for this question even in interactive mode, and will attempt to use the default value instead (see below).

default

In batch mode, the value to use if none is available from the command line or the persisted answer set from previous attempts to run ./Build.PL. In interactive mode, the value to offer to the user as the default.

mandatory

A Boolean indicating whether answering the question with a non-empty value is mandatory (see also "prompt" for a twist on what "non-empty" exactly means). The default mandatoryness is 1 if default is not returned, 0 if default is returned (even with an undef value).

Methods

option_value($optionname)

Returns the value selected for the option $optionname. From within an option declaration sub, this call may result in the question for $optionname (and its own dependencies, recursively) being asked on the terminal at once. If a loop is detected so doing, option_value() will die with a messsage that starts with the word "RECURSION".

Answers to questions are persisted using Module::Build's ->notes mechanism: outside the option declaration subs, option_value($optionname) is therefore an alias for notes("option:$optionname").

BUGS

The zero-wing easter egg only works through the Makefile.PL compatibility mode. On the other hand, "./Build your time" would not sound quite right, would it?

Perhaps the "Dependent option graph" features should be repackaged as a standalone Module::Build plug-in.

SEE ALSO

My::Tests::Below

t/maintainer/*.t