-package Catalyst::Plugin::ConfigLoader;\r
-\r
-use strict;\r
-use warnings;\r
-\r
-use NEXT;\r
-use Module::Pluggable::Fast\r
- name => '_config_loaders',\r
- search => [ __PACKAGE__ ],\r
- require => 1;\r
-use Data::Visitor::Callback;\r
-\r
-our $VERSION = '0.08';\r
-\r
-=head1 NAME\r
-\r
-Catalyst::Plugin::ConfigLoader - Load config files of various types\r
-\r
-=head1 SYNOPSIS\r
-\r
- package MyApp;\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
- # by default myapp.* will be loaded\r
- # you can specify a file if you'd like\r
- __PACKAGE__->config( file => 'config.yaml' ); \r
-\r
-=head1 DESCRIPTION\r
-\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
-\r
-=cut\r
-\r
-sub setup {\r
- my $c = shift;\r
- my( $path, $extension ) = $c->get_config_path;\r
- \r
- for my $loader ( $c->_config_loaders ) {\r
- my @files;\r
- my @extensions = $loader->extensions;\r
- if( $extension ) {\r
- next unless grep { $_ eq $extension } @extensions;\r
- push @files, $path;\r
- }\r
- else {\r
- @files = map { ( "$path.$_", "${path}_local.$_" ) } @extensions;\r
- }\r
-\r
- for( @files ) {\r
- next unless -f $_;\r
- my $config = $loader->load( $_ );\r
-\r
- $c->debug( "Loaded Config $_" ) if $c->debug;\r
- _fix_syntax( $config );\r
- $c->config( $config ) if $config;\r
- }\r
- }\r
-\r
- $c->finalize_config;\r
-\r
- $c->NEXT::setup( @_ );\r
-}\r
-\r
-=head2 finalize_config\r
-\r
-This method is called after the config file is loaded. It can be\r
-used to implement tuning of config values that can only be done\r
-at runtime. If you need to do this to properly configure any\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 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 {\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->config->{ file }>\r
-\r
-=item * C<$c->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 =~ /\.(.{1,4})$/ );\r
- \r
- if( -d $path ) {\r
- $path =~ s/[\/\\]$//;\r
- $path .= "/$prefix";\r
- }\r
- \r
- return( $path, $extension );\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
- }, qw( Component Model View Controller )\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
-=item * Brian Cassidy E<lt>bricas@cpan.orgE<gt>\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
-This library is free software; you can redistribute it and/or modify\r
-it under the same terms as Perl itself. \r
-\r
-=head1 SEE ALSO\r
-\r
-=over 4 \r
-\r
-=item * L<Catalyst>\r
-\r
-=back\r
-\r
-=cut\r
-\r
-1;\r
+package Catalyst::Plugin::ConfigLoader;
+
+use strict;
+use warnings;
+use Config::Any;
+use NEXT;
+use Data::Visitor::Callback;
+our $VERSION = '0.13';
+
+=head1 NAME
+
+Catalyst::Plugin::ConfigLoader - Load config files of various types
+
+=head1 SYNOPSIS
+
+ package MyApp;
+
+ # ConfigLoader should be first in your list so
+ # other plugins can get the config information
+ use Catalyst qw( ConfigLoader ... );
+
+ # by default myapp.* will be loaded
+ # you can specify a file if you'd like
+ __PACKAGE__->config( file => 'config.yaml' );
+
+=head1 DESCRIPTION
+
+This module will attempt to load find and load a configuration
+file of various types. Currently it supports YAML, JSON, XML,
+INI and Perl formats.
+
+To support the distinction between development and production environments,
+this module will also attemp to load a local config (e.g. myapp_local.yaml)
+which will override any duplicate settings.
+
+=head1 METHODS
+
+=head2 setup( )
+
+This method is automatically called by Catalyst's setup routine. It will
+attempt to use each plugin and, once a file has been successfully
+loaded, set the C<config()> section.
+
+=cut
+
+sub setup {
+ my $c = shift;
+
+ my @files = $c->find_files;
+ my $cfg = Config::Any->load_stems({stems => \@files, filter => \&_fix_syntax});
+
+ for my $ref (@$cfg) {
+ my ($file, $config) = each %$ref;
+ $c->config($config);
+ $c->log->debug( qq(Loaded Config "$file") )
+ if $c->debug;
+ }
+
+ $c->finalize_config;
+ $c->NEXT::setup( @_ );
+}
+
+=head2 find_files
+
+This method determines the potential file paths to be used for config loading.
+It returns an array of paths (up to the filename less the extension) to pass to
+L<Config::Any|Config::Any> for loading.
+
+=cut
+
+sub find_files {
+ my $c = shift;
+ my ($path, $extension) = $c->get_config_path;
+ my $suffix = $c->get_config_local_suffix;
+ my @extensions = @{ Config::Any->extensions };
+
+ my @files;
+ if ($extension) {
+ next unless grep { $_ eq $extension } @extensions;
+ push @files, $path;
+ } else {
+ @files = map { ( "$path.$_", "${path}_${suffix}.$_" ) } @extensions;
+ }
+ @files;
+}
+
+=head2 get_config_path
+
+This method determines the path, filename prefix and file extension to be used
+for config loading. It returns the path (up to the filename less the
+extension) to check and the specific extension to use (if it was specified).
+
+The order of preference is specified as:
+
+=over 4
+
+=item * C<$ENV{ MYAPP_CONFIG }>
+
+=item * C<$c-E<gt>config-E<gt>{ file }>
+
+=item * C<$c-E<gt>path_to( $application_prefix )>
+
+=back
+
+If either of the first two user-specified options are directories, the
+application prefix will be added on to the end of the path.
+
+=cut
+
+sub get_config_path {
+ my $c = shift;
+ my $appname = ref $c || $c;
+ my $prefix = Catalyst::Utils::appprefix( $appname );
+ my $path = $ENV{ Catalyst::Utils::class2env( $appname ) . '_CONFIG' }
+ || $c->config->{ file }
+ || $c->path_to( $prefix );
+
+ my( $extension ) = ( $path =~ m{\.(.{1,4})$} );
+
+ if( -d $path ) {
+ $path =~ s{[\/\\]$}{};
+ $path .= "/$prefix";
+ }
+
+ return( $path, $extension );
+}
+
+=head2 get_config_local_suffix
+
+Determines the suffix of files used to override the main config. By default
+this value is C<local>, but it can be specified in the following order of preference:
+
+=over 4
+
+=item * C<$ENV{ CATALYST_CONFIG_LOCAL_SUFFIX }>
+
+=item * C<$ENV{ MYAPP_CONFIG_LOCAL_SUFFIX }>
+
+=item * C<$c-E<gt>config-E<gt>{ config_local_suffix }>
+
+
+=back
+
+=cut
+
+sub get_config_local_suffix {
+ my $c = shift;
+ my $appname = ref $c || $c;
+ my $suffix = $ENV{ CATALYST_CONFIG_LOCAL_SUFFIX }
+ || $ENV{ Catalyst::Utils::class2env( $appname ) . '_CONFIG_LOCAL_SUFFIX' }
+ || $c->config->{ config_local_suffix }
+ || 'local';
+
+ return $suffix;
+}
+
+sub _fix_syntax {
+ my $config = shift;
+ my @components = (
+ map +{
+ prefix => $_ eq 'Component' ? '' : $_ . '::',
+ values => delete $config->{ lc $_ } || delete $config->{ $_ }
+ },
+ grep {
+ ref $config->{ lc $_ } || ref $config->{ $_ }
+ }
+ qw( Component Model M View V Controller C )
+ );
+
+ foreach my $comp ( @components ) {
+ my $prefix = $comp->{ prefix };
+ foreach my $element ( keys %{ $comp->{ values } } ) {
+ $config->{ "$prefix$element" } = $comp->{ values }->{ $element };
+ }
+ }
+}
+
+=head2 finalize_config
+
+This method is called after the config file is loaded. It can be
+used to implement tuning of config values that can only be done
+at runtime. If you need to do this to properly configure any
+plugins, it's important to load ConfigLoader before them.
+ConfigLoader provides a default finalize_config method which
+walks through the loaded config hash and replaces any strings
+beginning containing C<__HOME__> with the full path to
+app's home directory (i.e. C<$c-E<gt>path_to('')> ).
+You can also use C<__path_to(foo/bar)__> which translates to
+C<$c-E<gt>path_to('foo', 'bar')>
+
+=cut
+
+sub finalize_config {
+ my $c = shift;
+ my $v = Data::Visitor::Callback->new(
+ plain_value => sub {
+ return unless defined $_;
+ s{__HOME__}{ $c->path_to( '' ) }e;
+ s{__path_to\((.+)\)__}{ $c->path_to( split( '/', $1 ) ) }e;
+ }
+ );
+ $v->visit( $c->config );
+}
+
+1;