package Dist::Zilla::Plugin::Boilerplate;{
use Dist::Zilla 4 ();
use Moose;
use namespace::autoclean;
use PPI;
use Moose::Autobox 0.09;
use Path::Class;
with(
'Dist::Zilla::Role::FileMunger',
'Dist::Zilla::Role::FileFinderUser' => {
default_finders => [
':InstallModules',
':IncModules',
':ExecFiles',
':TestFiles',
],
},
'Dist::Zilla::Role::PPI',
);
sub mvp_multivalue_args { 'code_line' };
has code_line => (
is => 'ro',
isa => 'ArrayRef[Str]',
required => 1,
);
sub code { shift->code_line->join("\n") }
has _parsed_code => (
is => 'ro',
isa => 'PPI::Element',
init_arg => undef,
builder => '_build_parsed_code',
);
sub _build_parsed_code {
my ($self) = @_;
my $code = $self->code;
PPI::Document->new(\$code);
}
sub import {
my ($class,@tags) = @_;
my ($caller,$filename) = caller();
require Dist::Zilla::Dist::Builder;
my $zilla = Dist::Zilla::Dist::Builder->from_config({
chrome => Dist::Zilla::Plugin::Boilerplate::Chrome->new(),
dist_root => $class->_find_dzil_root($filename),
});
my %tags;@tags{@tags}=();
my @useful = $zilla->plugins->grep(
sub{
$_->isa($class) && exists $tags{$_->plugin_name}
}
)->flatten;
for my $instance (@useful) {
$instance->eval_in($caller);
}
1;
}
sub _find_dzil_root {
my ($self,$filename) = @_;
my $d = file($filename)->parent;
while ($d && ! glob($d->file('dist.*'))) { $d=$d->parent }
return $d;
}
sub eval_in {
my ($self,$package) = @_;
my $code = $self->code;my $name = $self->plugin_name;
my $str = "{package $package;$code;1}";
local $@;
eval $str
or $self->log_fatal("Couldn't eval code for boilerplate into $package: $@");
}
sub munge_files {
my ($self) = @_;
$self->munge_file($_) for $self->found_files->flatten;
}
sub munge_file {
my ($self, $file) = @_;
my $doc = $self->ppi_document_for_file($file);
my $my_uses = $doc->find(
sub{
my $element = $_[1];
$element->isa('PPI::Statement::Include') &&
$element->type eq 'use' &&
$element->module eq __PACKAGE__
}
);
return unless $my_uses;
for my $use ($my_uses->flatten) {
my $tags = $self->_find_tags_from_ppi($use->arguments);
if ($tags->first(sub{$_ eq $self->plugin_name})) {
for my $elem ($self->_parsed_code->children) {
$use->insert_before($elem)
or $self->log_fatal("Couldn't insert $elem before $use\n");
}
$use->delete;
}
}
$self->save_ppi_document_to_file($doc,$file);
}
sub _find_tags_from_ppi {
my ($self,$node) = @_;
if ($node->isa('PPI::Token::Quote')) {
return [$node->string];
}
elsif ($node->isa('PPI::Token::QuoteLike::Words')) {
return [$node->literal];
}
elsif ($node->isa('PPI::Token')) {
return [ $node->content ];
}
elsif ($node->can('find')) {
return [
($node->find('PPI::Token::Quote') || [])
->map(sub{$_->string})->flatten(),
($node->find('PPI::Token::QuoteLike::Words') || [])
->map(sub{$_->literal})->flatten,
];
}
else {
return []
}
}
}
package Dist::Zilla::Plugin::Boilerplate::Chrome;{
use Moose;
has logger => (
is => 'ro',
default => sub {
Log::Dispatchouli->new({
ident => 'Dist::Zilla::Plugin::Boilerplate',
log_pid => 0,
to_self => 0,
to_stdout => 0,
to_stderr => 1,
to_file => 0,
quiet_fatal => 'stderr',
});
}
);
with 'Dist::Zilla::Role::Chrome';
sub prompt_str { return '' }
sub prompt_yn { return 'n' }
sub prompt_any_key { return }
}
1;