Config-Record-1.1.2/0000755000076400007640000000000010727642245014311 5ustar berrangeberrangeConfig-Record-1.1.2/autobuild.sh0000755000076400007640000000214110727642236016636 0ustar berrangeberrange#!/bin/sh NAME="Config-Record" set -e # Make things clean. make -k realclean ||: rm -rf MANIFEST blib # Make makefiles. perl Makefile.PL PREFIX=$AUTOBUILD_INSTALL_ROOT # Build the RPM. make make manifest # Run test suite perl -MDevel::Cover -e '' 1>/dev/null 2>&1 && USE_COVER=1 || USE_COVER=0 if [ "$USE_COVER" = "1" ]; then cover -delete HARNESS_PERL_SWITCHES=-MDevel::Cover make test cover mkdir blib/coverage cp -a cover_db/*.html cover_db/*.css blib/coverage mv blib/coverage/coverage.html blib/coverage/index.html else make test fi # Install to virtual root make install # Make distribution & packages rm -f $NAME-*.tar.gz make dist if [ -f /usr/bin/rpmbuild ]; then if [ -n "$AUTOBUILD_COUNTER" ]; then EXTRA_RELEASE=".auto$AUTOBUILD_COUNTER" else NOW=`date +"%s"` EXTRA_RELEASE=".$USER$NOW" fi rpmbuild -ta --define "extra_release $EXTRA_RELEASE" --clean $NAME-*.tar.gz fi if [ -f /usr/bin/fakeroot -a -f /etc/debian_version -a -n "$AUTOBUILD_PACKAGE_ROOT" ]; then fakeroot debian/rules clean fakeroot debian/rules DESTDIR=$AUTOBUILD_PACKAGE_ROOT/debian binary fi Config-Record-1.1.2/Config-Record.spec0000644000076400007640000000266310727642243017613 0ustar berrangeberrange# Automatically generated by Config-Record.spec.PL %define appname Config-Record # This macro is used for the continuous automated builds. It just # allows an extra fragment based on the timestamp to be appended # to the release. This distinguishes automated builds, from formal # Fedora RPM builds %define _extra_release %{?dist:%{dist}}%{?extra_release:%{extra_release}} Summary: Config::Record - Simple configuration records Name: perl-%{appname} Version: 1.1.2 Release: 1%{_extra_release} License: GPLv2+ Group: Applications/Internet Source: http://www.cpan.org/authors/id/D/DA/DANBERR/%{appname}-%{version}.tar.gz BuildRoot: /var/tmp/%{appname}-%{version}-root BuildArchitectures: noarch Requires: perl(:MODULE_COMPAT_%(eval "`%{__perl} -V:version`"; echo $version)) %description Config::Record provides a module for loading configuration records. It supports scalar, array and hash parameters nested to an arbitrary depth. %prep %setup -q -n %{appname}-%{version} %build %{__perl} Makefile.PL INSTALLDIRS=vendor %__make \ %install rm -rf $RPM_BUILD_ROOT %__make install \ PERL_INSTALL_ROOT=$RPM_BUILD_ROOT find $RPM_BUILD_ROOT -name perllocal.pod -exec rm -f {} \; find $RPM_BUILD_ROOT -name .packlist -exec rm -f {} \; %check make test %clean rm -rf $RPM_BUILD_ROOT %files %defattr(-,root,root) %doc AUTHORS LICENSE README CHANGES %{perl_vendorlib}/Config/Record.pm %{perl_vendorlib}/Config/Record.pod %{_mandir}/man3/Config::Record.3pm* Config-Record-1.1.2/examples/0000755000076400007640000000000010727642245016127 5ustar berrangeberrangeConfig-Record-1.1.2/examples/auto-build.conf0000644000076400007640000002601410727642236021046 0ustar berrangeberrange# # Example configuration file showing many constructs. # Taken from the Test::AutoBuild distribution # # Test-AutoBuild main configuration file. # # Short documentation can be found inline, and for further # information consult the manual page 'man 5 auto-build.conf' # # Path to the build engine definition. This determines the # sequence of stages executed by the build engine, package # types to publish, and other miscellaneous aspects of the # build engine's runtime environment. # It will typically suffice to leave this on the default # setting engine = /etc/auto-build.d/engine/host-build.conf # If you want to use SELinux MAC, then uncomment this # and run with '/usr/bin/auto-build-secure' instead #engine = /etc/auto-build.d/engine/host-build-secure.conf # The location of the directory containing the template files # for the HTML status pages, and email alert messages templateDir = /etc/auto-build.d/templates # The directory under which the build engine will run. This # should match whatever path was provided when running the # 'auto-build-make-root' script. /var/lib/builder is the default # directory created by the RPM perl-Test-AutoBuild-account buildRoot = /var/lib/builder # A name for the build instance. This is used in the HTML # status pages, email alert subject, and RSS feeds label = Continous Automatic Builder # Name and email address of the build administrator adminEmail = admin@example.com adminName = Build Administrator # Name and email address of the development team writing the # software being built. Typically point it to the main developer # mailing list groupEmail = dev@example.com groupName = Build Developers # If the build host has multiple names, then specify which # one is used for the virtual host publishing the HTML status # pages. This will be used to construct links in the RSS feed # and email alert messages. If not set, defaults to the primary # hostname of the machine #hostname = example.com # The prefix under which the HTML status pages are located. # If using /etc/auto-build.d/httpd/aliased.conf, then #httpPrefix = /builder # Else with /etc/auto-build.d/httpd/user.conf, then #httpPrefix = /~builder # Finally with /etc/auto-build.d/httpd/vhost.conf, then httpPrefix = # Where to save a log of the build engine progress (this # data is also sent to STDERR, but when run from cron this # typically ends up in /dev/null) engineLogFile = /var/lib/builder/autobuild.log # The method used for acquiring a lock file to prevent multiple # build instances running at the same time against the same # buildRoot directory. # * fcntl - Best option, but only implemented for Linux, SunOS # and FreeBSD # * flock - Portable to any UNIX, but does not completely protect # if buildRoot is on an NFS volume # * file - Simple file creation/deletion test. If the build engine # or host machine crashes, it will be neccessary to manually # delete the lock file ($buildRoot/.build.mutex) lockMethod = fcntl # Define what high level features you want enabled features = { # If the cache is enabled, then modules will only be built if their # sources have changed since the previous build cycle. This provides # much faster cycle times if there are many modules in the build # config, only a few of which ever change cache = 1 # Whether to try and checkout the latest sources from version control # If checkout is disabled, the build will run with whatever sources # were checked out on the previous cycle. checkout = 1 # Whether to run the 'createrepo' tool against the RPMs on the HTTP # distribution site createrepo_index = 1 # Whether to run the 'yum-arch' tool against the RPMs on the HTTP # distribution site yum_index = 0 # Whether to generate an APT index of RPMs / Debian packages on the # HTTP distribution site apt_index = 0 # Whether to send email alerts at the end of cycles email_alerts = 1 } # Describe 'interesting' metadata about the build platform platform = { # Taken from /etc/issue, if not set #label = RHEL-4, Update 2 # Taken from uname(2) 'sysname' if not set #operating_system = GNU/Linux # Taken from uname(2) 'machine' if not set # architecture = i386 # Arbitrary administrator specific options... #options = { # compiler.cc = GCC 4.0.2 # linker = GNU ld 2.15.94.0.2.2 #} } # Criteria for sending email alerts alert = { # If the scope is set to # * builder - one email is sent with info on all modules # * module - one email is sent for each module scope = builder # Conditions for sending alerts # * always - send regardless of status # * fail - send whenever the status is 'failed' # * first-fail - send on the first failure only trigger = first-fail # If scope is set to 'builder' then # # * admin - use the global address defined for $adminEmail # * group - use the global address defined for $groupEmail # # If scope is set to 'module' then # # * admin - use the module specific address defined for $adminEmail # * group - use the module specific address defined for $groupEmail # # Or just set an explicit email address (separate multiple address with ,) to = group # What to set the 'From' address to #from = builder@example.com # The SMTP server to relay the mail via, defaults to localhost #smtpServer = mail.example.com } # Set the maximum disk space allowed for use by the cache maxCacheSize = 100M # Set the maximum number of days to keep a cache around before # considering it expired maxCacheAge = 7d # Module groups (for web status) groups = { software = { label = Software } autobuild = { label = Test-AutoBuild } # docs = { # label = Documentation # } } # Global environment variables which will be set whenever # any command is run by the build engine env = { USER = builder } # Define the source control repositories from which modules # will be checked out. There are 7 supported repository types # at this time. Depending on the 'type' parameter, various # 'env' or 'option' parameters may be required # # cvs - CVS. Specify the CVSROOT environment variable, and # optionally a CVS_RSH variable # # env = { # CVSROOT = :pserver:anonymous@cvs.gna.org:/cvs/testautobuild # } # # p4 - Perforce. Specify the P4CONFIG environment variable # for a client view. The viewspec will be filled in # automatically # # env = { # P4CONFIG = /var/lib/builder/.p4config # } # # tla - GNU Arch. Specify the 'archive-name' and 'archive-uri' # options for the remote repository. eg, # # options = { # archive-name = lord@emf.net--2004 # archive-uri = http://arch.quackerhead.com/~lord/archives/lord@emf.net--2004 # } # # hg - Mercurial. Specify the 'base-url' option to refer to # the base URL under which the repositories are located # # options = { # base-url = http://www.selenic.com/ # } # # git - Git. Specify the 'base-url' option to refer to # the base URL under which the repositories are located # # options = { # base-url = git://anongit.freedesktop.org/git/ # } # # darcs - Darcs. Specify the 'base-url' option to refer to # the base URL under which the repositories are located # # options = { # base-url = http://www.darcs.net/repos/ # } # # bzr - Bazaar. Specify the 'base-url' option to refer to # the base URL under which the repositories are located # # options = { # base-url = http://www.darcs.net/repos/ # } # # svn - Subversion. Specify the 'url' option to refer to the base # URL for the repository # # options = { # url = http://aplaws.redhat.com/svn/aplaws/ # } # # svk - SVK. No special options. The modules contain the full URL # # disk - Local disk. Specify the 'directory' otion to refer to the # base directory containing the files # # options = { # directory = /var/lib/builder/local-files # } # repositories = { gna-cvs = { label = GNA Anonymous CVS Server type = cvs env = { CVSROOT = :pserver:anonymous@cvs.gna.org:/cvs/testautobuild } } } # Now, the list of modules to checkout from the repositories # defined above. modules = { autobuild-dev = { # This is used in email alerts, HTML status pages & RSS feeds # to refer to the module label = Test AutoBuild Unstable # If different from global settings. These will be used if # the email alert scope is set to 'module' # #admin-email = autobuild-admin@example.com #admin-name = Module Administrator #group-email = autobuild-dev@example.com #group-name = Module Developers # The source code to check out source = { # Name of the repository defined above repository = gna-cvs # The path within the repository to be checked out path = testautobuild } # Any module specific environment variables to be set when # executing the module control file env = { HTMLURLPREFIX = /~builder/artifacts/autobuild-dev/apidocs } # List of groups (defined earlier) which this module is a # member of groups = ( autobuild software ) # Arbitrary list of hyperlinks to associate with this module # in the HTML status pages. Typically link to the module # developer web pages & source code browser links = ( { href = http://www.autobuild.org/ label = Homepage } { href = http://cvs.gna.org/viewcvs/testautobuild/testautobuild/ label = Browse CVS Repository } ) # List of artifacts generated during build which should be # published on the HTML pages. For example, code cover reports # API documentation. The 'src' parameter is relative to the # module's root source code directory. The 'dst' parameter is # the URL prefix under which to save the artifact. The optional # 'path' parameter is needed if there is no index file in the # directory copied. artifacts = ( { src = README dst = README label = Readme } { src = blib/coverage/* dst = coverage/ label = Code Test & POD coverage Reports } { src = blib/html/* dst = apidocs/ path = apidocs/Test/AutoBuild.html label = Module API documentation } ) } } # Optionally, the packages (RPMs, etc) generated during the # build can be built into an ISO image for distribution isos = { autobuild-unstable = { # File name for the ISO image name = autobuild-unstable.iso # Label to use in link for HTML status pages label = Test-AutoBuild Unstable # The package types to include in the ISO, can be # one or more of 'rpm', 'zip', 'debian' packageTypes = ( rpm zip ) # List of modules whose packages should be included # in the ISO modules = ( autobuild-dev ) } } # That's all folks! Config-Record-1.1.2/lib/0000755000076400007640000000000010727642245015057 5ustar berrangeberrangeConfig-Record-1.1.2/lib/Config/0000755000076400007640000000000010727642245016264 5ustar berrangeberrangeConfig-Record-1.1.2/lib/Config/Record.pod0000644000076400007640000001523610727642236020215 0ustar berrangeberrange=pod =head1 NAME Config::Record - Configuration file access =head1 SYNOPSIS use Config::Record; # Create an empty record & then load from file my $config = Config::Record->new(); $config->load("/etc/myapp.cfg"); # Create & load, then save to filename my $config = Config::Record->new(file => "/etc/myapp.cfg"); $config->save("/etc/myapp.cfg"); # Load / save from filehandle my $fh = IO::File->new("/etc/myapp.cfg"); my $config = Config::Record->new(file => $fh); $config->save($fh); # Get a config value, throw error if not found my $value = $config->get("foo"); # Get a config value, return 'eek' if not found my $value = $config->get("foo", "eek"); # Set a value $config->set("foobar", "wizz"); # Get a deep config value (ie nested hash) my $value = $config->get("foo/bar", "eek"); # Get first element of an array param my $value = $config->get("people/[0]/forename"); # Get the raw hash reference forming the record my $record = $config->record(); # Get a new config object rooted at a sub-hash my $config = $config->view("foo"); =head1 DESCRIPTION This module provides an API for loading and saving of simple configuration file records. Entries in the configuration file are essentially key,value pairs, with the key and values separated by a single equals symbol. The C consists only of alphanumeric characters. There are three types of values, scalar values can contain anything except newlines. Trailing whitespace will be trimmed unless the value is surrounded in double quotes. eg foo = Wizz foo = "Wizz.... " Long lines can be split with a backslash character, without introducing newlines. Without double quotes, whitespace at beginning and end of lines will be trimmed eg foo = This is a long \ line of text foo = "This is a long " \ "line of text" Multi-line strings can be provided as 'HERE' documents, eg foo = < per line, terminated by a single left round bracket. eg foo = ( Wizz "Wizz... " ) Hash values consist of a single right curly bracket, followed by one key,value pair per line, terminated by a single left curly bracket. eg foo = { one = Wizz two = "Wizz.... " } Arrays and hashes can be nested to arbitrary depth. =head1 EXAMPLE name = Foo title = "Wizz bang wallop" eek = ( OOhh Aahhh Wizz ) people = ( { forename = John surnamne = Doe } { forename = Some surname = One } ) wizz = { foo = "Elk" ooh = "fds" } =head1 EXTRA PARSER FEATURES The syntax described thus far is classed as the base feature set. By passing the C parameter when creating an instance of the C class, it is posible to turn on certain extra features =head2 QUOTED NON-ALPHANUMERIC KEYS The keys for configuration parameters are normally restricted to only contain the characters 'a-Z', '0-9', '_', '-' and '.'. Sometimes it is desirable to allow arbitrary characters for keys. If this capability is required then the C parameter can be set. =head3 EXAMPLE name = Foo title = "Wizz bang wallop" " some parameter " = ( foo bar } "an embeded \" quote" = bar "an embeded \\ backslash" = wizz =head2 EXTERNAL INCLUDE FILES With large configuration files it can be desirable to split them into a number of smaller files. If this capability is required, then the C feature can be requested. Each included file must follow the syntax rules already described. =head3 EXAMPLE In the main file name = Foo title = "Wizz bang wallop" foo = @include(somefile.cfg) And in somefile.cfg firstname = Joe lastname = Blogs Is equivalent to name = Foo title = "Wizz bang wallop" foo = { firstname = Joe lastname = Blogs } =head1 METHODS =over 4 =item my $config = Config::Record->new([file => $file], [features => \%features]); Creates a new config object, loading parameters from the file specified by the C parameter. The C parameter can either be a string representing a fully qualified filename, or a IO::Handle object. If the C parameter is a string, this filename will be saved and future calls to C or C are permitted to omit the filename. If the C parameter is not supplied then an empty configuration record is created. The C parameter allows extra parser features to be enabled. The two valid keys for the associated hash as C and C as described earlier in this document. =item $config->load([$file]); Loads and parses a configuration record. The C parameter can either be a string representing a fully qualified filename, or an IO::Handle object. The C<$file> parameter may be omitted, if a filename was specified in the constructor, or in previous calls to C or C. Prior to loading the record, the current contents of this configuration are cleared. =item $config->save([$file]); Saves the configuration record to a file. The C parameter can either be a string representing a fully qualified filename, or an IO::Handle object opened for writing. The C<$file> parameter may be omitted, if a filename was specified in the constructor, or in previous calls to C or C. =item my $value = $config->get($key[, $default]); Gets the value of a configuration parameter corresponding to the name C. If there is no value in the record, then the optional C is returned. =item $config->set($key, $value); Sets the value of a configuration parameter corresponding to the name C. =item $config->view($key) Return a new Config::Record object, rooted at the specified key. If the key doesn't resolve to a hash reference an error will be raised. =item my $record = $config->record(); Retrieves a hash reference for the entire configuration record. Currently this is the actual internal storage record, so changes will modify the configuration. In the next release this will be changed to be a deep clone of the internal storage record. =back =head1 BUGS Config::Record has the following limitations =over 4 =item * If you load and then save a configuration file all comments are removed & whitespace normalized. =item * Ordering of elements in hash ref are not preserved across load and save sequence =back These limitations may be fixed in a future release if there is demand from users... =head1 AUTHORS Daniel Berrange =head1 COPYRIGHT Copyright (C) 2000-2007 Daniel P. Berrange =head1 SEE ALSO C =cut Config-Record-1.1.2/lib/Config/Record.pm0000644000076400007640000004011110727642236020035 0ustar berrangeberrange# -*- perl -*- # # Config::Record by Daniel Berrange # # Copyright (C) 2000-2007 Daniel P. Berrange # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # $Id: Record.pm,v 1.12 2006/01/27 16:25:50 dan Exp $ package Config::Record; use strict; use warnings; use Carp qw(confess cluck); use IO::File; use warnings::register; use vars qw($VERSION); $VERSION = "1.1.2"; sub new { my $proto = shift; my $class = ref($proto) || $proto; my $self = {}; my %params = @_; $self->{record} = exists $params{record} ? $params{record} : {}; $self->{features} = exists $params{features} ? $params{features} : {}; $self->{debug} = $params{debug}; $self->{filename} = undef; bless $self, $class; if (defined $params{file}) { $self->load($params{file}); } return $self; } sub load { my $self = shift; my $file; if (@_) { $file = shift; } elsif ($self->{filename}) { $file = $self->{filename}; } else { die "no filename was specified"; } my $fh; if (ref($file)) { if (!$file->isa("IO::Handle")) { confess "file must be an instance of IO::Handle"; } $fh = $file; } else { $fh = IO::File->new($file) or confess "cannot read from $file: $!"; $self->{filename} = $file; } local $/ = undef; my $data = <$fh>; $self->{record} = $self->_parse($data, ref($file) ? "" : $file); $fh->close or confess "cannot close file: $!"; } sub _parse { my $self = shift; my $data = shift; my $filename = shift; my $value = {}; my @stack = $value; my $here; my $continuation; my $LABEL = '((?:\w|-|\.)+)'; # Hairy ! Escaping the escape chars really obscures the regex. # Need to allow any character except \ or " # unless they are written as \\ or \" my $QUOTED_LABEL = '((?:(?:[^"\\\])|(?:\\\\")|(?:\\\\\\\\))+)'; my $TRAILING_WHITESPACE = '\s*(?:\#.*)?'; my $lineno = 0; my @lines = split /\n/, $data; foreach my $line (@lines) { $lineno++; warn $lineno . ": '" . $line . "' here='" . (defined $here ? $here : '') . "' continue='" . (defined $continuation ? $continuation : '') . "'\n" if $self->{debug}; next if $line =~ m|^\s*#|; next if $line =~ m|^\s*$|; if ($here) { if ($line =~ /\s*${here}\s*$/) { # EOF warn "$lineno: End of here doc\n" if $self->{debug}; $here = undef; $continuation = undef; } else { # ... warn "$lineno: Middle of here doc\n" if $self->{debug}; ${$continuation} .= $line . "\n"; } } elsif ($continuation) { if ($line =~ /^\s*"(.*?)"\s*(\\)?\s*$/ || # "..." $line =~ /^\s*(.*?)\s*(\\)?\s*$/) { # ... warn "$lineno: Continuation\n" if $self->{debug}; ${$continuation} .= $1; $continuation = undef unless $2; } else { warn "$lineno: unexpected input '$line'\n"; } } else { if ($line =~ /^\s*$LABEL\s*=\s*\(${TRAILING_WHITESPACE}$/ || # foo = ( ($self->{features}->{quotedkeys} && $line =~ /^\s*"$QUOTED_LABEL"\s*=\s*\(${TRAILING_WHITESPACE}$/)) { # " foo " = ( warn "$lineno: Key '$1' with array\n" if $self->{debug}; if (ref($value) eq "ARRAY") { confess "unexpected key,value pair in $filename at line $lineno"; } my $key = $1; if ($self->{features}->{quotedkeys}) { $key =~ s,\\("|\\),$1,g; } my $new = []; $value->{$key} = $new; $value = $new; push @stack, $value; } elsif ($line =~ /^\s*\(${TRAILING_WHITESPACE}$/) { # ( warn "$lineno: Start of array\n" if $self->{debug}; if (ref($value) ne "ARRAY") { confess "unexpected array entry in $filename at line $lineno"; } my $new = []; push @{$value}, $new; $value = $new; push @stack, $value; } elsif ($line =~ /^\s*\)${TRAILING_WHITESPACE}$/) { # ) warn "$lineno: End of array\n" if $self->{debug}; if (ref($value) ne "ARRAY") { confess "mismatched closing round bracket in $filename at line $lineno"; } if ($#stack == 0) { confess "too many closing curley bracket in $filename at line $lineno"; } pop @stack; $value = $stack[$#stack]; } elsif ($line =~ /^\s*$LABEL\s*=\s*{${TRAILING_WHITESPACE}$/ || # foo = { ($self->{features}->{quotedkeys} && $line =~ /^\s*"$QUOTED_LABEL"\s*=\s*{${TRAILING_WHITESPACE}$/)) { # " foo " = { warn "$lineno: Key '$1' with hash\n" if $self->{debug}; if (ref($value) eq "ARRAY") { confess "unexpected key,value pair in $filename at line $lineno"; } my $key = $1; if ($self->{features}->{quotedkeys}) { $key =~ s,\\("|\\),$1,g; } my $new = {}; $value->{$key} = $new; $value = $new; push @stack, $value; } elsif ($line =~ /^\s*{${TRAILING_WHITESPACE}$/) { # { warn "$lineno: Start of hash\n" if $self->{debug}; if (ref($value) ne "ARRAY") { confess "unexpected array entry in $filename at line $lineno"; } my $new = {}; push @{$value}, $new; $value = $new; push @stack, $value; } elsif ($line =~ /^\s*}${TRAILING_WHITESPACE}$/) { # } warn "$lineno: End of hash\n" if $self->{debug}; if (ref($value) eq "ARRAY") { confess "mismatched closing curly bracket in $filename at line $lineno"; } if ($#stack == 0) { confess "too many closing curley bracket in $filename at line $lineno"; } pop @stack; $value = $stack[$#stack]; } elsif ($self->{features}->{includes} && ($line =~ /^\s*$LABEL\s*=\s*\@include\((.+)\)${TRAILING_WHITESPACE}$/ || # foo = @include(filename) ($self->{features}->{quotedkeys} && $line =~ /^\s*"$QUOTED_LABEL"\s*=\s*\@include\((.+)\)${TRAILING_WHITESPACE}$/))) { # " foo " = @include(filename) warn "$lineno: Include file\n" if $self->{debug}; my $key = $1; my $file = $2; if ($self->{features}->{quotedkeys}) { $key =~ s,\\("|\\),$1,g; } my $fh = IO::File->new($file) or confess "cannot read from $file: $!"; local $/ = undef; my $data = <$fh>; my $record = $self->_parse($data, ref($file) ? "" : $file); $fh->close or confess "cannot close file: $!"; $value->{$key} = $record; } elsif ($line =~ /^\s*$LABEL\s*=\s*<<(\w+)\s*$/ || # foo = <{features}->{quotedkeys} && $line =~ /^\s*"$QUOTED_LABEL"\s*=\s*<<(\w+)\s*$/)) { # " foo " = <{debug}; my $key = $1; my $val = ""; if ($self->{features}->{quotedkeys}) { $key =~ s,\\("|\\),$1,g; } $value->{$key} = $val; $here = $2; $continuation = \$value->{$key}; } elsif ($line =~ /^\s*$LABEL\s*=\s*"(.*)"\s*(\\)?${TRAILING_WHITESPACE}$/ || # foo = "..." ($self->{features}->{quotedkeys} && $line =~ /^\s*"$QUOTED_LABEL"\s*=\s*"(.*)"\s*(\\)?${TRAILING_WHITESPACE}$/) || # " foo " = "..." $line =~ /^\s*$LABEL\s*=\s*(.*?)(\\)?\s*$/ || # foo = ... ($self->{features}->{quotedkeys} && $line =~ /^\s*"$QUOTED_LABEL"\s*=\s*(.*?)(\\)?\s*$/)) { # " foo " = ... warn "$lineno: Key '$1' with string\n" if $self->{debug}; my $key = $1; my $val = $2; if ($self->{features}->{quotedkeys}) { $key =~ s,\\("|\\),$1,g; } if (ref($value) eq "ARRAY") { confess "expecting value, found key, value pair at line $lineno"; } $value->{$key} = $val; warn "$lineno: Start continuation\n" if $3 && $self->{debug}; $continuation = \$value->{$key} if $3; } elsif ($line =~ /^\s*<<(\w+)\s*$/) { # <{debug}; my $val = ""; if (ref($value) ne "ARRAY") { confess "expecting key,value pair, found value at line $lineno"; } push @{$value}, $val; $here = $1; $continuation = \$value->[$#{$value}]; } elsif ($self->{features}->{includes} && ($line =~ /^\s*\@include\((.+)\)${TRAILING_WHITESPACE}$/)) { # @include(filename) warn "$lineno: Include file\n" if $self->{debug}; my $file = $1; my $fh = IO::File->new($file) or confess "cannot read from $file: $!"; local $/ = undef; my $data = <$fh>; my $record = $self->_parse($data, ref($file) ? "" : $file); $fh->close or confess "cannot close file: $!"; if (ref($value) ne "ARRAY") { confess "expecting key,value pair, found value at line $lineno"; } push @{$value}, $record; } elsif ($line =~ /^\s*"(.*)"\s*(\\)?${TRAILING_WHITESPACE}$/ || # "..." $line =~ /^\s*(.*?)(\\)?\s*$/) { # ... warn "$lineno: Value\n" if $self->{debug}; my $val = $1; if (ref($value) ne "ARRAY") { confess "expecting key,value pair, found value at line $lineno"; } push @{$value}, $val; $continuation = \$value->[$#{$value}] if $2; } else { warn "Unexpected value '$line'\n"; } } } if ($#stack != 0) { confess "missing closing bracket in $filename at line $lineno"; } return $stack[$#stack]; } sub save { my $self = shift; my $file; if (@_) { $file = shift; } elsif ($self->{filename}) { $file = $self->{filename}; } else { die "no filename was specified"; } my $fh; if (ref($file)) { if (!$file->isa("IO::Handle")) { confess "file must be an instance of IO::Handle"; } $fh = $file; } else { $fh = IO::File->new(">$file") or confess "cannot write to $file: $!"; $self->{filename} = $file; } foreach my $key (keys %{$self->{record}}) { print $fh $self->_format_key($key), " = "; $self->_format($fh, $self->{record}->{$key}, ""); } $fh->close(); } sub _format { my $self = shift; my $fh = shift; my $value = shift; my $indent = shift; my $ref = ref($value); if ($ref) { if ($ref eq "HASH") { $self->_format_hash($fh, $value, $indent); } elsif ($ref eq "ARRAY") { $self->_format_array($fh, $value, $indent); } else { confess "unhandled reference $ref. Configuration files" . "can only contain unblessed scalars, array or hash references"; } } else { $self->_format_scalar($fh, $value, $indent); } } sub _format_hash { my $self = shift; my $fh = shift; my $record = shift; my $indent = shift; print $fh "{\n"; foreach my $key (keys %{$record}) { print $fh "$indent ", $self->_format_key($key), " = "; $self->_format($fh, $record->{$key}, "$indent "); } print $fh "$indent}\n"; } sub _format_array { my $self = shift; my $fh = shift; my $list = shift; my $indent = shift; print $fh "(\n"; foreach my $element (@{$list}) { print $fh "$indent "; $self->_format($fh, $element, "$indent "); } print $fh "$indent)\n"; } sub _format_scalar { my $self = shift; my $fh = shift; my $value = shift; my $indent = shift; if ($value =~ /\n/) { $value .= "\n" unless $value =~ /\n$/; print $fh "<{features}->{quotedkeys}) { if ($key =~ /^((?:\w|-|\.)+)$/) { return $key; } else { $key =~ s/\\/\\\\/g; $key =~ s/"/\\"/g; return '"' . $key . '"'; } } else { return $key; } } sub view { my $self = shift; my $key = shift; my $value = $self->get($key, @_); if (!ref($value) || ref($value) ne "HASH") { confess "value for $key is not a hash"; } return $self->new(record => $value, debug => $self->{debug}, features => $self->{features}); } sub get { my $self = shift; my $key = shift; my @key; warn "Key: '" . $key . "'\n" if $self->{debug}; foreach (split /((? '" . $_ . "'\n" if $self->{debug}; push @key, $_; } my $entry = $self->{record}; my $context; foreach my $fragment (@key) { $context = defined $context ? $context . "/" . $fragment : $fragment; if ($fragment =~ /^\[(\d+)\]$/) { my $index = $1; if (ref($entry) ne "ARRAY") { if (@_) { return shift; } confess "cannot find array value at '$context' for parameter '$key'"; } if ($#{$entry} < $index) { if (@_) { return shift; } confess "cannot find array value at '$context' for parameter '$key'"; } $entry = $entry->[$index]; } elsif ($self->{features}->{quotedkeys}) { $fragment =~ s/\\(\[|\]|\/|\\)/$1/g; warn "Quote '$fragment'\n" if $self->{debug}; if (ref($entry) ne "HASH") { if (@_) { return shift; } confess "cannot find hash value at '$context' for parameter '$key'"; } if (!exists $entry->{$fragment}) { if (@_) { return shift; } confess "cannot find hash value at '$context' for parameter '$key'"; } $entry = $entry->{$fragment}; } else { warn "NonQuote '$fragment'\n" if $self->{debug}; if ($fragment =~ /((?:\w|-|\.)+)/) { if (ref($entry) ne "HASH") { if (@_) { return shift; } confess "cannot find hash value at '$context' for parameter '$key'"; } if (!exists $entry->{$fragment}) { if (@_) { return shift; } confess "cannot find hash value at '$context' for parameter '$key'"; } $entry = $entry->{$fragment}; } else { confess "fragment '$fragment' should be alphanumeric, or an array index"; } } } return $entry; } sub set { my $self = shift; my $key = shift; my $value = shift; my @key; warn "Key: '" . $key . "'\n" if $self->{debug}; foreach (split /((? '" . $_ . "'\n" if $self->{debug}; push @key, $_; } my $entry = $self->{record}; my $context; while (defined (my $fragment = shift @key)) { $context = defined $context ? $context . "/" . $fragment : $fragment; if ($fragment =~ /^\[(\d+)\]$/) { my $index = $1; if (ref($entry) ne "ARRAY") { confess "cannot find array value at $context for parameter $key"; } if (@key) { if (exists $entry->[$index]) { $entry = $entry->[$index]; } else { if ($key[0] =~ /^\[(\d+)\]$/) { $entry->[$index] = []; } else { $entry->[$index] = {}; } $entry = $entry->[$index]; } } else { $entry->[$index] = $value; } } elsif ($self->{features}->{quotedkeys}) { $fragment =~ s/\\(\[|\]|\/|\\)/$1/g; warn "Quote '$fragment'\n" if $self->{debug}; if (ref($entry) ne "HASH") { confess "cannot find hash value at $context for parameter $key"; } if (@key) { if (exists $entry->{$fragment}) { $entry = $entry->{$fragment}; } else { if ($key[0] =~ /^\[(\d+)\]$/) { $entry->{$fragment} = []; } else { $entry->{$fragment} = {}; } $entry = $entry->[$fragment]; } } else { $entry->{$fragment} = $value; } } else { warn "NonQuote '$fragment'\n" if $self->{debug}; if ($fragment =~ /((?:\w|-|\.)+)/) { if (ref($entry) ne "HASH") { confess "cannot find hash value at $context for parameter $key"; } if (@key) { if (exists $entry->{$fragment}) { $entry = $entry->{$fragment}; } else { if ($key[0] =~ /^\[(\d+)\]$/) { $entry->{$fragment} = []; } else { $entry->{$fragment} = {}; } $entry = $entry->[$fragment]; } } else { $entry->{$fragment} = $value; } } else { confess "fragment '$fragment' should be alphanumeric, or an array index"; } } } } sub record { my $self = shift; return $self->{record}; } 1 # So that the require or use succeeds. Config-Record-1.1.2/MANIFEST.SKIP0000644000076400007640000000027210727642236016210 0ustar berrangeberrangepm_to_blib Config-Record- blib .*\.bak CVS .cvsignore .*~ .#.* #.* ^Makefile$ build-stamp debian/files debian/libconfig-record-perl.* cover_db ^.hg/ ^.hgtags ^.hgignore .*\.orig .*\.rej Config-Record-1.1.2/README0000644000076400007640000000072110727642236015171 0ustar berrangeberrangeConfig::Record - Simple configuration records --------------------------------------------- Config::Record provides a module for loading configuration records. It supports scalar, array and hash parameters nested to an arbitrary depth. See the manual page for Config::Record for details and example usage. Feedback, bug reports, patches ------------------------------ Please send patches in unified diff format to: Daniel Berrange -- End Config-Record-1.1.2/debian/0000755000076400007640000000000010727642245015533 5ustar berrangeberrangeConfig-Record-1.1.2/debian/rules0000755000076400007640000000334710727642236016622 0ustar berrangeberrange#!/usr/bin/make -f #-*- makefile -*- # Made with the aid of dh_make, by Craig Small # Sample debian/rules that uses debhelper. GNU copyright 1997 by Joey Hess. # Some lines taken from debmake, by Christoph Lameter. # Uncomment this to turn on verbose mode. #export DH_VERBOSE=1 export DH_COMPAT=3 PACKAGE=$(shell dh_listpackages) ifndef PERL PERL = /usr/bin/perl endif ifndef DESTDIR DESTDIR=.. endif TMP =`pwd`/debian/$(PACKAGE) build: build-stamp build-stamp: dh_testdir # Add here commands to compile the package. $(PERL) Makefile.PL INSTALLDIRS=vendor $(MAKE) OPTIMIZE="-O2 -g -Wall" touch build-stamp clean: dh_testdir dh_testroot rm -f build-stamp # Add here commands to clean up after the build process. -$(MAKE) realclean dh_clean install: dh_testdir dh_testroot dh_clean -k dh_installdirs # Add here commands to install the package into debian/tmp. #$(MAKE) install DESTDIR=`pwd`/debian/tmp $(MAKE) install PREFIX=$(TMP)/usr # Build architecture-independent files here. binary-indep: build install # We have nothing to do by default. # Build architecture-dependent files here. binary-arch: build install # dh_testversion dh_testdir dh_testroot dh_installdocs README dh_installexamples dh_installmenu # dh_installemacsen # dh_installinit dh_installcron dh_installman # dh_undocumented dh_installchangelogs CHANGES dh_link dh_strip dh_compress dh_fixperms # dh_makeshlibs dh_installdeb dh_perl dh_shlibdeps dh_gencontrol dh_md5sums dh_builddeb --destdir=$(DESTDIR) source diff: @echo >&2 'source and diff are obsolete - use dpkg-source -b'; false binary: binary-indep binary-arch .PHONY: build clean binary-indep binary-arch binary Config-Record-1.1.2/debian/changelog0000644000076400007640000000030310727642236017401 0ustar berrangeberrangelibconfig-record-perl (1.0.2-1) unstable; urgency=low * Initial Release. -- Daniel Berrange Wed, 7 Apr 2004 12:12:48 +0100 Local variables: mode: debian-changelog End: Config-Record-1.1.2/debian/README.Debian0000644000076400007640000000020310727642236017567 0ustar berrangeberrangeThis is the debian package for the Config::Record module. It was created by Daniel Berrange using dh-make-perl. Config-Record-1.1.2/debian/copyright0000644000076400007640000004345410727642236017500 0ustar berrangeberrangeThis copyright info was automatically extracted from the perl module. It may not be accurate, so you better check the module sources if don't want to get into legal troubles. The upstream author is: Daniel Berrange . GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 675 Mass Ave, Cambridge, MA 02139, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "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 PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. 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 PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (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 PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS Appendix: How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19yy name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. Config-Record-1.1.2/debian/control0000644000076400007640000000165110727642236017141 0ustar berrangeberrangeSource: libconfig-record-perl Section: interpreters Priority: optional Build-Depends: debhelper (>= 3.0.5), perl (>= 5.6.0-17) Maintainer: Daniel Berrange Standards-Version: 3.5.1 Package: libconfig-record-perl Architecture: all Depends: ${perl:Depends} Description: loading of configuration records This module provides for loading and saving of simple configuration file records. Entries in the configuration file are essentially key,value pairs, with the key and values separated by a single equals symbol. The key consists only of alphanumeric characters. There are three types of values, scalar values can contain anything except newlines. Trailing whitespace will be trimmed unless the value is surrounded in double quotes. eg . foo = Wizz foo = "Wizz.... " . Array values consist of a single right round bracket, following by one value per line, terminated by a single left round bracket. eg Config-Record-1.1.2/META.yml.PL0000644000076400007640000000226610727642236016102 0ustar berrangeberrange# Copyright (C) 2001-2007 Daniel Berrange use strict; use warnings; die unless (scalar @ARGV == 1); unless (do "lib/Config/Record.pm") { if ($@) { die $@ } die "lib/Config/Record.pm: $!" } local $/ = undef; $_ = ; s/\@VERSION\@/$Config::Record::VERSION/g; open YML, ">$ARGV[0]" or die "$!"; print YML $_; close YML; __DATA__ --- #YAML:1.0 name: Config-Record abstract: Configuration file access version: @VERSION@ author: - Daniel P. Berrange license: gpl generated_by: ExtUtils::MakeMaker version 6.30 requires: Carp: 0 IO::File: 0 build_requires: Test::More: 0 File::Temp: 0 Test::Pod: 0 Test::Pod::Coverage: 0 resources: license: http://www.gnu.org/licenses/gpl.html homepage: http://autobuild.org/ bugtracker: https://gna.org/bugs/?group=testautobuild repository: https://gna.org/cvs/?group=testautobuild MailingList: https://gna.org/mail/?group=testautobuild distribution_type: module meta-spec: version: 1.3 url: http://module-build.sourceforge.net/META-spec-v1.3.html Config-Record-1.1.2/LICENSE0000644000076400007640000004307610727642236015330 0ustar berrangeberrange GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 675 Mass Ave, Cambridge, MA 02139, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "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 PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. 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 PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (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 PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS Appendix: How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19yy name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. Config-Record-1.1.2/AUTHORS0000644000076400007640000000025210727642236015360 0ustar berrangeberrangeAUTHORS ------- Config::Record was originally written by Daniel Berrange The following people have also contributed: -- End Config-Record-1.1.2/CHANGES0000644000076400007640000000542510727642236015312 0ustar berrangeberrangeChange Log for Config::Record ============================= v1.1.2 (on 11-12-2007) ---------------------- This is a minor feature enhancement release with no backwards compatability breakage * Added support for including files via @include() tag * Added support for keys containing characters outside a-Z0-9, by quoting the keys * Remove non-portable Makefile testing cruft v1.1.1 (on 04-06-2006) ---------------------- This is a minor cleanup release with no backwards compatability breakage * Fixed POD comments * Added tests for POD comments & coverage * Allow a filename to be passed into save/load methods * Make RPM specfile install into vendor dirs, rather than site v1.1.0 (on 09-03-2005) ---------------------- This is a new major release since it breaks backwards compatability with 1.0.x series for compound keys. * Allow keys in config files to contain periods. * Change syntax for retrieving nested values from being period separated to be slash separated. eg, instead of $cfg->get("foo.bar"), use $cfg->get("foo/bar"); * Add support for selecting specific elements in an array with $cfg->get("foo/[0]"); * Add support for creating a view on a subset of the configuration record * Increased test coverage to hit 83% of statements, 64% of branches, 76% of conditionals, and 100% of subroutines. v1.0.5 (on 10-10-2004) ---------------------- * Fixed dumb mistake which would cause processing of configuration file to stop when encountering a blank line. v1.0.4 (on 26-09-2004) ---------------------- * Allow comments at the end of lines following a quoted string, an open/close bracket, an open/close brace * Allow long lines to be split with \ to break lines * Allow multi-line strings to be input using < "Config::Record", VERSION_FROM => 'lib/Config/Record.pm', AUTHOR => "Daniel P. Berrange (dan[at]berrange[dot]com)", dist => { COMPRESS => 'gzip --force --best', }, clean => { FILES => '*.bak *~', }, NO_META => 1, depend => { Makefile => '$(VERSION_FROM)', dist => 'Config-Record.spec META.yml', }, realclean => { FILES => 'Config-Record-*.tar.gz Config-Record.spec META.yml', } ); package MY; sub libscan { my ($self, $path) = @_; ($path =~ /\~$/) ? undef : $path; } __END__ Config-Record-1.1.2/t/0000755000076400007640000000000010727642245014554 5ustar berrangeberrangeConfig-Record-1.1.2/t/007-config-includes.t0000644000076400007640000000330410727642236020316 0ustar berrangeberrange# -*- perl -*- $Id: 005Config.t,v 1.8 2006/01/27 16:25:50 dan Exp $ use Test::More tests => 6; BEGIN { use_ok("Config::Record") } #$| = undef; use strict; use warnings; use Carp qw(confess); use Test::Harness; use File::Temp qw(tempfile); use IO::File; my ($fh, $file) = tempfile("tmpXXXXXXX", UNLINK => 1); my ($subfh1, $subfile1) = tempfile("tmpXXXXXXX", UNLINK => 1); my ($subfh2, $subfile2) = tempfile("tmpXXXXXXX", UNLINK => 1); my ($subfh3, $subfile3) = tempfile("tmpXXXXXXX", UNLINK => 1); my $config = <new(file => $file, features => { includes => 1 }, debug => ($ENV{TEST_DEBUG} || 0)); # Test nested hash/array lookups ok(defined $cfg->get("wibble/nice"), "Hash key defined"); ok(defined $cfg->get("wibble/nice/ooh"), "Hash, hash key defined"); ok($cfg->get("wibble/nice/ooh", ["oooh"])->[0] eq "weee", "Hash, hash, array value"); is_deeply($cfg->get("staff/[0]"), { firstname => "Joe", lastname => "Bloggs" }, "First person"); is_deeply($cfg->get("staff/[1]"), { firstname => "John", lastname => "Doe" }, "First person"); exit 0; # Local Variables: # mode: cperl # End: Config-Record-1.1.2/t/005-config-plain.t0000644000076400007640000001574510727642236017625 0ustar berrangeberrange# -*- perl -*- $Id: 005Config.t,v 1.8 2006/01/27 16:25:50 dan Exp $ use Test::More tests => 57; BEGIN { use_ok("Config::Record") } #$| = undef; use strict; use warnings; use Carp qw(confess); use File::Temp qw(tempfile); use IO::File; my $config = < 1); print $fh $config; close $fh; # First test the constructor with a filename my $cfg = Config::Record->new(file => $file, debug => ($ENV{TEST_DEBUG} || 0)); # Test plain string is($cfg->get("name"), "Foo", "Plain string"); # Test quoted string is($cfg->get("title"), "Wizz bang wallop", "Quoted string"); # Test continuation is($cfg->get("label"), "First string split across", "Continuation"); # Test here doc is($cfg->get("description"), <get("eek")->[2], "Wizz Bang", "Continuation"); # Test array here doc is($cfg->get("eek")->[3], "A long paragraph in\nhere\n", "Here doc"); # Test defaults is($cfg->get("nada", "eek"), "eek", "Defaults"); # Test nested hash/array lookups ok(defined $cfg->get("wibble/nice"), "Hash key defined"); ok(defined $cfg->get("wibble/nice/ooh"), "Hash, hash key defined"); ok($cfg->get("wibble/nice/ooh", ["oooh"])->[0] eq "weee", "Hash, hash, array value"); # Now test the constructor with a file handle $fh = IO::File->new($file); $cfg = Config::Record->new(file => $fh); # Test plain string is($cfg->get("name"), "Foo", "Plain string"); # Test quoted string is($cfg->get("title"), "Wizz bang wallop", "Quoted string"); # Test continuation is($cfg->get("label"), "First string split across", "Continuation"); # Test here doc is($cfg->get("description"), <get("eek")->[2], "Wizz Bang", "Continuation"); # Test array here doc is($cfg->get("eek")->[3], "A long paragraph in\nhere\n", "Here doc"); # Test defaults is($cfg->get("nada", "eek"), "eek", "Defaults"); # Test nested hash/array lookups ok(defined $cfg->get("wibble/nice"), "Hash key defined"); ok(defined $cfg->get("wibble/nice/ooh"), "Hash, hash key defined"); ok($cfg->get("wibble/nice/ooh", ["oooh"])->[0] eq "weee", "Hash, hash, array value"); ok(ref($cfg->get("people/[0]")) eq "HASH", "people/[0] is a hash"); is($cfg->get("people/[0]/forename"), "John", "First person forename is John"); is($cfg->get("people/[1]/forename"), "Some", "Second person forename is Some"); eval { $cfg->get("people/[2]/forename"); }; ok($@, "too many people"); $cfg->set("people/[2]", { "forename" => "Bob", "surname" => "Man" }); ok(ref($cfg->get("people/[2]")) eq "HASH", "people/[2] is a hash"); is($cfg->get("people/[2]/forename"), "Bob", "Third person forename is Bob"); eval { # Root element should be a hash! $cfg->get("[0]"); }; ok($@, "root should be a hash"); # Now lets get a view my $subcfg = $cfg->view("people/[2]"); is($subcfg->get("forename"), "Bob", "Got forename from view"); is($subcfg->get("surname"), "Man", "Got surname from view"); $subcfg->set("address", [{ "street" => "Long road", "phone" => [ "123", "456", ], "city" => "London" }, { "street" => "Other road", "phone" => [ "513", ], "city" => "London" }]); is($subcfg->get("address/[0]/street"), "Long road", "Street is long road"); is($subcfg->get("address/[0]/phone/[0]"), "123", "First phone number is 123"); is($subcfg->get("address/[1]/street"), "Other road", "Street is other road"); # Check the original config was altered too is($cfg->get("people/[2]/address/[0]/street"), "Long road", "Street is long road"); is($cfg->get("people/[2]/address/[0]/phone/[0]"), "123", "First phone number is 123"); is($cfg->get("people/[2]/address/[1]/street"), "Other road", "Street is other road"); # Now test a view or two that fail eval { $cfg->view("people"); }; ok($@, "getting view of people failed"); eval { $cfg->view("people/[1]/forename"); }; ok($@, "getting view of people/[1]/forename failed"); # Test with empty constructor & load method $cfg = Config::Record->new(); # Shouldn't be anything there yet eval "$cfg->get('name')"; ok($@ ? 1 : 0, "No defaults"); # Lets set an option $cfg->set("name" => "Blah"); is($cfg->get("name"), "Blah", "Set option"); # Now load the config record $fh = IO::File->new($file); $cfg->load($fh); # Test plain string - should have overwritten 'Blah' is($cfg->get("name"), "Foo", "Reload plain string"); # Test quoted string is($cfg->get("title"), "Wizz bang wallop", "Reloaded quoted string"); # Test defaults is($cfg->get("nada", "eek"), "eek", "Reloaded defaults"); # Test compound paths is($cfg->get("wizz/foo"), "Elk", "Compound paths"); # Test '.' in key names is($cfg->get("wizz/eek.wibble"), "Hurrah", "Compound paths with ."); # Now write it out to another file.... my ($fh2, $file2) = tempfile("tmpXXXXXXX", UNLINK => 1); $fh2->close; $cfg->save($file2); # ...and then read it back in my $cfg2 = Config::Record->new(file => $file2); # Test plain string is($cfg2->get("name"), "Foo", "Saved plain string"); # Test quoted string is($cfg2->get("title"), "Wizz bang wallop", "Saved quoted string"); # Test continuation is($cfg->get("label"), "First string split across", "Continuation"); # Test here doc is($cfg->get("description"), <get("eek")->[2], "Wizz Bang", "Continuation"); # Test array here doc is($cfg->get("eek")->[3], "A long paragraph in\nhere\n", "Here doc"); # Test defaults is($cfg2->get("nada", "eek"), "eek", "Saved defaults"); # Test nested hash/array lookups ok(defined $cfg2->get("wibble/nice"), "Hash key defined"); ok(defined $cfg2->get("wibble/nice/ooh"), "Hash, hash key defined"); ok($cfg2->get("wibble/nice/ooh", ["oooh"])->[0] eq "weee", "Hash, hash, array value"); # Now recursively compare entire hash is_deeply($cfg->record, $cfg2->record, "Entire hash"); # Finally test the constructor with bogus ref my $bogus = {}; bless $bogus, "Bogus"; eval "Config::Record->new(file => $bogus)"; ok($@ ? 1 : 0, "Bogus constructor"); exit 0; # Local Variables: # mode: cperl # End: Config-Record-1.1.2/t/010-pod.t0000644000076400007640000000023310727642236016017 0ustar berrangeberrangeuse Test::More; use strict; use warnings; eval "use Test::Pod 1.00"; plan skip_all => "Test::Pod 1.00 required for testing POD" if $@; all_pod_files_ok(); Config-Record-1.1.2/t/006-config-quoted.t0000644000076400007640000002150510727642236020013 0ustar berrangeberrange# -*- perl -*- $Id: 005Config.t,v 1.8 2006/01/27 16:25:50 dan Exp $ use Test::More tests => 68; BEGIN { use_ok("Config::Record") } #$| = undef; use strict; use warnings; use Carp qw(confess); use Test::Harness; use File::Temp qw(tempfile); use IO::File; my $config = < 1); print $fh $config; close $fh; # First test the constructor with a filename my $cfg = Config::Record->new(file => $file, debug => $ENV{TEST_DEBUG}, features => {quotedkeys => 1 }); # Test plain string is($cfg->get("name"), "Foo", "Plain string"); # Test quoted string is($cfg->get("title"), "Wizz bang wallop", "Quoted string"); # Test continuation is($cfg->get("label"), "First string split across", "Continuation"); # Test here doc is($cfg->get("description"), <get("eek")->[2], "Wizz Bang", "Continuation"); # Test array here doc is($cfg->get("eek")->[3], "A long paragraph in\nhere\n", "Here doc"); # Test defaults is($cfg->get("nada", "eek"), "eek", "Defaults"); # Test nested hash/array lookups ok(defined $cfg->get("wibble/nice"), "Hash key defined"); ok(defined $cfg->get("wibble/nice/ooh"), "Hash, hash key defined"); ok($cfg->get("wibble/nice/ooh", ["oooh"])->[0] eq "weee", "Hash, hash, array value"); # Now test the constructor with a file handle $fh = IO::File->new($file); $cfg = Config::Record->new(file => $fh, debug => $ENV{TEST_DEBUG}, features => {quotedkeys => 1}); # Test plain string is($cfg->get("name"), "Foo", "Plain string"); # Test quoted string is($cfg->get("title"), "Wizz bang wallop", "Quoted string"); # Test continuation is($cfg->get("label"), "First string split across", "Continuation"); # Test here doc is($cfg->get("description"), <get("eek")->[2], "Wizz Bang", "Continuation"); # Test array here doc is($cfg->get("eek")->[3], "A long paragraph in\nhere\n", "Here doc"); # Test defaults is($cfg->get("nada", "eek"), "eek", "Defaults"); # Test nested hash/array lookups ok(defined $cfg->get("wibble/nice"), "Hash key defined"); ok(defined $cfg->get("wibble/nice/ooh"), "Hash, hash key defined"); ok($cfg->get("wibble/nice/ooh", ["oooh"])->[0] eq "weee", "Hash, hash, array value"); ok(ref($cfg->get("people/[0]")) eq "HASH", "people/[0] is a hash"); is($cfg->get("people/[0]/forename"), "John", "First person forename is John"); is($cfg->get("people/[1]/forename"), "Some", "Second person forename is Some"); eval { $cfg->get("people/[2]/forename"); }; ok($@, "too many people"); $cfg->set("people/[2]", { "forename" => "Bob", "surname" => "Man" }); ok(ref($cfg->get("people/[2]")) eq "HASH", "people/[2] is a hash"); is($cfg->get("people/[2]/forename"), "Bob", "Third person forename is Bob"); eval { # Root element should be a hash! $cfg->get("[0]"); }; ok($@, "root should be a hash"); # Test keys with spaces in them is($cfg->get(' quoted one '), "wizz", "Quoted key + value"); is($cfg->get(' quoted \ two '), " wizz ", "Quoted key + value"); is_deeply($cfg->get('quoted " three'), ["yeah"], "Quoted key + array"); is_deeply($cfg->get('quoted \" four'), {"ooh" => "ahh" }, "Quoted key + hash with spaces"); # Testing keys with / and [] in them is($cfg->get('quoted " five/\\[0\\]/'), "notarray", "Special path chars one"); is($cfg->get('quoted " five/data/[0]/sub1\\/key'), "hello", "Special path chars two"); is($cfg->get('quoted " five/data/[0]/sub2\\\\/key'), "world", "Special path chars three"); is($cfg->get('quoted " five/data/[1]'), "wizz", "Special path chars four"); is($cfg->get('quoted " five/data/[2]/here [2] key/[0]'), "one", "Special path chars five"); is($cfg->get('quoted " five/data/[2]/here [2] key/[1]'), "two", "Special path chars six"); is_deeply($cfg->get('quoted " five/other \\\\/'), {"sub" => "one"}, "Special path chars seven"); # Now lets get a view my $subcfg = $cfg->view("people/[2]"); is($subcfg->get("forename"), "Bob", "Got forename from view"); is($subcfg->get("surname"), "Man", "Got surname from view"); $subcfg->set("address", [{ "street" => "Long road", "phone" => [ "123", "456", ], "city" => "London" }, { "street" => "Other road", "phone" => [ "513", ], "city" => "London" }]); is($subcfg->get("address/[0]/street"), "Long road", "Street is long road"); is($subcfg->get("address/[0]/phone/[0]"), "123", "First phone number is 123"); is($subcfg->get("address/[1]/street"), "Other road", "Street is other road"); # Check the original config was altered too is($cfg->get("people/[2]/address/[0]/street"), "Long road", "Street is long road"); is($cfg->get("people/[2]/address/[0]/phone/[0]"), "123", "First phone number is 123"); is($cfg->get("people/[2]/address/[1]/street"), "Other road", "Street is other road"); # Now test a view or two that fail eval { $cfg->view("people"); }; ok($@, "getting view of people failed"); eval { $cfg->view("people/[1]/forename"); }; ok($@, "getting view of people/[1]/forename failed"); # Test with empty constructor & load method $cfg = Config::Record->new(debug => $ENV{TEST_DEBUG}, features => {quotedkeys => 1}); # Shouldn't be anything there yet eval "$cfg->get('name')"; ok($@ ? 1 : 0, "No defaults"); # Lets set an option $cfg->set("name" => "Blah"); is($cfg->get("name"), "Blah", "Set option"); # Now load the config record $fh = IO::File->new($file); $cfg->load($fh); # Test plain string - should have overwritten 'Blah' is($cfg->get("name"), "Foo", "Reload plain string"); # Test quoted string is($cfg->get("title"), "Wizz bang wallop", "Reloaded quoted string"); # Test defaults is($cfg->get("nada", "eek"), "eek", "Reloaded defaults"); # Test compound paths is($cfg->get("wizz/foo"), "Elk", "Compound paths"); # Test '.' in key names is($cfg->get("wizz/eek.wibble"), "Hurrah", "Compound paths with ."); # Now write it out to another file.... my ($fh2, $file2) = tempfile("tmpXXXXXXX", UNLINK => 1); $fh2->close; $cfg->save($file2); # ...and then read it back in my $cfg2 = Config::Record->new(debug => $ENV{TEST_DEBUG}, file => $file2, features => {quotedkeys => 1}); # Test plain string is($cfg2->get("name"), "Foo", "Saved plain string"); # Test quoted string is($cfg2->get("title"), "Wizz bang wallop", "Saved quoted string"); # Test continuation is($cfg->get("label"), "First string split across", "Continuation"); # Test here doc is($cfg->get("description"), <get("eek")->[2], "Wizz Bang", "Continuation"); # Test array here doc is($cfg->get("eek")->[3], "A long paragraph in\nhere\n", "Here doc"); # Test defaults is($cfg2->get("nada", "eek"), "eek", "Saved defaults"); # Test nested hash/array lookups ok(defined $cfg2->get("wibble/nice"), "Hash key defined"); ok(defined $cfg2->get("wibble/nice/ooh"), "Hash, hash key defined"); ok($cfg2->get("wibble/nice/ooh", ["oooh"])->[0] eq "weee", "Hash, hash, array value"); # Now recursively compare entire hash use Data::Dumper; #warn Dumper($cfg->record); #warn Dumper($cfg2->record); is_deeply($cfg->record, $cfg2->record, "Entire hash"); # Finally test the constructor with bogus ref my $bogus = {}; bless $bogus, "Bogus"; eval "Config::Record->new(file => $bogus)"; ok($@ ? 1 : 0, "Bogus constructor"); exit 0; # Local Variables: # mode: cperl # End: Config-Record-1.1.2/t/015-pod-coverage.t0000644000076400007640000000041210727642236017614 0ustar berrangeberrange# -*- perl -*- use Test::More; use strict; use warnings; eval "use Test::Pod::Coverage 1.00 tests => 1"; plan skip_all => "Test::Pod::Coverage 1.00 required for testing POD coverage" if $@; pod_coverage_ok("Config::Record", { pod_from => "lib/Config/Record.pod"}); Config-Record-1.1.2/INSTALL0000644000076400007640000000011010727642236015332 0ustar berrangeberrangeTo install: perl Makefile.PL make and then as root: make install Config-Record-1.1.2/MANIFEST0000644000076400007640000000064510727642243015445 0ustar berrangeberrangeAUTHORS autobuild.sh CHANGES Config-Record.spec Config-Record.spec.PL debian/changelog debian/control debian/copyright debian/README.Debian debian/rules examples/auto-build.conf INSTALL lib/Config/Record.pm lib/Config/Record.pod LICENSE Makefile.PL MANIFEST This list of files MANIFEST.SKIP META.yml META.yml.PL README t/005-config-plain.t t/006-config-quoted.t t/007-config-includes.t t/010-pod.t t/015-pod-coverage.t Config-Record-1.1.2/Config-Record.spec.PL0000644000076400007640000000355610727642236020131 0ustar berrangeberrange# Copyright (C) 2001-2004 Daniel Berrange # # $Id: Config-Record.spec.PL,v 1.8 2006/01/27 16:25:50 dan Exp $ use strict; use warnings; die unless (scalar @ARGV == 1); unless (do 'lib/Config/Record.pm') { if ($@) { die $@ }; die "lib/Config/Record.pm: $!"; } local $/ = undef; $_ = ; s/\@VERSION\@/$Config::Record::VERSION/g; open SPEC, ">$ARGV[0]" or die "$!"; print SPEC $_; close SPEC; __DATA__ # Automatically generated by Config-Record.spec.PL %define appname Config-Record # This macro is used for the continuous automated builds. It just # allows an extra fragment based on the timestamp to be appended # to the release. This distinguishes automated builds, from formal # Fedora RPM builds %define _extra_release %{?dist:%{dist}}%{?extra_release:%{extra_release}} Summary: Config::Record - Simple configuration records Name: perl-%{appname} Version: @VERSION@ Release: 1%{_extra_release} License: GPLv2+ Group: Applications/Internet Source: http://www.cpan.org/authors/id/D/DA/DANBERR/%{appname}-%{version}.tar.gz BuildRoot: /var/tmp/%{appname}-%{version}-root BuildArchitectures: noarch Requires: perl(:MODULE_COMPAT_%(eval "`%{__perl} -V:version`"; echo $version)) %description Config::Record provides a module for loading configuration records. It supports scalar, array and hash parameters nested to an arbitrary depth. %prep %setup -q -n %{appname}-%{version} %build %{__perl} Makefile.PL INSTALLDIRS=vendor %__make \ %install rm -rf $RPM_BUILD_ROOT %__make install \ PERL_INSTALL_ROOT=$RPM_BUILD_ROOT find $RPM_BUILD_ROOT -name perllocal.pod -exec rm -f {} \; find $RPM_BUILD_ROOT -name .packlist -exec rm -f {} \; %check make test %clean rm -rf $RPM_BUILD_ROOT %files %defattr(-,root,root) %doc AUTHORS LICENSE README CHANGES %{perl_vendorlib}/Config/Record.pm %{perl_vendorlib}/Config/Record.pod %{_mandir}/man3/Config::Record.3pm* Config-Record-1.1.2/META.yml0000644000076400007640000000150310727642243015557 0ustar berrangeberrange--- #YAML:1.0 name: Config-Record abstract: Configuration file access version: 1.1.2 author: - Daniel P. Berrange license: gpl generated_by: ExtUtils::MakeMaker version 6.30 requires: Carp: 0 IO::File: 0 build_requires: Test::More: 0 File::Temp: 0 Test::Pod: 0 Test::Pod::Coverage: 0 resources: license: http://www.gnu.org/licenses/gpl.html homepage: http://autobuild.org/ bugtracker: https://gna.org/bugs/?group=testautobuild repository: https://gna.org/cvs/?group=testautobuild MailingList: https://gna.org/mail/?group=testautobuild distribution_type: module meta-spec: version: 1.3 url: http://module-build.sourceforge.net/META-spec-v1.3.html