From: Chris W. <la...@us...> - 2004-11-28 00:28:51
|
Update of /cvsroot/openinteract/OpenInteract2/lib/OpenInteract2/Config In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv23385/lib/OpenInteract2/Config Modified Files: Ini.pm Log Message: add functionality to bring in other INI configurations with @INCLUDE directive Index: Ini.pm =================================================================== RCS file: /cvsroot/openinteract/OpenInteract2/lib/OpenInteract2/Config/Ini.pm,v retrieving revision 1.17 retrieving revision 1.18 diff -C2 -d -r1.17 -r1.18 *** Ini.pm 9 Nov 2004 13:56:54 -0000 1.17 --- Ini.pm 27 Nov 2004 20:33:55 -0000 1.18 *************** *** 4,10 **** --- 4,13 ---- use strict; + use File::Basename qw( dirname ); + use File::Spec::Functions qw( catfile ); use Log::Log4perl qw( get_logger ); use OpenInteract2::Constants qw( :log ); use OpenInteract2::Context qw( CTX ); + use OpenInteract2::Exception qw( oi_error ); $OpenInteract2::Config::Ini::VERSION = sprintf("%d.%02d", q$Revision$ =~ /(\d+)\.(\d+)/); *************** *** 19,22 **** --- 22,26 ---- # comments (\%): key is full section name, value is comment scalar # filename ($): file read from + # directory ($): directory file read from sub new { *************** *** 25,34 **** --- 29,41 ---- my $self = bless( {}, $class ); if ( $self->{_m}{filename} = $params->{filename} ) { + $self->{_m}{directory} = $params->{directory} || dirname( $params->{filename} ); $self->_translate_ini( OpenInteract2::Config->read_file( $params->{filename} ) ); } elsif ( $params->{content} ) { + $self->{_m}{directory} = $params->{directory} || '.'; $self->_translate_ini( $params->{content} ); } elsif ( $params->{struct} ) { + $self->{_m}{directory} = $params->{directory} || '.'; $self->_translate_struct_to_ini( $params->{struct} ); } *************** *** 153,160 **** my $in_multiline = 0; # Cycle through the lines: skip blanks; accumulate comments for # each section; register section/subsection; add parameter/value ! for ( @{ $lines } ) { chomp; $line_number++; --- 160,169 ---- my $in_multiline = 0; + my $resolved_lines = $self->_resolve_all_includes( $lines ); + # Cycle through the lines: skip blanks; accumulate comments for # each section; register section/subsection; add parameter/value ! for ( @{ $resolved_lines } ) { chomp; $line_number++; *************** *** 236,239 **** --- 245,277 ---- + sub _resolve_all_includes { + my ( $self, $content ) = @_; + my @resolved = (); + for ( @{ $content } ) { + chomp; + if ( /^\@INCLUDE\s*=\s*(.*)\s*$/ ) { + my $include_file = $1; + my $absolute_file = catfile( $self->{_m}{directory}, $include_file ); + $log->is_debug && + $log->debug( "Asked to include file '$include_file'; ", + "using absolute filename ", $absolute_file ); + my $included_raw = eval { + OpenInteract2::Config->read_file( $absolute_file ) + }; + if ( $@ ) { + oi_error "Failed to read INI configuration -- cannot \@INCLUDE ", + "file '$include_file': $@"; + } + my $included_resolved = $self->_resolve_all_includes( $included_raw ); + push @resolved, @{ $included_resolved }; + } + else { + push @resolved, "$_\n"; + } + } + return \@resolved; + } + + sub _read_section_head { my ( $self, $full_section, $comments ) = @_; *************** *** 379,385 **** =head1 SYNOPSIS ! my $config = OpenInteract2::Config::Ini->new({ filename => 'myconf.ini' }); print "Main database driver is:", $config->{datasource}{main}{driver}, "\n"; $config->{datasource}{main}{username} = 'mariolemieux'; $config->write_file; --- 417,455 ---- =head1 SYNOPSIS ! # If no 'directory' specified @INCLUDE directives are assumed to be ! # in the same directory as the 'filename' ! ! my $config = OpenInteract2::Config::Ini->new({ ! filename => 'myconf.ini' ! }); ! ! # Pass in an explicit directory to resolve @INCLUDE directives ! ! my $config = OpenInteract2::Config::Ini->new({ ! filename => 'myconf.ini', ! directory => '/path/to/config', ! }); ! ! # Use a string with INI sections instead of a file; @INCLUDE ! # directives assumed to be in the current directory ! ! my $config = OpenInteract2::Config::Ini->new({ ! content => $some_string, ! }); ! ! # Pass in an explicit directory to resolve @INCLUDE directives ! ! my $config = OpenInteract2::Config::Ini->new({ ! content => $some_string, ! directory => '/path/to/config', ! }); ! ! # Use the configuration just like a hash print "Main database driver is:", $config->{datasource}{main}{driver}, "\n"; $config->{datasource}{main}{username} = 'mariolemieux'; + + # Write out the configuration; this should preserve order and + # comments + $config->write_file; *************** *** 440,448 **** @,object_field = active_on, content =back =head2 Example ! Given the following configuration in INI-style: [datasource] --- 510,550 ---- @,object_field = active_on, content + =item * + + From countless other configuration systems you can include the + contents of other files inline using '@INCLUDE'. So given the + following files: + + File: db_config.ini + [db] + dsn = DBI:Pg:dbname=foo + user = foo + password = bar + + File: caching.ini + [cache] + use = no + expiration = 600 + class = OpenInteract2::Cache::File + + [cache params] + directory = /path/to/cache + lock_directory = /path/to/cache_lock + + You can them bring them all together in one with: + + File: server.ini + [Global] + version = 1.19 + timezone = America/New_York + + @INCLUDE = db_config.ini + @INCLUDE = caching.ini + =back =head2 Example ! Given the following configurations: [datasource] *************** *** 533,540 **** translate it using the same means as reading a file. ! And if you pass in a hashref in the parameter 'struct' we attempt to ! map its keys and values to the internal format which can then be saved ! as normal. This will throw an exception if your structures are nested ! too deeply. For instance, this would be ok: my $foo = { --- 635,643 ---- translate it using the same means as reading a file. ! B<NOTE: THIS DOES NOT WORK YET> And if you pass in a hashref in the ! parameter 'struct' we attempt to map its keys and values to the ! internal format which can then be saved as normal. This will throw an ! exception if your structures are nested too deeply. For instance, this ! would be ok: my $foo = { *************** *** 619,622 **** --- 722,732 ---- C<$filename>. + Note: this B<DOES NOT> write any '@INCLUDE' directives back to the + files we read them from. Everything will be written to the same + file. (Patches welcome if you would like to change this, probably by + tagging the sections read in from a file with that absolute filename + and then writing those sections back out to the file from this + method.) + Items from the config object root go into 'Global'. *************** *** 636,643 **** Translate the arrayref C<\@lines> or the scalar C<content> from INI ! format into a Perl data structure. Returns: the object filled with the content. B<_read_section_head( $full_section, \@comments )> --- 746,766 ---- Translate the arrayref C<\@lines> or the scalar C<content> from INI ! format into a Perl data structure. Before we translate them into a ! data structure we first resolve all '@INCLUDE' directives. Returns: the object filled with the content. + B<_resolve_all_includes( \@lines )> + + Translate all '@INCLUDE' directives to the configuration they point + to. Throws an exception if we cannot read the file specified in the + directive. This file path is created by giving to C<catfile> in + L<File::Spec> the metadata value 'directory' (which can be passed in + to C<new()>) and the filename in the directive. + + Note that INCLUDE-ed files can themselves have '@INCLUDE' directives. + + Returns: arrayref of fully-resolved configuration. + B<_read_section_head( $full_section, \@comments )> |