File Coverage

blib/lib/Dist/Zilla/Plugin/DynamicPrereqs.pm
Criterion Covered Total %
statement 109 110 99.0
branch 35 44 79.5
condition 9 14 64.2
subroutine 25 25 100.0
pod 0 8 0.0
total 178 201 88.5


line stmt bran cond sub pod time code
1 21     21   44719711 use strict;
  21         90  
  21         626  
2 21     21   107 use warnings;
  21         46  
  21         1350  
3             # vim: set ts=8 sts=2 sw=2 tw=100 et :
4             # ABSTRACT: Specify dynamic (user-side) prerequisites for your distribution
5             # KEYWORDS: plugin distribution metadata MYMETA prerequisites Makefile.PL dynamic
6              
7             our $VERSION = '0.040';
8              
9             use Moose;
10 21     21   2705 with
  21         2238249  
  21         185  
11             'Dist::Zilla::Role::FileGatherer',
12             'Dist::Zilla::Role::ModuleMetadata',
13             'Dist::Zilla::Role::FileMunger',
14             'Dist::Zilla::Role::MetaProvider',
15             'Dist::Zilla::Role::PrereqSource',
16             'Dist::Zilla::Role::AfterBuild',
17             'Dist::Zilla::Role::TextTemplate',
18             ;
19             use List::Util 1.45 qw(first notall any uniq);
20 21     21   128746 use Module::Runtime 'module_notional_filename';
  21         560  
  21         1822  
21 21     21   154 use Try::Tiny;
  21         52  
  21         165  
22 21     21   984 use Path::Tiny;
  21         58  
  21         1154  
23 21     21   902 use File::ShareDir;
  21         9598  
  21         979  
24 21     21   3358 use namespace::autoclean;
  21         106538  
  21         982  
25 21     21   860 use Term::ANSIColor 3.00 'colored';
  21         12562  
  21         180  
26 21     21   15204  
  21         157662  
  21         59988  
27             has raw => (
28             isa => 'ArrayRef[Str]',
29             traits => ['Array'],
30             handles => { raw => 'elements' },
31             lazy => 1,
32             default => sub {
33             my $self = shift;
34              
35             my @lines;
36             if (my $filename = $self->raw_from_file) {
37             my $file = first { $_->name eq $filename } @{ $self->zilla->files };
38             $self->log_fatal([ 'no such file in build: %s' ], $filename) if not $file;
39             $self->zilla->prune_file($file);
40             try {
41             @lines = split(/\n/, $file->content);
42             }
43             catch {
44             $self->log_fatal($_);
45             };
46             }
47              
48             $self->log('no content found in -raw/-body!') if not @lines;
49             return \@lines;
50             },
51             );
52              
53             has raw_from_file => (
54             is => 'ro', isa => 'Str',
55             );
56              
57             has $_ => (
58             isa => 'ArrayRef[Str]',
59             traits => ['Array'],
60             handles => { $_ => 'elements' },
61             lazy => 1,
62             default => sub { [] },
63             ) foreach qw(include_subs conditions);
64              
65              
66 25     25 0 8579105 '-raw' => 'raw',
67             '-delimiter' => 'delimiter',
68             '-raw_from_file' => 'raw_from_file',
69 25     25 0 3591 '-include_sub' => 'include_subs',
70             '-condition' => 'conditions',
71             '-body' => 'raw',
72             '-body_from_file' => 'raw_from_file',
73             'body_from_file' => 'raw_from_file',
74             } }
75              
76             around BUILDARGS => sub {
77             my $orig = shift;
78             my $class = shift;
79              
80             my $args = $class->$orig(@_);
81              
82             my $delimiter = delete $args->{delimiter};
83             if (defined $delimiter and length($delimiter)) {
84             s/^\Q$delimiter\E// foreach @{$args->{raw}};
85             }
86              
87             return $args;
88             };
89              
90             my ($self, $args) = @_;
91              
92             $self->log_fatal('[MakeMaker::Awesome] must be at least version 0.19 to be used with [DynamicPrereqs]')
93             if $INC{module_notional_filename('Dist::Zilla::Plugin::MakeMaker::Awesome')}
94 25     25 0 95 and not eval { Dist::Zilla::Plugin::MakeMaker::Awesome->VERSION('0.19') };
95              
96             my %extra_args = %$args;
97             delete @extra_args{ map $_->name, $self->meta->get_all_attributes };
98 25 50 33     128 if (my @keys = keys %extra_args) {
  0         0  
99             $self->log('Warning: unrecognized argument' . (@keys > 1 ? 's' : '')
100 25         763 . ' (' . join(', ', @keys) . ') passed. Perhaps you need to upgrade?');
101 25         159 }
102 25 100       3805 }
103 1 50       10  
104             around dump_config => sub {
105             my ($orig, $self) = @_;
106             my $config = $self->$orig;
107              
108             my $data = {
109             blessed($self) ne __PACKAGE__ ? ( version => $VERSION ) : (),
110             };
111             $config->{+__PACKAGE__} = $data if keys %$data;
112              
113             return $config;
114             };
115              
116              
117             my $self = shift;
118             $self->log_fatal('Build.PL detected - dynamic prereqs will not be added to it!')
119             if first { $_->name eq 'Build.PL' } @{ $self->zilla->files };
120 20     20 0 244298 }
121              
122             # track which subs have already been included by some other instance
123 20     20 0 444837 my %included_subs;
124              
125 20 100   71   102 my $self = shift;
  71         2955  
  20         640  
126              
127             my $file = first { $_->name eq 'Makefile.PL' } @{$self->zilla->files};
128             $self->log_fatal('No Makefile.PL found! Is [MakeMaker] at least version 5.022?') if not $file;
129              
130             my $content = $file->content;
131              
132 23     23 0 45539 $self->log_debug('Inserting dynamic prereq into Makefile.PL...');
133              
134 23     78   186 # we insert our code just *before* this bit in Makefile.PL
  78         3167  
  23         701  
135 23 100       1247 my $insertion_breadcrumb = "\n\nunless ( eval { ExtUtils::MakeMaker";
136              
137 21         130 # insert after declarations for BOTH %WriteMakefileArgs, %FallbackPrereqs.
138             # TODO: if marker cannot be found, fall back to looking for just
139 21         1535 # %WriteMakefileArgs -- this requires modifying the content too.
140             $self->log_fatal('failed to find position in Makefile.PL to munge!')
141             if $content !~ m/\Q$insertion_breadcrumb/mg;
142 21         6244  
143             my $pos = pos($content) - length($insertion_breadcrumb);
144              
145             my $code = join("\n", $self->raw);
146             if (my $conditions = join(' && ', $self->conditions)) {
147 21 50       470 $code = "if ($conditions) {\n"
148             . $code . "\n"
149             . '}' . "\n";
150 21         93 }
151              
152 21         886 $content = substr($content, 0, $pos)
153 21 100       793 . "\n"
154 5         36 . $self->_header . "\n"
155             . $code . "\n"
156             . substr($content, $pos);
157              
158             $content =~ s/\n+\z/\n/;
159 21         733  
160             $content .= $self->_sub_definitions;
161              
162             $file->content($content);
163             return;
164             }
165 21         301  
166             has _header => (
167 21         699 is => 'ro', isa => 'Str',
168             lazy => 1,
169 20         123 default => sub {
170 20         4830 my $self = shift;
171             '# inserted by ' . blessed($self) . ' ' . $self->VERSION;
172             },
173             );
174              
175             has _sub_definitions => (
176             is => 'ro', isa => 'Str',
177             lazy => 1, builder => '_build__sub_definitions',
178             );
179              
180             my $self = shift;
181              
182             my @include_subs = grep +(not exists $included_subs{$_}), $self->_all_required_subs;
183             return '' if not @include_subs;
184              
185             my $content;
186             $content .= "\n" . $self->_header if not keys %included_subs;
187              
188 21     21   58 if (my @missing_subs = grep !-f path($self->_include_sub_root, $_), @include_subs) {
189             $self->log_fatal(
190 21         861 @missing_subs > 1
191 21 100       356 ? [ 'no definitions available for subs %s!', join(', ', map "'".$_."'", @missing_subs) ]
192             : [ 'no definition available for sub \'%s\'!', $missing_subs[0] ]
193 11         22 );
194 11 100       378 }
195              
196 11 100       354 # On consultation with ribasushi I agree that we cannot let authors
197 1 50       76 # use some sub definitions without copious danger tape.
198             $self->_warn_include_subs(@include_subs);
199              
200             my @sub_definitions = map path($self->_include_sub_root, $_)->slurp_utf8, @include_subs;
201             $content .= "\n"
202             . $self->fill_in_string(
203             join("\n", @sub_definitions), {
204             dist => \($self->zilla),
205             plugin => \$self,
206 10         588 },
207             );
208 10         1531 @included_subs{@include_subs} = (() x @include_subs);
209 10         2141  
210             return $content;
211             }
212              
213              
214             my %sub_prereqs = (
215             can_cc => {
216 10         9323 'Config' => '0', # core since perl 5.00307
217             },
218 10         364 can_run => {
219             'File::Spec' => '0', # core since perl 5.00405
220             'Config' => '0', # core since perl 5.00307
221             },
222             parse_args => {
223             'Text::ParseWords' => '0', # core since perl 5.000
224             },
225             has_module => {
226             'Module::Metadata' => '0', # core since perl 5.013009
227             'CPAN::Meta::Requirements' => '2.120620', # core since perl 5.015007
228             },
229             is_miniperl => {
230             'DynaLoader' => '0', # core since perl 5.000
231             },
232             );
233              
234             # instead of including these dependencies in configure-requires, we inline
235             # them right into the distribution in inc/.
236             my %sub_inc_dependencies = (
237             can_xs => {
238             'ExtUtils::HasCompiler' => '0.014',
239             },
240             );
241              
242             my $self = shift;
243              
244             foreach my $required_sub ($self->_all_required_subs) {
245             # FIXME: update %included_subs earlier to account for other coexisting
246             # plugins, or running two instances of the plugin will try to do this twice.
247             my $include_modules = $sub_inc_dependencies{$required_sub} || {};
248             foreach my $module (keys %$include_modules) {
249             (my $path = $module) =~ s{::}{/}g;
250             $path = path('inc', $path . '.pm');
251 25     25 0 1675224 my $cpath = $path->canonpath;
252              
253 25         1026 my $file = first { $_->name eq $path or $_->name eq $cpath } @{ $self->zilla->files };
254             if (not $file) {
255             $self->log([ 'inlining %s into inc/', $module ]);
256 32   100     134 my $installed_filename = Module::Metadata->find_module_by_name($module)
257 32         110 or $self->log_fatal([ 'Can\'t locate %s', $module ]);
258 3         10  
259 3         12 $file = Dist::Zilla::File::OnDisk->new({ name => $installed_filename });
260 3         87 $file->name($path->stringify);
261             $self->add_file($file);
262 3 50   12   18 }
  12         801  
  3         82  
263 3 50       231 $self->log_fatal([ 'failed to find %s in files', $module ]) if not $file;
264 3         20  
265 3 100       923 if (defined $include_modules->{$module} and $include_modules->{$module} > 0) {
266             # check that the file we got actually satisfies our dependency
267             my $mmd = $self->module_metadata_for_file($file);
268 2         597 $self->log_fatal([ '%s version %s required--only found version %s',
269 2         592 $module, $include_modules->{$module},
270 2         583 (defined $mmd->version ? $mmd->version->stringify : 'undef') ])
271             if ($mmd->version || 0) < $include_modules->{$module};
272 2 50       1046 }
273             }
274 2 50 33     18 }
275             }
276 2         13  
277             my $self = shift;
278             foreach my $required_sub ($self->_all_required_subs) {
279             my $configure_prereqs = $sub_prereqs{$required_sub} || {};
280 2 50 50     6712 $self->zilla->register_prereqs(
    100          
281             {
282             phase => 'configure',
283             type => 'requires',
284             },
285             %$configure_prereqs,
286             ) if %$configure_prereqs;
287 20     20 0 34971  
288 20         783 my $develop_prereqs = $sub_inc_dependencies{$required_sub} || {};
289 27   100     107 $self->zilla->register_prereqs(
290 27 100       274 {
291             phase => 'develop',
292             type => 'requires',
293             },
294             %$develop_prereqs,
295             ) if %$develop_prereqs;
296             }
297             }
298 27   100     1389  
299 27 100       126 has _include_sub_root => (
300             is => 'ro', isa => 'Str',
301             lazy => 1,
302             default => sub {
303             my $self = shift;
304             path(File::ShareDir::module_dir($self->meta->name), 'include_subs')->stringify;
305             },
306             );
307              
308             # indicates subs that require other subs to be included
309             my %sub_dependencies = (
310             can_cc => [ qw(can_run) ],
311             can_run => [ qw(maybe_command) ],
312             requires => [ qw(runtime_requires) ],
313             runtime_requires => [ qw(_add_prereq) ],
314             build_requires => [ qw(_add_prereq) ],
315             test_requires => [ qw(_add_prereq) ],
316             want_pp => [ qw(parse_args) ],
317             want_xs => [ qw(want_pp can_xs) ],
318             );
319              
320             has _all_required_subs => (
321             isa => 'ArrayRef[Str]',
322             traits => ['Array'],
323             handles => { _all_required_subs => 'elements' },
324             lazy => 1,
325             default => sub {
326             my $self = shift;
327             my @code = ($self->conditions, $self->raw);
328             my @subs_in_code = !@code ? () :
329             grep {
330             my $sub_name = $_;
331             any { /\b$sub_name\b\(/ } @code
332             } map $_->basename, path($self->_include_sub_root)->children;
333              
334             [ sort($self->_all_required_subs_for(uniq(
335             $self->include_subs, @subs_in_code,
336             ))) ];
337             },
338             );
339              
340             my %required_subs;
341             my ($self, @subs) = @_;
342              
343             @required_subs{@subs} = (() x @subs);
344              
345             foreach my $sub (@subs) {
346             my @subs = @{ $sub_dependencies{$sub} || [] };
347             $self->_all_required_subs_for(@subs)
348             if notall { exists $required_subs{$_} } @subs;
349             }
350              
351             return keys %required_subs;
352 36     36   937 }
353              
354 36         126 my %warn_include_sub = (
355             can_xs => 1,
356 36         97 can_cc => 1,
357 31 100       47 can_run => 1,
  31         188  
358             );
359 31 100   16   171  
  16         75  
360             my ($self, @include_subs) = @_;
361              
362 36         1091 $self->log(colored('Use ' . $_ . ' with great care! Please consult the documentation!', 'bright_yellow'))
363             foreach grep exists $warn_include_sub{$_}, @include_subs;
364             }
365              
366             __PACKAGE__->meta->make_immutable;
367              
368              
369             =pod
370              
371             =encoding UTF-8
372 10     10   38  
373             =head1 NAME
374              
375 10         78 Dist::Zilla::Plugin::DynamicPrereqs - Specify dynamic (user-side) prerequisites for your distribution
376              
377             =head1 VERSION
378              
379             version 0.040
380              
381             =head1 SYNOPSIS
382              
383             In your F<dist.ini>:
384              
385             [DynamicPrereqs]
386             -condition = has_module('Role::Tiny')
387             -condition = !want_pp()
388             -condition = can_xs()
389             -body = requires('Role::Tiny', '1.003000')
390              
391             or:
392              
393             [DynamicPrereqs]
394             -delimiter = |
395             -raw = |test_requires('Devel::Cover')
396             -raw = | if $ENV{EXTENDED_TESTING} or is_smoker();
397              
398             or:
399              
400             [DynamicPrereqs]
401             -raw_from_file = Makefile.args # code snippet in this file
402              
403             =head1 DESCRIPTION
404              
405             This is a L<Dist::Zilla> plugin that inserts code into your F<Makefile.PL> to
406             indicate dynamic (installer-side) prerequisites.
407              
408             Code is inserted immediately after the declarations for C<%WriteMakefileArgs>
409             and C<%FallbackPrereqs>, before they are conditionally modified (when an older
410             L<ExtUtils::MakeMaker> is installed). This gives you an opportunity to add to
411             the C<WriteMakefile> arguments: C<PREREQ_PM>, C<BUILD_REQUIRES>, and
412             C<TEST_REQUIRES>, and therefore modify the prerequisites in the user's
413             F<MYMETA.yml> and F<MYMETA.json> based on conditions found on the user's system.
414              
415             The C<dynamic_config> field in L<metadata|CPAN::Meta::Spec/dynamic_config> is
416             already set for you.
417              
418             =for stopwords usecase
419              
420             You could potentially use this plugin for performing other modifications in
421             F<Makefile.PL> other than user-side prerequisite modifications, but I can't
422             think of a situation where this makes sense. Contact me if you have any ideas!
423              
424             Only F<Makefile.PL> modification is supported at this time. This author
425             considers the use of L<Module::Build> to be questionable in all circumstances,
426             and L<Module::Build::Tiny> does not (yet?) support dynamic configuration.
427              
428             =head1 BE VIGILANT!
429              
430             You are urged to check the generated F<Makefile.PL> for sanity, and to run it
431             at least once to validate its syntax. Although every effort is made to
432             generate valid and correct code, mistakes can happen, so verification is
433             needed before shipping.
434              
435             Please also see the other warnings later in this document.
436              
437             =head1 CONFIGURATION OPTIONS
438              
439             =head2 C<-raw>
440              
441             =head2 C<-body>
442              
443             The code to be inserted; must be valid and complete perl statements. You can
444             reference and modify the already-declared C<%WriteMakefileArgs> and
445             C<%FallbackPrereqs> variables, as inserted into F<Makefile.PL> by
446             L<Dist::Zilla::Plugin::MakeMaker> and subclasses (e.g.
447             L<Dist::Zilla::Plugin::MakeMaker::Awesome> since L<Dist::Zilla> C<5.001>.
448              
449             This option can be used more than once; lines are added in the order in which they are provided.
450              
451             If you use external libraries in the code you are inserting, you B<must> add
452             these modules to C<configure_requires> prereqs in metadata (e.g. via
453             C<[Prereqs / ConfigureRequires]> in your F<dist.ini>).
454              
455             C<-body> first became available in version 0.018.
456              
457             =for Pod::Coverage mvp_multivalue_args mvp_aliases BUILD metadata after_build munge_files register_prereqs gather_files
458              
459             =head2 C<-delimiter>
460              
461             (Available since version 0.007)
462              
463             A string, usually a single character, which is stripped from the beginning of
464             all C<-raw>/C<-body> lines. This is because the INI file format strips all leading
465             whitespace from option values, so including this character at the front allows
466             you to use leading whitespace in an option string, so you can indent blocks of
467             code properly.
468              
469             =head2 C<-raw_from_file>
470              
471             (Available since version 0.010)
472              
473             =head2 C<-body_from_file>
474              
475             (Available since version 0.018)
476              
477             A filename that contains the code to be inserted; must be valid and complete
478             perl statements, as with C<-raw>/C<-body> above. This file must be part of the build,
479             but it is pruned from the built distribution.
480              
481             =head2 C<-condition>
482              
483             (Available since version 0.014)
484              
485             =for stopwords ANDed
486              
487             A perl expression to be included in the condition statement in the
488             F<Makefile.PL>. Multiple C<-condition>s can be provided, in which case they
489             are ANDed together to form the final condition statement. (You must
490             appropriately parenthesize each of your conditions to ensure correct order of
491             operations.) Any use of recognized subroutines will cause their definitions
492             to be included automatically (see L<AVAILABLE SUBROUTINE DEFINITIONS>, below).
493              
494             When combined with C<-raw>/C<-body> lines, the condition is placed first in a C<if>
495             statement, and the C<-raw>/C<-body> lines are contained as the body of the block. For example:
496              
497             [DynamicPrereqs]
498             -condition = "$]" > '5.020'
499             -body = requires('Role::Tiny', '1.003000')
500              
501             results in the F<Makefile.PL> snippet (note that whitespace is not added, in
502             case this affects the parsing:
503              
504             if ("$]" > '5.020') {
505             requires('Role::Tiny', '1.003000')
506             }
507              
508             =head2 C<-include_sub>
509              
510             (Available since version 0.010; rendered unnecessary in 0.016 (all definitions
511             are now included automatically, when used).
512              
513             =head1 AVAILABLE SUBROUTINE DEFINITIONS
514              
515             A number of helper subroutines are available for use within your code inserted
516             via C<-body>, C<-body_from_file>, C<-raw>, C<-raw_from_file>, or C<-condition> clauses. When used, their
517             definition(s) will be included automatically in F<Makefile.PL> (as well as
518             those of any other subroutines I<they> call); necessary prerequisite modules
519             will be added to C<configure requires> metadata.
520              
521             Unless otherwise noted, these all became available in version 0.010.
522             Available subs are:
523              
524             =over 4
525              
526             =item *
527              
528             C<prompt_default_yes($message)> - takes a string (appending "[Y/n]" to it), returns a boolean; see L<ExtUtils::MakeMaker/prompt>
529              
530             =item *
531              
532             C<prompt_default_no($message)> - takes a string (appending "[y/N]" to it), returns a boolean; see L<ExtUtils::MakeMaker/prompt>
533              
534             =item *
535              
536             C<parse_args()> - returns the hashref of options that were passed as arguments to C<perl Makefile.PL>
537              
538             =item *
539              
540             C<can_xs()> - XS capability testing via L<ExtUtils::HasCompiler> (don't forget to also check C<want_pp>!) Available in this form since 0.029.
541              
542             =item *
543              
544             C<can_cc()> - can we locate a (the) C compiler
545              
546             =item *
547              
548             C<can_run()> - check if we can run some command
549              
550             =item *
551              
552             C<is_miniperl()> - returns true if the current perl is miniperl (this may affect your ability to run XS code) Available since 0.033.
553              
554             =item *
555              
556             C<can_use($module [, $version ])> - checks if a module (optionally, at a specified version) can be loaded. (If you don't want to load the module, you should use C<< has_module >>, see below.)
557              
558             =for stopwords backcompat
559              
560             =item *
561              
562             C<has_module($module [, $version_or_range ])> - checks if a module (optionally, at a specified version or matching a L<version range|CPAN::Meta::Spec/version_ranges>) is available in C<%INC>. Does not load the module, so is safe to use with modules that have side effects when loaded. When passed a second argument, returns true or false; otherwise, returns undef or the module's C<$VERSION>. Note that for extremely simple usecases (module has no side effects when loading, and no explicit version is needed), it can be simpler and more backcompat-friendly to simply do: C<< eval { require Foo::Bar } >>. (Current API available since version 0.015.)
563              
564             =item *
565              
566             C<is_smoker()> - is the installation on a smoker machine?
567              
568             =item *
569              
570             C<is_interactive()> - is the installation in an interactive terminal?
571              
572             =item *
573              
574             C<is_trial()> - is the release a -TRIAL or _XXX-versioned release?
575              
576             =item *
577              
578             C<is_os($os, ...)> - true if the OS is any of those listed
579              
580             =item *
581              
582             C<isnt_os($os, ...)> - true if the OS is none of those listed
583              
584             =item *
585              
586             C<maybe_command> - actually a monkeypatch to C<< MM->maybe_command >> (please keep using the fully-qualified form) to work in Cygwin
587              
588             =item *
589              
590             C<runtime_requires($module [, $version ])> - adds the module to runtime prereqs (as a shorthand for editing the hashes in F<Makefile.PL> directly). Added in 0.016.
591              
592             =item *
593              
594             C<requires($module [, $version ])> - alias for C<runtime_requires>. Added in 0.016.
595              
596             =item *
597              
598             C<build_requires($module [, $version ])> - adds the module to build prereqs (as a shorthand for editing the hashes in F<Makefile.PL> directly). Added in 0.016.
599              
600             =item *
601              
602             C<test_requires($module [, $version ])> - adds the module to test prereqs (as a shorthand for editing the hashes in F<Makefile.PL> directly). Added in 0.016.
603              
604             =item *
605              
606             C<want_pp()> - true if the user or CPAN client explicitly specified C<PUREPERL_ONLY> (indicating that no XS-requiring modules or code should be installed). false if the user has explicitly specified C<PUREPERL_ONLY> as 0. undef if no preference was specified.
607              
608             =item *
609              
610             C<want_xs()> - true if C<PUREPERL_ONLY> was specified as 0, or if it was not specified and compiling XS modules is possible (checked via can_xs).
611              
612             =back
613              
614             =head1 WARNING: INCOMPLETE SUBROUTINE IMPLEMENTATIONS!
615              
616             The implementations for some subroutines (in particular, C<can_xs>, C<can_cc>
617             and C<can_run> are still works in progress, incompatible with some architectures and
618             cannot yet be considered a suitable generic solution. Until we are more
619             confident in their implementations, a warning will be printed (to the distribution author)
620             upon use, and
621             their use B<is not advised> without prior consultation with the author and
622             other members of the Perl Toolchain Gang
623             (see L<C<#toolchain> on C<irc.perl.org>|irc://irc.perl.org/#toolchain>).
624              
625             =head1 WARNING: UNSTABLE API!
626              
627             =for stopwords DarkPAN metacpan
628              
629             This plugin is still undergoing active development, and the interfaces B<will>
630             change and grow as I work through the proper way to do various things. As I
631             make changes, I will be using
632             L<metacpan's reverse dependencies list|https://metacpan.org/requires/distribution/Dist-Zilla-Plugin-DynamicPrereqs>
633             and L<http://grep.cpan.me> to find and fix any
634             upstream users, but I obviously cannot do this for DarkPAN users. Regardless,
635             please contact me (see below) and I will keep you directly advised of
636             interface changes.
637              
638             Future planned features:
639              
640             =for stopwords CPANFile
641              
642             =over 4
643              
644             =item *
645              
646             better compiler detection and conditional XS code inclusion
647              
648             =item *
649              
650             interoperability with the L<[CPANFile]|Dist::Zilla::Plugin::CPANFile> plugin (generation of dynamic prerequisites into a F<cpanfile>)
651              
652             =item *
653              
654             something like C<is_perl_at_least('5.008001')> for testing C<$]>
655              
656             =item *
657              
658             inlining of sub content for some checks, to allow constant folding (e.g. C<$^O> and C<$]> checks)
659              
660             =back
661              
662             =head1 LIMITATIONS
663              
664             It is not possible, given the current features of L<ExtUtils::MakeMaker>, to have dynamic prerequisites using the
665             C<recommends>, C<suggests> or C<conflicts> types. (This is because these get added via the C<META_ADD> or
666             C<META_MERGE> Makefile arguments, and these are ignored for the generation of F<MYMETA.json>.)
667              
668             =head1 SEE ALSO
669              
670             =over 4
671              
672             =item *
673              
674             L<Dist::Zilla::Plugin::MakeMaker>
675              
676             =item *
677              
678             L<ExtUtils::MakeMaker/Using Attributes and Parameters>
679              
680             =item *
681              
682             L<Dist::Zilla::Plugin::OSPrereqs>
683              
684             =item *
685              
686             L<Dist::Zilla::Plugin::PerlVersionPrereqs>
687              
688             =item *
689              
690             L<Module::Install::Can>
691              
692             =back
693              
694             =head1 SUPPORT
695              
696             Bugs may be submitted through L<the RT bug tracker|https://rt.cpan.org/Public/Dist/Display.html?Name=Dist-Zilla-Plugin-DynamicPrereqs>
697             (or L<bug-Dist-Zilla-Plugin-DynamicPrereqs@rt.cpan.org|mailto:bug-Dist-Zilla-Plugin-DynamicPrereqs@rt.cpan.org>).
698              
699             There is also a mailing list available for users of this distribution, at
700             L<http://dzil.org/#mailing-list>.
701              
702             There is also an irc channel available for users of this distribution, at
703             L<C<#distzilla> on C<irc.perl.org>|irc://irc.perl.org/#distzilla>.
704              
705             I am also usually active on irc, as 'ether' at C<irc.perl.org> and C<irc.libera.chat>.
706              
707             =head1 AUTHOR
708              
709             Karen Etheridge <ether@cpan.org>
710              
711             =head1 CONTRIBUTORS
712              
713             =for stopwords Graham Knop Ollis
714              
715             =over 4
716              
717             =item *
718              
719             Graham Knop <haarg@haarg.org>
720              
721             =item *
722              
723             Graham Ollis <plicease@cpan.org>
724              
725             =back
726              
727             =head1 COPYRIGHT AND LICENCE
728              
729             This software is copyright (c) 2014 by Karen Etheridge.
730              
731             This is free software; you can redistribute it and/or modify it under
732             the same terms as the Perl 5 programming language system itself.
733              
734             =cut