Alien-Selenium
view release on metacpan or search on metacpan
inc/My/Module/Build.pm view on Meta::CPAN
=for My::Tests::Below "META.yml excerpt" begin
no_index:
directory:
- examples
- inc
- t
=for My::Tests::Below "META.yml excerpt" end
(indentation is meaningful - "no_index:" must start at the very first
column and the indenting quantum is exactly 2 spaces, B<no tabs
allowed>)
If you prefer the META.yml file to be built automatically, do a
=for My::Tests::Below "distmeta" begin
./Build manifest
./Build distmeta
=for My::Tests::Below "distmeta" end
and the aforementioned no_index exclusions will be set up
automatically (but B<please double-check nevertheless>).
=back
=head2 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.
=head3 Unit tests
A large fraction of the unit tests are written as perlmodlib-style
__END__ documents attached directly to the module to test. See
L<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.
=head3 Extended C<test> action
The C<./Build test> action allows one to specify a list of individual
test scripts to run, in a less cumbersome fashion than straight
L<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, I<ACTION_test> assumes that I<verbose> mode is wanted (see
L<Module::Build/test>). This DWIM can be reversed on the command line:
./Build test verbose=0 t/sometest.t
In the case of running a single test, I<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 switch above applies here by default,
conveniently causing the test script to run in verbose mode in the
debugger.
Like the original L<Module::Build/test>, C<./Build test> accepts
supplemental key=value command line switches, as exemplified above
with C<verbose>. Additional switches are provided by
I<My::Module::Build>:
=over
=item I<< use_blib=0 >>
Load modules from the B<source> directory (e.g. C<lib>) instead of the
build directories (e.g. C<blib/lib> and C<blib/arch>). I use this to
debug L<Inline::C> code in a tight tweak-run-tweak-run loop, a
situation in which the MD5-on-C-code feature of L<Inline> saves a lot
of rebuilds.
=item I<full_debugging=1>
Sets the FULL_DEBUGGING environment variable to 1 while running
C<./Build test>, in addition to any environment customization already
performed by L</customize_env>. Packages of mine that use L<Inline>
enable extra debugging when this environment variable is set.
=back
=head3 Dependent Option Graph
This feature wraps around L<Module::Build/prompt>,
L<Module::Build/get_options> and L<Module::Build/notes> to streamline
the programming of optional features into a ./Build.PL script. Here is
a short synopsis for this feature:
=for My::Tests::Below "option-graph" begin
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
=for My::Tests::Below "option-graph" end
Options can then be fed from the command line (e.g. C<< ./Build.PL
--gender=f >>) or by answering the questions interactively on the
terminal. I<My::Module::Build> will ask the questions at L</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.
=head3 Syntax
As shown above, options are methods in a subclass to
I<My::Module::Build> with a subroutine attribute of the form C<<
Config_Option(key1=value1, ...) >>. Right now the
following keys are defined:
=over
=item I<type>
The datatype of this option, either as a word (e.g. "boolean", "integer" or
"string") or as a L<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.
=back
The name of the method is the internal key for the corresponding
option (e.g. for L</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:
=over
=item I<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, I<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).
=item I<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.
=item I<mandatory>
A Boolean indicating whether answering the question with a non-empty
value is mandatory (see also L</prompt> for a twist on what
"non-empty" exactly means). The default mandatoryness is 1 if
I<default> is not returned, 0 if I<default> is returned (even with an
undef value).
=back
=head1 REFERENCE
=cut
package My::Module::Build;
use strict;
use warnings;
use base "Module::Build";
use IO::File;
use File::Path qw(mkpath);
use File::Spec::Functions qw(catfile catdir splitpath splitdir);
use File::Basename qw(dirname);
use File::Spec::Unix ();
use File::Find;
=begin internals
=head2 Global variables
=head3 $running_under_emacs_debugger
Set by L</_massage_ARGV> if (you guessed it) we are currently running
under the Emacs debugger.
=cut
our $running_under_emacs_debugger;
=head2 Constants
=head3 is_win32
Your usual bugware-enabling OS checks.
=cut
use constant is_win32 => scalar($^O =~ /^(MS)?Win32$/);
=head2 read_file($file)
=head2 write_file($file, @lines)
Like in L<File::Slurp>.
=cut
sub read_file {
my ($filename) = @_;
defined(my $file = IO::File->new($filename, "<")) or die <<"MESSAGE";
Cannot open $filename for reading: $!.
MESSAGE
return wantarray? <$file> : join("", <$file>);
}
sub write_file {
my ($filename, @contents) = @_;
defined(my $file = IO::File->new($filename, ">")) or die <<"MESSAGE";
Cannot open $filename for writing: $!.
MESSAGE
($file->print(join("", @contents)) and $file->close()) or die <<"MESSAGE";
Cannot write into $filename: $!.
MESSAGE
}
=end internals
=head2 Constructors and Class Methods
These are intended to be called directly from Build.PL
=over
=item I<new(%named_options)>
Overloaded from parent class in order to call
L</check_maintainer_dependencies> if L</maintainer_mode_enabled> is
true. Also sets the C<recursive_test_files> property to true by
default (see L<Module::Build/test_files>), since I like to store
maintainer-only tests in C<t/maintainer> (as documented in
L</find_test_files>).
In addition to the %named_options documented in L<Module::Build/new>,
I<My::Module::Build> provides support for the following switches:
=over
=item I<< add_to_no_index => $data_structure >>
inc/My/Module/Build.pm view on Meta::CPAN
=back
=head2 Other Public Methods
Those methods will be called automatically from within the generated
./Build, but on the other hand one probably shouldn't call them
directly from C<Build.PL> . One may wish to overload some of them in
a package-specific subclass, however.
=over
=item I<ACTION_build>
Overloaded to add L</ACTION_buildXS> as a dependency.
=cut
sub ACTION_build {
my $self = shift;
$self->depends_on("buildXS");
$self->SUPER::ACTION_build(@_);
}
=item I<ACTION_dist>
Overloaded so that typing C<./Build dist> does The Right Thing and
regenerates everything that is needed in order to create the
distribution tarball. This includes the C<Makefile.PL> if so requested
(see L<Module::Build::Compat/create_makefile_pl>) and the C<MANIFEST>
file (see L<Module::Build/manifest>). On the other hand, the
C<META.yml> file is not regenerated automatically, so that the author
has the option of maintaining it by hand.
=cut
sub ACTION_dist {
my $self = shift;
$self->do_create_makefile_pl if $self->create_makefile_pl;
$self->do_create_readme if $self->create_readme;
$self->depends_on("manifest");
$self->SUPER::ACTION_dist(@_);
}
=item I<ACTION_buildXS>
Does nothing. Intended for overloading by packages that have XS code,
which e.g. may want to call L</process_Inline_C_file> there.
=cut
sub ACTION_buildXS { }
=item I<ACTION_test>
Overloaded to add t/lib and t/inc to the test scripts' @INC (we
sometimes put helper test classes in there), and also to implement the
features described in L</Extended C<test> action>. See also
L</_massage_ARGV> for more bits of the Emacs debugger support code.
=cut
sub ACTION_test {
my $self = shift;
# Tweak @INC (done this way, works regardless of whether we'll be
# doing the harnessing ourselves or not)
local @INC = (@INC, catdir($self->base_dir, "t", "lib"),
catdir($self->base_dir, "t", "inc"));
# use_blib feature, part 1:
$self->depends_on("buildXS") if $self->use_blib;
my @files_to_test = map {
our $initial_cwd; # Set at BEGIN time, see L<_startperl>
File::Spec->rel2abs($_, $initial_cwd)
} (@{$self->{args}->{ARGV} || []});
if ($running_under_emacs_debugger && @files_to_test == 1) {
# We want to run this script under a slave_editor debugger, so
# as to implement the documented trick. The simplest way
# (although inelegant) is to bypass Module::Build and
# Test::Harness entirely, and run the child Perl
# ourselves. Most of the code below was therefore cobbled
# together from the real T::H version 2.40 and M::B 0.26
$self->depends_on('code'); # As in original ACTION_test
# Compute adequate @INC for sub-perl:
my @inc = do { my %inc_dupes; grep { !$inc_dupes{$_}++ } @INC };
if (is_win32) { s/[\\\/+]$// foreach @inc; }
# Add blib/lib and blib/arch like the original ACTION_test does:
if ($self->use_blib) {
unshift @inc, catdir($self->base_dir(), $self->blib, 'lib'),
catdir($self->base_dir(), $self->blib, 'arch');
} else {
unshift @inc, catdir($self->base_dir(), 'lib');
}
# Parse shebang line to set taintedness properly:
local *TEST;
open(TEST, $files_to_test[0]) or die
"Can't open $files_to_test[0]. $!\n";
my $shebang = <TEST>;
close(TEST) or print "Can't close $files_to_test[0]. $!\n";
my $taint = ( $shebang =~ /^#!.*\bperl.*\s-\w*([Tt]+)/ );
my ($perl) = ($^X =~ m/^(.*)$/); # Untainted
system($perl, "-d",
($taint ? ("-T") : ()),
(map { ("-I" => $_) } @inc),
$files_to_test[0], "-emacs");
return;
}
# Localize stuff in order to fool our superclass for fun & profit
local %ENV = $self->customize_env(%ENV);
local $self->{FORCE_find_test_files_result}; # See L</find_test_files>
$self->{FORCE_find_test_files_result} = \@files_to_test if
@files_to_test;
# DWIM for ->{verbose} (see POD)
local $self->{properties} = { %{$self->{properties}} };
if (@files_to_test == 1) {
$self->{properties}->{verbose} = 1 if
(! defined $self->{properties}->{verbose});
}
# use_blib feature, cont'd:
no warnings "once";
local *blib = sub {
my $self = shift;
return File::Spec->curdir if ! $self->use_blib;
return $self->SUPER::blib(@_);
};
$self->SUPER::ACTION_test(@_);
}
=item I<ACTION_distmeta>
inc/My/Module/Build.pm view on Meta::CPAN
install it and re-run this command.
MESSAGE
# Steals a reference to the YAML object that will be constructed
# by the parent class (duhh)
local our $orig_yaml_node_new = \&YAML::Node::new;
local our $node;
no warnings "redefine";
local *YAML::Node::new = sub {
$node = $orig_yaml_node_new->(@_);
};
my $retval = $self->SUPER::ACTION_distmeta;
die "Failed to steal the YAML node" unless defined $node;
$node->{no_index} = $self->{properties}->{add_to_no_index} || {};
$node->{no_index}->{directory} ||= [];
unshift(@{$node->{no_index}->{directory}}, qw(examples inc t),
(map { File::Spec::Unix->catdir("lib", split m/::/) }
(@{$node->{no_index}->{namespace} || []})));
foreach my $package (keys %{$node->{provides}}) {
delete $node->{provides}->{$package} if
(grep {$package =~ m/^\Q$_\E/}
@{$node->{no_index}->{namespace} || []});
delete $node->{provides}->{$package} if
(grep {$package eq $_}
@{$node->{no_index}->{package} || []});
}
my $metafile =
$self->can("metafile") ? # True as of Module::Build 0.2805
$self->metafile() : $self->{metafile};
# YAML API changed after version 0.30
my $yaml_sub =
($YAML::VERSION le '0.30' ? \&YAML::StoreFile : \&YAML::DumpFile);
$yaml_sub->($metafile, $node)
or die "Could not write to $metafile: $!";
;
}
=item I<customize_env(%env)>
Returns a copy of %env, an environment hash, modified in a
package-specific fashion. To be used typically as
local %ENV = $self->customize_env(%ENV);
The default implementation sets PERL_INLINE_BUILD_NOISY to 1 and also
sets FULL_DEBUGGING if so directed by the command line (see L</
ACTION_test>).
=cut
sub customize_env {
my ($self, %env) = @_;
delete $env{FULL_DEBUGGING};
$env{PERL_INLINE_BUILD_NOISY} = 1;
$env{FULL_DEBUGGING} = 1 if ($self->{args}->{full_debugging});
return %env;
}
=item I<process_pm_files>
Called internally in Build to convert lib/**.pm files into their
blib/**.pm counterpart; overloaded here to remove the test suite (see
L</Unit tests>) and standardize the copyright of the files authored by
me.
=cut
sub process_pm_files {
no warnings "once";
local *copy_if_modified = \*process_pm_file_if_modified;
my $self = shift;
return $self->SUPER::process_pm_files(@_);
}
=item I<process_pm_file_if_modified(%args)>
Does the same as L<copy_file_if_modified> (which it actually replaces
while L<process_pm_files> runs), except that the L</new_pm_filter> is
applied instead of performing a vanilla copy as L<Module::Build> does.
=cut
sub process_pm_file_if_modified {
my ($self, %args) = @_;
my ($from, $to) = @args{qw(from to)};
return if $self->up_to_date($from, $to); # Already fresh
mkpath(dirname($to), 0, 0777);
# Do a filtering copy
print "$from -> $to\n" if $args{verbose};
die "Cannot open $from for reading: $!\n" unless
(my $fromfd = new IO::File($from, "r"));
die "Cannot open $to for writing: $!\n" unless
(my $tofd = new IO::File($to, "w"));
my $filter = $self->new_pm_filter;
while(my $line = <$fromfd>) {
my $moretext = $filter->filter($line);
if (defined($moretext) && length($moretext)) {
$tofd->print($moretext) or
die "Cannot write to $to: $!\n";
}
last if $filter->eof_reached();
}
$tofd->close() or die "Cannot close to $to: $!\n";
}
=item I<new_pm_filter>
Creates and returns a fresh filter object (see
L</My::Module::Build::PmFilter Ancillary Class>) that will be used by
L</process_pm_file_if_modified> to process the text of the .pm files.
Subclasses may find it convenient to overload I<new_pm_filter> in
order to provide a different filter. The filter object should obey
inc/My/Module/Build.pm view on Meta::CPAN
# Makefile.PL will set up us the Module::Build::Compat itself (and
# also we want to take off every zig of bloat when
# My::Module::Build is loaded from elsewhere). Moreover, "use
# base" is not yet belong to us at this time.
sub fake_makefile {
my $self = shift;
return $self->SUPER::fake_makefile(@_). <<'MAIN_SCREEN_TURN_ON';
# In 2101 AD war was beginning...
your:
@echo
@echo -n " All your codebase"
time:
@echo " are belong to us !"
@echo
MAIN_SCREEN_TURN_ON
}
}
=head2 Overloaded Internal Methods
Yeah I know, that's a pretty stupid thing to do, but that's the best I
could find to get Module::Build to do my bidding.
=over
=item I<subclass(%named_arguments)>
Overloaded from L<Module::Build::Base> to set @ISA at compile time and
to the correct value in the sub-classes generated from the C<< code >>
named argument. We need @ISA to be set up at compile-time so that the
method attributes work correctly; also we work around a bug present in
Module::Build 0.26 and already fixed in the development branch whence,
ironically, ->subclass does not work from a subclass.
=cut
sub subclass {
my ($pack, %opts) = @_;
$opts{code} = <<"KLUDGE_ME_UP" if defined $opts{code};
# Kludge inserted by My::Module::Build to work around some brokenness
# in the \@ISA setup code above:
use base "My::Module::Build";
our \@ISA;
BEGIN { our \@ISAorig = \@ISA; }
\@ISA = our \@ISAorig;
$opts{code}
KLUDGE_ME_UP
return $pack->SUPER::subclass(%opts);
}
=item I<_startperl>
Overloaded from parent to attempt a chdir() into the right place in
./Build during initialization. This is an essential enabler to the
Emacs debugger support (see L</ACTION_test>) because we simply cannot
tell where Emacs will be running us from.
=cut
sub _startperl {
my $self = shift;
my $basedir = $self->base_dir;
$basedir = Win32::GetShortPathName($basedir) if is_win32;
return $self->SUPER::_startperl(@_) . <<"MORE";
# Hack by My::Module::Build to give the Emacs debugger one
# more chance to work:
use Cwd;
BEGIN {
\$My::Module::Build::initial_cwd = \$My::Module::Build::initial_cwd =
Cwd::cwd;
chdir("$basedir") || 1;
}
MORE
}
=item I<_packages_inside($file)>
Returns a list of Perl packages to be found inside $file. Overloaded
from the parent class so as to refrain from parsing after the __END__
marker.
=cut
sub _packages_inside {
# Copied 'n modified from the parent class, doubleplusshame on me!
my ($self, $file) = @_;
my $fh = IO::File->new($file) or die "Can't read $file: $!";
my @packages;
while(my (undef, $p) = $self->_next_code_line
($fh, qr/^(?:__END__$|__DATA__$|[\s\{;]*package\s+([\w:]+))/)) {
last if ! defined $p;
push @packages, $p;
}
return @packages;
}
=back
=head2 Other Private Methods
=over
=item I<_massage_ARGV($ref_to_ARGV)>
Called as part of this module's startup code, in order to debogosify
the @ARGV array (to be passed as a reference) when we are invoked from
Emacs' M-x perldb. L</ACTION_test> will afterwards be able to take
advantage of the Emacs debugger we run under, by bogosifying the
command line back before invoking the script to test.
=cut
_massage_ARGV(\@ARGV);
sub _massage_ARGV {
my ($argvref) = @_;
my @argv = @$argvref;
return unless ($ENV{EMACS} && (grep {$_ eq "-emacs"} @argv));
$running_under_emacs_debugger = 1;
@argv = grep { $_ ne "-emacs" } @argv;
shift @argv if $argv[0] eq "-d"; # Was gratuitously added by former Emacsen
# XEmacs foolishly assumes that the second word in the perldb
# line is a filename and turns it into e.g. "/my/path/test":
(undef, undef, $argv[0]) = File::Spec->splitpath($argv[0]);
@$argvref = @argv;
}
=back
=head2 My::Module::Build::PmFilter Ancillary Class
This ancillary class, serving both as an object-oriented interface and
as a default implementation thereof, is the workhorse behind
L</process_pm_files> and L</process_pm_file_if_modified>. It consists
of a very simple filter API to transform the text of .pm files as they
are copied over from lib/ to blib/ during the build process. The
base-class implementation simply replaces copyright placeholders of
the form "(C) DOMQ" with appropriate legalese, and removes the
L<My::Tests::Below> test suite if one is found.
Subclasses of I<My::Module::Build> need only overload
L</new_pm_filter> in order to provide a different implementation of
this .pm filter. The object returned by said overloaded
I<new_pm_filter> needs only obey the API documented below for methods
I<filter> and I<eof_reached>; it may or may not elicit to inherit from
I<My::Module::Build::PmFilter> in order to do so.
=over
=cut
package My::Module::Build::PmFilter;
=item I<new()>
Object constructor. Does nothing in the base class.
=cut
sub new { bless {}, shift }
=item I<filter($line)>
Given $line, a line read from a .pm file in lib, returns a piece of
text that L</process_pm_file_if_modified> should replace this line
with. Note that it is perfectly appropriate for a filter
implementation to buffer stuff, and therefore not always return
something from I<filter>.
The base class does not buffer. Rather, it substitutes standard
copyright stanzas, and detects the end-of-file on behalf of
L</eof_reached>.
=cut
sub filter {
( run in 2.648 seconds using v1.01-cache-2.11-cpan-d6968d3fc7c )