use strict;
use warnings;
package Dist::Zilla::Plugin::Test::CleanNamespaces;
BEGIN {
  $Dist::Zilla::Plugin::Test::CleanNamespaces::AUTHORITY = 'cpan:ETHER';
}
# git description: v0.001-3-g5976807
$Dist::Zilla::Plugin::Test::CleanNamespaces::VERSION = '0.002';
# ABSTRACT: Generate a test to check that all namespaces are clean
# vim: set ts=8 sw=4 tw=78 et :

use Moose;
with (
    'Dist::Zilla::Role::FileGatherer',
    'Dist::Zilla::Role::FileMunger',
    'Dist::Zilla::Role::TextTemplate',
    'Dist::Zilla::Role::PrereqSource',
);
use MooseX::Types::Stringlike 'Stringlike';
use Path::Tiny;
use namespace::autoclean;

sub mvp_multivalue_args { qw(skips) }
sub mvp_aliases { return { skip => 'skips' } }

has skips => (
    isa => 'ArrayRef[Str]',
    traits => ['Array'],
    handles => { skips => 'elements' },
    lazy => 1,
    default => sub { [] },
);

has filename => (
    is => 'ro', isa => Stringlike,
    coerce => 1,
    lazy => 1,
    default => sub { path('xt', 'release', 'clean-namespaces.t') },
);

sub register_prereqs
{
    my $self = shift;

    $self->zilla->register_prereqs(
        {
            type  => 'requires',
            phase => $self->filename =~ /^t/ ? 'test' : 'develop',
        },
        'Test::CleanNamespaces' => '>= 0.04, != 0.06',
    );
}

sub gather_files
{
    my $self = shift;

    require Dist::Zilla::File::InMemory;
    $self->add_file( Dist::Zilla::File::InMemory->new(
        name => $self->filename,
        content => <<'TEST',
use strict;
use warnings;

# this test was generated with {{ ref($plugin) . ' ' . ($plugin->VERSION || '<self>') }}

use Test::More 0.94;
use Test::CleanNamespaces 0.04;

subtest all_namespaces_clean => sub { {{
    $skips
    ? "namespaces_clean(\n    "
        . 'grep { my $mod = $_; grep { $mod !~ $_ } ' . $skips . " } Test::CleanNamespaces->find_modules);\n"
    : 'all_namespaces_clean() '
}}};

done_testing;
TEST
    ));
}

sub munge_file
{
    my ($self, $file) = @_;

    return unless $file->name eq $self->filename;

    $file->content(
        $self->fill_in_string(
            $file->content,
            {
                dist => \($self->zilla),
                plugin => \$self,
                skips => \( join(', ', map { 'qr/' . $_ . '/' } $self->skips) ),
            }
        )
    );

    return;
}

__PACKAGE__->meta->make_immutable;

__END__

=pod

=encoding UTF-8

=for :stopwords Karen Etheridge FileFinder irc

=head1 NAME

Dist::Zilla::Plugin::Test::CleanNamespaces - Generate a test to check that all namespaces are clean

=head1 VERSION

version 0.002

=head1 SYNOPSIS

In your F<dist.ini>:

    [Test::CleanNamespaces]
    skip = ::Dirty$

=head1 DESCRIPTION

This is a L<Dist::Zilla> plugin that runs at the
L<gather files|Dist::Zilla::Role::FileGatherer> stage, providing a test file
(configurable, defaulting to F<xt/release/clean-namespaces.t>).

This test will scan all modules in your distribution and check that their
namespaces are "clean" -- that is, that there are no remaining imported
subroutines from other modules that are now callable as methods at runtime.

You can fix this in your code with L<namespace::clean> or
L<namespace::autoclean>.

=for Pod::Coverage mvp_multivalue_args mvp_aliases register_prereqs gather_files munge_file

=head1 CONFIGURATION OPTIONS

=head2 filename

The name of the generated test. Defaults to F<xt/release/clean-namespaces.t>.

=head2 skip

A regular expression describing a module name that should not be checked. Can
be repeated more than once.

=head1 TO DO (or: POSSIBLE FEATURES COMING IN FUTURE RELEASES)

=over 4

=item *

use of a configurable L<FileFinder|Dist::Zilla::Role::FileFinder> for finding

source files to check (depends on changes planned in L<Test::CleanNamespaces>)

=back

=head1 SUPPORT

Bugs may be submitted through L<the RT bug tracker|https://rt.cpan.org/Public/Dist/Display.html?Name=Dist-Zilla-Plugin-Test-CleanNamespaces>
(or L<bug-Dist-Zilla-Plugin-Test-CleanNamespaces@rt.cpan.org|mailto:bug-Dist-Zilla-Plugin-Test-CleanNamespaces@rt.cpan.org>).
I am also usually active on irc, as 'ether' at C<irc.perl.org>.

=head1 SEE ALSO

=over 4

=item *

L<Test::CleanNamespaces>

=item *

L<namespace::clean>

=item *

L<namespace::autoclean>

=item *

L<namespace::sweep>

=item *

L<Sub::Exporter::ForMethods>

=back

=head1 AUTHOR

Karen Etheridge <ether@cpan.org>

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2014 by Karen Etheridge.

This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.

=cut
