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