use warnings;\r
\r
use NEXT;\r
-use Module::Pluggable::Fast\r
- name => '_config_loaders',\r
- search => [ __PACKAGE__ ],\r
- require => 1;\r
+use Module::Pluggable::Object ();\r
use Data::Visitor::Callback;\r
\r
-our $VERSION = '0.04';\r
+our $VERSION = '0.12';\r
\r
=head1 NAME\r
\r
# ConfigLoader should be first in your list so\r
# other plugins can get the config information\r
use Catalyst qw( ConfigLoader ... );\r
- \r
+ \r
# by default myapp.* will be loaded\r
# you can specify a file if you'd like\r
- __PACKAGE__->config( file = > 'config.yaml' ); \r
+ __PACKAGE__->config( file => 'config.yaml' ); \r
\r
=head1 DESCRIPTION\r
\r
-This mdoule will attempt to load find and load a configuration\r
+This module will attempt to load find and load a configuration\r
file of various types. Currently it supports YAML, JSON, XML,\r
INI and Perl formats.\r
\r
+To support the distinction between development and production environments,\r
+this module will also attemp to load a local config (e.g. myapp_local.yaml)\r
+which will override any duplicate settings.\r
+\r
=head1 METHODS\r
\r
=head2 setup( )\r
\r
This method is automatically called by Catalyst's setup routine. It will\r
attempt to use each plugin and, once a file has been successfully\r
-loaded, set the C<config()> section.\r
+loaded, set the C<config()> section. \r
\r
=cut\r
\r
sub setup {\r
- my $c = shift;\r
- my $path = $c->config->{ file } || $c->path_to( Catalyst::Utils::appprefix( ref $c || $c ) );\r
+ my $c = shift;\r
+ my( $path, $extension ) = $c->get_config_path;\r
+ my $suffix = $c->get_config_local_suffix;\r
\r
- my( $extension ) = ( $path =~ /\.(.{1,4})$/ );\r
- \r
- for my $loader ( $c->_config_loaders ) {\r
+ my $finder = Module::Pluggable::Object->new(\r
+ search_path => [ __PACKAGE__ ],\r
+ require => 1\r
+ );\r
+\r
+ for my $loader ( $finder->plugins ) {\r
my @files;\r
my @extensions = $loader->extensions;\r
if( $extension ) {\r
push @files, $path;\r
}\r
else {\r
- push @files, "$path.$_" for @extensions;\r
+ @files = map { ( "$path.$_", "${path}_${suffix}.$_" ) } @extensions;\r
}\r
\r
for( @files ) {\r
next unless -f $_;\r
my $config = $loader->load( $_ );\r
- if( $config ) {\r
- $c->config( $config );\r
- last;\r
- }\r
+\r
+ $c->log->debug( qq(Loaded Config "$_") ) if $c->debug;\r
+ \r
+ next if !$config;\r
+\r
+ _fix_syntax( $config );\r
+ \r
+ $c->config( $config );\r
}\r
}\r
\r
plugins, it's important to load ConfigLoader before them.\r
ConfigLoader provides a default finalize_config method which\r
walks through the loaded config hash and replaces any strings\r
-beginning with C<< __HOME__/<path> >> with the full path to\r
-the file inside the app's home directory.\r
+beginning containing C<__HOME__> with the full path to\r
+app's home directory (i.e. C<$c-E<gt>path_to('')> ).\r
+You can also use C<__path_to(foo/bar)__> which translates to\r
+C<$c-E<gt>path_to('foo', 'bar')> \r
\r
=cut\r
\r
sub finalize_config {\r
my $c = shift;\r
my $v = Data::Visitor::Callback->new(\r
- plain_value => sub { s[^__HOME__/(.+)$][ $c->path_to($1) ]e }\r
+ plain_value => sub {\r
+ return unless defined $_;\r
+ s{__HOME__}{ $c->path_to( '' ) }e;\r
+ s{__path_to\((.+)\)__}{ $c->path_to( split( '/', $1 ) ) }e;\r
+ }\r
);\r
$v->visit( $c->config );\r
}\r
\r
+=head2 get_config_path\r
+\r
+This method determines the path, filename prefix and file extension to be used\r
+for config loading. It returns the path (up to the filename less the\r
+extension) to check and the specific extension to use (if it was specified).\r
+\r
+The order of preference is specified as:\r
+\r
+=over 4\r
+\r
+=item * C<$ENV{ MYAPP_CONFIG }>\r
+\r
+=item * C<$c-E<gt>config-E<gt>{ file }>\r
+\r
+=item * C<$c-E<gt>path_to( $application_prefix )>\r
+\r
+=back\r
+\r
+If either of the first two user-specified options are directories, the\r
+application prefix will be added on to the end of the path.\r
+\r
+=cut\r
+\r
+sub get_config_path {\r
+ my $c = shift;\r
+ my $appname = ref $c || $c;\r
+ my $prefix = Catalyst::Utils::appprefix( $appname );\r
+ my $path = $ENV{ Catalyst::Utils::class2env( $appname ) . '_CONFIG' }\r
+ || $c->config->{ file }\r
+ || $c->path_to( $prefix );\r
+\r
+ my( $extension ) = ( $path =~ m{\.(.{1,4})$} );\r
+ \r
+ if( -d $path ) {\r
+ $path =~ s{[\/\\]$}{};\r
+ $path .= "/$prefix";\r
+ }\r
+ \r
+ return( $path, $extension );\r
+}\r
+\r
+=head2 get_config_local_suffix\r
+\r
+Determines the suffix of files used to override the main config. By default\r
+this value is C<local>, but it can be specified in the following order of preference:\r
+\r
+=over 4\r
+\r
+=item * C<$ENV{ CATALYST_CONFIG_LOCAL_SUFFIX }>\r
+\r
+=item * C<$ENV{ MYAPP_CONFIG_LOCAL_SUFFIX }>\r
+\r
+=item * C<$c-E<gt>config-E<gt>{ config_local_suffix }>\r
+\r
+\r
+=back\r
+\r
+=cut\r
+\r
+sub get_config_local_suffix {\r
+ my $c = shift;\r
+ my $appname = ref $c || $c;\r
+ my $suffix = $ENV{ CATALYST_CONFIG_LOCAL_SUFFIX }\r
+ || $ENV{ Catalyst::Utils::class2env( $appname ) . '_CONFIG_LOCAL_SUFFIX' }\r
+ || $c->config->{ config_local_suffix }\r
+ || 'local';\r
+\r
+ return $suffix;\r
+}\r
+\r
+sub _fix_syntax {\r
+ my $config = shift;\r
+ my @components = (\r
+ map +{\r
+ prefix => $_ eq 'Component' ? '' : $_ . '::',\r
+ values => delete $config->{ lc $_ } || delete $config->{ $_ }\r
+ },\r
+ grep {\r
+ ref $config->{ lc $_ } || ref $config->{ $_ }\r
+ }\r
+ qw( Component Model M View V Controller C )\r
+ );\r
+\r
+ foreach my $comp ( @components ) {\r
+ my $prefix = $comp->{ prefix };\r
+ foreach my $element ( keys %{ $comp->{ values } } ) {\r
+ $config->{ "$prefix$element" } = $comp->{ values }->{ $element };\r
+ }\r
+ }\r
+}\r
+\r
=head1 AUTHOR\r
\r
=over 4 \r
\r
=back\r
\r
+=head1 CONTRIBUTORS\r
+\r
+The following people have generously donated their time to the\r
+development of this module:\r
+\r
+=over 4\r
+\r
+=item * David Kamholz E<lt>dkamholz@cpan.orgE<gt>\r
+\r
+=back\r
+\r
=head1 COPYRIGHT AND LICENSE\r
\r
Copyright 2006 by Brian Cassidy\r
\r
=cut\r
\r
-1;
\ No newline at end of file
+1;\r