From: Joel Bernstein Date: Wed, 9 Aug 2006 16:57:11 +0000 (+0000) Subject: Initial import of Config::Any (refactored from Catalyst::Plugin::ConfigLoader), and... X-Git-Tag: v0.04~12 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=p5sagit%2FConfig-Any.git;a=commitdiff_plain;h=c80a0905834ed09d487b84d7a00a3e92e44bbb62 Initial import of Config::Any (refactored from Catalyst::Plugin::ConfigLoader), and rewrite of C::P::CL to use C::A --- diff --git a/Build.PL b/Build.PL new file mode 100644 index 0000000..02a5026 --- /dev/null +++ b/Build.PL @@ -0,0 +1,18 @@ +use strict; +use warnings; +use Module::Build; + +my $builder = Module::Build->new( + module_name => 'Config::Any', + license => 'perl', + dist_author => 'Joel Bernstein ', + dist_version_from => 'lib/Config/Any.pm', + requires => { + 'Test::More' => 0, + 'version' => 0, + 'Module::Pluggable' => '3.01' + }, + add_to_cleanup => [ 'Config-Any-*' ], +); + +$builder->create_build_script(); diff --git a/Changes b/Changes new file mode 100644 index 0000000..95f6dc4 --- /dev/null +++ b/Changes @@ -0,0 +1,5 @@ +Revision history for Config-Any + +0.0.1 Mon Aug 7 15:15:15 2006 + Initial release. + diff --git a/MANIFEST b/MANIFEST new file mode 100644 index 0000000..b412a1b --- /dev/null +++ b/MANIFEST @@ -0,0 +1,17 @@ +Build.PL +Changes +lib/Config/Any.pm +lib/Config/Any/General.pm +lib/Config/Any/INI.pm +lib/Config/Any/JSON.pm +lib/Config/Any/Perl.pm +lib/Config/Any/XML.pm +lib/Config/Any/YAML.pm +Makefile.PL +MANIFEST +META.yml # Will be created by "make dist" +README +t/00.load.t +t/perlcritic.t +t/pod-coverage.t +t/pod.t diff --git a/README b/README new file mode 100644 index 0000000..3d80d7e --- /dev/null +++ b/README @@ -0,0 +1,26 @@ +Config-Any version 0.0.4 + +This module generalises loading class configuration data from a number of different +file formats. + +INSTALLATION + +To install this module, run the following commands: + perl Build.PL + ./Build + ./Build test + ./Build install + + +DEPENDENCIES + +Module::Pluggable >= 3.01 + +COPYRIGHT AND LICENCE + +The development of this module was sponsored by SAPO, a division of Portugal Telecom. + +Copyright (C) 2006, Portugal Telecom + +This library is free software; you can redistribute it and/or modify +it under the same terms as Perl itself. diff --git a/lib/Config/Any.pm b/lib/Config/Any.pm new file mode 100644 index 0000000..c6a30e2 --- /dev/null +++ b/lib/Config/Any.pm @@ -0,0 +1,227 @@ +package Config::Any; +# $Id: $ +use warnings; +use strict; +use Carp; +use Module::Pluggable::Object (); +our $VERSION = (qw$Rev: $)[-1]; + +sub load_files { + my ($class, $args) = @_; + croak "load_files requires a hashref argument" unless defined $args; + croak "no files specified!" unless defined $args->{files}; + my $files = [ grep { -f $_ } @{$args->{files}} ]; + my $filter_cb = delete $args->{filter}; + return $class->_load($files, $filter_cb); +} + +sub load_stems { + my ($class, $args) = @_; + croak "load_stems requires a hashref argument" unless defined $args; + croak "no stems specified!" unless defined $args->{stems}; + my $filter_cb = delete $args->{filter}; + my $stems = $args->{stems}; + my @files; + STEM: + for my $s (@$stems) { + EXT: + for my $ext ($class->extensions) { + my $file = "$s.$ext"; + next EXT unless -f $file; + push @files, $file; + last EXT; + } + } + return $class->_load(\@files, $filter_cb); +} + +sub _load { + my ($class, $files_ref, $filter_cb) = @_; + croak "_load requires a arrayref of file paths" unless defined $files_ref; + + my $final_configs = []; + + for my $loader ( $class->plugins ) { + for my $filename (@$files_ref) { + my $config = $loader->load( $filename ); + next if !$config; + $filter_cb->( $config ) if defined $filter_cb; + push @$final_configs, { $filename => $config }; + } + } + $final_configs; +} + +sub finder { + my $class = shift; + my $finder = Module::Pluggable::Object->new( + search_path => [ __PACKAGE__ ], + require => 1 + ); + $finder; +} + +sub plugins { + my $class = shift; + return $class->finder->plugins; +} + +sub extensions { + my $class = shift; + return [ map { $_->extensions } $class->plugins ]; +} + +1; # Magic true value required at end of module +__END__ + +=head1 NAME + +Config::Any - [One line description of module's purpose here] + + +=head1 VERSION + +This document describes Config::Any version 0.0.4 + + +=head1 SYNOPSIS + + use Config::Any; + + my $cfg = Config::Any->load_stems({stems => \@filepath_stems, ... }); + # or + my $cfg = Config::Any->load_files({files => \@filepaths, ... }); + + for (@$cfg) { + my ($filename, $config) = each %$_; + $class->config($config); + warn "loaded config from file: $filename"; + } + +=head1 DESCRIPTION + +=for author to fill in: + Write a full description of the module and its features here. + Use subsections (=head2, =head3) as appropriate. + + +=head1 INTERFACE + +=for author to fill in: + Write a separate section listing the public components of the modules + interface. These normally consist of either subroutines that may be + exported, or methods that may be called on objects belonging to the + classes provided by the module. + + +=head1 DIAGNOSTICS + +=for author to fill in: + List every single error and warning message that the module can + generate (even the ones that will "never happen"), with a full + explanation of each problem, one or more likely causes, and any + suggested remedies. + +=over + +=item C<< Error message here, perhaps with %s placeholders >> + +[Description of error here] + +=item C<< Another error message here >> + +[Description of error here] + +[Et cetera, et cetera] + +=back + + +=head1 CONFIGURATION AND ENVIRONMENT + +=for author to fill in: + A full explanation of any configuration system(s) used by the + module, including the names and locations of any configuration + files, and the meaning of any environment variables or properties + that can be set. These descriptions must also include details of any + configuration language used. + +Config::Any requires no configuration files or environment variables. + + +=head1 DEPENDENCIES + +=for author to fill in: + A list of all the other modules that this module relies upon, + including any restrictions on versions, and an indication whether + the module is part of the standard Perl distribution, part of the + module's distribution, or must be installed separately. ] + +None. + + +=head1 INCOMPATIBILITIES + +=for author to fill in: + A list of any modules that this module cannot be used in conjunction + with. This may be due to name conflicts in the interface, or + competition for system or program resources, or due to internal + limitations of Perl (for example, many modules that use source code + filters are mutually incompatible). + +None reported. + + +=head1 BUGS AND LIMITATIONS + +=for author to fill in: + A list of known problems with the module, together with some + indication Whether they are likely to be fixed in an upcoming + release. Also a list of restrictions on the features the module + does provide: data types that cannot be handled, performance issues + and the circumstances in which they may arise, practical + limitations on the size of data sets, special cases that are not + (yet) handled, etc. + +No bugs have been reported. + +Please report any bugs or feature requests to +C, or through the web interface at +L. + + +=head1 AUTHOR + +Joel Bernstein C<< >> + + +=head1 LICENCE AND COPYRIGHT + +Copyright (c) 2006, Portugal Telecom C<< http://www.sapo.pt/ >>. All rights reserved. + +This module is free software; you can redistribute it and/or +modify it under the same terms as Perl itself. See L. + + +=head1 DISCLAIMER OF WARRANTY + +BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER +EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE +ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH +YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL +NECESSARY SERVICING, REPAIR, OR CORRECTION. + +IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE SOFTWARE AS PERMITTED BY THE ABOVE LICENCE, BE +LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL, +OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE +THE SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. diff --git a/lib/Config/Any/General.pm b/lib/Config/Any/General.pm new file mode 100644 index 0000000..c91bd4d --- /dev/null +++ b/lib/Config/Any/General.pm @@ -0,0 +1,80 @@ +package Config::Any::General; + +use strict; +use warnings; + +=head1 NAME + +Config::Any::General - Load Config::General files + +=head1 DESCRIPTION + +Loads Config::General files. Example: + + name = TestApp + + foo bar + + + qux xyzzy + + +=head1 METHODS + +=head2 extensions( ) + +return an array of valid extensions (C, C). + +=cut + +sub extensions { + return qw( cnf conf ); +} + +=head2 load( $file ) + +Attempts to load C<$file> via Config::General. + +=cut + +sub load { + my $class = shift; + my $file = shift; + + require Config::General; + my $configfile = Config::General->new( $file ); + my $config = { $configfile->getall }; + + return $config; +} + +=head1 AUTHOR + +=over 4 + +=item * Brian Cassidy Ebricas@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 + +=item * L + +=item * L + +=back + +=cut + +1; \ No newline at end of file diff --git a/lib/Config/Any/INI.pm b/lib/Config/Any/INI.pm new file mode 100644 index 0000000..092362d --- /dev/null +++ b/lib/Config/Any/INI.pm @@ -0,0 +1,82 @@ +package Config::Any::INI; + +use strict; +use warnings; + +=head1 NAME + +Config::Any::INI - Load INI config files + +=head1 DESCRIPTION + +Loads INI files. Example: + + name=TestApp + + [Controller::Foo] + foo=bar + + [Model::Baz] + qux=xyzzy + +=head1 METHODS + +=head2 extensions( ) + +return an array of valid extensions (C). + +=cut + +sub extensions { + return qw( ini ); +} + +=head2 load( $file ) + +Attempts to load C<$file> as an INI file. + +=cut + +sub load { + my $class = shift; + my $file = shift; + + require Config::Tiny; + my $config = Config::Tiny->read( $file ); + my $main = delete $config->{ _ }; + + $config->{ $_ } = $main->{ $_ } for keys %$main; + + return $config; +} + +=head1 AUTHOR + +=over 4 + +=item * Brian Cassidy Ebricas@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 + +=item * L + +=item * L + +=back + +=cut + +1; \ No newline at end of file diff --git a/lib/Config/Any/JSON.pm b/lib/Config/Any/JSON.pm new file mode 100644 index 0000000..faa041d --- /dev/null +++ b/lib/Config/Any/JSON.pm @@ -0,0 +1,92 @@ +package Config::Any::JSON; + +use strict; +use warnings; + +=head1 NAME + +Config::Any::JSON - Load JSON config files + +=head1 DESCRIPTION + +Loads JSON files. Example: + + { + "name": "TestApp", + "Controller::Foo": { + "foo": "bar" + }, + "Model::Baz": { + "qux": "xyzzy" + } + } + +=head1 METHODS + +=head2 extensions( ) + +return an array of valid extensions (C, C). + +=cut + +sub extensions { + return qw( json jsn ); +} + +=head2 load( $file ) + +Attempts to load C<$file> as a JSON file. + +=cut + +sub load { + my $class = shift; + my $file = shift; + + open( my $fh, $file ) or die $!; + my $content = do { local $/; <$fh> }; + close $fh; + + eval { require JSON::Syck; }; + if( $@ ) { + require JSON; + JSON->import; + return jsonToObj( $content ); + } + else { + return JSON::Syck::Load( $content ); + } +} + +=head1 AUTHOR + +=over 4 + +=item * Brian Cassidy Ebricas@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 + +=item * L + +=item * L + +=item * L + +=back + +=cut + +1; \ No newline at end of file diff --git a/lib/Config/Any/Perl.pm b/lib/Config/Any/Perl.pm new file mode 100644 index 0000000..6c179f5 --- /dev/null +++ b/lib/Config/Any/Perl.pm @@ -0,0 +1,76 @@ +package Config::Any::Perl; + +use strict; +use warnings; + +=head1 NAME + +Config::Any::Perl - Load Perl config files + +=head1 DESCRIPTION + +Loads Perl files. Example: + + { + name => 'TestApp', + 'Controller::Foo' => { + foo => 'bar' + }, + 'Model::Baz' => { + qux => 'xyzzy' + } + } + +=head1 METHODS + +=head2 extensions( ) + +return an array of valid extensions (C, C). + +=cut + +sub extensions { + return qw( pl perl ); +} + +=head2 load( $file ) + +Attempts to load C<$file> as a Perl file. + +=cut + +sub load { + my $class = shift; + my $file = shift; + + return eval { require $file }; +} + +=head1 AUTHOR + +=over 4 + +=item * Brian Cassidy Ebricas@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 + +=item * L + +=back + +=cut + +1; \ No newline at end of file diff --git a/lib/Config/Any/XML.pm b/lib/Config/Any/XML.pm new file mode 100644 index 0000000..a37a2f2 --- /dev/null +++ b/lib/Config/Any/XML.pm @@ -0,0 +1,82 @@ +package Config::Any::XML; + +use strict; +use warnings; + +=head1 NAME + +Config::Any::XML - Load XML config files + +=head1 DESCRIPTION + +Loads XML files. Example: + + + TestApp + + bar + + + xyzzy + + + +=head1 METHODS + +=head2 extensions( ) + +return an array of valid extensions (C). + +=cut + +sub extensions { + return qw( xml ); +} + +=head2 load( $file ) + +Attempts to load C<$file> as an XML file. + +=cut + +sub load { + my $class = shift; + my $file = shift; + + require XML::Simple; + XML::Simple->import; + my $config = XMLin( $file, ForceArray => [ qw( component model view controller ) ] ); + + return $config; +} + +=head1 AUTHOR + +=over 4 + +=item * Brian Cassidy Ebricas@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 + +=item * L + +=item * L + +=back + +=cut + +1; \ No newline at end of file diff --git a/lib/Config/Any/YAML.pm b/lib/Config/Any/YAML.pm new file mode 100644 index 0000000..564fc52 --- /dev/null +++ b/lib/Config/Any/YAML.pm @@ -0,0 +1,88 @@ +package Config::Any::YAML; + +use strict; +use warnings; + +=head1 NAME + +Config::Any::YAML - Load YAML config files + +=head1 DESCRIPTION + +Loads YAML files. Example: + + --- + name: TestApp + Controller::Foo: + foo: bar + Model::Baz: + qux: xyzzy + + +=head1 METHODS + +=head2 extensions( ) + +return an array of valid extensions (C, C). + +=cut + +sub extensions { + return qw( yml yaml ); +} + +=head2 load( $file ) + +Attempts to load C<$file> as a YAML file. + +=cut + +sub load { + my $class = shift; + my $file = shift; + + eval { require YAML::Syck; }; + if( $@ ) { + require YAML; + return YAML::LoadFile( $file ); + } + else { + open( my $fh, $file ) or die $!; + my $content = do { local $/; <$fh> }; + close $fh; + return YAML::Syck::Load( $content ); + } +} + +=head1 AUTHOR + +=over 4 + +=item * Brian Cassidy Ebricas@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 + +=item * L + +=item * L + +=item * L + +=back + +=cut + +1; \ No newline at end of file diff --git a/t/00.load.t b/t/00.load.t new file mode 100644 index 0000000..459cbb3 --- /dev/null +++ b/t/00.load.t @@ -0,0 +1,7 @@ +use Test::More tests => 1; + +BEGIN { +use_ok( 'Config::Any' ); +} + +diag( "Testing Config::Any $Config::Any::VERSION" ); diff --git a/t/perlcritic.t b/t/perlcritic.t new file mode 100644 index 0000000..7e7b210 --- /dev/null +++ b/t/perlcritic.t @@ -0,0 +1,9 @@ +#!perl + +if (!require Test::Perl::Critic) { + Test::More::plan( + skip_all => "Test::Perl::Critic required for testing PBP compliance" + ); +} + +Test::Perl::Critic::all_critic_ok(); diff --git a/t/pod-coverage.t b/t/pod-coverage.t new file mode 100644 index 0000000..703f91d --- /dev/null +++ b/t/pod-coverage.t @@ -0,0 +1,6 @@ +#!perl -T + +use Test::More; +eval "use Test::Pod::Coverage 1.04"; +plan skip_all => "Test::Pod::Coverage 1.04 required for testing POD coverage" if $@; +all_pod_coverage_ok(); diff --git a/t/pod.t b/t/pod.t new file mode 100644 index 0000000..976d7cd --- /dev/null +++ b/t/pod.t @@ -0,0 +1,6 @@ +#!perl -T + +use Test::More; +eval "use Test::Pod 1.14"; +plan skip_all => "Test::Pod 1.14 required for testing POD" if $@; +all_pod_files_ok();