X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FCatalyst%2FPlugin%2FConfigLoader.pm;h=ab332da99ba3f35a81a5e6ac3567f278758273ba;hb=b773e0786fdcf35af131fc795b2df4fcc85e4e8b;hp=d4092cb51e0c294426482073a876168ded6ecc61;hpb=c7413665fa4fdabbd3d0e796070ef2f218eef333;p=catagits%2FCatalyst-Plugin-ConfigLoader.git diff --git a/lib/Catalyst/Plugin/ConfigLoader.pm b/lib/Catalyst/Plugin/ConfigLoader.pm index d4092cb..ab332da 100644 --- a/lib/Catalyst/Plugin/ConfigLoader.pm +++ b/lib/Catalyst/Plugin/ConfigLoader.pm @@ -4,12 +4,10 @@ use strict; use warnings; use NEXT; -use Module::Pluggable::Fast - name => '_config_loaders', - search => [ __PACKAGE__ ], - require => 1; +use Module::Pluggable::Object (); +use Data::Visitor::Callback; -our $VERSION = '0.02'; +our $VERSION = '0.12'; =head1 NAME @@ -19,36 +17,45 @@ Catalyst::Plugin::ConfigLoader - Load config files of various types package MyApp; - use Catalyst( ConfigLoader ); - + # 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' ); - + __PACKAGE__->config( file => 'config.yaml' ); =head1 DESCRIPTION -This mdoule will attempt to load find and load a configuration +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 set the C section once a file has been -successfully loaded. +attempt to use each plugin and, once a file has been successfully +loaded, set the C section. =cut sub setup { - my $c = shift; - my $path = $c->config->{ file } || $c->path_to( Catalyst::Utils::appprefix( ref $c || $c ) ); + my $c = shift; + my( $path, $extension ) = $c->get_config_path; + my $suffix = $c->get_config_local_suffix; - my( $extension ) = ( $path =~ /\.(.{1,4})$/ ); - - for my $loader ( $c->_config_loaders ) { + my $finder = Module::Pluggable::Object->new( + search_path => [ __PACKAGE__ ], + require => 1 + ); + + for my $loader ( $finder->plugins ) { my @files; my @extensions = $loader->extensions; if( $extension ) { @@ -56,22 +63,146 @@ sub setup { push @files, $path; } else { - push @files, "$path.$_" for @extensions; + @files = map { ( "$path.$_", "${path}_${suffix}.$_" ) } @extensions; } for( @files ) { next unless -f $_; my $config = $loader->load( $_ ); - if( $config ) { - $c->config( $config ); - last; - } + + $c->log->debug( qq(Loaded Config "$_") ) if $c->debug; + + next if !$config; + + _fix_syntax( $config ); + + $c->config( $config ); } } + $c->finalize_config; + $c->NEXT::setup( @_ ); } +=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-Epath_to('')> ). +You can also use C<__path_to(foo/bar)__> which translates to +C<$c-Epath_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 ); +} + +=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-Econfig-E{ file }> + +=item * C<$c-Epath_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, 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-Econfig-E{ 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 }; + } + } +} + =head1 AUTHOR =over 4 @@ -80,6 +211,17 @@ sub setup { =back +=head1 CONTRIBUTORS + +The following people have generously donated their time to the +development of this module: + +=over 4 + +=item * David Kamholz Edkamholz@cpan.orgE + +=back + =head1 COPYRIGHT AND LICENSE Copyright 2006 by Brian Cassidy @@ -97,4 +239,4 @@ it under the same terms as Perl itself. =cut -1; \ No newline at end of file +1;