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 )