--- /dev/null
+use strict;
+use warnings;
+use Module::Build;
+
+my $builder = Module::Build->new(
+ module_name => 'Config::Any',
+ license => 'perl',
+ dist_author => 'Joel Bernstein <rataxis@cpan.org>',
+ 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();
--- /dev/null
+Revision history for Config-Any
+
+0.0.1 Mon Aug 7 15:15:15 2006
+ Initial release.
+
--- /dev/null
+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
--- /dev/null
+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.
--- /dev/null
+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<bug-config-any@rt.cpan.org>, or through the web interface at
+L<http://rt.cpan.org>.
+
+
+=head1 AUTHOR
+
+Joel Bernstein C<< <rataxis@cpan.org> >>
+
+
+=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<perlartistic>.
+
+
+=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.
--- /dev/null
+package Config::Any::General;\r
+\r
+use strict;\r
+use warnings;\r
+\r
+=head1 NAME\r
+\r
+Config::Any::General - Load Config::General files\r
+\r
+=head1 DESCRIPTION\r
+\r
+Loads Config::General files. Example:\r
+\r
+ name = TestApp\r
+ <Component Controller::Foo>\r
+ foo bar\r
+ </Component>\r
+ <Model Baz>\r
+ qux xyzzy\r
+ </Model>\r
+\r
+=head1 METHODS\r
+\r
+=head2 extensions( )\r
+\r
+return an array of valid extensions (C<cnf>, C<conf>).\r
+\r
+=cut\r
+\r
+sub extensions {\r
+ return qw( cnf conf );\r
+}\r
+\r
+=head2 load( $file )\r
+\r
+Attempts to load C<$file> via Config::General.\r
+\r
+=cut\r
+\r
+sub load {\r
+ my $class = shift;\r
+ my $file = shift;\r
+\r
+ require Config::General;\r
+ my $configfile = Config::General->new( $file );\r
+ my $config = { $configfile->getall };\r
+ \r
+ return $config;\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 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
+=item * L<Config::Any>\r
+\r
+=item * L<Config::General>\r
+\r
+=back\r
+\r
+=cut\r
+\r
+1;
\ No newline at end of file
--- /dev/null
+package Config::Any::INI;\r
+\r
+use strict;\r
+use warnings;\r
+\r
+=head1 NAME\r
+\r
+Config::Any::INI - Load INI config files\r
+\r
+=head1 DESCRIPTION\r
+\r
+Loads INI files. Example:\r
+\r
+ name=TestApp\r
+ \r
+ [Controller::Foo]\r
+ foo=bar\r
+ \r
+ [Model::Baz]\r
+ qux=xyzzy\r
+\r
+=head1 METHODS\r
+\r
+=head2 extensions( )\r
+\r
+return an array of valid extensions (C<ini>).\r
+\r
+=cut\r
+\r
+sub extensions {\r
+ return qw( ini );\r
+}\r
+\r
+=head2 load( $file )\r
+\r
+Attempts to load C<$file> as an INI file.\r
+\r
+=cut\r
+\r
+sub load {\r
+ my $class = shift;\r
+ my $file = shift;\r
+\r
+ require Config::Tiny;\r
+ my $config = Config::Tiny->read( $file );\r
+ my $main = delete $config->{ _ };\r
+ \r
+ $config->{ $_ } = $main->{ $_ } for keys %$main;\r
+\r
+ return $config;\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 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
+=item * L<Config::Any>\r
+\r
+=item * L<Config::Tiny>\r
+\r
+=back\r
+\r
+=cut\r
+\r
+1;
\ No newline at end of file
--- /dev/null
+package Config::Any::JSON;\r
+\r
+use strict;\r
+use warnings;\r
+\r
+=head1 NAME\r
+\r
+Config::Any::JSON - Load JSON config files\r
+\r
+=head1 DESCRIPTION\r
+\r
+Loads JSON files. Example:\r
+\r
+ {\r
+ "name": "TestApp",\r
+ "Controller::Foo": {\r
+ "foo": "bar"\r
+ },\r
+ "Model::Baz": {\r
+ "qux": "xyzzy"\r
+ }\r
+ }\r
+\r
+=head1 METHODS\r
+\r
+=head2 extensions( )\r
+\r
+return an array of valid extensions (C<json>, C<jsn>).\r
+\r
+=cut\r
+\r
+sub extensions {\r
+ return qw( json jsn );\r
+}\r
+\r
+=head2 load( $file )\r
+\r
+Attempts to load C<$file> as a JSON file.\r
+\r
+=cut\r
+\r
+sub load {\r
+ my $class = shift;\r
+ my $file = shift;\r
+\r
+ open( my $fh, $file ) or die $!;\r
+ my $content = do { local $/; <$fh> };\r
+ close $fh;\r
+\r
+ eval { require JSON::Syck; };\r
+ if( $@ ) {\r
+ require JSON;\r
+ JSON->import;\r
+ return jsonToObj( $content );\r
+ }\r
+ else {\r
+ return JSON::Syck::Load( $content );\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 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
+=item * L<Config::Any>\r
+\r
+=item * L<JSON>\r
+\r
+=item * L<JSON::Syck>\r
+\r
+=back\r
+\r
+=cut\r
+\r
+1;
\ No newline at end of file
--- /dev/null
+package Config::Any::Perl;\r
+\r
+use strict;\r
+use warnings;\r
+\r
+=head1 NAME\r
+\r
+Config::Any::Perl - Load Perl config files\r
+\r
+=head1 DESCRIPTION\r
+\r
+Loads Perl files. Example:\r
+\r
+ {\r
+ name => 'TestApp',\r
+ 'Controller::Foo' => {\r
+ foo => 'bar'\r
+ },\r
+ 'Model::Baz' => {\r
+ qux => 'xyzzy'\r
+ }\r
+ }\r
+\r
+=head1 METHODS\r
+\r
+=head2 extensions( )\r
+\r
+return an array of valid extensions (C<pl>, C<perl>).\r
+\r
+=cut\r
+\r
+sub extensions {\r
+ return qw( pl perl );\r
+}\r
+\r
+=head2 load( $file )\r
+\r
+Attempts to load C<$file> as a Perl file.\r
+\r
+=cut\r
+\r
+sub load {\r
+ my $class = shift;\r
+ my $file = shift;\r
+\r
+ return eval { require $file };\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 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
+=item * L<Config::Any>\r
+\r
+=back\r
+\r
+=cut\r
+\r
+1;
\ No newline at end of file
--- /dev/null
+package Config::Any::XML;\r
+\r
+use strict;\r
+use warnings;\r
+\r
+=head1 NAME\r
+\r
+Config::Any::XML - Load XML config files\r
+\r
+=head1 DESCRIPTION\r
+\r
+Loads XML files. Example:\r
+\r
+ <config>\r
+ <name>TestApp</name>\r
+ <component name="Controller::Foo">\r
+ <foo>bar</foo>\r
+ </component>\r
+ <model name="Baz">\r
+ <qux>xyzzy</qux>\r
+ </model>\r
+ </config>\r
+\r
+=head1 METHODS\r
+\r
+=head2 extensions( )\r
+\r
+return an array of valid extensions (C<xml>).\r
+\r
+=cut\r
+\r
+sub extensions {\r
+ return qw( xml );\r
+}\r
+\r
+=head2 load( $file )\r
+\r
+Attempts to load C<$file> as an XML file.\r
+\r
+=cut\r
+\r
+sub load {\r
+ my $class = shift;\r
+ my $file = shift;\r
+\r
+ require XML::Simple;\r
+ XML::Simple->import;\r
+ my $config = XMLin( $file, ForceArray => [ qw( component model view controller ) ] );\r
+\r
+ return $config;\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 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
+=item * L<Config::Any>\r
+\r
+=item * L<XML::Simple>\r
+\r
+=back\r
+\r
+=cut\r
+\r
+1;
\ No newline at end of file
--- /dev/null
+package Config::Any::YAML;\r
+\r
+use strict;\r
+use warnings;\r
+\r
+=head1 NAME\r
+\r
+Config::Any::YAML - Load YAML config files\r
+\r
+=head1 DESCRIPTION\r
+\r
+Loads YAML files. Example:\r
+\r
+ ---\r
+ name: TestApp\r
+ Controller::Foo:\r
+ foo: bar\r
+ Model::Baz:\r
+ qux: xyzzy\r
+ \r
+\r
+=head1 METHODS\r
+\r
+=head2 extensions( )\r
+\r
+return an array of valid extensions (C<yml>, C<yaml>).\r
+\r
+=cut\r
+\r
+sub extensions {\r
+ return qw( yml yaml );\r
+}\r
+\r
+=head2 load( $file )\r
+\r
+Attempts to load C<$file> as a YAML file.\r
+\r
+=cut\r
+\r
+sub load {\r
+ my $class = shift;\r
+ my $file = shift;\r
+\r
+ eval { require YAML::Syck; };\r
+ if( $@ ) {\r
+ require YAML;\r
+ return YAML::LoadFile( $file );\r
+ }\r
+ else {\r
+ open( my $fh, $file ) or die $!;\r
+ my $content = do { local $/; <$fh> };\r
+ close $fh;\r
+ return YAML::Syck::Load( $content );\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 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
+=item * L<Config::Any>\r
+\r
+=item * L<YAML>\r
+\r
+=item * L<YAML::Syck>\r
+\r
+=back\r
+\r
+=cut\r
+\r
+1;
\ No newline at end of file
--- /dev/null
+use Test::More tests => 1;
+
+BEGIN {
+use_ok( 'Config::Any' );
+}
+
+diag( "Testing Config::Any $Config::Any::VERSION" );
--- /dev/null
+#!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();
--- /dev/null
+#!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();
--- /dev/null
+#!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();