e312c72cf2bc8f2513a2ccac146802838b3f5d6c
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / Optional / Dependencies.pm
1 package DBIx::Class::Optional::Dependencies;
2
3 use warnings;
4 use strict;
5
6 use Carp ();
7
8 # NO EXTERNAL NON-5.8.1 CORE DEPENDENCIES EVER (e.g. C::A::G)
9 # This module is to be loaded by Makefile.PM on a pristine system
10
11 # POD is generated automatically by calling _gen_pod from the
12 # Makefile.PL in $AUTHOR mode
13
14 my $json_any = {
15   'JSON::Any'                     => '1.23',
16 };
17
18 my $moose_basic = {
19   'Moose'                         => '0.98',
20   'MooseX::Types'                 => '0.21',
21   'MooseX::Types::LoadableClass'  => '0.011',
22 };
23
24 my $replicated = {
25   %$moose_basic,
26 };
27
28 my $admin_basic = {
29   %$moose_basic,
30   %$json_any,
31   'MooseX::Types::Path::Class'    => '0.05',
32   'MooseX::Types::JSON'           => '0.02',
33   'namespace::autoclean'          => '0.09',
34 };
35
36 my $admin_script = {
37   %$moose_basic,
38   %$admin_basic,
39   'Getopt::Long::Descriptive' => '0.081',
40   'Text::CSV'                 => '1.16',
41 };
42
43 my $datetime_basic = {
44   'DateTime'                      => '0.55',
45   'DateTime::Format::Strptime'    => '1.2',
46 };
47
48 my $id_shortener = {
49   'Math::BigInt'                  => '1.80',
50   'Math::Base36'                  => '0.07',
51 };
52
53 my $rdbms_sqlite = {
54   'DBD::SQLite'                   => '0',
55 };
56 my $rdbms_pg = {
57   'DBD::Pg'                       => '0',
58 };
59 my $rdbms_mssql_odbc = {
60   'DBD::ODBC'                     => '0',
61 };
62 my $rdbms_mssql_sybase = {
63   'DBD::Sybase'                   => '0',
64 };
65 my $rdbms_mssql_ado = {
66   'DBD::ADO'                      => '0',
67 };
68 my $rdbms_msaccess_odbc = {
69   'DBD::ODBC'                     => '0',
70 };
71 my $rdbms_msaccess_ado = {
72   'DBD::ADO'                      => '0',
73 };
74 my $rdbms_mysql = {
75   'DBD::mysql'                    => '0',
76 };
77 my $rdbms_oracle = {
78   'DBD::Oracle'                   => '0',
79   %$id_shortener,
80 };
81 my $rdbms_ase = {
82   'DBD::Sybase'                   => '0',
83 };
84 my $rdbms_db2 = {
85   'DBD::DB2'                      => '0',
86 };
87 my $rdbms_db2_400 = {
88   'DBD::ODBC'                     => '0',
89 };
90 my $rdbms_informix = {
91   'DBD::Informix'                 => '0',
92 };
93 my $rdbms_sqlanywhere = {
94   'DBD::SQLAnywhere'              => '0',
95 };
96 my $rdbms_sqlanywhere_odbc = {
97   'DBD::ODBC'                     => '0',
98 };
99 my $rdbms_firebird = {
100   'DBD::Firebird'                 => '0',
101 };
102 my $rdbms_firebird_interbase = {
103   'DBD::InterBase'                => '0',
104 };
105 my $rdbms_firebird_odbc = {
106   'DBD::ODBC'                     => '0',
107 };
108
109 my $reqs = {
110   replicated => {
111     req => $replicated,
112     pod => {
113       title => 'Storage::Replicated',
114       desc => 'Modules required for L<DBIx::Class::Storage::DBI::Replicated>',
115     },
116   },
117
118   test_replicated => {
119     req => {
120       %$replicated,
121       'Test::Moose'               => '0',
122     },
123   },
124
125
126   admin => {
127     req => {
128       %$admin_basic,
129     },
130     pod => {
131       title => 'DBIx::Class::Admin',
132       desc => 'Modules required for the DBIx::Class administrative library',
133     },
134   },
135
136   admin_script => {
137     req => {
138       %$admin_script,
139     },
140     pod => {
141       title => 'dbicadmin',
142       desc => 'Modules required for the CLI DBIx::Class interface dbicadmin',
143     },
144   },
145
146   deploy => {
147     req => {
148       'SQL::Translator'           => '0.11016',
149     },
150     pod => {
151       title => 'Storage::DBI::deploy()',
152       desc => 'Modules required for L<DBIx::Class::Storage::DBI/deploy> and L<DBIx::Class::Storage::DBI/deployment_statements>',
153     },
154   },
155
156   id_shortener => {
157     req => $id_shortener,
158   },
159
160   test_component_accessor => {
161     req => {
162       'Class::Unload'             => '0.07',
163     },
164   },
165
166   test_pod => {
167     req => {
168       'Test::Pod'                 => '1.42',
169     },
170   },
171
172   test_podcoverage => {
173     req => {
174       'Test::Pod::Coverage'       => '1.08',
175       'Pod::Coverage'             => '0.20',
176     },
177   },
178
179   test_whitespace => {
180     req => {
181       'Test::EOL'                 => '1.0',
182       'Test::NoTabs'              => '0.9',
183     },
184   },
185
186   test_strictures => {
187     req => {
188       'Test::Strict'              => '0.20',
189     },
190   },
191
192   test_prettydebug => {
193     req => $json_any,
194   },
195
196   test_admin_script => {
197     req => {
198       %$admin_script,
199       'JSON::Any' => '1.30',
200       'JSON' => 0,
201       'JSON::PP' => 0,
202       'Cpanel::JSON::XS' => 0,
203       'JSON::XS' => 0,
204       $^O eq 'MSWin32'
205         # for t/admin/10script.t
206         ? ('Win32::ShellQuote' => 0)
207         # DWIW does not compile (./configure even) on win32
208         : ('JSON::DWIW' => 0 )
209       ,
210     }
211   },
212
213   test_leaks => {
214     req => {
215       'Test::Memory::Cycle'       => '0',
216       'Devel::Cycle'              => '1.10',
217     },
218   },
219
220   test_dt => {
221     req => $datetime_basic,
222   },
223
224   test_dt_sqlite => {
225     req => {
226       %$datetime_basic,
227       # t/36datetime.t
228       # t/60core.t
229       'DateTime::Format::SQLite'  => '0',
230     },
231   },
232
233   test_dt_mysql => {
234     req => {
235       %$datetime_basic,
236       # t/inflate/datetime_mysql.t
237       # (doesn't need Mysql itself)
238       'DateTime::Format::MySQL'   => '0',
239     },
240   },
241
242   test_dt_pg => {
243     req => {
244       %$datetime_basic,
245       # t/inflate/datetime_pg.t
246       # (doesn't need PG itself)
247       'DateTime::Format::Pg'      => '0.16004',
248     },
249   },
250
251   test_cdbicompat => {
252     req => {
253       'Class::DBI::Plugin::DeepAbstractSearch' => '0',
254       %$datetime_basic,
255       'Time::Piece::MySQL'        => '0',
256       'Date::Simple'              => '3.03',
257     },
258   },
259
260   # this is just for completeness as SQLite
261   # is a core dep of DBIC for testing
262   rdbms_sqlite => {
263     req => {
264       %$rdbms_sqlite,
265     },
266     pod => {
267       title => 'SQLite support',
268       desc => 'Modules required to connect to SQLite',
269     },
270   },
271
272   rdbms_pg => {
273     req => {
274       # when changing this list make sure to adjust xt/optional_deps.t
275       %$rdbms_pg,
276     },
277     pod => {
278       title => 'PostgreSQL support',
279       desc => 'Modules required to connect to PostgreSQL',
280     },
281   },
282
283   rdbms_mssql_odbc => {
284     req => {
285       %$rdbms_mssql_odbc,
286     },
287     pod => {
288       title => 'MSSQL support via DBD::ODBC',
289       desc => 'Modules required to connect to MSSQL via DBD::ODBC',
290     },
291   },
292
293   rdbms_mssql_sybase => {
294     req => {
295       %$rdbms_mssql_sybase,
296     },
297     pod => {
298       title => 'MSSQL support via DBD::Sybase',
299       desc => 'Modules required to connect to MSSQL via DBD::Sybase',
300     },
301   },
302
303   rdbms_mssql_ado => {
304     req => {
305       %$rdbms_mssql_ado,
306     },
307     pod => {
308       title => 'MSSQL support via DBD::ADO (Windows only)',
309       desc => 'Modules required to connect to MSSQL via DBD::ADO. This particular DBD is available on Windows only',
310     },
311   },
312
313   rdbms_msaccess_odbc => {
314     req => {
315       %$rdbms_msaccess_odbc,
316     },
317     pod => {
318       title => 'MS Access support via DBD::ODBC',
319       desc => 'Modules required to connect to MS Access via DBD::ODBC',
320     },
321   },
322
323   rdbms_msaccess_ado => {
324     req => {
325       %$rdbms_msaccess_ado,
326     },
327     pod => {
328       title => 'MS Access support via DBD::ADO (Windows only)',
329       desc => 'Modules required to connect to MS Access via DBD::ADO. This particular DBD is available on Windows only',
330     },
331   },
332
333   rdbms_mysql => {
334     req => {
335       %$rdbms_mysql,
336     },
337     pod => {
338       title => 'MySQL support',
339       desc => 'Modules required to connect to MySQL',
340     },
341   },
342
343   rdbms_oracle => {
344     req => {
345       %$rdbms_oracle,
346     },
347     pod => {
348       title => 'Oracle support',
349       desc => 'Modules required to connect to Oracle',
350     },
351   },
352
353   rdbms_ase => {
354     req => {
355       %$rdbms_ase,
356     },
357     pod => {
358       title => 'Sybase ASE support',
359       desc => 'Modules required to connect to Sybase ASE',
360     },
361   },
362
363   rdbms_db2 => {
364     req => {
365       %$rdbms_db2,
366     },
367     pod => {
368       title => 'DB2 support',
369       desc => 'Modules required to connect to DB2',
370     },
371   },
372
373   rdbms_db2_400 => {
374     req => {
375       %$rdbms_db2_400,
376     },
377     pod => {
378       title => 'DB2 on AS/400 support',
379       desc => 'Modules required to connect to DB2 on AS/400',
380     },
381   },
382
383   rdbms_informix => {
384     req => {
385       %$rdbms_informix,
386     },
387     pod => {
388       title => 'Informix support',
389       desc => 'Modules required to connect to Informix',
390     },
391   },
392
393   rdbms_sqlanywhere => {
394     req => {
395       %$rdbms_sqlanywhere,
396     },
397     pod => {
398       title => 'SQLAnywhere support',
399       desc => 'Modules required to connect to SQLAnywhere',
400     },
401   },
402
403   rdbms_sqlanywhere_odbc => {
404     req => {
405       %$rdbms_sqlanywhere_odbc,
406     },
407     pod => {
408       title => 'SQLAnywhere support via DBD::ODBC',
409       desc => 'Modules required to connect to SQLAnywhere via DBD::ODBC',
410     },
411   },
412
413   rdbms_firebird => {
414     req => {
415       %$rdbms_firebird,
416     },
417     pod => {
418       title => 'Firebird support',
419       desc => 'Modules required to connect to Firebird',
420     },
421   },
422
423   rdbms_firebird_interbase => {
424     req => {
425       %$rdbms_firebird_interbase,
426     },
427     pod => {
428       title => 'Firebird support via DBD::InterBase',
429       desc => 'Modules required to connect to Firebird via DBD::InterBase',
430     },
431   },
432
433   rdbms_firebird_odbc => {
434     req => {
435       %$rdbms_firebird_odbc,
436     },
437     pod => {
438       title => 'Firebird support via DBD::ODBC',
439       desc => 'Modules required to connect to Firebird via DBD::ODBC',
440     },
441   },
442
443 # the order does matter because the rdbms support group might require
444 # a different version that the test group
445   test_rdbms_pg => {
446     req => {
447       $ENV{DBICTEST_PG_DSN}
448         ? (
449           # when changing this list make sure to adjust xt/optional_deps.t
450           %$rdbms_pg,
451           ($^O ne 'MSWin32' ? ('Sys::SigAction' => '0') : ()),
452           'DBD::Pg'               => '2.009002',
453         ) : ()
454     },
455   },
456
457   test_rdbms_mssql_odbc => {
458     req => {
459       $ENV{DBICTEST_MSSQL_ODBC_DSN}
460         ? (
461           %$rdbms_mssql_odbc,
462         ) : ()
463     },
464   },
465
466   test_rdbms_mssql_ado => {
467     req => {
468       $ENV{DBICTEST_MSSQL_ADO_DSN}
469         ? (
470           %$rdbms_mssql_ado,
471         ) : ()
472     },
473   },
474
475   test_rdbms_mssql_sybase => {
476     req => {
477       $ENV{DBICTEST_MSSQL_DSN}
478         ? (
479           %$rdbms_mssql_sybase,
480         ) : ()
481     },
482   },
483
484   test_rdbms_msaccess_odbc => {
485     req => {
486       $ENV{DBICTEST_MSACCESS_ODBC_DSN}
487         ? (
488           %$rdbms_msaccess_odbc,
489           %$datetime_basic,
490           'Data::GUID' => '0',
491         ) : ()
492     },
493   },
494
495   test_rdbms_msaccess_ado => {
496     req => {
497       $ENV{DBICTEST_MSACCESS_ADO_DSN}
498         ? (
499           %$rdbms_msaccess_ado,
500           %$datetime_basic,
501           'Data::GUID' => 0,
502         ) : ()
503     },
504   },
505
506   test_rdbms_mysql => {
507     req => {
508       $ENV{DBICTEST_MYSQL_DSN}
509         ? (
510           %$rdbms_mysql,
511         ) : ()
512     },
513   },
514
515   test_rdbms_oracle => {
516     req => {
517       $ENV{DBICTEST_ORA_DSN}
518         ? (
519           %$rdbms_oracle,
520           'DateTime::Format::Oracle' => '0',
521           'DBD::Oracle'              => '1.24',
522         ) : ()
523     },
524   },
525
526   test_rdbms_ase => {
527     req => {
528       $ENV{DBICTEST_SYBASE_DSN}
529         ? (
530           %$rdbms_ase,
531         ) : ()
532     },
533   },
534
535   test_rdbms_db2 => {
536     req => {
537       $ENV{DBICTEST_DB2_DSN}
538         ? (
539           %$rdbms_db2,
540         ) : ()
541     },
542   },
543
544   test_rdbms_db2_400 => {
545     req => {
546       $ENV{DBICTEST_DB2_400_DSN}
547         ? (
548           %$rdbms_db2_400,
549         ) : ()
550     },
551   },
552
553   test_rdbms_informix => {
554     req => {
555       $ENV{DBICTEST_INFORMIX_DSN}
556         ? (
557           %$rdbms_informix,
558         ) : ()
559     },
560   },
561
562   test_rdbms_sqlanywhere => {
563     req => {
564       $ENV{DBICTEST_SQLANYWHERE_DSN}
565         ? (
566           %$rdbms_sqlanywhere,
567         ) : ()
568     },
569   },
570
571   test_rdbms_sqlanywhere_odbc => {
572     req => {
573       $ENV{DBICTEST_SQLANYWHERE_ODBC_DSN}
574         ? (
575           %$rdbms_sqlanywhere_odbc,
576         ) : ()
577     },
578   },
579
580   test_rdbms_firebird => {
581     req => {
582       $ENV{DBICTEST_FIREBIRD_DSN}
583         ? (
584           %$rdbms_firebird,
585         ) : ()
586     },
587   },
588
589   test_rdbms_firebird_interbase => {
590     req => {
591       $ENV{DBICTEST_FIREBIRD_INTERBASE_DSN}
592         ? (
593           %$rdbms_firebird_interbase,
594         ) : ()
595     },
596   },
597
598   test_rdbms_firebird_odbc => {
599     req => {
600       $ENV{DBICTEST_FIREBIRD_ODBC_DSN}
601         ? (
602           %$rdbms_firebird_odbc,
603         ) : ()
604     },
605   },
606
607   test_memcached => {
608     req => {
609       $ENV{DBICTEST_MEMCACHED}
610         ? (
611           'Cache::Memcached' => 0,
612         ) : ()
613     },
614   },
615
616   dist_dir => {
617     req => {
618       'ExtUtils::MakeMaker' => '6.64',
619       'Pod::Inherit'        => '0.90',
620       'Pod::Tree'           => '0',
621     }
622   },
623
624   dist_upload => {
625     req => {
626       'CPAN::Uploader' => '0.103001',
627     },
628   },
629
630 };
631
632 our %req_availability_cache;
633
634 sub req_list_for {
635   my ($class, $group) = @_;
636
637   Carp::croak "req_list_for() expects a requirement group name"
638     unless $group;
639
640   my $deps = $reqs->{$group}{req}
641     or Carp::croak "Requirement group '$group' does not exist";
642
643   return { %$deps };
644 }
645
646
647 sub die_unless_req_ok_for {
648   my ($class, $group) = @_;
649
650   Carp::croak "die_unless_req_ok_for() expects a requirement group name"
651     unless $group;
652
653   $class->_check_deps($group)->{status}
654     or die sprintf( "Required modules missing, unable to continue: %s\n", $class->_check_deps($group)->{missing} );
655 }
656
657 sub req_ok_for {
658   my ($class, $group) = @_;
659
660   Carp::croak "req_ok_for() expects a requirement group name"
661     unless $group;
662
663   return $class->_check_deps($group)->{status};
664 }
665
666 sub req_missing_for {
667   my ($class, $group) = @_;
668
669   Carp::croak "req_missing_for() expects a requirement group name"
670     unless $group;
671
672   return $class->_check_deps($group)->{missing};
673 }
674
675 sub req_errorlist_for {
676   my ($class, $group) = @_;
677
678   Carp::croak "req_errorlist_for() expects a requirement group name"
679     unless $group;
680
681   return $class->_check_deps($group)->{errorlist};
682 }
683
684 sub _check_deps {
685   my ($class, $group) = @_;
686
687   return $req_availability_cache{$group} ||= do {
688
689     my $deps = $class->req_list_for ($group);
690
691     my %errors;
692     for my $mod (keys %$deps) {
693       my $req_line = "require $mod;";
694       if (my $ver = $deps->{$mod}) {
695         $req_line .= "$mod->VERSION($ver);";
696       }
697
698       eval $req_line;
699
700       $errors{$mod} = $@ if $@;
701     }
702
703     my $res;
704
705     if (keys %errors) {
706       my $missing = join (', ', map { $deps->{$_} ? "$_ >= $deps->{$_}" : $_ } (sort keys %errors) );
707       $missing .= " (see $class for details)" if $reqs->{$group}{pod};
708       $res = {
709         status => 0,
710         errorlist => \%errors,
711         missing => $missing,
712       };
713     }
714     else {
715       $res = {
716         status => 1,
717         errorlist => {},
718         missing => '',
719       };
720     }
721
722     $res;
723   };
724 }
725
726 sub req_group_list {
727   return { map { $_ => { %{ $reqs->{$_}{req} || {} } } } (keys %$reqs) };
728 }
729
730 # This is to be called by the author only (automatically in Makefile.PL)
731 sub _gen_pod {
732   my ($class, $distver, $pod_dir) = @_;
733
734   die "No POD root dir supplied" unless $pod_dir;
735
736   $distver ||=
737     eval { require DBIx::Class; DBIx::Class->VERSION; }
738       ||
739     die
740 "\n\n---------------------------------------------------------------------\n" .
741 'Unable to load core DBIx::Class module to determine current version, '.
742 'possibly due to missing dependencies. Author-mode autodocumentation ' .
743 "halted\n\n" . $@ .
744 "\n\n---------------------------------------------------------------------\n"
745   ;
746
747   # do not ask for a recent version, use 1.x API calls
748   # this *may* execute on a smoker with old perl or whatnot
749   require File::Path;
750
751   (my $modfn = __PACKAGE__ . '.pm') =~ s|::|/|g;
752
753   (my $podfn = "$pod_dir/$modfn") =~ s/\.pm$/\.pod/;
754   (my $dir = $podfn) =~ s|/[^/]+$||;
755
756   File::Path::mkpath([$dir]);
757
758   my $sqltver = $class->req_list_for ('deploy')->{'SQL::Translator'}
759     or die "Hrmm? No sqlt dep?";
760
761   my @chunks = (
762     <<"EOC",
763 #########################################################################
764 #####################  A U T O G E N E R A T E D ########################
765 #########################################################################
766 #
767 # The contents of this POD file are auto-generated.  Any changes you make
768 # will be lost. If you need to change the generated text edit _gen_pod()
769 # at the end of $modfn
770 #
771 EOC
772     '=head1 NAME',
773     "$class - Optional module dependency specifications (for module authors)",
774     '=head1 SYNOPSIS',
775     <<"EOS",
776 Somewhere in your build-file (e.g. L<Module::Install>'s Makefile.PL):
777
778   ...
779
780   configure_requires 'DBIx::Class' => '$distver';
781
782   require $class;
783
784   my \$deploy_deps = $class->req_list_for('deploy');
785
786   for (keys %\$deploy_deps) {
787     requires \$_ => \$deploy_deps->{\$_};
788   }
789
790   ...
791
792 Note that there are some caveats regarding C<configure_requires()>, more info
793 can be found at L<Module::Install/configure_requires>
794 EOS
795     '=head1 DESCRIPTION',
796     <<'EOD',
797 Some of the less-frequently used features of L<DBIx::Class> have external
798 module dependencies on their own. In order not to burden the average user
799 with modules he will never use, these optional dependencies are not included
800 in the base Makefile.PL. Instead an exception with a descriptive message is
801 thrown when a specific feature is missing one or several modules required for
802 its operation. This module is the central holding place for  the current list
803 of such dependencies, for DBIx::Class core authors, and DBIx::Class extension
804 authors alike.
805 EOD
806     '=head1 CURRENT REQUIREMENT GROUPS',
807     <<'EOD',
808 Dependencies are organized in C<groups> and each group can list one or more
809 required modules, with an optional minimum version (or 0 for any version).
810 The group name can be used in the
811 EOD
812   );
813
814   for my $group (sort keys %$reqs) {
815     my $p = $reqs->{$group}{pod}
816       or next;
817
818     my $modlist = $reqs->{$group}{req}
819       or next;
820
821     next unless keys %$modlist;
822
823     push @chunks, (
824       "=head2 $p->{title}",
825       "$p->{desc}",
826       '=over',
827       ( map { "=item * $_" . ($modlist->{$_} ? " >= $modlist->{$_}" : '') } (sort keys %$modlist) ),
828       '=back',
829       "Requirement group: B<$group>",
830     );
831   }
832
833   push @chunks, (
834     '=head1 METHODS',
835     '=head2 req_group_list',
836     '=over',
837     '=item Arguments: none',
838     '=item Return Value: \%list_of_requirement_groups',
839     '=back',
840     <<'EOD',
841 This method should be used by DBIx::Class packagers, to get a hashref of all
842 dependencies keyed by dependency group. Each key (group name) can be supplied
843 to one of the group-specific methods below.
844 EOD
845
846     '=head2 req_list_for',
847     '=over',
848     '=item Arguments: $group_name',
849     '=item Return Value: \%list_of_module_version_pairs',
850     '=back',
851     <<'EOD',
852 This method should be used by DBIx::Class extension authors, to determine the
853 version of modules a specific feature requires in the B<current> version of
854 DBIx::Class. See the L</SYNOPSIS> for a real-world
855 example.
856 EOD
857
858     '=head2 req_ok_for',
859     '=over',
860     '=item Arguments: $group_name',
861     '=item Return Value: 1|0',
862     '=back',
863     <<'EOD',
864 Returns true or false depending on whether all modules required by
865 C<$group_name> are present on the system and loadable.
866 EOD
867
868     '=head2 req_missing_for',
869     '=over',
870     '=item Arguments: $group_name',
871     '=item Return Value: $error_message_string',
872     '=back',
873     <<"EOD",
874 Returns a single line string suitable for inclusion in larger error messages.
875 This method would normally be used by DBIx::Class core-module author, to
876 indicate to the user that he needs to install specific modules before he will
877 be able to use a specific feature.
878
879 For example if some of the requirements for C<deploy> are not available,
880 the returned string could look like:
881
882  SQL::Translator >= $sqltver (see $class for details)
883
884 The author is expected to prepend the necessary text to this message before
885 returning the actual error seen by the user.
886 EOD
887
888     '=head2 die_unless_req_ok_for',
889     '=over',
890     '=item Arguments: $group_name',
891     '=back',
892     <<'EOD',
893 Checks if L</req_ok_for> passes for the supplied C<$group_name>, and
894 in case of failure throws an exception including the information
895 from L</req_missing_for>.
896 EOD
897
898     '=head2 req_errorlist_for',
899     '=over',
900     '=item Arguments: $group_name',
901     '=item Return Value: \%list_of_loaderrors_per_module',
902     '=back',
903     <<'EOD',
904 Returns a hashref containing the actual errors that occurred while attempting
905 to load each module in the requirement group.
906 EOD
907     '=head1 AUTHOR',
908     'See L<DBIx::Class/CONTRIBUTORS>.',
909     '=head1 LICENSE',
910     'You may distribute this code under the same terms as Perl itself',
911   );
912
913   open (my $fh, '>', $podfn) or Carp::croak "Unable to write to $podfn: $!";
914   print $fh join ("\n\n", @chunks);
915   print $fh "\n";
916   close ($fh);
917 }
918
919 1;