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