Overhaul serialization test, add optional Memcached testing
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / Optional / Dependencies.pm
CommitLineData
8057ed01 1package DBIx::Class::Optional::Dependencies;
2
3use warnings;
4use strict;
5
fb39747c 6use Carp;
7
8# NO EXTERNAL NON-5.8.1 CORE DEPENDENCIES EVER (e.g. C::A::G)
8057ed01 9# This module is to be loaded by Makefile.PM on a pristine system
10
f6b26571 11# POD is generated automatically by calling _gen_pod from the
12# Makefile.PL in $AUTHOR mode
13
2a2a7b23 14my $json_any = {
15 'JSON::Any' => '1.22',
16};
17
2b48ebff 18my $moose_basic = {
68de9438 19 'Moose' => '0.98',
20 'MooseX::Types' => '0.21',
21};
22
23my $replicated = {
24 %$moose_basic,
25 'Hash::Merge' => '0.12',
2b48ebff 26};
27
ebcd0e4f 28my $admin_basic = {
29 %$moose_basic,
2a2a7b23 30 %$json_any,
68de9438 31 'MooseX::Types::Path::Class' => '0.05',
32 'MooseX::Types::JSON' => '0.02',
68de9438 33 'namespace::autoclean' => '0.09',
34};
35
36my $datetime_basic = {
37 'DateTime' => '0.55',
38 'DateTime::Format::Strptime' => '1.2',
ebcd0e4f 39};
40
8057ed01 41my $reqs = {
42 dist => {
43 #'Module::Install::Pod::Inherit' => '0.01',
44 },
45
46 replicated => {
68de9438 47 req => $replicated,
f6b26571 48 pod => {
49 title => 'Storage::Replicated',
50 desc => 'Modules required for L<DBIx::Class::Storage::DBI::Replicated>',
51 },
8057ed01 52 },
53
68de9438 54 test_replicated => {
55 req => {
56 %$replicated,
57 'Test::Moose' => '0',
58 },
59 },
60
61
8057ed01 62 admin => {
2b48ebff 63 req => {
ebcd0e4f 64 %$admin_basic,
65 },
66 pod => {
67 title => 'DBIx::Class::Admin',
68 desc => 'Modules required for the DBIx::Class administrative library',
69 },
70 },
71
a4a02f15 72 admin_script => {
ebcd0e4f 73 req => {
2b48ebff 74 %$moose_basic,
ebcd0e4f 75 %$admin_basic,
2b48ebff 76 'Getopt::Long::Descriptive' => '0.081',
2b48ebff 77 'Text::CSV' => '1.16',
78 },
e144415f 79 pod => {
80 title => 'dbicadmin',
81 desc => 'Modules required for the CLI DBIx::Class interface dbicadmin',
82 },
8057ed01 83 },
84
85 deploy => {
f6b26571 86 req => {
9e34d554 87 'SQL::Translator' => '0.11006',
f6b26571 88 },
89 pod => {
90 title => 'Storage::DBI::deploy()',
91 desc => 'Modules required for L<DBIx::Class::Storage::DBI/deploy> and L<DBIx::Class::Storage::DBI/deploymen_statements>',
92 },
8057ed01 93 },
94
a109c954 95 test_pod => {
f6b26571 96 req => {
14d17d71 97 'Test::Pod' => '1.41',
a109c954 98 },
99 },
100
101 test_podcoverage => {
102 req => {
f6b26571 103 'Test::Pod::Coverage' => '1.08',
104 'Pod::Coverage' => '0.20',
a109c954 105 },
106 },
107
108 test_notabs => {
109 req => {
d146b340 110 'Test::NoTabs' => '0.9',
a109c954 111 },
112 },
113
114 test_eol => {
115 req => {
d146b340 116 'Test::EOL' => '0.6',
f6b26571 117 },
8057ed01 118 },
119
2a2a7b23 120 test_prettydebug => {
121 req => $json_any,
122 },
123
226d1c35 124 test_leaks => {
f6b26571 125 req => {
f6b26571 126 'Test::Memory::Cycle' => '0',
127 'Devel::Cycle' => '1.10',
a109c954 128 },
129 },
f6b26571 130
68de9438 131 test_dt => {
132 req => $datetime_basic,
133 },
134
135 test_dt_sqlite => {
a109c954 136 req => {
68de9438 137 %$datetime_basic,
f6b26571 138 # t/36datetime.t
139 # t/60core.t
140 'DateTime::Format::SQLite' => '0',
68de9438 141 },
142 },
f6b26571 143
68de9438 144 test_dt_mysql => {
145 req => {
146 %$datetime_basic,
9c92bb1c 147 # t/inflate/datetime_mysql.t
148 # (doesn't need Mysql itself)
68de9438 149 'DateTime::Format::MySQL' => '0',
150 },
151 },
9c92bb1c 152
68de9438 153 test_dt_pg => {
154 req => {
155 %$datetime_basic,
9c92bb1c 156 # t/inflate/datetime_pg.t
157 # (doesn't need PG itself)
ab35aeab 158 'DateTime::Format::Pg' => '0.16004',
f6b26571 159 },
8057ed01 160 },
161
68de9438 162 test_cdbicompat => {
f6b26571 163 req => {
164 'DBIx::ContextualFetch' => '0',
165 'Class::DBI::Plugin::DeepAbstractSearch' => '0',
166 'Class::Trigger' => '0',
167 'Time::Piece::MySQL' => '0',
168 'Clone' => '0',
169 'Date::Simple' => '3.03',
170 },
8057ed01 171 },
172
68de9438 173 test_rdbms_pg => {
f6b26571 174 req => {
175 $ENV{DBICTEST_PG_DSN}
176 ? (
177 'Sys::SigAction' => '0',
178 'DBD::Pg' => '2.009002',
f6b26571 179 ) : ()
180 },
8057ed01 181 },
182
afae8507 183 test_rdbms_mssql_odbc => {
184 req => {
185 $ENV{DBICTEST_MSSQL_ODBC_DSN}
186 ? (
187 'DBD::ODBC' => '0',
188 ) : ()
189 },
190 },
191
192 test_rdbms_mssql_sybase => {
193 req => {
194 $ENV{DBICTEST_MSSQL_DSN}
195 ? (
196 'DBD::Sybase' => '0',
197 ) : ()
198 },
199 },
200
68de9438 201 test_rdbms_mysql => {
f6b26571 202 req => {
203 $ENV{DBICTEST_MYSQL_DSN}
204 ? (
afae8507 205 'DBD::mysql' => '0',
f6b26571 206 ) : ()
207 },
8057ed01 208 },
209
68de9438 210 test_rdbms_oracle => {
f6b26571 211 req => {
212 $ENV{DBICTEST_ORA_DSN}
213 ? (
214 'DateTime::Format::Oracle' => '0',
e1b7e9b4 215 'DBD::Oracle' => '1.24',
f6b26571 216 ) : ()
217 },
8057ed01 218 },
219
68de9438 220 test_rdbms_ase => {
f6b26571 221 req => {
222 $ENV{DBICTEST_SYBASE_DSN}
223 ? (
224 'DateTime::Format::Sybase' => 0,
225 ) : ()
226 },
8057ed01 227 },
228
68de9438 229 test_rdbms_db2 => {
f58a165c 230 req => {
231 $ENV{DBICTEST_DB2_DSN}
232 ? (
233 'DBD::DB2' => 0,
234 ) : ()
235 },
236 },
237
42168332 238 test_memcached => {
239 req => {
240 $ENV{DBICTEST_MEMCACHED}
241 ? (
242 'Cache::Memcached' => 0,
243 ) : ()
244 },
245 },
246
8057ed01 247};
248
f6b26571 249
fb39747c 250sub req_list_for {
251 my ($class, $group) = @_;
252
f6b26571 253 croak "req_list_for() expects a requirement group name"
fb39747c 254 unless $group;
255
f6b26571 256 my $deps = $reqs->{$group}{req}
257 or croak "Requirement group '$group' does not exist";
fb39747c 258
259 return { %$deps };
260}
261
262
263our %req_availability_cache;
264sub req_ok_for {
265 my ($class, $group) = @_;
266
267 croak "req_ok_for() expects a requirement group name"
268 unless $group;
269
d8799bab 270 return $class->_check_deps($group)->{status};
fb39747c 271}
272
273sub req_missing_for {
274 my ($class, $group) = @_;
275
276 croak "req_missing_for() expects a requirement group name"
277 unless $group;
278
d8799bab 279 return $class->_check_deps($group)->{missing};
fb39747c 280}
281
282sub req_errorlist_for {
283 my ($class, $group) = @_;
284
285 croak "req_errorlist_for() expects a requirement group name"
286 unless $group;
287
d8799bab 288 return $class->_check_deps($group)->{errorlist};
fb39747c 289}
290
291sub _check_deps {
292 my ($class, $group) = @_;
293
d8799bab 294 return $req_availability_cache{$group} ||= do {
295
296 my $deps = $class->req_list_for ($group);
297
298 my %errors;
299 for my $mod (keys %$deps) {
300 my $req_line = "require $mod;";
301 if (my $ver = $deps->{$mod}) {
302 $req_line .= "$mod->VERSION($ver);";
303 }
304
305 eval $req_line;
306
307 $errors{$mod} = $@ if $@;
308 }
309
310 my $res;
fb39747c 311
d8799bab 312 if (keys %errors) {
313 my $missing = join (', ', map { $deps->{$_} ? "$_ >= $deps->{$_}" : $_ } (sort keys %errors) );
314 $missing .= " (see $class for details)" if $reqs->{$group}{pod};
315 $res = {
316 status => 0,
317 errorlist => \%errors,
318 missing => $missing,
319 };
fb39747c 320 }
321 else {
d8799bab 322 $res = {
323 status => 1,
324 errorlist => {},
325 missing => '',
326 };
fb39747c 327 }
328
d8799bab 329 $res;
330 };
fb39747c 331}
332
e3fc11e1 333sub req_group_list {
334 return { map { $_ => { %{ $reqs->{$_}{req} || {} } } } (keys %$reqs) };
335}
336
337# This is to be called by the author only (automatically in Makefile.PL)
f6b26571 338sub _gen_pod {
ccebe1f1 339 my ($class, $distver) = @_;
31fa1764 340
af4ac504 341 my $modfn = __PACKAGE__ . '.pm';
342 $modfn =~ s/\:\:/\//g;
f6b26571 343
31fa1764 344 my $podfn = __FILE__;
345 $podfn =~ s/\.pm$/\.pod/;
346
ccebe1f1 347 $distver ||=
31fa1764 348 eval { require DBIx::Class; DBIx::Class->VERSION; }
349 ||
ccebe1f1 350 die
31fa1764 351"\n\n---------------------------------------------------------------------\n" .
352'Unable to load core DBIx::Class module to determine current version, '.
353'possibly due to missing dependencies. Author-mode autodocumentation ' .
354"halted\n\n" . $@ .
355"\n\n---------------------------------------------------------------------\n"
31fa1764 356 ;
357
e3fc11e1 358 my $sqltver = $class->req_list_for ('deploy')->{'SQL::Translator'}
359 or die "Hrmm? No sqlt dep?";
7e3dc46f 360
f6b26571 361 my @chunks = (
d8799bab 362 <<'EOC',
af4ac504 363#########################################################################
364##################### A U T O G E N E R A T E D ########################
365#########################################################################
366#
367# The contents of this POD file are auto-generated. Any changes you make
368# will be lost. If you need to change the generated text edit _gen_pod()
369# at the end of $modfn
370#
371EOC
f6b26571 372 '=head1 NAME',
7e3dc46f 373 "$class - Optional module dependency specifications (for module authors)",
e3fc11e1 374 '=head1 SYNOPSIS',
d8799bab 375 <<"EOS",
7e3dc46f 376Somewhere in your build-file (e.g. L<Module::Install>'s Makefile.PL):
377
378 ...
379
380 configure_requires 'DBIx::Class' => '$distver';
381
382 require $class;
383
384 my \$deploy_deps = $class->req_list_for ('deploy');
385
386 for (keys %\$deploy_deps) {
387 requires \$_ => \$deploy_deps->{\$_};
388 }
389
390 ...
391
392Note that there are some caveats regarding C<configure_requires()>, more info
393can be found at L<Module::Install/configure_requires>
394EOS
f6b26571 395 '=head1 DESCRIPTION',
396 <<'EOD',
397Some of the less-frequently used features of L<DBIx::Class> have external
398module dependencies on their own. In order not to burden the average user
399with modules he will never use, these optional dependencies are not included
400in the base Makefile.PL. Instead an exception with a descriptive message is
401thrown when a specific feature is missing one or several modules required for
402its operation. This module is the central holding place for the current list
7e3dc46f 403of such dependencies, for DBIx::Class core authors, and DBIx::Class extension
404authors alike.
f6b26571 405EOD
406 '=head1 CURRENT REQUIREMENT GROUPS',
407 <<'EOD',
408Dependencies are organized in C<groups> and each group can list one or more
409required modules, with an optional minimum version (or 0 for any version).
ecb68746 410The group name can be used in the
f6b26571 411EOD
412 );
413
414 for my $group (sort keys %$reqs) {
415 my $p = $reqs->{$group}{pod}
416 or next;
417
418 my $modlist = $reqs->{$group}{req}
419 or next;
420
421 next unless keys %$modlist;
422
423 push @chunks, (
424 "=head2 $p->{title}",
425 "$p->{desc}",
426 '=over',
427 ( map { "=item * $_" . ($modlist->{$_} ? " >= $modlist->{$_}" : '') } (sort keys %$modlist) ),
428 '=back',
429 "Requirement group: B<$group>",
430 );
431 }
432
433 push @chunks, (
434 '=head1 METHODS',
e3fc11e1 435 '=head2 req_group_list',
436 '=over',
d8799bab 437 '=item Arguments: none',
e3fc11e1 438 '=item Returns: \%list_of_requirement_groups',
439 '=back',
d8799bab 440 <<'EOD',
e3fc11e1 441This method should be used by DBIx::Class packagers, to get a hashref of all
442dependencies keyed by dependency group. Each key (group name) can be supplied
443to one of the group-specific methods below.
444EOD
445
f6b26571 446 '=head2 req_list_for',
447 '=over',
448 '=item Arguments: $group_name',
449 '=item Returns: \%list_of_module_version_pairs',
450 '=back',
d8799bab 451 <<'EOD',
f6b26571 452This method should be used by DBIx::Class extension authors, to determine the
7e3dc46f 453version of modules a specific feature requires in the B<current> version of
e3fc11e1 454DBIx::Class. See the L</SYNOPSIS> for a real-world
7e3dc46f 455example.
f6b26571 456EOD
457
458 '=head2 req_ok_for',
459 '=over',
460 '=item Arguments: $group_name',
461 '=item Returns: 1|0',
462 '=back',
d8799bab 463 <<'EOD',
464Returns true or false depending on whether all modules required by
465C<$group_name> are present on the system and loadable.
466EOD
f6b26571 467
468 '=head2 req_missing_for',
469 '=over',
470 '=item Arguments: $group_name',
471 '=item Returns: $error_message_string',
472 '=back',
d8799bab 473 <<"EOD",
f6b26571 474Returns a single line string suitable for inclusion in larger error messages.
475This method would normally be used by DBIx::Class core-module author, to
476indicate to the user that he needs to install specific modules before he will
477be able to use a specific feature.
478
e3fc11e1 479For example if some of the requirements for C<deploy> are not available,
480the returned string could look like:
f6b26571 481
e3fc11e1 482 SQL::Translator >= $sqltver (see $class for details)
f6b26571 483
484The author is expected to prepend the necessary text to this message before
485returning the actual error seen by the user.
486EOD
487
488 '=head2 req_errorlist_for',
489 '=over',
490 '=item Arguments: $group_name',
491 '=item Returns: \%list_of_loaderrors_per_module',
492 '=back',
493 <<'EOD',
494Returns a hashref containing the actual errors that occured while attempting
495to load each module in the requirement group.
496EOD
fb8ae353 497 '=head1 AUTHOR',
498 'See L<DBIx::Class/CONTRIBUTORS>.',
499 '=head1 LICENSE',
500 'You may distribute this code under the same terms as Perl itself',
f6b26571 501 );
502
31fa1764 503 open (my $fh, '>', $podfn) or croak "Unable to write to $podfn: $!";
f6b26571 504 print $fh join ("\n\n", @chunks);
505 close ($fh);
506}
507
8057ed01 5081;