Advanced-Config
view release on metacpan or search on metacpan
So it's limitations with earlier Perl versions wouldn't affect this one.
- Updated copyrights to 2024 on all files, both *.PM & t/*.t.
- Fixed t/75-check_all_languages.t to ignore buggy language definitions.
- Fixed t/75-check_all_languages.t & t/76-check_all_languages2.t to
make sure it creates the fish log before it tries to load optional
modules. So the developer tests will find the proper number of
fish files. Also speeded up the test cases.
- Fixed POD NAME on all *.pm files to follow Perl standards.
- Corrected various typos in the POD.
- Updated stale links in the POD.
- Config.pm & Options.pm - Added On/Off to get_boolean() & updated the POD
to say so.
- Config.pm - removed depreciated function section().
- Makefile.PL - Fixed build script bug.
- Fixed to require Fred::Fish::DBUG v2.09 so I could use it's new Test module
in the t/*.t test scripts. Simplified a lot of code.
- Updated copyright to 2025 in all files.
1.09 2020-10-05 08:30:00
- Fixed so minimum version of 2.01 required for using Fred::Fish::DBUG.
- Modified all *.pm files to eliminate the BEGIN logic the older versions
- Updated the VERSION in all *.pm files.
- Fixed some POD formatting errors in Options.pm
- Fixed some POD typos in Reader.pm
- Fixed some POD typos in Date.pm
- Fixed 2 digit year bug in parse_date() in Date.pm, parsing two digit years
are still problematic and quite frequently ambiguous.
- More enhancements for parsing 2 & 4 digit year dates in parse_date().
- Added more date tests in t/09-basic_date.t to further test various date
formats.
- Advanced::Config::Options now disallows 2 digit year dates by default
due to the ambiguity involved in trying to parse them. Also updated
the POD to say so in Date.pm & Options.pm.
- Replaced option 'date_disable_yy' with "date_enable_yy" to make the 2 digit
date handling default more intuitive.
- Retired option 'date_reverse_test' in favor of option "date_format" to make
the parsing of numeric dates less ambiguous. Required a reorg of the
arguments to all the parse date functions. Also required to replace arg $up
with $order so we must pick & choose which format to use.
- Fixed t/13-alt-get-tests.t to explicitly use "date_enable_yy => 1"
during all calls to get_date() to allow 2-year dates in the tests!
- Fixed t/t/09-basic_date.t to explicitly allow 2-year dates in it's
F<Advanced::Config> is an enhanced implementation of a config file manager
that allows you to manage almost any config file as a true object with a common
interface. It allows you to configure for almost any look and feel inside your
config files.
You will need to create one object per configuration file that you wish to
manipulate. And any updates you make to the object in memory will not make it
back into the config file itself.
It also has options for detecting if the data in the config file has been
updated since you loaded it into memory and allows you to refresh the
configuration object. So that your long running programs never have to execute
against stale configuration data.
This module supports config file features such as variable substitution,
sourcing in other config files, comments, breaking your configuration data
up into sections, encryping/decrypting individual tag values, and even more ...
So feel free to experiment with this module on the best way to access your
data in your config files. And never have to worry about having multiple
versions of your config files again for Production vs Development vs QA vs
my $res = $self->load_string ( $string, @_ );
DBUG_RETURN ( (defined $res) ? 1 : 0 );
}
#######################################
=item $boolean = $cfg->refresh_config ( %refresh_opts );
This boolean function detects if your config file or one of it's dependancies
has been updated. If your config file sources in other config files, those
config files are checked for changes as well.
These changes could be to the config file itself or to any referenced variables
in your config file whose value has changed.
If it detects any updates, then it will reload the config file into memory,
tossing any customizations you may have added via calls to B<set_value()>. It
will keep the current B<Read> options unchanged.
=over 4
=item Supported Refresh Options Are:
"test_only => 1" - It will skip the reloading of the config file even if it
detects something changed. And just tell you if it detected any changes.
"force => 1" - It will assume you know better and that something was updated.
It will almost always return true (B<1>) when used.
=back
It returns true (B<1>) if any updates were detected or the B<force> option was
used. It will return false (B<0>) otherwise.
It will also return false (B<0>) if you never called B<load_conifg()> or
B<load_string()> against this configuration object. In which case there is
nothing to refresh.
=cut
sub refresh_config
{
DBUG_ENTER_FUNC (@_);
my $self = shift;
my %opts = (ref ($_[0]) eq "HASH" ) ? %{$_[0]} : @_;
my $updated = 0; # Assume no updates ...
my $skip = 0;
# Do a case insensitive lookup of the options hash ...
foreach my $k ( keys %opts ) {
next unless ( $opts{$k} ); # Skip if set to false ...
if ( $k =~ m/^force$/i ) {
$updated = 1; # Force an update ...
} elsif ( $k =~ m/^test_only$/i ) {
$skip = 1; # Skip any refresh of the config file ...
}
}
$self = $self->{PARENT} || $self; # Force to the "main" section ...
if ( $self->{CONTROL}->{SENSITIVE_CNT} != sensitive_cnt () ) {
$updated = 1;
}
# If not forcing an update, try to detect any changes to the %ENV hash ...
unless ( $updated ) {
DBUG_PRINT ("INFO", "Checking for changes to %ENV ...");
foreach my $k ( sort keys %{$self->{CONTROL}->{ENV}} ) {
if ( ! defined $ENV{$k} ) {
$updated = 1; # Env. Var. was removed from the environment.
} elsif ( $ENV{$k} ne $self->{CONTROL}->{ENV}->{$k} ) {
$updated = 1; # Env. Var. was modified ...
}
if ( $updated ) {
DBUG_PRINT ("WARN", "ENV{%s} changed it's value!", $k);
last;
}
}
}
# If any of the special date vars were referenced in the config file,
# assume the program's been running long enough for one of them to change!
my %dates;
if ( $self->{CONTROL}->{DATE_USED} ) {
DBUG_PRINT ("INFO", "Checking the special date variables for changes ...");
my $res = set_special_date_vars ($self->{CONTROL}->{date_opts},
\%dates, $self->{CONTROL}->{DATES});
if ( $res >= $self->{CONTROL}->{DATE_USED} ) {
DBUG_PRINT ("WARN", "A referenced special date variable's value changed!");
$updated = 1;
} else {
$dates{timestamp} = $self->{CONTROL}->{DATES}->{timestamp};
}
}
# Try to detect if any config files were modified ...
unless ( $updated ) {
DBUG_PRINT ("INFO", "Checking the file timestamps ...");
foreach my $f ( sort keys %{$self->{CONTROL}->{REFRESH_MODIFY_TIME}} ) {
# Can't do ref($f) since key is stored as a string here.
my $modify_time = ( $f =~ m/^SCALAR[(]0x[0-9a-f]+[)]$/ ) ? 0 : (stat( $f ))[9];
if ( $modify_time > $self->{CONTROL}->{REFRESH_MODIFY_TIME}->{$f} ) {
DBUG_PRINT ("WARN", "File was modified: %s", $f);
$updated = 1;
last;
}
}
}
# Refresh the config file's contents in memory ...
if ( $updated && $skip == 0 ) {
my $f = $self->{CONTROL}->{filename};
my @mlst = @{$self->{CONTROL}->{MERGE}};
my $opts = $self->{CONTROL}->{REFRESH_READ_OPTIONS};
# Update date info gathered earlier only if these vars are used.
if ( $self->{CONTROL}->{DATE_USED} ) {
$self->{CONTROL}->{DATES} = \%dates;
$self->{CONTROL}->{DATE_USED} = 0;
}
foreach my $m (@mlst) {
DBUG_PRINT ("LOG", "Calling Merge Function ... %s", ref ($m));
if ( ref ( $m ) eq "SCALAR" ) {
$self->merge_string ( ${$m}, $opts->{$m} );
} else {
$self->merge_config ( $m, $opts->{$m} );
}
}
}
DBUG_RETURN ( $updated );
}
#######################################
# Private method ...
# Checks for recursion while sourcing in sub-files.
# Returns: 1 (yes) or 0 (no)
sub _recursion_check
{
=over
=item $status = $cfg->encrypt_config_file ( [$file[, $encryptFile[, \%rOpts]]] );
This function encrypts all tag values inside the specified confg file that are
marked as ready for encryption and generates a new config file with everything
encrypted. If a tag/value pair isn't marked as ready for encryption it is left
alone. By default this label is B<ENCRYPT>.
After a tag's value has been encrypted, the label in the comment is updated
from B<ENCRYPT> to B<DECRYPT> in the config file.
If you are adding new B<ENCRYPT> tags to an existing config file that already
has B<DECRYPT> tags in it, you must use the same encryption related options in
I<%rOpts> as the last time. Otherwise you won't be able to decrypt all
encrypted values.
Finally if you provide argument I<$encryptFile>, it will write the encrypted
file to that new file instead of overwriting the current file. But if you do
this, you will require the use of the I<alias> option to be able to decrypt
#######################################
=item $status = $cfg->decrypt_config_file ( [$file[, $decryptFile[, \%rOpts]]] );
This function decrypts all tag values inside the specified confg file that are
marked as ready for decryption and generates a new config file with everything
decrypted. If a tag/value pair isn't marked as ready for decryption it is left
alone. By default this label is B<DECRYPT>.
After a tag's value has been decrypted, the label in the comment is updated
from B<DECRYPT> to B<ENCRYPT> in the config file.
For this to work, the encryption related options in I<\%rOpts> must match what
was used in the call to I<encrypt_config_file> or the decryption will fail.
Finally if you provide argument I<$decryptFile>, it will write the decrypted
file to that new file instead of overwriting the current file. This file only
gets created if the return status is B<1>.
If you leave off the I<$file> and I<\%rOpts>, it will instead use the values
config file to reference as a single object.
3) Supports the use of variables in the config file.
4) Supports the use of sections to better organize your config file's data.
5) Supports inheritance between sections.
6) Supports encrypting/decrypting values in your config files to keep
the contents of your config files safe from prying eyes but usable in
your code.
7) Supports the overriding of the default operators used. Such as using
different comment indicators or other special symbols interpreted when
loading the config file into memory.
8) Detecting if a config file has been updated since your program first
loaded it for dynamic refreshes for long running processes.
9) Custom accessor functions (get_*), allowing you to do basic validation
that each tag contains the expected data type.
10) And many, many more features.
lib/Advanced/Config/Options.pm view on Meta::CPAN
$ref = _get_opt_base ( $current, $ref ) if ( defined $current );
$ref = _get_opt_base ( $user_opts, $ref ) if ( defined $user_opts );
DBUG_RETURN ( $ref );
}
# ==============================================================
=item $ref = apply_get_rules ( $tag, $section, $val1, $val2, $wide, $getOpts )
Returns an updated hash reference containing the requested data value after all
the I<$getOpts> rules have been applied. If the I<$tag> doesn't exist then it
will return B<undef> instead or B<die> if it's I<required>.
I<$val1> is the DATA hash value from the specified section.
I<$val2> is the DATA hash value from the parent section. This value is ignored
unless the I<inherit> option was specified via I<$getOpts>.
I<$wide> tells if UTF-8 dates are allowed.
lib/Advanced/Config/Reader.pm view on Meta::CPAN
# ==============================================================
=item $status = encrypt_config_file_details ( $file, $writeFile, \%rOpts )
This function encrypts all tag values inside the specified confg file that are
marked as ready for encryption and generates a new config file with everything
encrypted. If a tag/value pair isn't marked as ready for encryption it is left
alone. By default this label is B<ENCRYPT>.
After a tag's value has been encrypted, the label in the comment is updated
from B<ENCRYPT> to B<DECRYPT> in the new file.
If you are adding new B<ENCRYPT> tags to an existing config file that already
has B<DECRYPT> tags in it, you must use the same encryption related options in
I<%rOpts> as the last time. Otherwise you won't be able to decrypt all
encrypted values.
This method ignores any request to source in other config files. You must
encryt each file individually.
lib/Advanced/Config/Reader.pm view on Meta::CPAN
# ==============================================================
=item $status = decrypt_config_file_details ( $file, $writeFile, \%rOpts )
This function decrypts all tag values inside the specified confg file that are
marked as encrypted and generates a new file with everyting decrypted. If a
tag/value pair isn't marked as being encrypted it is left alone. By default
this label is B<DECRYPT>.
After a tag's value has been decrypted, the label in the comment is updated
from B<DECRYPT> to B<ENCRYPT> in the config file.
For this to work, the encryption related options in I<\%rOpts> must match what
was used in the call to I<encrypt_config_file_details> or the decryption will
fail.
This method ignores any request to source in other config files. You must
decrypt each file individually.
It writes the results of the decryption process to I<$writeFile>.
( run in 1.056 second using v1.01-cache-2.11-cpan-0a6323c29d9 )