From: Brian Cassidy Date: Fri, 25 Aug 2006 02:22:55 +0000 (+0000) Subject: remerge into trunk X-Git-Tag: v0.13~1 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=catagits%2FCatalyst-Plugin-ConfigLoader.git;a=commitdiff_plain;h=f004a98a1b34eb8c14c5beb42aae9cc5c20e41d5 remerge into trunk --- diff --git a/Build.PL b/Build.PL index 23ead95..4b272ed 100644 --- a/Build.PL +++ b/Build.PL @@ -3,16 +3,16 @@ use strict; use Module::Build; my $build = Module::Build->new( - module_name => 'Catalyst::Plugin::ConfigLoader', - dist_author => 'Brian Cassidy ', - license => 'perl', - create_readme => 1, - create_makefile_pl => 'traditional', - requires => { - 'Catalyst::Runtime' => '0', - 'Data::Visitor' => '0.02', - 'Module::Pluggable' => '3.01' - }, + module_name => 'Catalyst::Plugin::ConfigLoader', + dist_author => 'Brian Cassidy ', + license => 'perl', + create_readme => 1, + create_makefile_pl => 'traditional', + requires => { + 'Catalyst::Runtime' => '0', + 'Data::Visitor' => '0.02', + 'Config::Any' => '0.04' + }, ); -$build->create_build_script; \ No newline at end of file +$build->create_build_script; diff --git a/Changes b/Changes index 0aaad62..ef46e9d 100644 --- a/Changes +++ b/Changes @@ -1,5 +1,9 @@ Revision history for Perl extension Catalyst::Plugin::ConfigLoader. +0.13 Fri Aug 25 2006 + - loading code factored out into Config::Any [rataxis@cpan.org] + sponsored by Portugal Telecom + 0.12 Wed Jul 12 2006 - made the "local" suffix overrideable - fixed __path_to()__ docs diff --git a/MANIFEST b/MANIFEST index 1addae9..b5c6971 100644 --- a/MANIFEST +++ b/MANIFEST @@ -1,31 +1,12 @@ Build.PL Changes lib/Catalyst/Plugin/ConfigLoader.pm -lib/Catalyst/Plugin/ConfigLoader/General.pm -lib/Catalyst/Plugin/ConfigLoader/INI.pm -lib/Catalyst/Plugin/ConfigLoader/JSON.pm -lib/Catalyst/Plugin/ConfigLoader/Perl.pm -lib/Catalyst/Plugin/ConfigLoader/XML.pm -lib/Catalyst/Plugin/ConfigLoader/YAML.pm MANIFEST -META.yml t/01-use.t t/10-live_auto.t t/20-mock_load.t -t/50-general.t -t/51-ini.t -t/52-json.t -t/53-perl.t -t/54-xml.t -t/55-yaml.t t/98-pod_coverage.t t/99-pod.t -t/conf/conf.general -t/conf/conf.ini -t/conf/conf.json -t/conf/conf.pl -t/conf/conf.xml -t/conf/conf.yml t/lib/TestApp.pm t/lib/TestApp/testapp.pl t/lib/TestApp/Controller/Config.pm diff --git a/README b/README deleted file mode 100644 index e69de29..0000000 diff --git a/lib/Catalyst/Plugin/ConfigLoader.pm b/lib/Catalyst/Plugin/ConfigLoader.pm index ab332da..99500ec 100644 --- a/lib/Catalyst/Plugin/ConfigLoader.pm +++ b/lib/Catalyst/Plugin/ConfigLoader.pm @@ -1,242 +1,286 @@ -package Catalyst::Plugin::ConfigLoader; - -use strict; -use warnings; - -use NEXT; -use Module::Pluggable::Object (); -use Data::Visitor::Callback; - -our $VERSION = '0.12'; - -=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 section. - -=cut - -sub setup { - my $c = shift; - my( $path, $extension ) = $c->get_config_path; - my $suffix = $c->get_config_local_suffix; - - my $finder = Module::Pluggable::Object->new( - search_path => [ __PACKAGE__ ], - require => 1 - ); - - for my $loader ( $finder->plugins ) { - my @files; - my @extensions = $loader->extensions; - if( $extension ) { - next unless grep { $_ eq $extension } @extensions; - push @files, $path; - } - else { - @files = map { ( "$path.$_", "${path}_${suffix}.$_" ) } @extensions; - } - - for( @files ) { - next unless -f $_; - my $config = $loader->load( $_ ); - - $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 - -=item * Brian Cassidy Ebricas@cpan.orgE - -=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 - -This library is free software; you can redistribute it and/or modify -it under the same terms as Perl itself. - -=head1 SEE ALSO - -=over 4 - -=item * L - -=back - -=cut - -1; +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 section. + +=cut + +sub setup { + my $c = shift; + my @files = $c->find_files; + my $cfg = Config::Any->load_files( { + files => \@files, + filter => \&_fix_syntax, + use_ext => 1 + } ); + + # split the responses into normal and local cfg + my $local_suffix = $c->get_config_local_suffix; + my( @cfg, @localcfg ); + for( @$cfg ) { + if( ( keys %$_ )[ 0 ] =~ m{ $local_suffix \. }xms ) { + push @localcfg, $_; + } else { + push @cfg, $_; + } + } + + # load all the normal cfgs, then the local cfgs last so they can override + # normal cfgs + $c->load_config( $_ ) for @cfg, @localcfg; + + $c->finalize_config; + $c->NEXT::setup( @_ ); +} + +=head2 load_config + +This method handles loading the configuration data into the Catalyst +context object. It does not return a value. + +=cut + +sub load_config { + my $c = shift; + my $ref = shift; + + my( $file, $config ) = each %$ref; + + $c->config( $config ); + $c->log->debug( qq(Loaded Config "$file") ) + if $c->debug; + + return; +} + +=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 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, "${path}_${suffix}"; + } 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-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 }; + } + } +} + +=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 ); +} + +=head1 AUTHOR + +=over 4 + +=item * Brian Cassidy Ebricas@cpan.orgE + +=back + +=head1 CONTRIBUTORS + +The following people have generously donated their time to the +development of this module: + +=over 4 + +=item * Joel Bernstein Erataxis@cpan.orgE - Rewrite to use L + +=item * David Kamholz Edkamholz@cpan.orgE - L integration + +=back + +Work to this module has been generously sponsored by: + +=over 4 + +=item * Portugal Telecom L - Work done by Joel Bernstein + +=back + +=head1 COPYRIGHT AND LICENSE + +Copyright 2006 by Brian Cassidy + +This library is free software; you can redistribute it and/or modify +it under the same terms as Perl itself. + +=head1 SEE ALSO + +=over 4 + +=item * L + +=item * L + +=back + +=cut + +1; diff --git a/t/01-use.t b/t/01-use.t index 322f0ef..1f67099 100644 --- a/t/01-use.t +++ b/t/01-use.t @@ -1,10 +1,5 @@ -use Test::More tests => 6; +use Test::More tests => 1; BEGIN { use_ok( 'Catalyst::Plugin::ConfigLoader' ); - use_ok( 'Catalyst::Plugin::ConfigLoader::INI' ); - use_ok( 'Catalyst::Plugin::ConfigLoader::JSON' ); - use_ok( 'Catalyst::Plugin::ConfigLoader::Perl' ); - use_ok( 'Catalyst::Plugin::ConfigLoader::XML' ); - use_ok( 'Catalyst::Plugin::ConfigLoader::YAML' ); } diff --git a/t/50-general.t b/t/50-general.t deleted file mode 100644 index c308c3f..0000000 --- a/t/50-general.t +++ /dev/null @@ -1,11 +0,0 @@ -use Test::More tests => 2; - -use Catalyst::Plugin::ConfigLoader::General; - -my $config = eval { Catalyst::Plugin::ConfigLoader::General->load( 't/conf/conf.general' ) }; - -SKIP: { - skip "Couldn't Load Config::General plugin", 2 if $@; - ok( $config ); - is( $config->{ name }, 'TestApp' ); -} diff --git a/t/51-ini.t b/t/51-ini.t deleted file mode 100644 index ad88549..0000000 --- a/t/51-ini.t +++ /dev/null @@ -1,11 +0,0 @@ -use Test::More tests => 2; - -use Catalyst::Plugin::ConfigLoader::INI; - -my $config = eval { Catalyst::Plugin::ConfigLoader::INI->load( 't/conf/conf.ini' ) }; - -SKIP: { - skip "Couldn't Load INI plugin", 2 if $@; - ok( $config ); - is( $config->{ name }, 'TestApp' ); -} \ No newline at end of file diff --git a/t/52-json.t b/t/52-json.t deleted file mode 100644 index 2481d05..0000000 --- a/t/52-json.t +++ /dev/null @@ -1,11 +0,0 @@ -use Test::More tests => 2; - -use Catalyst::Plugin::ConfigLoader::JSON; - -my $config = eval { Catalyst::Plugin::ConfigLoader::JSON->load( 't/conf/conf.json' ) }; - -SKIP: { - skip "Couldn't Load JSON plugin", 2 if $@; - ok( $config ); - is( $config->{ name }, 'TestApp' ); -} diff --git a/t/53-perl.t b/t/53-perl.t deleted file mode 100644 index e3385b0..0000000 --- a/t/53-perl.t +++ /dev/null @@ -1,11 +0,0 @@ -use Test::More tests => 2; - -use Catalyst::Plugin::ConfigLoader::Perl; - -my $config = eval { Catalyst::Plugin::ConfigLoader::Perl->load( 't/conf/conf.pl' ) }; - -SKIP: { - skip "Couldn't Load Perl plugin", 2 if $@; - ok( $config ); - is( $config->{ name }, 'TestApp' ); -} diff --git a/t/54-xml.t b/t/54-xml.t deleted file mode 100644 index 8be701b..0000000 --- a/t/54-xml.t +++ /dev/null @@ -1,11 +0,0 @@ -use Test::More tests => 2; - -use Catalyst::Plugin::ConfigLoader::XML; - -my $config = eval { Catalyst::Plugin::ConfigLoader::XML->load( 't/conf/conf.xml' ) }; - -SKIP: { - skip "Couldn't Load XML plugin", 2 if $@; - ok( $config ); - is( $config->{ name }, 'TestApp' ); -} diff --git a/t/55-yaml.t b/t/55-yaml.t deleted file mode 100644 index 630d1f9..0000000 --- a/t/55-yaml.t +++ /dev/null @@ -1,11 +0,0 @@ -use Test::More tests => 2; - -use Catalyst::Plugin::ConfigLoader::YAML; - -my $config = eval { Catalyst::Plugin::ConfigLoader::YAML->load( 't/conf/conf.yml' ) }; - -SKIP: { - skip "Couldn't Load YAML plugin", 2 if $@; - ok( $config ); - is( $config->{ name }, 'TestApp' ); -} diff --git a/t/conf/conf.general b/t/conf/conf.general deleted file mode 100644 index 3f22055..0000000 --- a/t/conf/conf.general +++ /dev/null @@ -1,7 +0,0 @@ -name = TestApp - - foo bar - - - qux xyzzy - \ No newline at end of file diff --git a/t/conf/conf.ini b/t/conf/conf.ini deleted file mode 100644 index 366619e..0000000 --- a/t/conf/conf.ini +++ /dev/null @@ -1,7 +0,0 @@ -name=TestApp - -[Controller::Foo] -foo=bar - -[Model::Baz] -qux=xyzzy diff --git a/t/conf/conf.json b/t/conf/conf.json deleted file mode 100644 index 0afd4bd..0000000 --- a/t/conf/conf.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "name": "TestApp", - "Controller::Foo": { - "foo": "bar" - }, - "Model::Baz": { - "qux": "xyzzy" - } -} \ No newline at end of file diff --git a/t/conf/conf.pl b/t/conf/conf.pl deleted file mode 100644 index 8683545..0000000 --- a/t/conf/conf.pl +++ /dev/null @@ -1,9 +0,0 @@ -{ - name => 'TestApp', - 'Controller::Foo' => { - foo => 'bar' - }, - 'Model::Baz' => { - qux => 'xyzzy' - } -} \ No newline at end of file diff --git a/t/conf/conf.xml b/t/conf/conf.xml deleted file mode 100644 index c9f49ca..0000000 --- a/t/conf/conf.xml +++ /dev/null @@ -1,9 +0,0 @@ - - TestApp - - bar - - - xyzzy - - \ No newline at end of file diff --git a/t/conf/conf.yml b/t/conf/conf.yml deleted file mode 100644 index 018d216..0000000 --- a/t/conf/conf.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -name: TestApp -Controller::Foo: - foo: bar -Model::Baz: - qux: xyzzy