File Coverage

blib/lib/Dist/Zilla/Role/ModuleIncluder.pm
Criterion Covered Total %
statement 72 74 97.3
branch 12 16 75.0
condition 3 3 100.0
subroutine 15 15 100.0
pod 1 1 100.0
total 103 109 94.5


line stmt bran cond sub pod time code
1             package Dist::Zilla::Role::ModuleIncluder;
2             $Dist::Zilla::Role::ModuleIncluder::VERSION = '0.007';
3             # vim: ts=4 sts=0 sw=0 noet
4 4     4   2024 use Moose::Role;
  4         4  
  4         27  
5 4     4   13621 use MooseX::Types::Moose qw/Bool/;
  4         5  
  4         27  
6              
7 4     4   14427 use Dist::Zilla::File::InMemory 5.000;
  4         227112  
  4         147  
8 4     4   2340 use File::Slurper 'read_binary';
  4         3454  
  4         202  
9 4     4   22 use Scalar::Util qw/reftype/;
  4         3  
  4         184  
10 4     4   18 use List::Util 1.45 'uniq';
  4         58  
  4         199  
11 4     4   9492 use Module::CoreList 5.20160520;
  4         129636  
  4         32  
12 4     4   3840 use Module::Metadata;
  4         15756  
  4         127  
13 4     4   1542 use Perl::PrereqScanner;
  4         415334  
  4         157  
14              
15 4     4   28 use namespace::autoclean;
  4         5  
  4         22  
16              
17             with 'Dist::Zilla::Role::FileInjector';
18              
19             sub _mod_to_filename {
20 14     14   96 my $module = shift;
21 14         162 return File::Spec->catfile('inc', split / :: | ' /x, $module) . '.pm';
22             }
23              
24             my $version = \%Module::CoreList::version;
25              
26             ## no critic (Variables::ProhibitPackageVars)
27              
28             has include_dependencies => (
29             is => 'ro',
30             isa => Bool,
31             default => 1,
32             );
33              
34             {
35             # cache of Module::Metadata objects
36             my %module_files;
37             sub _find_module_by_name {
38 26     26   37 my $module = shift;
39 26 100       106 return $module_files{$module} if exists $module_files{$module};
40 14 50       156 $module_files{$module} = Module::Metadata->find_module_by_name($module)
41             or confess "Can't locate $module";
42             }
43             }
44              
45             around dump_config => sub
46             {
47             my ($orig, $self) = @_;
48             my $config = $self->$orig;
49              
50             my $data = {
51             version => __PACKAGE__->VERSION || '<self>',
52             include_dependencies => ($self->include_dependencies ? 1 : 0),
53             'Module::CoreList' => Module::CoreList->VERSION,
54             };
55             $config->{+__PACKAGE__} = $data;
56              
57             return $config;
58             };
59              
60             sub _get_reqs {
61 12     12   34 my ($self, $reqs, $scanner, $module, $background, $blacklist) = @_;
62 12         67 my $module_file = _find_module_by_name($module);
63 12         3198 my %new_reqs = %{ $scanner->scan_file($module_file)->as_string_hash };
  12         72  
64 12         5649158 $self->log_debug([ 'found dependency of %s: %s %s', $module, $_, $new_reqs{$_} ]) foreach keys %new_reqs;
65              
66             my @real_reqs = grep {
67 12   100     20933 !$blacklist->{$_} && !Module::CoreList::is_core($_, $new_reqs{$_} ? $new_reqs{$_} : undef, $background)
  80         981758  
68             } keys %new_reqs;
69 12         183334 for my $req (@real_reqs) {
70 34 100       3989 if (defined $reqs->{$module}) {
71 25 100       119 next if $reqs->{$module} >= $new_reqs{$req};
72 1         4 $reqs->{$req} = $new_reqs{$req};
73             }
74             else {
75 9         37 $reqs->{$req} = $new_reqs{$req};
76 9         52 $self->_get_reqs($reqs, $scanner, $req, $background, $blacklist);
77             }
78 10         122 $self->log_debug([ 'adding to requirements list: %s %s', $req, $new_reqs{$req} ]);
79             }
80 12         1127 return;
81             }
82              
83             sub _version_normalize {
84 3     3   5 my $version = shift;
85 3 50       178 return $version >= 5.010 ? sprintf "%1.6f", $version->numify : $version->numify;
86             }
87              
88             sub include_modules {
89 4     4 1 9 my ($self, $modules, $background, $options) = @_;
90 4 50       23 my %modules = reftype($modules) eq 'HASH' ? %{$modules} : map { $_ => 0 } @{$modules};
  4         20  
  0         0  
  0         0  
91 4         5 my %reqs;
92 4         48 my $scanner = Perl::PrereqScanner->new;
93 4 50       153910 my %blacklist = map { ( $_ => 1 ) } 'perl', @{ $options->{blacklist} || [] };
  4         17  
  4         33  
94 4 100       142 if ($self->include_dependencies) {
95 3         24 $self->_get_reqs(\%reqs, $scanner, $_, _version_normalize($background), \%blacklist) for keys %modules;
96             }
97 4         16 my @modules = grep { !$modules{$_} } keys %modules;
  4         20  
98 4         37 my %location_for = map { _mod_to_filename($_) => _find_module_by_name($_) } uniq(@modules, keys %reqs);
  14         26  
99             return map {
100 4         530 my $filename = $_;
  14         22  
101 14         58 $self->log_debug([ 'copying for inclusion: %s', $location_for{$filename} ]);
102 14         3490 my $file = Dist::Zilla::File::InMemory->new({name => $filename, encoded_content => read_binary($location_for{$filename})});
103 14         5360 $self->add_file($file);
104 14         6501 $file;
105             } keys %location_for;
106             }
107              
108             1;
109              
110             #ABSTRACT: Include modules and their dependencies in inc/
111              
112             __END__
113              
114             =pod
115              
116             =encoding UTF-8
117              
118             =head1 NAME
119              
120             Dist::Zilla::Role::ModuleIncluder - Include modules and their dependencies in inc/
121              
122             =head1 VERSION
123              
124             version 0.007
125              
126             =head1 DESCRIPTION
127              
128             This role allows your plugin to include one or more modules into the distribution for build time purposes. The modules will not be installed.
129              
130             =head1 ATTRIBUTES
131              
132             =head2 include_dependencies
133              
134             This decides if dependencies should be included as well. This defaults to true.
135              
136             =head1 METHODS
137              
138             =head2 include_modules($modules, $background_perl, $options)
139              
140             Include all modules (and possibly their dependencies) in C<@$modules>, in F<inc/>, except those that are core modules as of perl version C<$background_perl> (which is expected to be a version object). C<$options> is a hash that currently has only one possible key, C<blacklist>, to specify dependencies that shouldn't be included.
141              
142             All the file objects that were added to the distribution are returned as a list.
143              
144             =head1 AUTHOR
145              
146             Leon Timmermans <leont@cpan.org>
147              
148             =head1 COPYRIGHT AND LICENSE
149              
150             This software is copyright (c) 2011 by Leon Timmermans.
151              
152             This is free software; you can redistribute it and/or modify it under
153             the same terms as the Perl 5 programming language system itself.
154              
155             =cut