Alien-Selenium

 view release on metacpan or  search on metacpan

inc/My/Module/Build.pm  view on Meta::CPAN

#!perl -wT
# Copyright Dominique Quatravaux 2006 - Licensed under the same terms as Perl itself

use strict;
use warnings;
use 5.006; # "our" keyword

=head1 NAME

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

=head1 SYNOPSIS

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

=for My::Tests::Below "synopsis" begin

  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

=for My::Tests::Below "synopsis" end

=head1 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 L<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.

=head2 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!

=over

=item 1.

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

   module-starter --mb --module=Main::Screen::Turn::On \
     --author='Dominique Quatravaux' --email='domq@cpan.org' --force

=item 2.

create an C<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 L<SEE
ALSO>.)

=item 3.

Amend the Build.PL as highlighted in the L</SYNOPSIS>.

=item 4.

B<VERY IMPORTANT!> Arrange for My::Module::Build and friends to
B<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:

inc/My/Module/Build.pm  view on Meta::CPAN

    local *MODULE;
    unless (open(MODULE, "<", $module)) {
        warn "Cannot open $module: $!";
        return;
    }
    return 1 if grep {
        m/^require\s+My::Tests::Below\s+unless\s+caller/
    } (<MODULE>);
    return;
}

sub find_test_files_in_directories {
    grep { -d } ("lib", catdir("t", "lib"), "examples");
}

=back

=begin internals

=head1 INTERNAL DOCUMENTATION

This section describes how My::Module::Build works internally. It
should be useful only to people who intend to modify it.

=over

=item I<My::Module::Build::do_create_makefile_pl>

=item I<My::Module::Build::HowAreYouGentlemen::fake_makefile>

Overloaded respectively from L<Module::Build::Base> and
L<Module::Build::Compat> so that typing

=for My::Tests::Below "great justice" begin

   perl Makefile.PL
   make your time

=for My::Tests::Below "great justice" end

produces a helpful message in packages that have a Makefile.PL (see
L<Module::Build/create_makefile_pl> for how to do that). You won't get
signal if you use a "traditional" style Makefile.PL (but on the other
hand the rest of I<My::Module::Build> will not work either, so don't
do that).

This easter egg was a feature of an old GNU-make based build framework
that I created in a former life.  So there.

=cut

sub do_create_makefile_pl {
  my ($self, %args) = @_;
  warn("Cannot take off any Zig, sorry"),
      return $self->SUPER::do_create_makefile_pl(%args) if ($args{fh});
  $args{file} ||= 'Makefile.PL';
  my $retval = $self->SUPER::do_create_makefile_pl(%args);
  my $MakefilePL = read_file($args{file});
  $MakefilePL = <<'PREAMBLE' . $MakefilePL;
use FindBin qw($Bin);
use lib "$Bin/inc";
PREAMBLE
  $MakefilePL =~ s|Module::Build::Compat->write_makefile|My::Module::Build::HowAreYouGentlemen->write_makefile|;
  write_file($args{file}, $MakefilePL);
  return $retval;
}

{
    package My::Module::Build::HowAreYouGentlemen;
    our @ISA=qw(Module::Build::Compat); # Do not explicitly load it because
    # 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}

inc/My/Module/Build.pm  view on Meta::CPAN

copy(catfile($Bin, $Script),
            "$fakemoduledir/inc/My/Module/Build.pm");
write_file(catfile($fakemoduledir, qw(lib My Private Stuff Indeed.pm)),
           <<"BOGON");
#!perl -w

package My::Private::Stuff::Indeed;
use strict;

1;

BOGON

my ($perl) = ($^X =~ m/^(.*)$/); # Untainted
chdir($fakemoduledir);

my $pipe = new IO::Pipe();
$pipe->reader($perl, "$fakemoduledir/Build.PL");
my $log = join('', <$pipe>);
$pipe->close(); is($?, 0, "Running Build.PL");
like($log, qr/version.*0.42/, "Build.PL found the version string");

SKIP: {
    skip "Not testing Build distmeta (YAML not available)", 2
        unless eval { require YAML };

    my $snippet = My::Tests::Below->pod_data_snippet("distmeta");
    my $errfile = "$fakemoduledir/meta-yml-error.log";
    my $script = <<"SCRIPT";
exec > "$errfile" 2>&1
set -x
cd "$fakemoduledir"
$snippet
SCRIPT
    system($script);
    is($?, 0, "creating META.yml using documented procedure")
        or diag($script . read_file($errfile));
    my $META_yml = read_file("$fakemoduledir/META.yml");
    my $excerpt = My::Tests::Below->pod_data_snippet("META.yml excerpt");
    $excerpt =~ s/\n+/\n/gs; $excerpt =~ s/^\n//s;
    like($META_yml, qr/\Q$excerpt\E/,
        "META.yml contains provisions against indexing My::* modules");
    like($META_yml, qr|My\b.*\bPrivate\b.*\bStuff|,
        "these provisions can be customized");
    like($META_yml, qr/\bFake::Module\b/,
        "Fake::Module is indexed");
    like($META_yml, qr/\bFake::Module::Ancillary::Class\b/,
        "Fake::Module::Ancillary::Class is indexed");
    unlike($META_yml, qr/This::Package::Should::Not::Be::Reported/,
        "META.yml should not index stuff that is after __END__");
    unlike($META_yml, qr/Indeed/,
        "META.yml should not index stuff that is in add_to_no_index");
}

# You have no chance to survive...
test_Makefile_PL_your_time($_) for
    ($sample_Build_PL, <<'SUBCLASSED_BUILD_PL');
use strict;
use warnings;

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

my $subclass = My::Module::Build->subclass(code => "");

my $builder = $subclass->new(
      module_name         => 'Fake::Module',
      license             => 'perl',
      dist_author         => 'Octave Hergebelle <hector@tdlgb.org>',
      dist_version_from   => 'lib/Fake/Module.pm',
      dist_abstract       => 'required for Module::Build 0.2805, sheesh',
      requires            => {
        'Module::Build' => 0,
      },
      create_makefile_pl  => 'passthrough',

   build_requires =>    {
#         'Acme::Pony'    => 0,
         My::Module::Build->requires_for_build(),
   },
);

$builder->create_build_script();
1;


SUBCLASSED_BUILD_PL

sub test_Makefile_PL_your_time {
    my ($Build_PL_contents) = @_;
    write_file("$fakemoduledir/Build.PL", $Build_PL_contents);
    system($perl, "$fakemoduledir/Build.PL");
    is($?, 0, "Running Build.PL");
    system("$fakemoduledir/Build", "dist");
    is($?, 0, "Running Build dist");
    unlink("$fakemoduledir/Fake-Module-0.42.tar.gz");
    write_file("$fakemoduledir/test.sh",
           <<"PREAMBLE",
set -e
cd $fakemoduledir
PREAMBLE
               My::Tests::Below->pod_data_snippet("great justice"));
    $pipe = new IO::Pipe;
    $pipe->reader("/bin/sh", "$fakemoduledir/test.sh");
    my $text = join('', <$pipe>);
    $pipe->close();
    is($?, 0, "You are on the way to destruction")
        or warn $text;
    like($text, qr/belong/, "Still first hit on Google, after all these years!");
}



( run in 1.390 second using v1.01-cache-2.11-cpan-cdf2f3d4e48 )