Remove Config::Any from the core dep set
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / Optional / Dependencies.pm
1 package DBIx::Class::Optional::Dependencies;
2
3 ### This may look crazy, but it in fact tangibly ( by 50(!)% ) shortens
4 #   the skip-test time when everything requested is unavailable
5 BEGIN {
6   if ( $ENV{RELEASE_TESTING} ) {
7     require warnings and warnings->import;
8     require strict and strict->import;
9   }
10 }
11
12 sub croak {
13   require Carp;
14   Carp::croak(@_);
15 };
16 ###
17
18 # NO EXTERNAL NON-5.8.1 CORE DEPENDENCIES EVER (e.g. C::A::G)
19 # This module is to be loaded by Makefile.PM on a pristine system
20
21 # POD is generated automatically by calling _gen_pod from the
22 # Makefile.PL in $AUTHOR mode
23
24 # *DELIBERATELY* not making a group for these - they must disappear
25 # forever as optdeps in the first place
26 my $moose_basic = {
27   'Moose'                         => '0.98',
28   'MooseX::Types'                 => '0.21',
29   'MooseX::Types::LoadableClass'  => '0.011',
30 };
31
32 my $dbic_reqs = {
33
34   # NOTE: the rationale for 2 JSON::Any versions is that
35   # we need the newer only to work around JSON::XS, which
36   # itself is an optional dep
37   _json_any => {
38     req => {
39       'JSON::Any' => '1.23',
40     },
41   },
42
43   _json_xs_compatible_json_any => {
44     req => {
45       'JSON::Any' => '1.31',
46     },
47   },
48
49   # a common placeholder for engines with IC::DT support based off DT::F::S
50   _ic_dt_strptime_based => {
51     augment => {
52       ic_dt => {
53         req => {
54           'DateTime::Format::Strptime' => '1.2',
55         },
56       },
57     }
58   },
59
60   _rdbms_generic_odbc => {
61     req => {
62       'DBD::ODBC' => 0,
63     }
64   },
65
66   _rdbms_generic_ado => {
67     req => {
68       'DBD::ADO' => 0,
69     }
70   },
71
72   # must list any dep used by adhoc testing
73   # this prevents the "skips due to forgotten deps" issue
74   test_adhoc => {
75     req => {
76       'Class::DBI::Plugin::DeepAbstractSearch' => '0',
77       'Class::DBI' => '3.000005',
78       'Date::Simple' => '3.03',
79       'YAML' => '0',
80       'Class::Unload' => '0.07',
81       'Time::Piece' => '0',
82       'Time::Piece::MySQL' => '0',
83     },
84   },
85
86   replicated => {
87     req => $moose_basic,
88     pod => {
89       title => 'Storage::Replicated',
90       desc => 'Modules required for L<DBIx::Class::Storage::DBI::Replicated>',
91     },
92   },
93
94   test_replicated => {
95     include => 'replicated',
96     req => {
97       'Test::Moose' => '0',
98     },
99   },
100
101   config_file_reader => {
102     pod => {
103       title => 'Generic config reader',
104       desc => 'Modules required for generic config file parsing, currently Config::Any (rarely used at runtime)',
105     },
106     req => {
107       'Config::Any' => '0.20',
108     },
109   },
110
111   admin => {
112     include => [qw( _json_any config_file_reader )],
113     req => {
114       %$moose_basic,
115       'MooseX::Types::Path::Class' => '0.05',
116       'MooseX::Types::JSON' => '0.02',
117     },
118     pod => {
119       title => 'DBIx::Class::Admin',
120       desc => 'Modules required for the DBIx::Class administrative library',
121     },
122   },
123
124   admin_script => {
125     include => 'admin',
126     req => {
127       'Getopt::Long::Descriptive' => '0.081',
128       'Text::CSV' => '1.16',
129     },
130     pod => {
131       title => 'dbicadmin',
132       desc => 'Modules required for the CLI DBIx::Class interface dbicadmin',
133     },
134   },
135
136   deploy => {
137     req => {
138       'SQL::Translator'           => '0.11018',
139     },
140     pod => {
141       title => 'Storage::DBI::deploy()',
142       desc => 'Modules required for L<DBIx::Class::Storage::DBI/deployment_statements> and L<DBIx::Class::Schema/deploy>',
143     },
144   },
145
146   ic_dt => {
147     req => {
148       'DateTime' => '0.55',
149       'DateTime::TimeZone::OlsonDB' => 0,
150     },
151     pod => {
152       title => 'InflateColumn::DateTime support',
153       desc =>
154         'Modules required for L<DBIx::Class::InflateColumn::DateTime>. '
155       . 'Note that this group does not require much on its own, but '
156       . 'instead is augmented by various RDBMS-specific groups. See the '
157       . 'documentation of each C<rbms_*> group for details',
158     },
159   },
160
161   id_shortener => {
162     req => {
163       'Math::BigInt' => '1.80',
164       'Math::Base36' => '0.07',
165     },
166   },
167
168   cdbicompat => {
169     req => {
170       'Class::Data::Inheritable' => '0',
171       'Class::Trigger' => '0',
172       'DBIx::ContextualFetch' => '0',
173       'Clone' => '0.32',
174     },
175     pod => {
176       title => 'DBIx::Class::CDBICompat support',
177       desc => 'Modules required for L<DBIx::Class::CDBICompat>'
178     },
179   },
180
181   test_pod => {
182     req => {
183       'Test::Pod'                 => '1.42',
184     },
185     release_testing_mandatory => 1,
186   },
187
188   test_podcoverage => {
189     req => {
190       'Test::Pod::Coverage'       => '1.08',
191       'Pod::Coverage'             => '0.20',
192     },
193     release_testing_mandatory => 1,
194   },
195
196   test_whitespace => {
197     req => {
198       'Test::EOL'                 => '1.0',
199       'Test::NoTabs'              => '0.9',
200     },
201     release_testing_mandatory => 1,
202   },
203
204   test_strictures => {
205     req => {
206       'Test::Strict'              => '0.20',
207     },
208     release_testing_mandatory => 1,
209   },
210
211   test_prettydebug => {
212     include => '_json_any',
213   },
214
215   test_admin_script => {
216     include => [qw( admin_script _json_xs_compatible_json_any )],
217     req => {
218       'JSON' => 0,
219       'JSON::PP' => 0,
220       'Cpanel::JSON::XS' => 0,
221       'JSON::XS' => 0,
222       $^O eq 'MSWin32'
223         # for t/admin/10script.t
224         ? ('Win32::ShellQuote' => 0)
225         # DWIW does not compile (./configure even) on win32
226         : ('JSON::DWIW' => 0 )
227       ,
228     }
229   },
230
231   test_leaks_heavy => {
232     req => {
233       'Class::MethodCache' => '0.02',
234       'PadWalker' => '1.06',
235     },
236   },
237
238
239   # this is just for completeness as SQLite
240   # is a core dep of DBIC for testing
241   rdbms_sqlite => {
242     req => {
243       'DBD::SQLite' => 0,
244     },
245     pod => {
246       title => 'SQLite support',
247       desc => 'Modules required to connect to SQLite',
248     },
249     augment => {
250       ic_dt => {
251         req => {
252           'DateTime::Format::SQLite' => '0',
253         },
254       },
255     },
256   },
257
258   # centralize the specification, as we have ICDT tests which can
259   # test the full behavior of RDBMS-specific ICDT on top of bare SQLite
260   _ic_dt_pg_base => {
261     augment => {
262       ic_dt => {
263         req => {
264           'DateTime::Format::Pg' => '0.16004',
265         },
266       },
267     },
268   },
269
270   ic_dt_pg => {
271     include => [qw( ic_dt _ic_dt_pg_base )],
272   },
273
274   rdbms_pg => {
275     include => '_ic_dt_pg_base',
276     req => {
277       # when changing this list make sure to adjust xt/optional_deps.t
278       'DBD::Pg' => 0,
279     },
280     pod => {
281       title => 'PostgreSQL support',
282       desc => 'Modules required to connect to PostgreSQL',
283     },
284   },
285
286   _rdbms_mssql_common => {
287     include => '_ic_dt_strptime_based',
288   },
289
290   rdbms_mssql_odbc => {
291     include => [qw( _rdbms_generic_odbc _rdbms_mssql_common )],
292     pod => {
293       title => 'MSSQL support via DBD::ODBC',
294       desc => 'Modules required to connect to MSSQL via DBD::ODBC',
295     },
296   },
297
298   rdbms_mssql_sybase => {
299     include => '_rdbms_mssql_common',
300     req => {
301       'DBD::Sybase' => 0,
302     },
303     pod => {
304       title => 'MSSQL support via DBD::Sybase',
305       desc => 'Modules required to connect to MSSQL via DBD::Sybase',
306     },
307   },
308
309   rdbms_mssql_ado => {
310     include => [qw( _rdbms_generic_ado _rdbms_mssql_common )],
311     pod => {
312       title => 'MSSQL support via DBD::ADO (Windows only)',
313       desc => 'Modules required to connect to MSSQL via DBD::ADO. This particular DBD is available on Windows only',
314     },
315   },
316
317   _rdbms_msaccess_common => {
318     include => '_ic_dt_strptime_based',
319   },
320
321   rdbms_msaccess_odbc => {
322     include => [qw( _rdbms_generic_odbc _rdbms_msaccess_common )],
323     pod => {
324       title => 'MS Access support via DBD::ODBC',
325       desc => 'Modules required to connect to MS Access via DBD::ODBC',
326     },
327   },
328
329   rdbms_msaccess_ado => {
330     include => [qw( _rdbms_generic_ado _rdbms_msaccess_common )],
331     pod => {
332       title => 'MS Access support via DBD::ADO (Windows only)',
333       desc => 'Modules required to connect to MS Access via DBD::ADO. This particular DBD is available on Windows only',
334     },
335   },
336
337   # centralize the specification, as we have ICDT tests which can
338   # test the full behavior of RDBMS-specific ICDT on top of bare SQLite
339   _ic_dt_mysql_base => {
340     augment => {
341       ic_dt => {
342         req => {
343           'DateTime::Format::MySQL' => '0',
344         },
345       },
346     },
347   },
348
349   ic_dt_mysql => {
350     include => [qw( ic_dt _ic_dt_mysql_base )],
351   },
352
353   rdbms_mysql => {
354     include => '_ic_dt_mysql_base',
355     req => {
356       'DBD::mysql' => 0,
357     },
358     pod => {
359       title => 'MySQL support',
360       desc => 'Modules required to connect to MySQL',
361     },
362   },
363
364   rdbms_oracle => {
365     include => 'id_shortener',
366     req => {
367       'DBD::Oracle' => 0,
368     },
369     pod => {
370       title => 'Oracle support',
371       desc => 'Modules required to connect to Oracle',
372     },
373     augment => {
374       ic_dt => {
375         req => {
376           'DateTime::Format::Oracle' => '0',
377         },
378       },
379     },
380   },
381
382   rdbms_ase => {
383     include => '_ic_dt_strptime_based',
384     req => {
385       'DBD::Sybase' => 0,
386     },
387     pod => {
388       title => 'Sybase ASE support',
389       desc => 'Modules required to connect to Sybase ASE',
390     },
391   },
392
393   _rdbms_db2_common => {
394     augment => {
395       ic_dt => {
396         req => {
397           'DateTime::Format::DB2' => '0',
398         },
399       },
400     },
401   },
402
403   rdbms_db2 => {
404     include => '_rdbms_db2_common',
405     req => {
406       'DBD::DB2' => 0,
407     },
408     pod => {
409       title => 'DB2 support',
410       desc => 'Modules required to connect to DB2',
411     },
412   },
413
414   rdbms_db2_400 => {
415     include => [qw( _rdbms_generic_odbc _rdbms_db2_common )],
416     pod => {
417       title => 'DB2 on AS/400 support',
418       desc => 'Modules required to connect to DB2 on AS/400',
419     },
420   },
421
422   rdbms_informix => {
423     include => '_ic_dt_strptime_based',
424     req => {
425       'DBD::Informix' => 0,
426     },
427     pod => {
428       title => 'Informix support',
429       desc => 'Modules required to connect to Informix',
430     },
431   },
432
433   _rdbms_sqlanywhere_common => {
434     include => '_ic_dt_strptime_based',
435   },
436
437   rdbms_sqlanywhere => {
438     include => '_rdbms_sqlanywhere_common',
439     req => {
440       'DBD::SQLAnywhere' => 0,
441     },
442     pod => {
443       title => 'SQLAnywhere support',
444       desc => 'Modules required to connect to SQLAnywhere',
445     },
446   },
447
448   rdbms_sqlanywhere_odbc => {
449     include => [qw( _rdbms_generic_odbc _rdbms_sqlanywhere_common )],
450     pod => {
451       title => 'SQLAnywhere support via DBD::ODBC',
452       desc => 'Modules required to connect to SQLAnywhere via DBD::ODBC',
453     },
454   },
455
456   _rdbms_firebird_common => {
457     include => '_ic_dt_strptime_based',
458   },
459
460   rdbms_firebird => {
461     include => '_rdbms_firebird_common',
462     req => {
463       'DBD::Firebird' => 0,
464     },
465     pod => {
466       title => 'Firebird support',
467       desc => 'Modules required to connect to Firebird',
468     },
469   },
470
471   rdbms_firebird_interbase => {
472     include => '_rdbms_firebird_common',
473     req => {
474       'DBD::InterBase' => 0,
475     },
476     pod => {
477       title => 'Firebird support via DBD::InterBase',
478       desc => 'Modules required to connect to Firebird via DBD::InterBase',
479     },
480   },
481
482   rdbms_firebird_odbc => {
483     include => [qw( _rdbms_generic_odbc _rdbms_firebird_common )],
484     pod => {
485       title => 'Firebird support via DBD::ODBC',
486       desc => 'Modules required to connect to Firebird via DBD::ODBC',
487     },
488   },
489
490   test_rdbms_sqlite => {
491     include => 'rdbms_sqlite',
492     req => {
493       ###
494       ### IMPORTANT - do not raise this dependency
495       ### even though many bugfixes are present in newer versions, the general DBIC
496       ### rule is to bend over backwards for available DBDs (given upgrading them is
497       ### often *not* easy or even possible)
498       ###
499       'DBD::SQLite' => '1.29',
500     },
501   },
502
503   test_rdbms_pg => {
504     include => 'rdbms_pg',
505     env => [
506       DBICTEST_PG_DSN => 1,
507       DBICTEST_PG_USER => 0,
508       DBICTEST_PG_PASS => 0,
509     ],
510     req => {
511       # the order does matter because the rdbms support group might require
512       # a different version that the test group
513       #
514       # when changing this list make sure to adjust xt/optional_deps.t
515       'DBD::Pg' => '2.009002',  # specific version to test bytea
516     },
517   },
518
519   test_rdbms_mssql_odbc => {
520     include => 'rdbms_mssql_odbc',
521     env => [
522       DBICTEST_MSSQL_ODBC_DSN => 1,
523       DBICTEST_MSSQL_ODBC_USER => 0,
524       DBICTEST_MSSQL_ODBC_PASS => 0,
525     ],
526   },
527
528   test_rdbms_mssql_ado => {
529     include => 'rdbms_mssql_ado',
530     env => [
531       DBICTEST_MSSQL_ADO_DSN => 1,
532       DBICTEST_MSSQL_ADO_USER => 0,
533       DBICTEST_MSSQL_ADO_PASS => 0,
534     ],
535   },
536
537   test_rdbms_mssql_sybase => {
538     include => 'rdbms_mssql_sybase',
539     env => [
540       DBICTEST_MSSQL_DSN => 1,
541       DBICTEST_MSSQL_USER => 0,
542       DBICTEST_MSSQL_PASS => 0,
543     ],
544   },
545
546   test_rdbms_msaccess_odbc => {
547     include => 'rdbms_msaccess_odbc',
548     env => [
549       DBICTEST_MSACCESS_ODBC_DSN => 1,
550       DBICTEST_MSACCESS_ODBC_USER => 0,
551       DBICTEST_MSACCESS_ODBC_PASS => 0,
552     ],
553     req => {
554       'Data::GUID' => '0',
555     },
556   },
557
558   test_rdbms_msaccess_ado => {
559     include => 'rdbms_msaccess_ado',
560     env => [
561       DBICTEST_MSACCESS_ADO_DSN => 1,
562       DBICTEST_MSACCESS_ADO_USER => 0,
563       DBICTEST_MSACCESS_ADO_PASS => 0,
564     ],
565     req => {
566       'Data::GUID' => 0,
567     },
568   },
569
570   test_rdbms_mysql => {
571     include => 'rdbms_mysql',
572     env => [
573       DBICTEST_MYSQL_DSN => 1,
574       DBICTEST_MYSQL_USER => 0,
575       DBICTEST_MYSQL_PASS => 0,
576     ],
577   },
578
579   test_rdbms_oracle => {
580     include => 'rdbms_oracle',
581     env => [
582       DBICTEST_ORA_DSN => 1,
583       DBICTEST_ORA_USER => 0,
584       DBICTEST_ORA_PASS => 0,
585     ],
586     req => {
587       'DBD::Oracle'              => '1.24',
588     },
589   },
590
591   test_rdbms_ase => {
592     include => 'rdbms_ase',
593     env => [
594       DBICTEST_SYBASE_DSN => 1,
595       DBICTEST_SYBASE_USER => 0,
596       DBICTEST_SYBASE_PASS => 0,
597     ],
598   },
599
600   test_rdbms_db2 => {
601     include => 'rdbms_db2',
602     env => [
603       DBICTEST_DB2_DSN => 1,
604       DBICTEST_DB2_USER => 0,
605       DBICTEST_DB2_PASS => 0,
606     ],
607   },
608
609   test_rdbms_db2_400 => {
610     include => 'rdbms_db2_400',
611     env => [
612       DBICTEST_DB2_400_DSN => 1,
613       DBICTEST_DB2_400_USER => 0,
614       DBICTEST_DB2_400_PASS => 0,
615     ],
616   },
617
618   test_rdbms_informix => {
619     include => 'rdbms_informix',
620     env => [
621       DBICTEST_INFORMIX_DSN => 1,
622       DBICTEST_INFORMIX_USER => 0,
623       DBICTEST_INFORMIX_PASS => 0,
624     ],
625   },
626
627   test_rdbms_sqlanywhere => {
628     include => 'rdbms_sqlanywhere',
629     env => [
630       DBICTEST_SQLANYWHERE_DSN => 1,
631       DBICTEST_SQLANYWHERE_USER => 0,
632       DBICTEST_SQLANYWHERE_PASS => 0,
633     ],
634   },
635
636   test_rdbms_sqlanywhere_odbc => {
637     include => 'rdbms_sqlanywhere_odbc',
638     env => [
639       DBICTEST_SQLANYWHERE_ODBC_DSN => 1,
640       DBICTEST_SQLANYWHERE_ODBC_USER => 0,
641       DBICTEST_SQLANYWHERE_ODBC_PASS => 0,
642     ],
643   },
644
645   test_rdbms_firebird => {
646     include => 'rdbms_firebird',
647     env => [
648       DBICTEST_FIREBIRD_DSN => 1,
649       DBICTEST_FIREBIRD_USER => 0,
650       DBICTEST_FIREBIRD_PASS => 0,
651     ],
652   },
653
654   test_rdbms_firebird_interbase => {
655     include => 'rdbms_firebird_interbase',
656     env => [
657       DBICTEST_FIREBIRD_INTERBASE_DSN => 1,
658       DBICTEST_FIREBIRD_INTERBASE_USER => 0,
659       DBICTEST_FIREBIRD_INTERBASE_PASS => 0,
660     ],
661   },
662
663   test_rdbms_firebird_odbc => {
664     include => 'rdbms_firebird_odbc',
665     env => [
666       DBICTEST_FIREBIRD_ODBC_DSN => 1,
667       DBICTEST_FIREBIRD_ODBC_USER => 0,
668       DBICTEST_FIREBIRD_ODBC_PASS => 0,
669     ],
670   },
671
672   test_memcached => {
673     env => [
674       DBICTEST_MEMCACHED => 1,
675     ],
676     req => {
677       'Cache::Memcached' => 0,
678     },
679   },
680
681   dist_dir => {
682     # we need to run the dbicadmin so we can self-generate its POD
683     # also we do not want surprises in case JSON::XS is in the path
684     # so make sure we get an always-working JSON::Any
685     include => [qw(
686       admin_script
687       _json_xs_compatible_json_any
688       id_shortener
689       deploy
690       test_pod
691       test_podcoverage
692       test_whitespace
693       test_strictures
694     )],
695     req => {
696       'ExtUtils::MakeMaker' => '6.64',
697       'Module::Install'     => '1.06',
698       'Pod::Inherit'        => '0.91',
699     },
700   },
701
702   dist_upload => {
703     req => {
704       'CPAN::Uploader' => '0.103001',
705     },
706   },
707 };
708
709
710
711 ### Public API
712
713 sub import {
714   my $class = shift;
715
716   if (@_) {
717
718     my $action = shift;
719
720     if ($action eq '-die_without') {
721       my $err;
722       {
723         local $@;
724         eval { $class->die_unless_req_ok_for(\@_); 1 }
725           or $err = $@;
726       }
727       die "\n$err\n" if $err;
728     }
729     elsif ($action eq '-list_missing') {
730       print $class->modreq_missing_for(\@_);
731       print "\n";
732       exit 0;
733     }
734     elsif ($action eq '-skip_all_without') {
735
736       # sanity check - make sure ->current_test is 0 and no plan has been declared
737       do {
738         local $@;
739         defined eval {
740           Test::Builder->new->current_test
741             or
742           Test::Builder->new->has_plan
743         };
744       } and croak("Unable to invoke -skip_all_without after testing has started");
745
746       if ( my $missing = $class->req_missing_for(\@_) ) {
747
748         die ("\nMandatory requirements not satisfied during release-testing: $missing\n\n")
749           if $ENV{RELEASE_TESTING} and $class->_groups_to_reqs(\@_)->{release_testing_mandatory};
750
751         print "1..0 # SKIP requirements not satisfied: $missing\n";
752         exit 0;
753       }
754     }
755     elsif ($action =~ /^-/) {
756       croak "Unknown import-time action '$action'";
757     }
758     else {
759       croak "$class is not an exporter, unable to import '$action'";
760     }
761   }
762
763   1;
764 }
765
766 sub unimport {
767   croak( __PACKAGE__ . " does not implement unimport" );
768 }
769
770 # OO for (mistakenly considered) ease of extensibility, not due to any need to
771 # carry state of any sort. This API is currently used outside, so leave as-is.
772 # FIXME - make sure to not propagate this further if module is extracted as a
773 # standalone library - keep the stupidity to a DBIC-secific shim!
774 #
775 sub req_list_for {
776   shift->_groups_to_reqs(shift)->{effective_modreqs};
777 }
778
779 sub modreq_list_for {
780   shift->_groups_to_reqs(shift)->{modreqs};
781 }
782
783 sub req_group_list {
784   +{ map
785     { $_ => $_[0]->_groups_to_reqs($_) }
786     grep { $_ !~ /^_/ } keys %$dbic_reqs
787   }
788 }
789
790 sub req_errorlist_for { shift->modreq_errorlist_for(shift) }  # deprecated
791 sub modreq_errorlist_for {
792   my ($self, $groups) = @_;
793   $self->_errorlist_for_modreqs( $self->_groups_to_reqs($groups)->{modreqs} );
794 }
795
796 sub req_ok_for {
797   shift->req_missing_for(shift) ? 0 : 1;
798 }
799
800 sub req_missing_for {
801   my ($self, $groups) = @_;
802
803   my $reqs = $self->_groups_to_reqs($groups);
804
805   my $mods_missing = $reqs->{missing_envvars}
806     ? $self->_list_physically_missing_modules( $reqs->{modreqs} )
807     : $self->modreq_missing_for($groups)
808   ;
809
810   return '' if
811     ! $mods_missing
812       and
813     ! $reqs->{missing_envvars}
814   ;
815
816   my @res = $mods_missing || ();
817
818   push @res, 'the following group(s) of environment variables: ' . join ' and ', sort map
819     { __envvar_group_desc($_) }
820     @{$reqs->{missing_envvars}}
821   if $reqs->{missing_envvars};
822
823   return (
824     ( join ' as well as ', @res )
825       .
826     ( $reqs->{modreqs_fully_documented} ? " (see @{[ ref $self || $self ]} documentation for details)" : '' ),
827   );
828 }
829
830 sub modreq_missing_for {
831   my ($self, $groups) = @_;
832
833   my $reqs = $self->_groups_to_reqs($groups);
834   my $modreq_errors = $self->_errorlist_for_modreqs($reqs->{modreqs})
835     or return '';
836
837   join ' ', map
838     { $reqs->{modreqs}{$_} ? "$_~$reqs->{modreqs}{$_}" : $_ }
839     sort { lc($a) cmp lc($b) } keys %$modreq_errors
840   ;
841 }
842
843 my $tb;
844 sub skip_without {
845   my ($self, $groups) = @_;
846
847   $tb ||= do { local $@; eval { Test::Builder->new } }
848     or croak "Calling skip_without() before loading Test::Builder makes no sense";
849
850   if ( my $err = $self->req_missing_for($groups) ) {
851     my ($fn, $ln) = (caller(0))[1,2];
852     $tb->skip("block in $fn around line $ln requires $err");
853     local $^W = 0;
854     last SKIP;
855   }
856
857   1;
858 }
859
860 sub die_unless_req_ok_for {
861   if (my $err = shift->req_missing_for(shift) ) {
862     die "Unable to continue due to missing requirements: $err\n";
863   }
864 }
865
866
867
868 ### Private functions
869
870 # potentially shorten group desc
871 sub __envvar_group_desc {
872   my @envs = @{$_[0]};
873
874   my (@res, $last_prefix);
875   while (my $ev = shift @envs) {
876     my ($pref, $sep, $suff) = split / ([\_\-]) (?= [^\_\-]+ \z )/x, $ev;
877
878     if ( defined $sep and ($last_prefix||'') eq $pref ) {
879         push @res, "...${sep}${suff}"
880     }
881     else {
882       push @res, $ev;
883     }
884
885     $last_prefix = $pref if $sep;
886   }
887
888   join '/', @res;
889 }
890
891 my $groupname_re = qr/ [a-z_] [0-9_a-z]* /x;
892 my $modname_re = qr/ [A-Z_a-z] [0-9A-Z_a-z]* (?:::[0-9A-Z_a-z]+)* /x;
893 my $modver_re = qr/ [0-9]+ (?: \. [0-9]+ )? /x;
894
895 # Expand includes from a random group in a specific order:
896 # nonvariable groups first, then their includes, then the variable groups,
897 # then their includes.
898 # This allows reliably marking the rest of the mod reqs as variable (this is
899 # also why variable includes are currently not allowed)
900 sub __expand_includes {
901   my ($groups, $seen) = @_;
902
903   # !! DIFFERENT !! behavior and return depending on invocation mode
904   # (easier to recurse this way)
905   my $is_toplevel = $seen
906     ? 0
907     : !! ($seen = {})
908   ;
909
910   my ($res_per_type, $missing_envvars);
911
912   # breadth-first evaluation, with non-variable includes on top
913   for my $g (@$groups) {
914
915     croak "Invalid requirement group name '$g': only ascii alphanumerics and _ are allowed"
916       if $g !~ qr/ \A $groupname_re \z/x;
917
918     my $r = $dbic_reqs->{$g}
919       or croak "Requirement group '$g' is not defined";
920
921     # always do this check *before* the $seen check
922     croak "Group '$g' with variable effective_modreqs can not be specified as an 'include'"
923       if ( $r->{env} and ! $is_toplevel );
924
925     next if $seen->{$g}++;
926
927     my $req_type = 'static';
928
929     if ( my @e = @{$r->{env}||[]} ) {
930
931       croak "Unexpected 'env' attribute under group '$g' (only allowed in test_* groups)"
932         unless $g =~ /^test_/;
933
934       croak "Unexpected *odd* list in 'env' under group '$g'"
935         if @e % 2;
936
937       # deconstruct the whole thing
938       my (@group_envnames_list, $some_envs_required, $some_required_missing);
939       while (@e) {
940         push @group_envnames_list, my $envname = shift @e;
941
942         # env required or not
943         next unless shift @e;
944
945         $some_envs_required ||= 1;
946
947         $some_required_missing ||= (
948           ! defined $ENV{$envname}
949             or
950           ! length $ENV{$envname}
951         );
952       }
953
954       croak "None of the envvars in group '$g' declared as required, making the requirement moot"
955         unless $some_envs_required;
956
957       if ($some_required_missing) {
958         push @{$missing_envvars->{$g}}, \@group_envnames_list;
959         $req_type = 'variable';
960       }
961     }
962
963     push @{$res_per_type->{"base_${req_type}"}}, $g;
964
965     if (my $i = $dbic_reqs->{$g}{include}) {
966       $i = [ $i ] unless ref $i eq 'ARRAY';
967
968       croak "Malformed 'include' for group '$g': must be another existing group name or arrayref of existing group names"
969         unless @$i;
970
971       push @{$res_per_type->{"incs_${req_type}"}}, @$i;
972     }
973   }
974
975   my @ret = map {
976     @{ $res_per_type->{"base_${_}"} || [] },
977     ( $res_per_type->{"incs_${_}"} ? __expand_includes( $res_per_type->{"incs_${_}"}, $seen ) : () ),
978   } qw(static variable);
979
980   return ! $is_toplevel ? @ret : do {
981     my $rv = {};
982     $rv->{$_} = {
983       idx => 1 + keys %$rv,
984       missing_envvars => $missing_envvars->{$_},
985     } for @ret;
986     $rv->{$_}{user_requested} = 1 for @$groups;
987     $rv;
988   };
989 }
990
991 ### Private OO API
992 our %req_unavailability_cache;
993
994 # this method is just a lister and envvar/metadata checker - it does not try to load anything
995 sub _groups_to_reqs {
996   my ($self, $want) = @_;
997
998   $want = [ $want || () ]
999     unless ref $want eq 'ARRAY';
1000
1001   croak "@{[ (caller(1))[3] ]}() expects a requirement group name or arrayref of group names"
1002     unless @$want;
1003
1004   my $ret = {
1005     modreqs => {},
1006     modreqs_fully_documented => 1,
1007   };
1008
1009   my $groups;
1010   for my $piece (@$want) {
1011     if ($piece =~ qr/ \A $groupname_re \z /x) {
1012       push @$groups, $piece;
1013     }
1014     elsif ( my ($mod, $ver) = $piece =~ qr/ \A ($modname_re) \>\= ($modver_re) \z /x ) {
1015       croak "Ad hoc module specification lists '$mod' twice"
1016         if exists $ret->{modreqs}{$mod};
1017
1018       croak "Ad hoc module specification '${mod} >= $ver' (or greater) not listed in the test_adhoc optdep group" if (
1019         ! defined $dbic_reqs->{test_adhoc}{req}{$mod}
1020           or
1021         $dbic_reqs->{test_adhoc}{req}{$mod} < $ver
1022       );
1023
1024       $ret->{modreqs}{$mod} = $ver;
1025       $ret->{modreqs_fully_documented} = 0;
1026     }
1027     else {
1028       croak "Unsupported argument '$piece' supplied to @{[ (caller(1))[3] ]}()"
1029     }
1030   }
1031
1032   my $all_groups = __expand_includes($groups);
1033
1034   # pre-assemble list of augmentations, perform basic sanity checks
1035   # Note that below we *DO NOT* respect the source/target reationship, but
1036   # instead always default to augment the "later" group
1037   # This is done so that the "stable/variable" boundary keeps working as
1038   # expected
1039   my $augmentations;
1040   for my $requesting_group (keys %$all_groups) {
1041     if (my $ag = $dbic_reqs->{$requesting_group}{augment}) {
1042       for my $target_group (keys %$ag) {
1043
1044         croak "Group '$requesting_group' claims to augment a non-existent group '$target_group'"
1045           unless $dbic_reqs->{$target_group};
1046
1047         croak "Augmentation combined with variable effective_modreqs currently unsupported for group '$requesting_group'"
1048           if $dbic_reqs->{$requesting_group}{env};
1049
1050         croak "Augmentation of group '$target_group' with variable effective_modreqs unsupported (requested by '$requesting_group')"
1051           if $dbic_reqs->{$target_group}{env};
1052
1053         if (my @foreign = grep { $_ ne 'req' } keys %{$ag->{$target_group}} ) {
1054           croak "Only 'req' augmentations are currently supported (group '$requesting_group' attempts to alter '$foreign[0]' of group '$target_group'";
1055         }
1056
1057         $ret->{augments}{$target_group} = 1;
1058
1059         # no augmentation for stuff that hasn't been selected
1060         if ( $all_groups->{$target_group} and my $ar = $ag->{$target_group}{req} ) {
1061           push @{$augmentations->{
1062             ( $all_groups->{$requesting_group}{idx} < $all_groups->{$target_group}{idx} )
1063               ? $target_group
1064               : $requesting_group
1065           }}, $ar;
1066         }
1067       }
1068     }
1069   }
1070
1071   for my $group (sort { $all_groups->{$a}{idx} <=> $all_groups->{$b}{idx} } keys %$all_groups ) {
1072
1073     my $group_reqs = $dbic_reqs->{$group}{req};
1074
1075     # sanity-check
1076     for my $req_bag ($group_reqs, @{ $augmentations->{$group} || [] } ) {
1077       for (keys %$req_bag) {
1078
1079         $_ =~ / \A $modname_re \z /x
1080           or croak "Requirement '$_' in group '$group' is not a valid module name";
1081
1082         # !!!DO NOT CHANGE!!!
1083         # remember - version.pm may not be available on the system
1084         croak "Requirement '$_' in group '$group' specifies an invalid version '$req_bag->{$_}' (only plain non-underscored floating point decimals are supported)"
1085           if ( ($req_bag->{$_}||0) !~ qr/ \A $modver_re \z /x );
1086       }
1087     }
1088
1089     if (my $e = $all_groups->{$group}{missing_envvars}) {
1090       push @{$ret->{missing_envvars}}, @$e;
1091     }
1092
1093     # assemble into the final ret
1094     for my $type (
1095       'modreqs',
1096       ( $ret->{missing_envvars} ? () : 'effective_modreqs' ),
1097     ) {
1098       for my $req_bag ($group_reqs, @{ $augmentations->{$group} || [] } ) {
1099         for my $mod (keys %$req_bag) {
1100
1101           $ret->{$type}{$mod} = $req_bag->{$mod}||0 if (
1102
1103             ! exists $ret->{$type}{$mod}
1104               or
1105             # we sanitized the version to be numeric above - we can just -gt it
1106             ($req_bag->{$mod}||0) > $ret->{$type}{$mod}
1107
1108           );
1109         }
1110       }
1111     }
1112
1113     $ret->{modreqs_fully_documented} &&= !!$dbic_reqs->{$group}{pod}
1114       if $all_groups->{$group}{user_requested};
1115
1116     $ret->{release_testing_mandatory} ||= !!$dbic_reqs->{$group}{release_testing_mandatory};
1117   }
1118
1119   return $ret;
1120 }
1121
1122
1123 # this method tries to find/load specified modreqs and returns a hashref of
1124 # module/loaderror pairs for anything that failed
1125 sub _errorlist_for_modreqs {
1126   # args supposedly already went through _groups_to_reqs and are therefore sanitized
1127   # safe to eval at will
1128   my ($self, $reqs) = @_;
1129
1130   my $ret;
1131
1132   for my $m ( keys %$reqs ) {
1133     my $v = $reqs->{$m};
1134
1135     if (! exists $req_unavailability_cache{$m}{$v} ) {
1136       local $@;
1137       eval( "require $m;" . ( $v ? "$m->VERSION(q($v))" : '' ) );
1138       $req_unavailability_cache{$m}{$v} = $@;
1139     }
1140
1141     $ret->{$m} = $req_unavailability_cache{$m}{$v}
1142       if $req_unavailability_cache{$m}{$v};
1143   }
1144
1145   $ret;
1146 }
1147
1148 # Unlike the above DO NOT try to load anything
1149 # This is executed when some needed envvars are not available
1150 # which in turn means a module load will never be reached anyway
1151 # This is important because some modules (especially DBDs) can be
1152 # *really* fickle when a require() is attempted, with pretty confusing
1153 # side-effects (especially on windows)
1154 sub _list_physically_missing_modules {
1155   my ($self, $modreqs) = @_;
1156
1157   # in case there is a coderef in @INC there is nothing we can definitively prove
1158   # so short circuit directly
1159   return '' if grep { length ref $_ } @INC;
1160
1161   my @definitely_missing;
1162   for my $mod (keys %$modreqs) {
1163     (my $fn = $mod . '.pm') =~ s|::|/|g;
1164
1165     push @definitely_missing, $mod unless grep
1166       # this should work on any combination of slashes
1167       { $_ and -d $_ and -f "$_/$fn" and -r "$_/$fn" }
1168       @INC
1169     ;
1170   }
1171
1172   join ' ', map
1173     { $modreqs->{$_} ? "$_~$modreqs->{$_}" : $_ }
1174     sort { lc($a) cmp lc($b) } @definitely_missing
1175   ;
1176 }
1177
1178
1179 # This is to be called by the author only (automatically in Makefile.PL)
1180 sub _gen_pod {
1181   my ($class, $distver, $pod_dir) = @_;
1182
1183   die "No POD root dir supplied" unless $pod_dir;
1184
1185   $distver ||=
1186     eval { require DBIx::Class; DBIx::Class->VERSION; }
1187       ||
1188     die
1189 "\n\n---------------------------------------------------------------------\n" .
1190 'Unable to load core DBIx::Class module to determine current version, '.
1191 'possibly due to missing dependencies. Author-mode autodocumentation ' .
1192 "halted\n\n" . $@ .
1193 "\n\n---------------------------------------------------------------------\n"
1194   ;
1195
1196   # do not ask for a recent version, use 1.x API calls
1197   # this *may* execute on a smoker with old perl or whatnot
1198   require File::Path;
1199
1200   (my $modfn = __PACKAGE__ . '.pm') =~ s|::|/|g;
1201
1202   (my $podfn = "$pod_dir/$modfn") =~ s/\.pm$/\.pod/;
1203   (my $dir = $podfn) =~ s|/[^/]+$||;
1204
1205   File::Path::mkpath([$dir]);
1206
1207   my $sqltver = $class->req_list_for('deploy')->{'SQL::Translator'}
1208     or die "Hrmm? No sqlt dep?";
1209
1210
1211   my @chunks;
1212
1213 #@@
1214 #@@ HEADER
1215 #@@
1216   push @chunks, <<"EOC";
1217 #########################################################################
1218 #####################  A U T O G E N E R A T E D ########################
1219 #########################################################################
1220 #
1221 # The contents of this POD file are auto-generated.  Any changes you make
1222 # will be lost. If you need to change the generated text edit _gen_pod()
1223 # at the end of $modfn
1224 #
1225
1226 =head1 NAME
1227
1228 $class - Optional module dependency specifications (for module authors)
1229 EOC
1230
1231
1232 #@@
1233 #@@ SYNOPSIS HEADING
1234 #@@
1235   push @chunks, <<"EOC";
1236 =head1 SYNOPSIS
1237
1238 Somewhere in your build-file (e.g. L<ExtUtils::MakeMaker>'s F<Makefile.PL>):
1239
1240   ...
1241
1242   \$EUMM_ARGS{CONFIGURE_REQUIRES} = {
1243     \%{ \$EUMM_ARGS{CONFIGURE_REQUIRES} || {} },
1244     'DBIx::Class' => '$distver',
1245   };
1246
1247   ...
1248
1249   my %DBIC_DEPLOY_AND_ORACLE_DEPS = %{ eval {
1250     require $class;
1251     $class->req_list_for([qw( deploy rdbms_oracle ic_dt )]);
1252   } || {} };
1253
1254   \$EUMM_ARGS{PREREQ_PM} = {
1255     \%DBIC_DEPLOY_AND_ORACLE_DEPS,
1256     \%{ \$EUMM_ARGS{PREREQ_PM} || {} },
1257   };
1258
1259   ...
1260
1261   ExtUtils::MakeMaker::WriteMakefile(\%EUMM_ARGS);
1262
1263 B<Note>: The C<eval> protection within the example is due to support for
1264 requirements during L<the C<configure> build phase|CPAN::Meta::Spec/Phases>
1265 not being available on a sufficient portion of production installations of
1266 Perl. Robust support for such dependency requirements is available in the
1267 L<CPAN> installer only since version C<1.94_56> first made available for
1268 production with perl version C<5.12>. It is the belief of the current
1269 maintainer that support for requirements during the C<configure> build phase
1270 will not be sufficiently ubiquitous until the B<year 2020> at the earliest,
1271 hence the extra care demonstrated above. It should also be noted that some
1272 3rd party installers (e.g. L<cpanminus|App::cpanminus>) do the right thing
1273 with configure requirements independent from the versions of perl and CPAN
1274 available.
1275 EOC
1276
1277
1278 #@@
1279 #@@ DESCRIPTION HEADING
1280 #@@
1281   push @chunks, <<'EOC';
1282 =head1 DESCRIPTION
1283
1284 Some of the less-frequently used features of L<DBIx::Class> have external
1285 module dependencies on their own. In order not to burden the average user
1286 with modules they will never use, these optional dependencies are not included
1287 in the base Makefile.PL. Instead an exception with a descriptive message is
1288 thrown when a specific feature can't find one or several modules required for
1289 its operation. This module is the central holding place for the current list
1290 of such dependencies, for DBIx::Class core authors, and DBIx::Class extension
1291 authors alike.
1292
1293 Dependencies are organized in L<groups|/CURRENT REQUIREMENT GROUPS> where each
1294 group can list one or more required modules, with an optional minimum version
1295 (or 0 for any version). In addition groups prefixed with C<test_> can specify
1296 a set of environment variables, some (or all) of which are marked as required
1297 for the group to be considered by L</req_list_for>
1298
1299 Each group name (or a combination thereof) can be used in the
1300 L<public methods|/METHODS> as described below.
1301 EOC
1302
1303
1304 #@@
1305 #@@ REQUIREMENT GROUPLIST HEADING
1306 #@@
1307   push @chunks, '=head1 CURRENT REQUIREMENT GROUPS';
1308
1309   my $standalone_info;
1310
1311   for my $group (sort keys %$dbic_reqs) {
1312
1313     my $info = $standalone_info->{$group} ||= $class->_groups_to_reqs($group);
1314
1315     next unless (
1316       $info->{modreqs_fully_documented}
1317         and
1318       ( $info->{augments} or $info->{modreqs} )
1319     );
1320
1321     my $p = $dbic_reqs->{$group}{pod};
1322
1323     push @chunks, (
1324       "=head2 $p->{title}",
1325       "=head3 $group",
1326       $p->{desc},
1327       '=over',
1328     );
1329
1330     if ( keys %{ $info->{modreqs}||{} } ) {
1331       push @chunks, map
1332         { "=item * $_" . ($info->{modreqs}{$_} ? " >= $info->{modreqs}{$_}" : '') }
1333         ( sort keys %{ $info->{modreqs} } )
1334       ;
1335     }
1336     else {
1337       push @chunks, '=item * No standalone requirements',
1338     }
1339
1340     push @chunks, '=back';
1341
1342     for my $ag ( sort keys %{ $info->{augments} || {} } ) {
1343       my $ag_info = $standalone_info->{$ag} ||= $class->_groups_to_reqs($ag);
1344
1345       my $newreqs = $class->modreq_list_for([ $group, $ag ]);
1346       for (keys %$newreqs) {
1347         delete $newreqs->{$_} if (
1348           ( defined $info->{modreqs}{$_}    and $info->{modreqs}{$_}    == $newreqs->{$_} )
1349             or
1350           ( defined $ag_info->{modreqs}{$_} and $ag_info->{modreqs}{$_} == $newreqs->{$_} )
1351         );
1352       }
1353
1354       if (keys %$newreqs) {
1355         push @chunks, (
1356           "Combined with L</$ag> additionally requires:",
1357           '=over',
1358           ( map
1359             { "=item * $_" . ($newreqs->{$_} ? " >= $newreqs->{$_}" : '') }
1360             ( sort keys %$newreqs )
1361           ),
1362           '=back',
1363         );
1364       }
1365     }
1366   }
1367
1368
1369 #@@
1370 #@@ API DOCUMENTATION HEADING
1371 #@@
1372   push @chunks, <<'EOC';
1373
1374 =head1 IMPORT-LIKE ACTIONS
1375
1376 Even though this module is not an L<Exporter>, it recognizes several C<actions>
1377 supplied to its C<import> method.
1378
1379 =head2 -skip_all_without
1380
1381 =over
1382
1383 =item Arguments: @group_names
1384
1385 =back
1386
1387 A convenience wrapper for use during testing:
1388 EOC
1389
1390   push @chunks, " use $class -skip_all_without => qw(admin test_rdbms_mysql);";
1391
1392   push @chunks, 'Roughly equivalent to the following code:';
1393
1394   push @chunks, sprintf <<'EOS', ($class) x 2;
1395
1396  BEGIN {
1397    require %s;
1398    if ( my $missing = %s->req_missing_for(\@group_names_) ) {
1399      print "1..0 # SKIP requirements not satisfied: $missing\n";
1400      exit 0;
1401    }
1402  }
1403 EOS
1404
1405   push @chunks, <<'EOC';
1406
1407 It also takes into account the C<RELEASE_TESTING> environment variable and
1408 behaves like L</-die_without> for any requirement groups marked as
1409 C<release_testing_mandatory>.
1410
1411 =head2 -die_without
1412
1413 =over
1414
1415 =item Arguments: @group_names
1416
1417 =back
1418
1419 A convenience wrapper around L</die_unless_req_ok_for>:
1420 EOC
1421
1422   push @chunks, " use $class -die_without => qw(deploy admin);";
1423
1424   push @chunks, <<'EOC';
1425
1426 =head2 -list_missing
1427
1428 =over
1429
1430 =item Arguments: @group_names
1431
1432 =back
1433
1434 A convenience wrapper around L</modreq_missing_for>:
1435
1436  perl -Ilib -MDBIx::Class::Optional::Dependencies=-list_missing,deploy,admin | cpanm
1437
1438 =head1 METHODS
1439
1440 =head2 req_group_list
1441
1442 =over
1443
1444 =item Arguments: none
1445
1446 =item Return Value: \%list_of_requirement_groups
1447
1448 =back
1449
1450 This method should be used by DBIx::Class packagers, to get a hashref of all
1451 dependencies B<keyed> by dependency group. Each key (group name), or a combination
1452 thereof (as an arrayref) can be supplied to the methods below.
1453 The B<values> of the returned hash are currently a set of options B<without a
1454 well defined structure>. If you have use for any of the contents - contact the
1455 maintainers, instead of treating this as public (left alone stable) API.
1456
1457 =head2 req_list_for
1458
1459 =over
1460
1461 =item Arguments: $group_name | \@group_names
1462
1463 =item Return Value: \%set_of_module_version_pairs
1464
1465 =back
1466
1467 This method should be used by DBIx::Class extension authors, to determine the
1468 version of modules a specific set of features requires for this version of
1469 DBIx::Class (regardless of their availability on the system).
1470 See the L</SYNOPSIS> for a real-world example.
1471
1472 When handling C<test_*> groups this method behaves B<differently> from
1473 L</modreq_list_for> below (and is the only such inconsistency among the
1474 C<req_*> methods). If a particular group declares as requirements some
1475 C<environment variables> and these requirements are not satisfied (the envvars
1476 are unset) - then the C<module requirements> of this group are not included in
1477 the returned list.
1478
1479 =head2 modreq_list_for
1480
1481 =over
1482
1483 =item Arguments: $group_name | \@group_names
1484
1485 =item Return Value: \%set_of_module_version_pairs
1486
1487 =back
1488
1489 Same as L</req_list_for> but does not take into consideration any
1490 C<environment variable requirements> - returns just the list of required
1491 modules.
1492
1493 =head2 req_ok_for
1494
1495 =over
1496
1497 =item Arguments: $group_name | \@group_names
1498
1499 =item Return Value: 1|0
1500
1501 =back
1502
1503 Returns true or false depending on whether all modules/envvars required by
1504 the group(s) are loadable/set on the system.
1505
1506 =head2 req_missing_for
1507
1508 =over
1509
1510 =item Arguments: $group_name | \@group_names
1511
1512 =item Return Value: $error_message_string
1513
1514 =back
1515
1516 Returns a single-line string suitable for inclusion in larger error messages.
1517 This method would normally be used by DBIx::Class core features, to indicate to
1518 the user that they need to install specific modules and/or set specific
1519 environment variables before being able to use a specific feature set.
1520
1521 For example if some of the requirements for C<deploy> are not available,
1522 the returned string could look like:
1523 EOC
1524
1525   push @chunks, qq{ "SQL::Translator~$sqltver" (see $class documentation for details)};
1526
1527   push @chunks, <<'EOC';
1528 The author is expected to prepend the necessary text to this message before
1529 returning the actual error seen by the user. See also L</modreq_missing_for>
1530
1531 =head2 modreq_missing_for
1532
1533 =over
1534
1535 =item Arguments: $group_name | \@group_names
1536
1537 =item Return Value: $error_message_string
1538
1539 =back
1540
1541 Same as L</req_missing_for> except that the error string is guaranteed to be
1542 either empty, or contain a set of module requirement specifications suitable
1543 for piping to e.g. L<cpanminus|App::cpanminus>. The method explicitly does not
1544 attempt to validate the state of required environment variables (if any).
1545
1546 For instance if some of the requirements for C<deploy> are not available,
1547 the returned string could look like:
1548 EOC
1549
1550   push @chunks, qq{ "SQL::Translator~$sqltver"};
1551
1552   push @chunks, <<'EOC';
1553
1554 See also L</-list_missing>.
1555
1556 =head2 skip_without
1557
1558 =over
1559
1560 =item Arguments: $group_name | \@group_names
1561
1562 =back
1563
1564 A convenience wrapper around L<skip|Test::More/SKIP>. It does not take neither
1565 a reason (it is generated by L</req_missing_for>) nor an amount of skipped tests
1566 (it is always C<1>, thus mandating unconditional use of
1567 L<done_testing|Test::More/done_testing>). Most useful in combination with ad hoc
1568 requirement specifications:
1569 EOC
1570
1571   push @chunks, <<EOC;
1572   SKIP: {
1573     $class->skip_without([ deploy YAML>=0.90 ]);
1574
1575     ...
1576   }
1577 EOC
1578
1579   push @chunks, <<'EOC';
1580
1581 =head2 die_unless_req_ok_for
1582
1583 =over
1584
1585 =item Arguments: $group_name | \@group_names
1586
1587 =back
1588
1589 Checks if L</req_ok_for> passes for the supplied group(s), and
1590 in case of failure throws an exception including the information
1591 from L</req_missing_for>. See also L</-die_without>.
1592
1593 =head2 modreq_errorlist_for
1594
1595 =over
1596
1597 =item Arguments: $group_name | \@group_names
1598
1599 =item Return Value: \%set_of_loaderrors_per_module
1600
1601 =back
1602
1603 Returns a hashref containing the actual errors that occurred while attempting
1604 to load each module in the requirement group(s).
1605
1606 =head2 req_errorlist_for
1607
1608 Deprecated method name, equivalent (via proxy) to L</modreq_errorlist_for>.
1609
1610 EOC
1611
1612 #@@
1613 #@@ FOOTER
1614 #@@
1615   push @chunks, <<'EOC';
1616 =head1 FURTHER QUESTIONS?
1617
1618 Check the list of L<additional DBIC resources|DBIx::Class/GETTING HELP/SUPPORT>.
1619
1620 =head1 COPYRIGHT AND LICENSE
1621
1622 This module is free software L<copyright|DBIx::Class/COPYRIGHT AND LICENSE>
1623 by the L<DBIx::Class (DBIC) authors|DBIx::Class/AUTHORS>. You can
1624 redistribute it and/or modify it under the same terms as the
1625 L<DBIx::Class library|DBIx::Class/COPYRIGHT AND LICENSE>.
1626 EOC
1627
1628   eval {
1629     open (my $fh, '>', $podfn) or die;
1630     print $fh join ("\n\n", @chunks) or die;
1631     print $fh "\n" or die;
1632     close ($fh) or die;
1633   } or croak( "Unable to write $podfn: " . ( $! || $@ || 'unknown error') );
1634 }
1635
1636 1;