Config-Model
view release on metacpan or search on metacpan
lib/Config/Model/Value.pm view on Meta::CPAN
foreach my $path ( values %$var ) {
if ( defined $path and not ref $path ) {
# is ref during test case
#print "path is '$path'\n";
next if $path =~ /\$/; # next if path also contain a variable
my $master = $self->grab($path);
next unless $master->can('register_dependency');
$master->register_dependency($self);
}
}
return;
}
# internal
sub perform_compute {
my $self = shift;
$logger->trace("called");
my $result = $self->compute_obj->compute;
# check if the computed result fits with the constraints of the
# Value model, but don't check if it's mandatory
my ($value, $error, $warn) = $self->_check_value(value => $result);
if ( scalar $error->@* ) {
my $error = join("\n", (@$error, $self->compute_info));
Config::Model::Exception::WrongValue->throw(
object => $self,
error => "computed value error:\n\t" . $error
);
}
$logger->trace("done");
return $result;
}
# internal, used to generate error messages
sub compute_info {
my $self = shift;
return $self->compute_obj->compute_info;
}
sub set_migrate_from {
my ( $self, $arg_ref ) = @_;
my $mig_ref = delete $arg_ref->{migrate_from};
if ( ref($mig_ref) eq 'HASH' ) {
$self->migrate_from($mig_ref);
}
else {
Config::Model::Exception::Model->throw(
object => $self,
error => "migrate_from value must be a hash ref not $mig_ref"
);
}
my @migrate_data;
foreach (qw/formula variables replace use_eval undef_is/) {
push @migrate_data, $_, $mig_ref->{$_} if defined $mig_ref->{$_};
}
$self->{_migrate_from} = Config::Model::ValueComputer->new(
@migrate_data,
value_object => $self,
value_type => $self->{value_type} );
# resolve any recursive variables before registration
my $v = $self->{_migrate_from}->compute_variables;
return;
}
# FIXME: should it be used only once ???
sub migrate_value {
my $self = shift;
# migrate value is always used as a scalar, even in list
# context. Not returning undef would break a hash assignment done
# with something like:
# my %args = (value => $obj->migrate_value, fix => 1).
## no critic(Subroutines::ProhibitExplicitReturnUndef)
return undef if $self->{migration_done};
return undef if $self->instance->initial_load;
$self->{migration_done} = 1;
# avoid warning when reading deprecated values
my $result = $self->{_migrate_from}->compute( check => 'skip' );
return undef unless defined $result;
# check if the migrated result fits with the constraints of the
# Value object
my $ok = $self->check_value( value => $result );
#print "check result: $ok\n";
if ( not $ok ) {
Config::Model::Exception::WrongValue->throw(
object => $self,
error => "migrated value error:\n\t" . $self->error_msg
);
}
# old value is always undef when this method is called
$self->notify_change( note => 'migrated value', new => $result )
if length($result); # skip empty value (i.e. '')
$self->{data} = $result;
return $ok ? $result : undef;
}
sub setup_enum_choice ($self, @args) {
my @choice = ref $args[0] ? @{ $args[0] } : @args;
$logger->debug( $self->name, " setup_enum_choice with '", join( "','", @choice ), "'" );
$self->{choice} = \@choice;
lib/Config/Model/Value.pm view on Meta::CPAN
else {
@res = @args;
}
return wantarray ? @res : $res[0];
}
sub user_value {
return shift->{data};
}
sub fetch_preset {
my $self = shift;
return $self->map_write_as( $self->{preset} );
}
sub clear ($self, @args){
$self->store(value => undef, @args);
return;
}
sub clear_preset {
my $self = shift;
delete $self->{preset};
return defined $self->{layered} || defined $self->{data};
}
sub fetch_layered {
my $self = shift;
return $self->map_write_as( $self->{layered} );
}
sub clear_layered {
my $self = shift;
delete $self->{layered};
return defined $self->{preset} || defined $self->{data};
}
sub get ($self, @args) {
my %args = @args > 1 ? @args : ( path => $args[0] );
my $path = delete $args{path};
if ($path) {
Config::Model::Exception::User->throw(
object => $self,
message => "get() called with a value with non-empty path: '$path'"
);
}
return $self->fetch(%args);
}
sub set ($self, $path, @data) {
if ($path) {
Config::Model::Exception::User->throw(
object => $self,
message => "set() called with a value with non-empty path: '$path'"
);
}
return $self->store(@data);
}
#These methods are important when this leaf value is used as a warp
#master, or a variable in a compute formula.
# register a dependency, This information may be used by external
# tools
sub register_dependency {
my $self = shift;
my $slave = shift;
unshift @{ $self->{depend_on_me} }, $slave;
# weaken only applies to the passed reference, and there's no way
# to duplicate a weak ref. Only a strong ref is created.
weaken( $self->{depend_on_me}[0] );
return;
}
sub get_depend_slave {
my $self = shift;
my @result = ();
push @result, @{ $self->{depend_on_me} }
if defined $self->{depend_on_me};
push @result, $self->get_warped_slaves;
# needs to clean up weak ref to object that were destroyed
return grep { defined $_ } @result;
}
__PACKAGE__->meta->make_immutable;
1;
# ABSTRACT: Strongly typed configuration value
__END__
=pod
=encoding UTF-8
=head1 NAME
Config::Model::Value - Strongly typed configuration value
=head1 VERSION
version 2.163
=head1 SYNOPSIS
use Config::Model;
# define configuration tree object
my $model = Config::Model->new;
$model ->create_config_class (
name => "MyClass",
element => [
foo => {
type => 'leaf',
lib/Config/Model/Value.pm view on Meta::CPAN
configuration file.
=item *
C<default>: The value is known by the model, but not by the
application. This value must be written in the configuration file.
=item *
C<computed>: The value is computed from other configuration
elements. This value must be written in the configuration file.
=item *
C<preset>: The value is not known by the model or by the
application. But it can be found by an automatic program and stored
while the configuration L<Config::Model::Instance|instance> is in
L<preset mode|Config::Model::Instance/"preset_start ()">
=back
Then there is the value entered by the user. This overrides all
kind of "default" value.
The L<fetch_standard> function returns the "highest" level of
default value, but does not return a custom value, i.e. a value
entered by the user.
=head1 Constructor
Value object should not be created directly.
=head1 Value model declaration
A leaf element must be declared with the following parameters:
=over
=item value_type
Either C<boolean>, C<enum>, C<integer>, C<number>,
C<uniline>, C<string>, C<file>, C<dir>. Mandatory. See L</"Value types">.
=item default
Specify the default value (optional)
=item upstream_default
Specify a built in default value (optional). I.e a value known by the application
which does not need to be written in the configuration file.
=item write_as
Array ref. Reserved for boolean value. Specify how to write a boolean value.
Default is C<[0,1]> which may not be the most readable. C<write_as> can be
specified as C<['false','true']> or C<['no','yes']>.
=item compute
Computes a value according to a formula and other values. By default
a computed value cannot be set. See L<Config::Model::ValueComputer> for
computed value declaration.
=item migrate_from
This is a special parameter to cater for smooth configuration
upgrade. This parameter can be used to copy the value of a deprecated
parameter to its replacement. See L</Upgrade> for details.
=item convert => [uc | lc ]
When stored, the value is converted to uppercase (uc) or
lowercase (lc).
=item min
Specify the minimum value (optional, only for integer, number)
=item max
Specify the maximum value (optional, only for integer, number)
=item mandatory
Set to 1 if the configuration value B<must> be set by the
configuration user (default: 0)
=item choice
Array ref of the possible value of an enum. Example :
choice => [ qw/foo bar/]
=item match
Perl regular expression. The value is matched with the regex to
assert its validity. Example C<< match => '^foo' >> means that the
parameter value must begin with "foo". Valid only for C<string> or
C<uniline> values.
=item warn_if_match
Hash ref. Keys are made of Perl regular expression. The value can
specify a warning message (leave empty or undefined for a default warning
message) and instructions to fix the value. A warning is issued
when the value matches the passed regular expression. Valid only for
C<string> or C<uniline> values. The fix instructions is evaluated
when L<apply_fixes> is called. C<$_> contains the value to fix.
C<$_> is stored as the new value once the instructions are done.
C<$self> contains the value object. Use with care.
In the example below, any value matching 'foo' is converted in uppercase:
warn_if_match => {
'foo' => {
fix => 'uc;',
msg => 'value $_ contains foo'
},
'BAR' => {
fix =>'lc;',
lib/Config/Model/Value.pm view on Meta::CPAN
warn_unless => {
type => 'leaf',
value_type => 'string',
warn_unless_match => {
foo => {
msg => '',
fix => '$_ = "foo".$_;'
}
},
},
=head2 Always issue a warning
always_warn => {
type => 'leaf',
value_type => 'string',
warn => 'Always warn whenever used',
},
=head2 Computed values
See L<Config::Model::ValueComputer/Examples>.
=head1 Upgrade
Upgrade is a special case when the configuration of an application has
changed. Some parameters can be removed and replaced by another
one. To avoid trouble on the application user side, Config::Model
offers a possibility to handle the migration of configuration data
through a special declaration in the configuration model.
This declaration must:
=over
=item *
Declare the deprecated parameter with a C<status> set to C<deprecated>
=item *
Declare the new parameter with the instructions to load the semantic
content from the deprecated parameter. These instructions are declared
in the C<migrate_from> parameters (which is similar to the C<compute>
parameter)
=back
Here an example where a URL parameter is changed to a set of 2
parameters (host and path):
'old_url' => {
type => 'leaf',
value_type => 'uniline',
status => 'deprecated',
},
'host' => {
type => 'leaf',
value_type => 'uniline',
# the formula must end with '$1' so the result of the capture is used
# as the host value
migrate_from => {
formula => '$old =~ m!http://([\w\.]+)!; $1 ;',
variables => {
old => '- old_url'
},
use_eval => 1,
},
},
'path' => {
type => 'leaf',
value_type => 'uniline',
migrate_from => {
formula => '$old =~ m!http://[\w\.]+(/.*)!; $1 ;',
variables => {
old => '- old_url'
},
use_eval => 1,
},
},
=head1 EXCEPTION HANDLING
When an error is encountered, this module may throw the following
exceptions:
Config::Model::Exception::Model
Config::Model::Exception::Formula
Config::Model::Exception::WrongValue
Config::Model::Exception::WarpError
See L<Config::Model::Exception> for more details.
=head1 AUTHOR
Dominique Dumont, (ddumont at cpan dot org)
=head1 SEE ALSO
L<Config::Model>, L<Config::Model::Node>,
L<Config::Model::AnyId>, L<Config::Model::Warper>, L<Config::Model::Exception>
L<Config::Model::ValueComputer>,
=head1 AUTHOR
Dominique Dumont
=head1 COPYRIGHT AND LICENSE
This software is Copyright (c) 2005-2022 by Dominique Dumont.
This is free software, licensed under:
The GNU Lesser General Public License, Version 2.1, February 1999
=cut
( run in 0.634 second using v1.01-cache-2.11-cpan-d7f47b0818f )