c29837676ea1e7fe6f95394914e0177b9dc20b84
[dbsrgits/DBIx-Class-Schema-Loader.git] / lib / DBIx / Class / Schema / Loader / Base.pm
1 package DBIx::Class::Schema::Loader::Base;
2
3 use strict;
4 use warnings;
5 use base qw/Class::Accessor::Grouped Class::C3::Componentised/;
6 use mro 'c3';
7 use Carp::Clan qw/^DBIx::Class/;
8 use DBIx::Class::Schema::Loader::RelBuilder;
9 use Data::Dump qw/ dump /;
10 use POSIX qw//;
11 use File::Spec qw//;
12 use Cwd qw//;
13 use Digest::MD5 qw//;
14 use Lingua::EN::Inflect::Number qw//;
15 use Lingua::EN::Inflect::Phrase qw//;
16 use File::Temp qw//;
17 use Class::Unload;
18 use Class::Inspector ();
19 use Scalar::Util 'looks_like_number';
20 use File::Slurp 'slurp';
21 use DBIx::Class::Schema::Loader::Utils qw/split_name dumper_squashed eval_without_redefine_warnings/;
22 use DBIx::Class::Schema::Loader::Optional::Dependencies ();
23 use Try::Tiny;
24 use DBIx::Class ();
25 use Class::Load 'load_class';
26 use namespace::clean;
27
28 our $VERSION = '0.07010';
29
30 __PACKAGE__->mk_group_ro_accessors('simple', qw/
31                                 schema
32                                 schema_class
33
34                                 exclude
35                                 constraint
36                                 additional_classes
37                                 additional_base_classes
38                                 left_base_classes
39                                 components
40                                 skip_relationships
41                                 skip_load_external
42                                 moniker_map
43                                 col_accessor_map
44                                 custom_column_info
45                                 inflect_singular
46                                 inflect_plural
47                                 debug
48                                 dump_directory
49                                 dump_overwrite
50                                 really_erase_my_files
51                                 resultset_namespace
52                                 default_resultset_class
53                                 schema_base_class
54                                 result_base_class
55                                 use_moose
56                                 overwrite_modifications
57
58                                 relationship_attrs
59
60                                 db_schema
61                                 _tables
62                                 classes
63                                 _upgrading_classes
64                                 monikers
65                                 dynamic
66                                 naming
67                                 datetime_timezone
68                                 datetime_locale
69                                 config_file
70                                 loader_class
71                                 qualify_objects
72 /);
73
74
75 __PACKAGE__->mk_group_accessors('simple', qw/
76                                 version_to_dump
77                                 schema_version_to_dump
78                                 _upgrading_from
79                                 _upgrading_from_load_classes
80                                 _downgrading_to_load_classes
81                                 _rewriting_result_namespace
82                                 use_namespaces
83                                 result_namespace
84                                 generate_pod
85                                 pod_comment_mode
86                                 pod_comment_spillover_length
87                                 preserve_case
88                                 col_collision_map
89                                 rel_collision_map
90                                 real_dump_directory
91                                 result_component_map
92                                 datetime_undef_if_invalid
93                                 _result_class_methods
94 /);
95
96 =head1 NAME
97
98 DBIx::Class::Schema::Loader::Base - Base DBIx::Class::Schema::Loader Implementation.
99
100 =head1 SYNOPSIS
101
102 See L<DBIx::Class::Schema::Loader>
103
104 =head1 DESCRIPTION
105
106 This is the base class for the storage-specific C<DBIx::Class::Schema::*>
107 classes, and implements the common functionality between them.
108
109 =head1 CONSTRUCTOR OPTIONS
110
111 These constructor options are the base options for
112 L<DBIx::Class::Schema::Loader/loader_options>.  Available constructor options are:
113
114 =head2 skip_relationships
115
116 Skip setting up relationships.  The default is to attempt the loading
117 of relationships.
118
119 =head2 skip_load_external
120
121 Skip loading of other classes in @INC. The default is to merge all other classes
122 with the same name found in @INC into the schema file we are creating.
123
124 =head2 naming
125
126 Static schemas (ones dumped to disk) will, by default, use the new-style
127 relationship names and singularized Results, unless you're overwriting an
128 existing dump made by an older version of L<DBIx::Class::Schema::Loader>, in
129 which case the backward compatible RelBuilder will be activated, and the
130 appropriate monikerization used.
131
132 Specifying
133
134     naming => 'current'
135
136 will disable the backward-compatible RelBuilder and use
137 the new-style relationship names along with singularized Results, even when
138 overwriting a dump made with an earlier version.
139
140 The option also takes a hashref:
141
142     naming => { relationships => 'v7', monikers => 'v7' }
143
144 The keys are:
145
146 =over 4
147
148 =item relationships
149
150 How to name relationship accessors.
151
152 =item monikers
153
154 How to name Result classes.
155
156 =item column_accessors
157
158 How to name column accessors in Result classes.
159
160 =back
161
162 The values can be:
163
164 =over 4
165
166 =item current
167
168 Latest style, whatever that happens to be.
169
170 =item v4
171
172 Unsingularlized monikers, C<has_many> only relationships with no _id stripping.
173
174 =item v5
175
176 Monikers singularized as whole words, C<might_have> relationships for FKs on
177 C<UNIQUE> constraints, C<_id> stripping for belongs_to relationships.
178
179 Some of the C<_id> stripping edge cases in C<0.05003> have been reverted for
180 the v5 RelBuilder.
181
182 =item v6
183
184 All monikers and relationships are inflected using
185 L<Lingua::EN::Inflect::Phrase>, and there is more aggressive C<_id> stripping
186 from relationship names.
187
188 In general, there is very little difference between v5 and v6 schemas.
189
190 =item v7
191
192 This mode is identical to C<v6> mode, except that monikerization of CamelCase
193 table names is also done correctly.
194
195 CamelCase column names in case-preserving mode will also be handled correctly
196 for relationship name inflection. See L</preserve_case>.
197
198 In this mode, CamelCase L</column_accessors> are normalized based on case
199 transition instead of just being lowercased, so C<FooId> becomes C<foo_id>.
200
201 If you don't have any CamelCase table or column names, you can upgrade without
202 breaking any of your code.
203
204 =back
205
206 Dynamic schemas will always default to the 0.04XXX relationship names and won't
207 singularize Results for backward compatibility, to activate the new RelBuilder
208 and singularization put this in your C<Schema.pm> file:
209
210     __PACKAGE__->naming('current');
211
212 Or if you prefer to use 0.07XXX features but insure that nothing breaks in the
213 next major version upgrade:
214
215     __PACKAGE__->naming('v7');
216
217 =head2 generate_pod
218
219 By default POD will be generated for columns and relationships, using database
220 metadata for the text if available and supported.
221
222 Reading database metadata (e.g. C<COMMENT ON TABLE some_table ...>) is only
223 supported for Postgres right now.
224
225 Set this to C<0> to turn off all POD generation.
226
227 =head2 pod_comment_mode
228
229 Controls where table comments appear in the generated POD. Smaller table
230 comments are appended to the C<NAME> section of the documentation, and larger
231 ones are inserted into C<DESCRIPTION> instead. You can force a C<DESCRIPTION>
232 section to be generated with the comment always, only use C<NAME>, or choose
233 the length threshold at which the comment is forced into the description.
234
235 =over 4
236
237 =item name
238
239 Use C<NAME> section only.
240
241 =item description
242
243 Force C<DESCRIPTION> always.
244
245 =item auto
246
247 Use C<DESCRIPTION> if length > L</pod_comment_spillover_length>, this is the
248 default.
249
250 =back
251
252 =head2 pod_comment_spillover_length
253
254 When pod_comment_mode is set to C<auto>, this is the length of the comment at
255 which it will be forced into a separate description section.
256
257 The default is C<60>
258
259 =head2 relationship_attrs
260
261 Hashref of attributes to pass to each generated relationship, listed
262 by type.  Also supports relationship type 'all', containing options to
263 pass to all generated relationships.  Attributes set for more specific
264 relationship types override those set in 'all'.
265
266 For example:
267
268   relationship_attrs => {
269     belongs_to => { is_deferrable => 0 },
270   },
271
272 use this to turn off DEFERRABLE on your foreign key constraints.
273
274 =head2 debug
275
276 If set to true, each constructive L<DBIx::Class> statement the loader
277 decides to execute will be C<warn>-ed before execution.
278
279 =head2 db_schema
280
281 Set the name of the schema to load (schema in the sense that your database
282 vendor means it).  Does not currently support loading more than one schema
283 name.
284
285 =head2 constraint
286
287 Only load tables matching regex.  Best specified as a qr// regex.
288
289 =head2 exclude
290
291 Exclude tables matching regex.  Best specified as a qr// regex.
292
293 =head2 moniker_map
294
295 Overrides the default table name to moniker translation.  Can be either
296 a hashref of table keys and moniker values, or a coderef for a translator
297 function taking a single scalar table name argument and returning
298 a scalar moniker.  If the hash entry does not exist, or the function
299 returns a false value, the code falls back to default behavior
300 for that table name.
301
302 The default behavior is to split on case transition and non-alphanumeric
303 boundaries, singularize the resulting phrase, then join the titlecased words
304 together. Examples:
305
306     Table Name       | Moniker Name
307     ---------------------------------
308     luser            | Luser
309     luser_group      | LuserGroup
310     luser-opts       | LuserOpt
311     stations_visited | StationVisited
312     routeChange      | RouteChange
313
314 =head2 col_accessor_map
315
316 Same as moniker_map, but for column accessor names.  If a coderef is
317 passed, the code is called with arguments of
318
319    the name of the column in the underlying database,
320    default accessor name that DBICSL would ordinarily give this column,
321    {
322       table_class     => name of the DBIC class we are building,
323       table_moniker   => calculated moniker for this table (after moniker_map if present),
324       table_name      => name of the database table,
325       full_table_name => schema-qualified name of the database table (RDBMS specific),
326       schema_class    => name of the schema class we are building,
327       column_info     => hashref of column info (data_type, is_nullable, etc),
328     }
329
330 =head2 inflect_plural
331
332 Just like L</moniker_map> above (can be hash/code-ref, falls back to default
333 if hash key does not exist or coderef returns false), but acts as a map
334 for pluralizing relationship names.  The default behavior is to utilize
335 L<Lingua::EN::Inflect::Phrase/to_PL>.
336
337 =head2 inflect_singular
338
339 As L</inflect_plural> above, but for singularizing relationship names.
340 Default behavior is to utilize L<Lingua::EN::Inflect::Phrase/to_S>.
341
342 =head2 schema_base_class
343
344 Base class for your schema classes. Defaults to 'DBIx::Class::Schema'.
345
346 =head2 result_base_class
347
348 Base class for your table classes (aka result classes). Defaults to
349 'DBIx::Class::Core'.
350
351 =head2 additional_base_classes
352
353 List of additional base classes all of your table classes will use.
354
355 =head2 left_base_classes
356
357 List of additional base classes all of your table classes will use
358 that need to be leftmost.
359
360 =head2 additional_classes
361
362 List of additional classes which all of your table classes will use.
363
364 =head2 components
365
366 List of additional components to be loaded into all of your table
367 classes.  A good example would be
368 L<InflateColumn::DateTime|DBIx::Class::InflateColumn::DateTime>
369
370 =head2 result_component_map
371
372 A hashref of moniker keys and component values.  Unlike C<components>, which loads the
373 given components into every table class, this option allows you to load certain
374 components for specified tables.  For example:
375
376   result_component_map => {
377       StationVisited => '+YourApp::Schema::Component::StationVisited',
378       RouteChange    => [
379                             '+YourApp::Schema::Component::RouteChange',
380                             'InflateColumn::DateTime',
381                         ],
382   }
383   
384 You may use this in conjunction with C<components>.
385
386 =head2 use_namespaces
387
388 This is now the default, to go back to L<DBIx::Class::Schema/load_classes> pass
389 a C<0>.
390
391 Generate result class names suitable for
392 L<DBIx::Class::Schema/load_namespaces> and call that instead of
393 L<DBIx::Class::Schema/load_classes>. When using this option you can also
394 specify any of the options for C<load_namespaces> (i.e. C<result_namespace>,
395 C<resultset_namespace>, C<default_resultset_class>), and they will be added
396 to the call (and the generated result class names adjusted appropriately).
397
398 =head2 dump_directory
399
400 The value of this option is a perl libdir pathname.  Within
401 that directory this module will create a baseline manual
402 L<DBIx::Class::Schema> module set, based on what it creates at runtime.
403
404 The created schema class will have the same classname as the one on
405 which you are setting this option (and the ResultSource classes will be
406 based on this name as well).
407
408 Normally you wouldn't hard-code this setting in your schema class, as it
409 is meant for one-time manual usage.
410
411 See L<DBIx::Class::Schema::Loader/dump_to_dir> for examples of the
412 recommended way to access this functionality.
413
414 =head2 dump_overwrite
415
416 Deprecated.  See L</really_erase_my_files> below, which does *not* mean
417 the same thing as the old C<dump_overwrite> setting from previous releases.
418
419 =head2 really_erase_my_files
420
421 Default false.  If true, Loader will unconditionally delete any existing
422 files before creating the new ones from scratch when dumping a schema to disk.
423
424 The default behavior is instead to only replace the top portion of the
425 file, up to and including the final stanza which contains
426 C<# DO NOT MODIFY THE FIRST PART OF THIS FILE>
427 leaving any customizations you placed after that as they were.
428
429 When C<really_erase_my_files> is not set, if the output file already exists,
430 but the aforementioned final stanza is not found, or the checksum
431 contained there does not match the generated contents, Loader will
432 croak and not touch the file.
433
434 You should really be using version control on your schema classes (and all
435 of the rest of your code for that matter).  Don't blame me if a bug in this
436 code wipes something out when it shouldn't have, you've been warned.
437
438 =head2 overwrite_modifications
439
440 Default false.  If false, when updating existing files, Loader will
441 refuse to modify any Loader-generated code that has been modified
442 since its last run (as determined by the checksum Loader put in its
443 comment lines).
444
445 If true, Loader will discard any manual modifications that have been
446 made to Loader-generated code.
447
448 Again, you should be using version control on your schema classes.  Be
449 careful with this option.
450
451 =head2 custom_column_info
452
453 Hook for adding extra attributes to the
454 L<column_info|DBIx::Class::ResultSource/column_info> for a column.
455
456 Must be a coderef that returns a hashref with the extra attributes.
457
458 Receives the table name, column name and column_info.
459
460 For example:
461
462   custom_column_info => sub {
463       my ($table_name, $column_name, $column_info) = @_;
464
465       if ($column_name eq 'dog' && $column_info->{default_value} eq 'snoopy') {
466           return { is_snoopy => 1 };
467       }
468   },
469
470 This attribute can also be used to set C<inflate_datetime> on a non-datetime
471 column so it also receives the L</datetime_timezone> and/or L</datetime_locale>.
472
473 =head2 datetime_timezone
474
475 Sets the timezone attribute for L<DBIx::Class::InflateColumn::DateTime> for all
476 columns with the DATE/DATETIME/TIMESTAMP data_types.
477
478 =head2 datetime_locale
479
480 Sets the locale attribute for L<DBIx::Class::InflateColumn::DateTime> for all
481 columns with the DATE/DATETIME/TIMESTAMP data_types.
482
483 =head2 datetime_undef_if_invalid
484
485 Pass a C<0> for this option when using MySQL if you B<DON'T> want C<<
486 datetime_undef_if_invalid => 1 >> in your column info for DATE, DATETIME and
487 TIMESTAMP columns.
488
489 The default is recommended to deal with data such as C<00/00/00> which
490 sometimes ends up in such columns in MySQL.
491
492 =head2 config_file
493
494 File in Perl format, which should return a HASH reference, from which to read
495 loader options.
496
497 =head2 preserve_case
498
499 Usually column names are lowercased, to make them easier to work with in
500 L<DBIx::Class>. This option lets you turn this behavior off, if the driver
501 supports it.
502
503 Drivers for case sensitive databases like Sybase ASE or MSSQL with a
504 case-sensitive collation will turn this option on unconditionally.
505
506 Currently the drivers for SQLite, mysql, MSSQL and Firebird/InterBase support
507 setting this option.
508
509 =head2 qualify_objects
510
511 Set to true to prepend the L</db_schema> to table names for C<<
512 __PACKAGE__->table >> calls, and to some other things like Oracle sequences.
513
514 =head2 use_moose
515
516 Creates Schema and Result classes that use L<Moose>, L<MooseX::NonMoose> and
517 L<namespace::autoclean>. The default content after the md5 sum also makes the
518 classes immutable.
519
520 It is safe to upgrade your existing Schema to this option.
521
522 =head2 col_collision_map
523
524 This option controls how accessors for column names which collide with perl
525 methods are named. See L</COLUMN ACCESSOR COLLISIONS> for more information.
526
527 This option takes either a single L<sprintf|perlfunc/sprintf> format or a hashref of
528 strings which are compiled to regular expressions that map to
529 L<sprintf|perlfunc/sprintf> formats.
530
531 Examples:
532
533     col_collision_map => 'column_%s'
534
535     col_collision_map => { '(.*)' => 'column_%s' }
536
537     col_collision_map => { '(foo).*(bar)' => 'column_%s_%s' }
538
539 =head2 rel_collision_map
540
541 Works just like L</col_collision_map>, but for relationship names/accessors
542 rather than column names/accessors.
543
544 The default is to just append C<_rel> to the relationship name, see
545 L</RELATIONSHIP NAME COLLISIONS>.
546
547 =head1 METHODS
548
549 None of these methods are intended for direct invocation by regular
550 users of L<DBIx::Class::Schema::Loader>. Some are proxied via
551 L<DBIx::Class::Schema::Loader>.
552
553 =cut
554
555 my $CURRENT_V = 'v7';
556
557 my @CLASS_ARGS = qw(
558     schema_base_class result_base_class additional_base_classes
559     left_base_classes additional_classes components
560 );
561
562 # ensure that a peice of object data is a valid arrayref, creating
563 # an empty one or encapsulating whatever's there.
564 sub _ensure_arrayref {
565     my $self = shift;
566
567     foreach (@_) {
568         $self->{$_} ||= [];
569         $self->{$_} = [ $self->{$_} ]
570             unless ref $self->{$_} eq 'ARRAY';
571     }
572 }
573
574 =head2 new
575
576 Constructor for L<DBIx::Class::Schema::Loader::Base>, used internally
577 by L<DBIx::Class::Schema::Loader>.
578
579 =cut
580
581 sub new {
582     my ( $class, %args ) = @_;
583
584     if (exists $args{column_accessor_map}) {
585         $args{col_accessor_map} = delete $args{column_accessor_map};
586     }
587
588     my $self = { %args };
589
590     # don't lose undef options
591     for (values %$self) {
592         $_ = 0 unless defined $_;
593     }
594
595     bless $self => $class;
596
597     if (my $config_file = $self->config_file) {
598         my $config_opts = do $config_file;
599
600         croak "Error reading config from $config_file: $@" if $@;
601
602         croak "Config file $config_file must be a hashref" unless ref($config_opts) eq 'HASH';
603
604         while (my ($k, $v) = each %$config_opts) {
605             $self->{$k} = $v unless exists $self->{$k};
606         }
607     }
608
609     $self->_ensure_arrayref(qw/additional_classes
610                                additional_base_classes
611                                left_base_classes
612                                components
613                               /);
614
615     $self->_validate_class_args;
616
617     if ($self->result_component_map) {
618         my %rc_map = %{ $self->result_component_map };
619         foreach my $moniker (keys %rc_map) {
620             $rc_map{$moniker} = [ $rc_map{$moniker} ] unless ref $rc_map{$moniker};
621         }
622         $self->result_component_map(\%rc_map);
623     }
624     else {
625         $self->result_component_map({});
626     }
627     $self->_validate_result_component_map;
628
629     if ($self->use_moose) {
630         if (not DBIx::Class::Schema::Loader::Optional::Dependencies->req_ok_for('use_moose')) {
631             die sprintf "You must install the following CPAN modules to enable the use_moose option: %s.\n",
632                 DBIx::Class::Schema::Loader::Optional::Dependencies->req_missing_for('use_moose');
633         }
634     }
635
636     $self->{monikers} = {};
637     $self->{classes} = {};
638     $self->{_upgrading_classes} = {};
639
640     $self->{schema_class} ||= ( ref $self->{schema} || $self->{schema} );
641     $self->{schema} ||= $self->{schema_class};
642
643     croak "dump_overwrite is deprecated.  Please read the"
644         . " DBIx::Class::Schema::Loader::Base documentation"
645             if $self->{dump_overwrite};
646
647     $self->{dynamic} = ! $self->{dump_directory};
648     $self->{temp_directory} ||= File::Temp::tempdir( 'dbicXXXX',
649                                                      TMPDIR  => 1,
650                                                      CLEANUP => 1,
651                                                    );
652
653     $self->{dump_directory} ||= $self->{temp_directory};
654
655     $self->real_dump_directory($self->{dump_directory});
656
657     $self->version_to_dump($DBIx::Class::Schema::Loader::VERSION);
658     $self->schema_version_to_dump($DBIx::Class::Schema::Loader::VERSION);
659
660     if ((not ref $self->naming) && defined $self->naming) {
661         my $naming_ver = $self->naming;
662         $self->{naming} = {
663             relationships => $naming_ver,
664             monikers => $naming_ver,
665             column_accessors => $naming_ver,
666         };
667     }
668
669     if ($self->naming) {
670         for (values %{ $self->naming }) {
671             $_ = $CURRENT_V if $_ eq 'current';
672         }
673     }
674     $self->{naming} ||= {};
675
676     if ($self->custom_column_info && ref $self->custom_column_info ne 'CODE') {
677         croak 'custom_column_info must be a CODE ref';
678     }
679
680     $self->_check_back_compat;
681
682     $self->use_namespaces(1) unless defined $self->use_namespaces;
683     $self->generate_pod(1)   unless defined $self->generate_pod;
684     $self->pod_comment_mode('auto')         unless defined $self->pod_comment_mode;
685     $self->pod_comment_spillover_length(60) unless defined $self->pod_comment_spillover_length;
686
687     if (my $col_collision_map = $self->col_collision_map) {
688         if (my $reftype = ref $col_collision_map) {
689             if ($reftype ne 'HASH') {
690                 croak "Invalid type $reftype for option 'col_collision_map'";
691             }
692         }
693         else {
694             $self->col_collision_map({ '(.*)' => $col_collision_map });
695         }
696     }
697
698     $self;
699 }
700
701 sub _check_back_compat {
702     my ($self) = @_;
703
704 # dynamic schemas will always be in 0.04006 mode, unless overridden
705     if ($self->dynamic) {
706 # just in case, though no one is likely to dump a dynamic schema
707         $self->schema_version_to_dump('0.04006');
708
709         if (not %{ $self->naming }) {
710             warn <<EOF unless $ENV{SCHEMA_LOADER_BACKCOMPAT};
711
712 Dynamic schema detected, will run in 0.04006 mode.
713
714 Set the 'naming' attribute or the SCHEMA_LOADER_BACKCOMPAT environment variable
715 to disable this warning.
716
717 Also consider setting 'use_namespaces => 1' if/when upgrading.
718
719 See perldoc DBIx::Class::Schema::Loader::Manual::UpgradingFromV4 for more
720 details.
721 EOF
722         }
723         else {
724             $self->_upgrading_from('v4');
725         }
726
727         $self->naming->{relationships} ||= 'v4';
728         $self->naming->{monikers}      ||= 'v4';
729
730         if ($self->use_namespaces) {
731             $self->_upgrading_from_load_classes(1);
732         }
733         else {
734             $self->use_namespaces(0);
735         }
736
737         return;
738     }
739
740 # otherwise check if we need backcompat mode for a static schema
741     my $filename = $self->_get_dump_filename($self->schema_class);
742     return unless -e $filename;
743
744     my ($old_gen, $old_md5, $old_ver, $old_ts, $old_custom) =
745       $self->_parse_generated_file($filename);
746
747     return unless $old_ver;
748
749     # determine if the existing schema was dumped with use_moose => 1
750     if (! defined $self->use_moose) {
751         $self->{use_moose} = 1 if $old_gen =~ /^ (?!\s*\#) use \s+ Moose/xm;
752     }
753
754     my $load_classes = ($old_gen =~ /^__PACKAGE__->load_classes;/m) ? 1 : 0;
755     my $result_namespace = do { ($old_gen =~ /result_namespace => '([^']+)'/) ? $1 : '' };
756
757     if ($load_classes && (not defined $self->use_namespaces)) {
758         warn <<"EOF"  unless $ENV{SCHEMA_LOADER_BACKCOMPAT};
759
760 'load_classes;' static schema detected, turning off 'use_namespaces'.
761
762 Set the 'use_namespaces' attribute or the SCHEMA_LOADER_BACKCOMPAT environment
763 variable to disable this warning.
764
765 See perldoc DBIx::Class::Schema::Loader::Manual::UpgradingFromV4 for more
766 details.
767 EOF
768         $self->use_namespaces(0);
769     }
770     elsif ($load_classes && $self->use_namespaces) {
771         $self->_upgrading_from_load_classes(1);
772     }
773     elsif ((not $load_classes) && defined $self->use_namespaces && ! $self->use_namespaces) {
774         $self->_downgrading_to_load_classes(
775             $result_namespace || 'Result'
776         );
777     }
778     elsif ((not defined $self->use_namespaces) || $self->use_namespaces) {
779         if (not $self->result_namespace) {
780             $self->result_namespace($result_namespace || 'Result');
781         }
782         elsif ($result_namespace ne $self->result_namespace) {
783             $self->_rewriting_result_namespace(
784                 $result_namespace || 'Result'
785             );
786         }
787     }
788
789     # XXX when we go past .0 this will need fixing
790     my ($v) = $old_ver =~ /([1-9])/;
791     $v = "v$v";
792
793     return if ($v eq $CURRENT_V || $old_ver =~ /^0\.\d\d999/);
794
795     if (not %{ $self->naming }) {
796         warn <<"EOF" unless $ENV{SCHEMA_LOADER_BACKCOMPAT};
797
798 Version $old_ver static schema detected, turning on backcompat mode.
799
800 Set the 'naming' attribute or the SCHEMA_LOADER_BACKCOMPAT environment variable
801 to disable this warning.
802
803 See: 'naming' in perldoc DBIx::Class::Schema::Loader::Base .
804
805 See perldoc DBIx::Class::Schema::Loader::Manual::UpgradingFromV4 if upgrading
806 from version 0.04006.
807 EOF
808
809         $self->naming->{relationships}    ||= $v;
810         $self->naming->{monikers}         ||= $v;
811         $self->naming->{column_accessors} ||= $v;
812
813         $self->schema_version_to_dump($old_ver);
814     }
815     else {
816         $self->_upgrading_from($v);
817     }
818 }
819
820 sub _validate_class_args {
821     my $self = shift;
822
823     foreach my $k (@CLASS_ARGS) {
824         next unless $self->$k;
825
826         my @classes = ref $self->$k eq 'ARRAY' ? @{ $self->$k } : $self->$k;
827         $self->_validate_classes($k, \@classes);
828     }
829 }
830
831 sub _validate_result_component_map {
832     my $self = shift;
833
834     my $map = $self->result_component_map;
835     return unless $map && ref $map eq 'HASH';
836
837     foreach my $classes (values %$map) {
838         $self->_validate_classes('result_component_map', [@$classes]);
839     }
840 }
841
842 sub _validate_classes {
843     my $self = shift;
844     my $key  = shift;
845     my $classes = shift;
846
847     foreach my $c (@$classes) {
848         # components default to being under the DBIx::Class namespace unless they
849         # are preceeded with a '+'
850         if ( $key =~ m/component/ && $c !~ s/^\+// ) {
851             $c = 'DBIx::Class::' . $c;
852         }
853
854         # 1 == installed, 0 == not installed, undef == invalid classname
855         my $installed = Class::Inspector->installed($c);
856         if ( defined($installed) ) {
857             if ( $installed == 0 ) {
858                 croak qq/$c, as specified in the loader option "$key", is not installed/;
859             }
860         } else {
861             croak qq/$c, as specified in the loader option "$key", is an invalid class name/;
862         }
863     }
864 }
865
866
867 sub _find_file_in_inc {
868     my ($self, $file) = @_;
869
870     foreach my $prefix (@INC) {
871         my $fullpath = File::Spec->catfile($prefix, $file);
872         return $fullpath if -f $fullpath
873             # abs_path throws on Windows for nonexistant files
874             and (try { Cwd::abs_path($fullpath) }) ne
875                ((try { Cwd::abs_path(File::Spec->catfile($self->dump_directory, $file)) }) || '');
876     }
877
878     return;
879 }
880
881 sub _class_path {
882     my ($self, $class) = @_;
883
884     my $class_path = $class;
885     $class_path =~ s{::}{/}g;
886     $class_path .= '.pm';
887
888     return $class_path;
889 }
890
891 sub _find_class_in_inc {
892     my ($self, $class) = @_;
893
894     return $self->_find_file_in_inc($self->_class_path($class));
895 }
896
897 sub _rewriting {
898     my $self = shift;
899
900     return $self->_upgrading_from
901         || $self->_upgrading_from_load_classes
902         || $self->_downgrading_to_load_classes
903         || $self->_rewriting_result_namespace
904     ;
905 }
906
907 sub _rewrite_old_classnames {
908     my ($self, $code) = @_;
909
910     return $code unless $self->_rewriting;
911
912     my %old_classes = reverse %{ $self->_upgrading_classes };
913
914     my $re = join '|', keys %old_classes;
915     $re = qr/\b($re)\b/;
916
917     $code =~ s/$re/$old_classes{$1} || $1/eg;
918
919     return $code;
920 }
921
922 sub _load_external {
923     my ($self, $class) = @_;
924
925     return if $self->{skip_load_external};
926
927     # so that we don't load our own classes, under any circumstances
928     local *INC = [ grep $_ ne $self->dump_directory, @INC ];
929
930     my $real_inc_path = $self->_find_class_in_inc($class);
931
932     my $old_class = $self->_upgrading_classes->{$class}
933         if $self->_rewriting;
934
935     my $old_real_inc_path = $self->_find_class_in_inc($old_class)
936         if $old_class && $old_class ne $class;
937
938     return unless $real_inc_path || $old_real_inc_path;
939
940     if ($real_inc_path) {
941         # If we make it to here, we loaded an external definition
942         warn qq/# Loaded external class definition for '$class'\n/
943             if $self->debug;
944
945         my $code = $self->_rewrite_old_classnames(scalar slurp $real_inc_path);
946
947         if ($self->dynamic) { # load the class too
948             eval_without_redefine_warnings($code);
949         }
950
951         $self->_ext_stmt($class,
952           qq|# These lines were loaded from '$real_inc_path' found in \@INC.\n|
953          .qq|# They are now part of the custom portion of this file\n|
954          .qq|# for you to hand-edit.  If you do not either delete\n|
955          .qq|# this section or remove that file from \@INC, this section\n|
956          .qq|# will be repeated redundantly when you re-create this\n|
957          .qq|# file again via Loader!  See skip_load_external to disable\n|
958          .qq|# this feature.\n|
959         );
960         chomp $code;
961         $self->_ext_stmt($class, $code);
962         $self->_ext_stmt($class,
963             qq|# End of lines loaded from '$real_inc_path' |
964         );
965     }
966
967     if ($old_real_inc_path) {
968         my $code = slurp $old_real_inc_path;
969
970         $self->_ext_stmt($class, <<"EOF");
971
972 # These lines were loaded from '$old_real_inc_path',
973 # based on the Result class name that would have been created by an older
974 # version of the Loader. For a static schema, this happens only once during
975 # upgrade. See skip_load_external to disable this feature.
976 EOF
977
978         $code = $self->_rewrite_old_classnames($code);
979
980         if ($self->dynamic) {
981             warn <<"EOF";
982
983 Detected external content in '$old_real_inc_path', a class name that would have
984 been used by an older version of the Loader.
985
986 * PLEASE RENAME THIS CLASS: from '$old_class' to '$class', as that is the
987 new name of the Result.
988 EOF
989             eval_without_redefine_warnings($code);
990         }
991
992         chomp $code;
993         $self->_ext_stmt($class, $code);
994         $self->_ext_stmt($class,
995             qq|# End of lines loaded from '$old_real_inc_path' |
996         );
997     }
998 }
999
1000 =head2 load
1001
1002 Does the actual schema-construction work.
1003
1004 =cut
1005
1006 sub load {
1007     my $self = shift;
1008
1009     $self->_load_tables(
1010         $self->_tables_list({ constraint => $self->constraint, exclude => $self->exclude })
1011     );
1012 }
1013
1014 =head2 rescan
1015
1016 Arguments: schema
1017
1018 Rescan the database for changes. Returns a list of the newly added table
1019 monikers.
1020
1021 The schema argument should be the schema class or object to be affected.  It
1022 should probably be derived from the original schema_class used during L</load>.
1023
1024 =cut
1025
1026 sub rescan {
1027     my ($self, $schema) = @_;
1028
1029     $self->{schema} = $schema;
1030     $self->_relbuilder->{schema} = $schema;
1031
1032     my @created;
1033     my @current = $self->_tables_list({ constraint => $self->constraint, exclude => $self->exclude });
1034
1035     foreach my $table (@current) {
1036         if(!exists $self->{_tables}->{$table}) {
1037             push(@created, $table);
1038         }
1039     }
1040
1041     my %current;
1042     @current{@current} = ();
1043     foreach my $table (keys %{ $self->{_tables} }) {
1044         if (not exists $current{$table}) {
1045             $self->_unregister_source_for_table($table);
1046         }
1047     }
1048
1049     delete $self->{_dump_storage};
1050     delete $self->{_relations_started};
1051
1052     my $loaded = $self->_load_tables(@current);
1053
1054     return map { $self->monikers->{$_} } @created;
1055 }
1056
1057 sub _relbuilder {
1058     my ($self) = @_;
1059
1060     return if $self->{skip_relationships};
1061
1062     return $self->{relbuilder} ||= do {
1063
1064         no warnings 'uninitialized';
1065         my $relbuilder_suff =
1066             {qw{
1067                 v4  ::Compat::v0_040
1068                 v5  ::Compat::v0_05
1069                 v6  ::Compat::v0_06
1070             }}
1071             ->{ $self->naming->{relationships}};
1072
1073         my $relbuilder_class = 'DBIx::Class::Schema::Loader::RelBuilder'.$relbuilder_suff;
1074         load_class $relbuilder_class;
1075         $relbuilder_class->new( $self );
1076
1077     };
1078 }
1079
1080 sub _load_tables {
1081     my ($self, @tables) = @_;
1082
1083     # Save the new tables to the tables list
1084     foreach (@tables) {
1085         $self->{_tables}->{$_} = 1;
1086     }
1087
1088     $self->_make_src_class($_) for @tables;
1089
1090     # sanity-check for moniker clashes
1091     my $inverse_moniker_idx;
1092     for (keys %{$self->monikers}) {
1093       push @{$inverse_moniker_idx->{$self->monikers->{$_}}}, $_;
1094     }
1095
1096     my @clashes;
1097     for (keys %$inverse_moniker_idx) {
1098       my $tables = $inverse_moniker_idx->{$_};
1099       if (@$tables > 1) {
1100         push @clashes, sprintf ("tables %s reduced to the same source moniker '%s'",
1101           join (', ', map { "'$_'" } @$tables),
1102           $_,
1103         );
1104       }
1105     }
1106
1107     if (@clashes) {
1108       die   'Unable to load schema - chosen moniker/class naming style results in moniker clashes. '
1109           . 'Either change the naming style, or supply an explicit moniker_map: '
1110           . join ('; ', @clashes)
1111           . "\n"
1112       ;
1113     }
1114
1115
1116     $self->_setup_src_meta($_) for @tables;
1117
1118     if(!$self->skip_relationships) {
1119         # The relationship loader needs a working schema
1120         $self->{quiet} = 1;
1121         local $self->{dump_directory} = $self->{temp_directory};
1122         $self->_reload_classes(\@tables);
1123         $self->_load_relationships($_) for @tables;
1124         $self->_relbuilder->cleanup;
1125         $self->{quiet} = 0;
1126
1127         # Remove that temp dir from INC so it doesn't get reloaded
1128         @INC = grep $_ ne $self->dump_directory, @INC;
1129     }
1130
1131     $self->_load_external($_)
1132         for map { $self->classes->{$_} } @tables;
1133
1134     # Reload without unloading first to preserve any symbols from external
1135     # packages.
1136     $self->_reload_classes(\@tables, { unload => 0 });
1137
1138     # Drop temporary cache
1139     delete $self->{_cache};
1140
1141     return \@tables;
1142 }
1143
1144 sub _reload_classes {
1145     my ($self, $tables, $opts) = @_;
1146
1147     my @tables = @$tables;
1148
1149     my $unload = $opts->{unload};
1150     $unload = 1 unless defined $unload;
1151
1152     # so that we don't repeat custom sections
1153     @INC = grep $_ ne $self->dump_directory, @INC;
1154
1155     $self->_dump_to_dir(map { $self->classes->{$_} } @tables);
1156
1157     unshift @INC, $self->dump_directory;
1158     
1159     my @to_register;
1160     my %have_source = map { $_ => $self->schema->source($_) }
1161         $self->schema->sources;
1162
1163     for my $table (@tables) {
1164         my $moniker = $self->monikers->{$table};
1165         my $class = $self->classes->{$table};
1166         
1167         {
1168             no warnings 'redefine';
1169             local *Class::C3::reinitialize = sub {};  # to speed things up, reinitialized below
1170             use warnings;
1171
1172             if (my $mc = $self->_moose_metaclass($class)) {
1173                 $mc->make_mutable;
1174             }
1175             Class::Unload->unload($class) if $unload;
1176             my ($source, $resultset_class);
1177             if (
1178                 ($source = $have_source{$moniker})
1179                 && ($resultset_class = $source->resultset_class)
1180                 && ($resultset_class ne 'DBIx::Class::ResultSet')
1181             ) {
1182                 my $has_file = Class::Inspector->loaded_filename($resultset_class);
1183                 if (my $mc = $self->_moose_metaclass($resultset_class)) {
1184                     $mc->make_mutable;
1185                 }
1186                 Class::Unload->unload($resultset_class) if $unload;
1187                 $self->_reload_class($resultset_class) if $has_file;
1188             }
1189             $self->_reload_class($class);
1190         }
1191         push @to_register, [$moniker, $class];
1192     }
1193
1194     Class::C3->reinitialize;
1195     for (@to_register) {
1196         $self->schema->register_class(@$_);
1197     }
1198 }
1199
1200 sub _moose_metaclass {
1201   return undef unless $INC{'Class/MOP.pm'};   # if CMOP is not loaded the class could not have loaded in the 1st place
1202
1203   my $class = $_[1];
1204
1205   my $mc = try { Class::MOP::class_of($class) }
1206     or return undef;
1207
1208   return $mc->isa('Moose::Meta::Class') ? $mc : undef;
1209 }
1210
1211 # We use this instead of ensure_class_loaded when there are package symbols we
1212 # want to preserve.
1213 sub _reload_class {
1214     my ($self, $class) = @_;
1215
1216     my $class_path = $self->_class_path($class);
1217     delete $INC{ $class_path };
1218
1219 # kill redefined warnings
1220     try {
1221         eval_without_redefine_warnings ("require $class");
1222     }
1223     catch {
1224         my $source = slurp $self->_get_dump_filename($class);
1225         die "Failed to reload class $class: $_.\n\nCLASS SOURCE:\n\n$source";
1226     };
1227 }
1228
1229 sub _get_dump_filename {
1230     my ($self, $class) = (@_);
1231
1232     $class =~ s{::}{/}g;
1233     return $self->dump_directory . q{/} . $class . q{.pm};
1234 }
1235
1236 =head2 get_dump_filename
1237
1238 Arguments: class
1239
1240 Returns the full path to the file for a class that the class has been or will
1241 be dumped to. This is a file in a temp dir for a dynamic schema.
1242
1243 =cut
1244
1245 sub get_dump_filename {
1246     my ($self, $class) = (@_);
1247
1248     local $self->{dump_directory} = $self->real_dump_directory;
1249
1250     return $self->_get_dump_filename($class);
1251 }
1252
1253 sub _ensure_dump_subdirs {
1254     my ($self, $class) = (@_);
1255
1256     my @name_parts = split(/::/, $class);
1257     pop @name_parts; # we don't care about the very last element,
1258                      # which is a filename
1259
1260     my $dir = $self->dump_directory;
1261     while (1) {
1262         if(!-d $dir) {
1263             mkdir($dir) or croak "mkdir('$dir') failed: $!";
1264         }
1265         last if !@name_parts;
1266         $dir = File::Spec->catdir($dir, shift @name_parts);
1267     }
1268 }
1269
1270 sub _dump_to_dir {
1271     my ($self, @classes) = @_;
1272
1273     my $schema_class = $self->schema_class;
1274     my $schema_base_class = $self->schema_base_class || 'DBIx::Class::Schema';
1275
1276     my $target_dir = $self->dump_directory;
1277     warn "Dumping manual schema for $schema_class to directory $target_dir ...\n"
1278         unless $self->{dynamic} or $self->{quiet};
1279
1280     my $schema_text =
1281           qq|package $schema_class;\n\n|
1282         . qq|# Created by DBIx::Class::Schema::Loader\n|
1283         . qq|# DO NOT MODIFY THE FIRST PART OF THIS FILE\n\n|;
1284
1285     if ($self->use_moose) {
1286         $schema_text.= qq|use Moose;\nuse namespace::autoclean;\nextends '$schema_base_class';\n\n|;
1287     }
1288     else {
1289         $schema_text .= qq|use strict;\nuse warnings;\n\nuse base '$schema_base_class';\n\n|;
1290     }
1291
1292     if ($self->use_namespaces) {
1293         $schema_text .= qq|__PACKAGE__->load_namespaces|;
1294         my $namespace_options;
1295
1296         my @attr = qw/resultset_namespace default_resultset_class/;
1297
1298         unshift @attr, 'result_namespace' unless (not $self->result_namespace) || $self->result_namespace eq 'Result';
1299
1300         for my $attr (@attr) {
1301             if ($self->$attr) {
1302                 $namespace_options .= qq|    $attr => '| . $self->$attr . qq|',\n|
1303             }
1304         }
1305         $schema_text .= qq|(\n$namespace_options)| if $namespace_options;
1306         $schema_text .= qq|;\n|;
1307     }
1308     else {
1309         $schema_text .= qq|__PACKAGE__->load_classes;\n|;
1310     }
1311
1312     {
1313         local $self->{version_to_dump} = $self->schema_version_to_dump;
1314         $self->_write_classfile($schema_class, $schema_text, 1);
1315     }
1316
1317     my $result_base_class = $self->result_base_class || 'DBIx::Class::Core';
1318
1319     foreach my $src_class (@classes) {
1320         my $src_text = 
1321               qq|package $src_class;\n\n|
1322             . qq|# Created by DBIx::Class::Schema::Loader\n|
1323             . qq|# DO NOT MODIFY THE FIRST PART OF THIS FILE\n\n|
1324             . qq|use strict;\nuse warnings;\n\n|;
1325         if ($self->use_moose) {
1326             $src_text.= qq|use Moose;\nuse MooseX::NonMoose;\nuse namespace::autoclean;|;
1327
1328             # these options 'use base' which is compile time
1329             if (@{ $self->left_base_classes } || @{ $self->additional_base_classes }) {
1330                 $src_text .= qq|\nBEGIN { extends '$result_base_class' }\n\n|;
1331             }
1332             else {
1333                 $src_text .= qq|\nextends '$result_base_class';\n\n|;
1334             }
1335         }
1336         else {
1337              $src_text .= qq|use base '$result_base_class';\n\n|;
1338         }
1339         $self->_write_classfile($src_class, $src_text);
1340     }
1341
1342     # remove Result dir if downgrading from use_namespaces, and there are no
1343     # files left.
1344     if (my $result_ns = $self->_downgrading_to_load_classes
1345                         || $self->_rewriting_result_namespace) {
1346         my $result_namespace = $self->_result_namespace(
1347             $schema_class,
1348             $result_ns,
1349         );
1350
1351         (my $result_dir = $result_namespace) =~ s{::}{/}g;
1352         $result_dir = $self->dump_directory . '/' . $result_dir;
1353
1354         unless (my @files = glob "$result_dir/*") {
1355             rmdir $result_dir;
1356         }
1357     }
1358
1359     warn "Schema dump completed.\n" unless $self->{dynamic} or $self->{quiet};
1360
1361 }
1362
1363 sub _sig_comment {
1364     my ($self, $version, $ts) = @_;
1365     return qq|\n\n# Created by DBIx::Class::Schema::Loader|
1366          . qq| v| . $version
1367          . q| @ | . $ts 
1368          . qq|\n# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:|;
1369 }
1370
1371 sub _write_classfile {
1372     my ($self, $class, $text, $is_schema) = @_;
1373
1374     my $filename = $self->_get_dump_filename($class);
1375     $self->_ensure_dump_subdirs($class);
1376
1377     if (-f $filename && $self->really_erase_my_files) {
1378         warn "Deleting existing file '$filename' due to "
1379             . "'really_erase_my_files' setting\n" unless $self->{quiet};
1380         unlink($filename);
1381     }
1382
1383     my ($old_gen, $old_md5, $old_ver, $old_ts, $old_custom)
1384         = $self->_parse_generated_file($filename);
1385
1386     if (! $old_gen && -f $filename) {
1387         croak "Cannot overwrite '$filename' without 'really_erase_my_files',"
1388             . " it does not appear to have been generated by Loader"
1389     }
1390
1391     my $custom_content = $old_custom || '';
1392
1393     # prepend extra custom content from a *renamed* class (singularization effect)
1394     if (my $renamed_class = $self->_upgrading_classes->{$class}) {
1395         my $old_filename = $self->_get_dump_filename($renamed_class);
1396
1397         if (-f $old_filename) {
1398             my $extra_custom = ($self->_parse_generated_file ($old_filename))[4];
1399
1400             $extra_custom =~ s/\n\n# You can replace.*\n1;\n//;
1401
1402             $custom_content = join ("\n", '', $extra_custom, $custom_content)
1403                 if $extra_custom;
1404
1405             unlink $old_filename;
1406         }
1407     }
1408
1409     $custom_content ||= $self->_default_custom_content($is_schema);
1410
1411     # If upgrading to use_moose=1 replace default custom content with default Moose custom content.
1412     # If there is already custom content, which does not have the Moose content, add it.
1413     if ($self->use_moose) {
1414
1415         my $non_moose_custom_content = do {
1416             local $self->{use_moose} = 0;
1417             $self->_default_custom_content;
1418         };
1419
1420         if ($custom_content eq $non_moose_custom_content) {
1421             $custom_content = $self->_default_custom_content($is_schema);
1422         }
1423         elsif ($custom_content !~ /\Q@{[$self->_default_moose_custom_content($is_schema)]}\E/) {
1424             $custom_content .= $self->_default_custom_content($is_schema);
1425         }
1426     }
1427     elsif (defined $self->use_moose && $old_gen) {
1428         croak 'It is not possible to "downgrade" a schema that was loaded with use_moose => 1 to use_moose => 0, due to differing custom content'
1429             if $old_gen =~ /use \s+ MooseX?\b/x;
1430     }
1431
1432     $custom_content = $self->_rewrite_old_classnames($custom_content);
1433
1434     $text .= qq|$_\n|
1435         for @{$self->{_dump_storage}->{$class} || []};
1436
1437     # Check and see if the dump is infact differnt
1438
1439     my $compare_to;
1440     if ($old_md5) {
1441       $compare_to = $text . $self->_sig_comment($old_ver, $old_ts);
1442       if (Digest::MD5::md5_base64($compare_to) eq $old_md5) {
1443         return unless $self->_upgrading_from && $is_schema;
1444       }
1445     }
1446
1447     $text .= $self->_sig_comment(
1448       $self->version_to_dump,
1449       POSIX::strftime('%Y-%m-%d %H:%M:%S', localtime)
1450     );
1451
1452     open(my $fh, '>', $filename)
1453         or croak "Cannot open '$filename' for writing: $!";
1454
1455     # Write the top half and its MD5 sum
1456     print $fh $text . Digest::MD5::md5_base64($text) . "\n";
1457
1458     # Write out anything loaded via external partial class file in @INC
1459     print $fh qq|$_\n|
1460         for @{$self->{_ext_storage}->{$class} || []};
1461
1462     # Write out any custom content the user has added
1463     print $fh $custom_content;
1464
1465     close($fh)
1466         or croak "Error closing '$filename': $!";
1467 }
1468
1469 sub _default_moose_custom_content {
1470     my ($self, $is_schema) = @_;
1471
1472     if (not $is_schema) {
1473         return qq|\n__PACKAGE__->meta->make_immutable;|;
1474     }
1475     
1476     return qq|\n__PACKAGE__->meta->make_immutable(inline_constructor => 0);|;
1477 }
1478
1479 sub _default_custom_content {
1480     my ($self, $is_schema) = @_;
1481     my $default = qq|\n\n# You can replace this text with custom|
1482          . qq| code or comments, and it will be preserved on regeneration|;
1483     if ($self->use_moose) {
1484         $default .= $self->_default_moose_custom_content($is_schema);
1485     }
1486     $default .= qq|\n1;\n|;
1487     return $default;
1488 }
1489
1490 sub _parse_generated_file {
1491     my ($self, $fn) = @_;
1492
1493     return unless -f $fn;
1494
1495     open(my $fh, '<', $fn)
1496         or croak "Cannot open '$fn' for reading: $!";
1497
1498     my $mark_re =
1499         qr{^(# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:)([A-Za-z0-9/+]{22})\n};
1500
1501     my ($md5, $ts, $ver, $gen);
1502     while(<$fh>) {
1503         if(/$mark_re/) {
1504             my $pre_md5 = $1;
1505             $md5 = $2;
1506
1507             # Pull out the version and timestamp from the line above
1508             ($ver, $ts) = $gen =~ m/^# Created by DBIx::Class::Schema::Loader v(.*?) @ (.*?)\Z/m;
1509
1510             $gen .= $pre_md5;
1511             croak "Checksum mismatch in '$fn', the auto-generated part of the file has been modified outside of this loader.  Aborting.\nIf you want to overwrite these modifications, set the 'overwrite_modifications' loader option.\n"
1512                 if !$self->overwrite_modifications && Digest::MD5::md5_base64($gen) ne $md5;
1513
1514             last;
1515         }
1516         else {
1517             $gen .= $_;
1518         }
1519     }
1520
1521     my $custom = do { local $/; <$fh> }
1522         if $md5;
1523
1524     close ($fh);
1525
1526     return ($gen, $md5, $ver, $ts, $custom);
1527 }
1528
1529 sub _use {
1530     my $self = shift;
1531     my $target = shift;
1532
1533     foreach (@_) {
1534         warn "$target: use $_;" if $self->debug;
1535         $self->_raw_stmt($target, "use $_;");
1536     }
1537 }
1538
1539 sub _inject {
1540     my $self = shift;
1541     my $target = shift;
1542
1543     my $blist = join(q{ }, @_);
1544
1545     return unless $blist;
1546
1547     warn "$target: use base qw/$blist/;" if $self->debug;
1548     $self->_raw_stmt($target, "use base qw/$blist/;");
1549 }
1550
1551 sub _result_namespace {
1552     my ($self, $schema_class, $ns) = @_;
1553     my @result_namespace;
1554
1555     if ($ns =~ /^\+(.*)/) {
1556         # Fully qualified namespace
1557         @result_namespace = ($1)
1558     }
1559     else {
1560         # Relative namespace
1561         @result_namespace = ($schema_class, $ns);
1562     }
1563
1564     return wantarray ? @result_namespace : join '::', @result_namespace;
1565 }
1566
1567 # Create class with applicable bases, setup monikers, etc
1568 sub _make_src_class {
1569     my ($self, $table) = @_;
1570
1571     my $schema       = $self->schema;
1572     my $schema_class = $self->schema_class;
1573
1574     my $table_moniker = $self->_table2moniker($table);
1575     my @result_namespace = ($schema_class);
1576     if ($self->use_namespaces) {
1577         my $result_namespace = $self->result_namespace || 'Result';
1578         @result_namespace = $self->_result_namespace(
1579             $schema_class,
1580             $result_namespace,
1581         );
1582     }
1583     my $table_class = join(q{::}, @result_namespace, $table_moniker);
1584
1585     if ((my $upgrading_v = $self->_upgrading_from)
1586             || $self->_rewriting) {
1587         local $self->naming->{monikers} = $upgrading_v
1588             if $upgrading_v;
1589
1590         my @result_namespace = @result_namespace;
1591         if ($self->_upgrading_from_load_classes) {
1592             @result_namespace = ($schema_class);
1593         }
1594         elsif (my $ns = $self->_downgrading_to_load_classes) {
1595             @result_namespace = $self->_result_namespace(
1596                 $schema_class,
1597                 $ns,
1598             );
1599         }
1600         elsif ($ns = $self->_rewriting_result_namespace) {
1601             @result_namespace = $self->_result_namespace(
1602                 $schema_class,
1603                 $ns,
1604             );
1605         }
1606
1607         my $old_class = join(q{::}, @result_namespace,
1608             $self->_table2moniker($table));
1609
1610         $self->_upgrading_classes->{$table_class} = $old_class
1611             unless $table_class eq $old_class;
1612     }
1613
1614 # this was a bad idea, should be ok now without it
1615 #    my $table_normalized = lc $table;
1616 #    $self->classes->{$table_normalized} = $table_class;
1617 #    $self->monikers->{$table_normalized} = $table_moniker;
1618
1619     $self->classes->{$table} = $table_class;
1620     $self->monikers->{$table} = $table_moniker;
1621
1622     $self->_use   ($table_class, @{$self->additional_classes});
1623     $self->_inject($table_class, @{$self->left_base_classes});
1624
1625     my @components = @{ $self->components || [] };
1626
1627     push @components, @{ $self->result_component_map->{$table_moniker} }
1628         if exists $self->result_component_map->{$table_moniker};
1629
1630     $self->_dbic_stmt($table_class, 'load_components', @components) if @components;
1631
1632     $self->_inject($table_class, @{$self->additional_base_classes});
1633 }
1634
1635 sub _is_result_class_method {
1636     my ($self, $name, $table_name) = @_;
1637
1638     my $table_moniker = $table_name ? $self->_table2moniker($table_name) : '';
1639
1640     if (not $self->_result_class_methods) {
1641         my (@methods, %methods);
1642         my $base       = $self->result_base_class || 'DBIx::Class::Core';
1643
1644         my @components = @{ $self->components || [] };
1645
1646         push @components, @{ $self->result_component_map->{$table_moniker} }
1647             if exists $self->result_component_map->{$table_moniker};
1648
1649         for my $c (@components) {
1650             $c = $c =~ /^\+/ ? substr($c,1) : "DBIx::Class::$c";
1651         }
1652
1653         for my $class ($base, @components, $self->use_moose ? 'Moose::Object' : ()) {
1654             load_class $class;
1655
1656             push @methods, @{ Class::Inspector->methods($class) || [] };
1657         }
1658
1659         push @methods, @{ Class::Inspector->methods('UNIVERSAL') };
1660
1661         @methods{@methods} = ();
1662
1663         $self->_result_class_methods(\%methods);
1664     }
1665     my $result_methods = $self->_result_class_methods;
1666
1667     return exists $result_methods->{$name};
1668 }
1669
1670 sub _resolve_col_accessor_collisions {
1671     my ($self, $table, $col_info) = @_;
1672
1673     my $table_name = ref $table ? $$table : $table;
1674
1675     while (my ($col, $info) = each %$col_info) {
1676         my $accessor = $info->{accessor} || $col;
1677
1678         next if $accessor eq 'id'; # special case (very common column)
1679
1680         if ($self->_is_result_class_method($accessor, $table_name)) {
1681             my $mapped = 0;
1682
1683             if (my $map = $self->col_collision_map) {
1684                 for my $re (keys %$map) {
1685                     if (my @matches = $col =~ /$re/) {
1686                         $info->{accessor} = sprintf $map->{$re}, @matches;
1687                         $mapped = 1;
1688                     }
1689                 }
1690             }
1691
1692             if (not $mapped) {
1693                 warn <<"EOF";
1694 Column '$col' in table '$table_name' collides with an inherited method.
1695 See "COLUMN ACCESSOR COLLISIONS" in perldoc DBIx::Class::Schema::Loader::Base .
1696 EOF
1697                 $info->{accessor} = undef;
1698             }
1699         }
1700     }
1701 }
1702
1703 # use the same logic to run moniker_map, col_accessor_map, and
1704 # relationship_name_map
1705 sub _run_user_map {
1706     my ( $self, $map, $default_code, $ident, @extra ) = @_;
1707
1708     my $default_ident = $default_code->( $ident, @extra );
1709     my $new_ident;
1710     if( $map && ref $map eq 'HASH' ) {
1711         $new_ident = $map->{ $ident };
1712     }
1713     elsif( $map && ref $map eq 'CODE' ) {
1714         $new_ident = $map->( $ident, $default_ident, @extra );
1715     }
1716
1717     $new_ident ||= $default_ident;
1718
1719     return $new_ident;
1720 }
1721
1722 sub _default_column_accessor_name {
1723     my ( $self, $column_name ) = @_;
1724
1725     my $accessor_name = $column_name;
1726     $accessor_name =~ s/\W+/_/g;
1727
1728     if ((($self->naming->{column_accessors}||'') =~ /(\d+)/ && $1 < 7) || (not $self->preserve_case)) {
1729         # older naming just lc'd the col accessor and that's all.
1730         return lc $accessor_name;
1731     }
1732
1733     return join '_', map lc, split_name $column_name;
1734
1735 }
1736
1737 sub _make_column_accessor_name {
1738     my ($self, $column_name, $column_context_info ) = @_;
1739
1740     my $accessor = $self->_run_user_map(
1741         $self->col_accessor_map,
1742         sub { $self->_default_column_accessor_name( shift ) },
1743         $column_name,
1744         $column_context_info,
1745        );
1746
1747     return $accessor;
1748 }
1749
1750 # Set up metadata (cols, pks, etc)
1751 sub _setup_src_meta {
1752     my ($self, $table) = @_;
1753
1754     my $schema       = $self->schema;
1755     my $schema_class = $self->schema_class;
1756
1757     my $table_class = $self->classes->{$table};
1758     my $table_moniker = $self->monikers->{$table};
1759
1760     my $table_name = $table;
1761     my $name_sep   = $self->schema->storage->sql_maker->name_sep;
1762
1763     if ($name_sep && $table_name =~ /\Q$name_sep\E/) {
1764         $table_name = \ $self->_quote_table_name($table_name);
1765     }
1766
1767     my $full_table_name = ($self->qualify_objects ? ($self->db_schema . '.') : '') . (ref $table_name ? $$table_name : $table_name);
1768
1769     # be careful to not create refs Data::Dump can "optimize"
1770     $full_table_name    = \do {"".$full_table_name} if ref $table_name;
1771
1772     $self->_dbic_stmt($table_class, 'table', $full_table_name);
1773
1774     my $cols     = $self->_table_columns($table);
1775     my $col_info = $self->__columns_info_for($table);
1776
1777     ### generate all the column accessor names
1778     while (my ($col, $info) = each %$col_info) {
1779         # hashref of other info that could be used by
1780         # user-defined accessor map functions
1781         my $context = {
1782             table_class     => $table_class,
1783             table_moniker   => $table_moniker,
1784             table_name      => $table_name,
1785             full_table_name => $full_table_name,
1786             schema_class    => $schema_class,
1787             column_info     => $info,
1788         };
1789
1790         $info->{accessor} = $self->_make_column_accessor_name( $col, $context );
1791     }
1792
1793     $self->_resolve_col_accessor_collisions($full_table_name, $col_info);
1794
1795     # prune any redundant accessor names
1796     while (my ($col, $info) = each %$col_info) {
1797         no warnings 'uninitialized';
1798         delete $info->{accessor} if $info->{accessor} eq $col;
1799     }
1800
1801     my $fks = $self->_table_fk_info($table);
1802
1803     foreach my $fkdef (@$fks) {
1804         for my $col (@{ $fkdef->{local_columns} }) {
1805             $col_info->{$col}{is_foreign_key} = 1;
1806         }
1807     }
1808
1809     my $pks = $self->_table_pk_info($table) || [];
1810
1811     foreach my $pkcol (@$pks) {
1812         $col_info->{$pkcol}{is_nullable} = 0;
1813     }
1814
1815     $self->_dbic_stmt(
1816         $table_class,
1817         'add_columns',
1818         map { $_, ($col_info->{$_}||{}) } @$cols
1819     );
1820
1821     my %uniq_tag; # used to eliminate duplicate uniqs
1822
1823     @$pks ? $self->_dbic_stmt($table_class,'set_primary_key',@$pks)
1824           : carp("$table has no primary key");
1825     $uniq_tag{ join("\0", @$pks) }++ if @$pks; # pk is a uniq
1826
1827     my $uniqs = $self->_table_uniq_info($table) || [];
1828     for (@$uniqs) {
1829         my ($name, $cols) = @$_;
1830         next if $uniq_tag{ join("\0", @$cols) }++; # skip duplicates
1831         $self->_dbic_stmt($table_class,'add_unique_constraint', $name, $cols);
1832     }
1833
1834 }
1835
1836 sub __columns_info_for {
1837     my ($self, $table) = @_;
1838
1839     my $result = $self->_columns_info_for($table);
1840
1841     while (my ($col, $info) = each %$result) {
1842         $info = { %$info, %{ $self->_custom_column_info  ($table, $col, $info) } };
1843         $info = { %$info, %{ $self->_datetime_column_info($table, $col, $info) } };
1844
1845         $result->{$col} = $info;
1846     }
1847
1848     return $result;
1849 }
1850
1851 =head2 tables
1852
1853 Returns a sorted list of loaded tables, using the original database table
1854 names.
1855
1856 =cut
1857
1858 sub tables {
1859     my $self = shift;
1860
1861     return keys %{$self->_tables};
1862 }
1863
1864 # Make a moniker from a table
1865 sub _default_table2moniker {
1866     no warnings 'uninitialized';
1867     my ($self, $table) = @_;
1868
1869     if ($self->naming->{monikers} eq 'v4') {
1870         return join '', map ucfirst, split /[\W_]+/, lc $table;
1871     }
1872     elsif ($self->naming->{monikers} eq 'v5') {
1873         return join '', map ucfirst, split /[\W_]+/,
1874             Lingua::EN::Inflect::Number::to_S(lc $table);
1875     }
1876     elsif ($self->naming->{monikers} eq 'v6') {
1877         (my $as_phrase = lc $table) =~ s/_+/ /g;
1878         my $inflected = Lingua::EN::Inflect::Phrase::to_S($as_phrase);
1879
1880         return join '', map ucfirst, split /\W+/, $inflected;
1881     }
1882
1883     my @words = map lc, split_name $table;
1884     my $as_phrase = join ' ', @words;
1885
1886     my $inflected = Lingua::EN::Inflect::Phrase::to_S($as_phrase);
1887
1888     return join '', map ucfirst, split /\W+/, $inflected;
1889 }
1890
1891 sub _table2moniker {
1892     my ( $self, $table ) = @_;
1893
1894     $self->_run_user_map(
1895         $self->moniker_map,
1896         sub { $self->_default_table2moniker( shift ) },
1897         $table
1898        );
1899 }
1900
1901 sub _load_relationships {
1902     my ($self, $table) = @_;
1903
1904     my $tbl_fk_info = $self->_table_fk_info($table);
1905     foreach my $fkdef (@$tbl_fk_info) {
1906         $fkdef->{remote_source} =
1907             $self->monikers->{delete $fkdef->{remote_table}};
1908     }
1909     my $tbl_uniq_info = $self->_table_uniq_info($table);
1910
1911     my $local_moniker = $self->monikers->{$table};
1912     my $rel_stmts = $self->_relbuilder->generate_code($local_moniker, $tbl_fk_info, $tbl_uniq_info);
1913
1914     foreach my $src_class (sort keys %$rel_stmts) {
1915         my $src_stmts = $rel_stmts->{$src_class};
1916         foreach my $stmt (@$src_stmts) {
1917             $self->_dbic_stmt($src_class,$stmt->{method},@{$stmt->{args}});
1918         }
1919     }
1920 }
1921
1922 # Overload these in driver class:
1923
1924 # Returns an arrayref of column names
1925 sub _table_columns { croak "ABSTRACT METHOD" }
1926
1927 # Returns arrayref of pk col names
1928 sub _table_pk_info { croak "ABSTRACT METHOD" }
1929
1930 # Returns an arrayref of uniqs [ [ foo => [ col1, col2 ] ], [ bar => [ ... ] ] ]
1931 sub _table_uniq_info { croak "ABSTRACT METHOD" }
1932
1933 # Returns an arrayref of foreign key constraints, each
1934 #   being a hashref with 3 keys:
1935 #   local_columns (arrayref), remote_columns (arrayref), remote_table
1936 sub _table_fk_info { croak "ABSTRACT METHOD" }
1937
1938 # Returns an array of lower case table names
1939 sub _tables_list { croak "ABSTRACT METHOD" }
1940
1941 # Execute a constructive DBIC class method, with debug/dump_to_dir hooks.
1942 sub _dbic_stmt {
1943     my $self   = shift;
1944     my $class  = shift;
1945     my $method = shift;
1946
1947     # generate the pod for this statement, storing it with $self->_pod
1948     $self->_make_pod( $class, $method, @_ ) if $self->generate_pod;
1949
1950     my $args = dump(@_);
1951     $args = '(' . $args . ')' if @_ < 2;
1952     my $stmt = $method . $args . q{;};
1953
1954     warn qq|$class\->$stmt\n| if $self->debug;
1955     $self->_raw_stmt($class, '__PACKAGE__->' . $stmt);
1956     return;
1957 }
1958
1959 # generates the accompanying pod for a DBIC class method statement,
1960 # storing it with $self->_pod
1961 sub _make_pod {
1962     my $self   = shift;
1963     my $class  = shift;
1964     my $method = shift;
1965
1966     if ( $method eq 'table' ) {
1967         my ($table) = @_;
1968         my $pcm = $self->pod_comment_mode;
1969         my ($comment, $comment_overflows, $comment_in_name, $comment_in_desc);
1970         $comment = $self->__table_comment($table);
1971         $comment_overflows = ($comment and length $comment > $self->pod_comment_spillover_length);
1972         $comment_in_name   = ($pcm eq 'name' or ($pcm eq 'auto' and !$comment_overflows));
1973         $comment_in_desc   = ($pcm eq 'description' or ($pcm eq 'auto' and $comment_overflows));
1974         $self->_pod( $class, "=head1 NAME" );
1975         my $table_descr = $class;
1976         $table_descr .= " - " . $comment if $comment and $comment_in_name;
1977         $self->{_class2table}{ $class } = $table;
1978         $self->_pod( $class, $table_descr );
1979         if ($comment and $comment_in_desc) {
1980             $self->_pod( $class, "=head1 DESCRIPTION" );
1981             $self->_pod( $class, $comment );
1982         }
1983         $self->_pod_cut( $class );
1984     } elsif ( $method eq 'add_columns' ) {
1985         $self->_pod( $class, "=head1 ACCESSORS" );
1986         my $col_counter = 0;
1987         my @cols = @_;
1988         while( my ($name,$attrs) = splice @cols,0,2 ) {
1989             $col_counter++;
1990             $self->_pod( $class, '=head2 ' . $name  );
1991             $self->_pod( $class,
1992                 join "\n", map {
1993                     my $s = $attrs->{$_};
1994                     $s = !defined $s          ? 'undef'             :
1995                         length($s) == 0       ? '(empty string)'    :
1996                         ref($s) eq 'SCALAR'   ? $$s                 :
1997                         ref($s)               ? dumper_squashed $s  :
1998                         looks_like_number($s) ? $s                  : qq{'$s'};
1999
2000                     "  $_: $s"
2001                  } sort keys %$attrs,
2002             );
2003             if (my $comment = $self->__column_comment($self->{_class2table}{$class}, $col_counter, $name)) {
2004                 $self->_pod( $class, $comment );
2005             }
2006         }
2007         $self->_pod_cut( $class );
2008     } elsif ( $method =~ /^(belongs_to|has_many|might_have)$/ ) {
2009         $self->_pod( $class, "=head1 RELATIONS" ) unless $self->{_relations_started} { $class } ;
2010         my ( $accessor, $rel_class ) = @_;
2011         $self->_pod( $class, "=head2 $accessor" );
2012         $self->_pod( $class, 'Type: ' . $method );
2013         $self->_pod( $class, "Related object: L<$rel_class>" );
2014         $self->_pod_cut( $class );
2015         $self->{_relations_started} { $class } = 1;
2016     }
2017 }
2018
2019 sub _filter_comment {
2020     my ($self, $txt) = @_;
2021
2022     $txt = '' if not defined $txt;
2023
2024     $txt =~ s/(?:\015?\012|\015\012?)/\n/g;
2025
2026     return $txt;
2027 }
2028
2029 sub __table_comment {
2030     my $self = shift;
2031
2032     if (my $code = $self->can('_table_comment')) {
2033         return $self->_filter_comment($self->$code(@_));
2034     }
2035     
2036     return '';
2037 }
2038
2039 sub __column_comment {
2040     my $self = shift;
2041
2042     if (my $code = $self->can('_column_comment')) {
2043         return $self->_filter_comment($self->$code(@_));
2044     }
2045
2046     return '';
2047 }
2048
2049 # Stores a POD documentation
2050 sub _pod {
2051     my ($self, $class, $stmt) = @_;
2052     $self->_raw_stmt( $class, "\n" . $stmt  );
2053 }
2054
2055 sub _pod_cut {
2056     my ($self, $class ) = @_;
2057     $self->_raw_stmt( $class, "\n=cut\n" );
2058 }
2059
2060 # Store a raw source line for a class (for dumping purposes)
2061 sub _raw_stmt {
2062     my ($self, $class, $stmt) = @_;
2063     push(@{$self->{_dump_storage}->{$class}}, $stmt);
2064 }
2065
2066 # Like above, but separately for the externally loaded stuff
2067 sub _ext_stmt {
2068     my ($self, $class, $stmt) = @_;
2069     push(@{$self->{_ext_storage}->{$class}}, $stmt);
2070 }
2071
2072 sub _quote_table_name {
2073     my ($self, $table) = @_;
2074
2075     my $qt = $self->schema->storage->sql_maker->quote_char;
2076
2077     return $table unless $qt;
2078
2079     if (ref $qt) {
2080         return $qt->[0] . $table . $qt->[1];
2081     }
2082
2083     return $qt . $table . $qt;
2084 }
2085
2086 sub _custom_column_info {
2087     my ( $self, $table_name, $column_name, $column_info ) = @_;
2088
2089     if (my $code = $self->custom_column_info) {
2090         return $code->($table_name, $column_name, $column_info) || {};
2091     }
2092     return {};
2093 }
2094
2095 sub _datetime_column_info {
2096     my ( $self, $table_name, $column_name, $column_info ) = @_;
2097     my $result = {};
2098     my $type = $column_info->{data_type} || '';
2099     if ((grep $_, @{ $column_info }{map "inflate_$_", qw/date datetime timestamp/})
2100             or ($type =~ /date|timestamp/i)) {
2101         $result->{timezone} = $self->datetime_timezone if $self->datetime_timezone;
2102         $result->{locale}   = $self->datetime_locale   if $self->datetime_locale;
2103     }
2104     return $result;
2105 }
2106
2107 sub _lc {
2108     my ($self, $name) = @_;
2109
2110     return $self->preserve_case ? $name : lc($name);
2111 }
2112
2113 sub _uc {
2114     my ($self, $name) = @_;
2115
2116     return $self->preserve_case ? $name : uc($name);
2117 }
2118
2119 sub _unregister_source_for_table {
2120     my ($self, $table) = @_;
2121
2122     try {
2123         local $@;
2124         my $schema = $self->schema;
2125         # in older DBIC it's a private method
2126         my $unregister = $schema->can('unregister_source') || $schema->can('_unregister_source');
2127         $schema->$unregister($self->_table2moniker($table));
2128         delete $self->monikers->{$table};
2129         delete $self->classes->{$table};
2130         delete $self->_upgrading_classes->{$table};
2131         delete $self->{_tables}{$table};
2132     };
2133 }
2134
2135 # remove the dump dir from @INC on destruction
2136 sub DESTROY {
2137     my $self = shift;
2138
2139     @INC = grep $_ ne $self->dump_directory, @INC;
2140 }
2141
2142 =head2 monikers
2143
2144 Returns a hashref of loaded table to moniker mappings.  There will
2145 be two entries for each table, the original name and the "normalized"
2146 name, in the case that the two are different (such as databases
2147 that like uppercase table names, or preserve your original mixed-case
2148 definitions, or what-have-you).
2149
2150 =head2 classes
2151
2152 Returns a hashref of table to class mappings.  In some cases it will
2153 contain multiple entries per table for the original and normalized table
2154 names, as above in L</monikers>.
2155
2156 =head1 COLUMN ACCESSOR COLLISIONS
2157
2158 Occasionally you may have a column name that collides with a perl method, such
2159 as C<can>. In such cases, the default action is to set the C<accessor> of the
2160 column spec to C<undef>.
2161
2162 You can then name the accessor yourself by placing code such as the following
2163 below the md5:
2164
2165     __PACKAGE__->add_column('+can' => { accessor => 'my_can' });
2166
2167 Another option is to use the L</col_collision_map> option.
2168
2169 =head1 RELATIONSHIP NAME COLLISIONS
2170
2171 In very rare cases, you may get a collision between a generated relationship
2172 name and a method in your Result class, for example if you have a foreign key
2173 called C<belongs_to>.
2174
2175 This is a problem because relationship names are also relationship accessor
2176 methods in L<DBIx::Class>.
2177
2178 The default behavior is to append C<_rel> to the relationship name and print
2179 out a warning that refers to this text.
2180
2181 You can also control the renaming with the L</rel_collision_map> option.
2182
2183 =head1 SEE ALSO
2184
2185 L<DBIx::Class::Schema::Loader>
2186
2187 =head1 AUTHOR
2188
2189 See L<DBIx::Class::Schema::Loader/AUTHOR> and L<DBIx::Class::Schema::Loader/CONTRIBUTORS>.
2190
2191 =head1 LICENSE
2192
2193 This library is free software; you can redistribute it and/or modify it under
2194 the same terms as Perl itself.
2195
2196 =cut
2197
2198 1;
2199 # vim:et sts=4 sw=4 tw=0: