#!perl

use strict;
use warnings;

package Rose::DBx::MoreConfig;

use parent 'Rose::DB';

use File::Basename qw(dirname);
use File::Spec;
use Scalar::Util qw(blessed);

our ($VERSION) = '1.01';

sub auto_load_fixups {
    my ( $self, @args ) = @_;
    my $tried = 0;
    my $home  = eval {
        require File::HomeDir;
        File::HomeDir->my_home;
    }
      || $ENV{HOME}
      || $ENV{LOGDIR}
      || eval { ( getpwuid($<) )[7] }
      || '__ALAS_NO_IDEA__';
    $home = File::Spec->catfile( $home, '.rosedbrc' );
    my $classpm = blessed($self);
    if ($classpm) {

       # Clear the suffix Rose::DB adds to make a generated implementation class
        $classpm =~ s[::__RoseDBPrivate__::.*\.pm$][.pm];
        $classpm =~ s[::][/]g;
        $classpm = $INC{$classpm} || $classpm;
    }
    else {
        $classpm = (caller)[1];
    }
    $classpm = File::Spec->catfile( dirname($classpm), '.rosedbrc' );

    # Hush warnings from Rose::DB::load_yaml_fixup_file() about data
    # sources the current class doesn't implement
    my $warnhook = $SIG{__WARN__};
    local $SIG{__WARN__} = sub {
        my $msg = $_[0];
        return if $msg =~ /^No \S+ data source found/;
        if ( defined $warnhook ) { return $warnhook => (@_); }
        else                     { warn @_; }
    };

    # First, give Rose::DB (or other parent) a chance to do its thing,
    # so ROSEDB_DEVINIT is handled.
    $self->SUPER::auto_load_fixups(@args);

    foreach my $cand ( '/etc/rosedbrc',
        File::Spec->catfile( dirname( $INC{'Rose/DB.pm'} ), '.rosedbrc' ),
        $home, $classpm, $ENV{ROSEDBRC} )
    {
        next unless defined($cand) && -r $cand;
        $tried++;
        $self->load_yaml_fixup_file( $cand, @args );
    }

    return $tried;
}

1;

__END__


=head1 NAME

Rose::DBx::MoreConfig - Rose::DB base class with extra configuration options

=head1 SYNOPSIS

  package My::Data::Source;
  use parent 'Rose::DBx::MoreConfig';
  ... define data sources ...
  __PACKAGE__->auto_load_fixups;
  ...

=head1 DESCRIPTION

This package provides a base class for modules defining L<Rose::DB>
data sources.  It extends L<Rose::DB> to allow more flexibility in
placement of the YAML configuration file, in order to better
accommodate packaged distributions, shared repositories, and the like.

=head2 METHOD

=over 4

=item auto_load_fixups

Because it's common to break up data sources for different and
possibly overlapping projects into several classes, it's difficult to
store credentials for each datasource using L<Rose::DB>'s default YAML
configuration scheme.  It's built around the idea of a single rc file,
but complains if that file includes fixups for data sources not known
when the current class calls C<auto_load_fixups>.  So we override the
L<Rose::DB> default behavior in two ways:

=over 4

=item *

Warnings for data found in the rc file that apply to a data source we
haven't (yet) seen are suppressed.  This allows you to use a global rc
file to supply credentials for several different classes.

=item *

Several different possibilities are checked, in order, for rc files:

=over 4

=item *

F</etc/rosedbrc>

=item *

A F<.rosedbrc> file in the same directory as F<Rose/DB.pm>

=item *

A F<.rosedbrc> file in your home directory

=item *

A F<.rosedbrc> file in the same directory as the Perl module for the
calling class.  (This assumes that the class is defined in a F<.pm>
file with the same name as the class, as is typical.)

=item *

C<$ENV{ROSEDBRC}>

=back

If more than one of these files are present, they are evaluated in the order
shown, so you can override values from "systemwide" files with
"class-local" files.

=back

=back

=head2 Implementation note

One of the goals of the "local F<.rosedbrc>" option provided here is
to facilitate the distribution of L<Rose::DB>-derived classes for a
particular set of databases as packages or in an application's local
library tree.  However, for the same reasons that you want the content
in your F<.rosedbrc> separate from the rest of your module, you will
likely not want to store a F<.rosedbrc> with user credentials in a SCM
repository that is visible by others.  Depending on your SCM system,
you may be able to exclude this file via an "ignore me" configuration
directive (e.g. a F<.gitignore> file or C<svn:ignore> property).
Othewise, you will need to keep these files outside the development
tree and include them when you build or deploy your distribution.

=head2 EXPORT

None.

=head1 DIAGNOSTICS

Any message that can be returned by an included package.  Warnings
generated by L<Rose::DB> about unrecognized data sources encountered
in a configuration file are suppressed.

=head1 BUGS AND CAVEATS

Are there, for certain, but have yet to be cataloged.  Please don't
hesitate to report any you find, using either CPAN or GitHub.

=head1 SEE ALSO

L<Rose::DB>

=head1 VERSION

version 1.01

=head1 REVISION

$Revision$ $Date$

=head1 AUTHOR

Charles Bailey <cbail@cpan.org>

=head1 COPYRIGHT AND LICENSE

Copyright (C) 2015 by Charles Bailey

This software may be used under the terms of the Artistic License or
the GNU General Public License, as the user prefers.

=head1 ACKNOWLEDGMENT

The code incorporated into this package was originally written with
United States federal funding as part of research work done by the
author at the Children's Hospital of Philadelphia.

=cut
