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