Config-Model

 view release on metacpan or  search on metacpan

lib/Config/Model/WarpedNode.pm  view on Meta::CPAN

#
# This file is part of Config-Model
#
# 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
#
package Config::Model::WarpedNode 2.162;

use v5.20;
use Mouse;

use Carp qw(cluck croak);

use Config::Model::Exception;
use Config::Model::Warper;
use Data::Dumper ();
use Log::Log4perl qw(get_logger :levels);
use Storable qw/dclone/;
use Scalar::Util qw/weaken/;

extends qw/Config::Model::AnyThing/;

with "Config::Model::Role::NodeLoader";
with "Config::Model::Role::Grab";

use feature qw/postderef signatures/;
no warnings qw/experimental::postderef experimental::signatures/;

my $logger = get_logger("Tree::Node::Warped");

# don't authorize to warp 'morph' parameter as it may lead to
# difficult maintenance

# status is not warpable either as an obsolete parameter must stay
# obsolete

my @allowed_warp_params = qw/config_class_name level gist/;

has 'backup' => ( is => 'rw', isa => 'HashRef', default => sub { {}; } );

has 'warp'  => ( is => 'rw', isa => 'HashRef', default => sub { {}; });
has 'morph' => ( is => 'ro', isa => 'Bool', default => 0 );

has warper => ( is => 'rw', isa => 'Config::Model::Warper' );

has is_building => (
    is => 'ro',
    isa     => 'Bool',
    traits  => ['Bool'],
    default => 0,
    handles => {
        building  => 'set',
        build_done => 'unset',
    },
);

my @backup_list = @allowed_warp_params;

around BUILDARGS => sub ($orig, $class, %args) {
    my %h     = map { ( $_ => $args{$_} ); } grep { defined $args{$_} } @backup_list;
    return $class->$orig( backup => dclone( \%h ), %args );
};

sub BUILD ($self, $) {
    # WarpedNode registers this object in a Value object (the
    # warper).  When the warper gets a new value, it modifies the
    # WarpedNode according to the data passed by the user.

    $self->building;
    my $warp_info = $self->warp;
    $warp_info->{follow} //= {};
    $warp_info->{rules}  //= [];
    my $w = Config::Model::Warper->new(
        warped_object => $self,
        %$warp_info,
        allowed       => \@allowed_warp_params
    );

    $self->warper($w);

lib/Config/Model/WarpedNode.pm  view on Meta::CPAN

    # only changes underneath changes the tree. And these changes below triggers
    # their own change notif. So there's no need to call notify_change when transitioning
    # from an undef object into a real object. On the other hand, warping out an object does
    # NOT trigger notify_changes from below. So notify_change must be called
    if ( defined $old_object and $old_config_class_name) {
        my $from = $old_config_class_name ;
        my $to   = $config_class_name     // '<undef>';
        $self->notify_change( note => "warped node from $from to $to" );
    }

    # need to call trigger on all registered objects only after all is setup
    $self->trigger_warp;

    return;
}

sub create_node ($self, $config_class_name) {
    my @args = (
        config_class_name => $config_class_name,
        instance          => $self->{instance},
        element_name      => $self->{element_name},
        parent            => $self->parent,
        container         => $self->container,
    );

    push @args, index_value => $self->index_value if defined $self->index_value;

    return $self->load_node(@args);
}

sub clear ($self) {
    delete $self->{data};
    return;
}

sub load_data ($self, @args) {
    my %args = @args > 1 ? @args : ( data => $args[0] );
    my $data  = $args{data};
    my $check = $self->_check_check( $args{check} );

    if ( ref($data) ne 'HASH' ) {
        Config::Model::Exception::LoadData->throw(
            object     => $self,
            message    => "load_data called with non hash ref arg",
            wrong_data => $data,
        );
    }

    return $self->get_actual_node->load_data(%args);
}

sub is_auto_write_for_type ($self, @args) {
    $self->get_actual_node->is_auto_write_for_type(@args);
    return;
}

# register warper that goes through this path when looking for warp master value
sub register ($self, $warped, $w_idx) {
    $logger->debug( "WarpedNode: " . $self->name, " registered " . $warped->name );

    # weaken only applies to the passed reference, and there's no way
    # to duplicate a weak ref. Only a strong ref is created. See
    #  qw(weaken) module for weaken()
    my @tmp = ( $warped, $w_idx );
    weaken( $tmp[0] );
    push @{ $self->{warp_these_objects} }, \@tmp;
    return;
}

sub trigger_warp ($self) {
    # warp_these_objects is modified by the calls below, so this copy
    # must be done before the loop
    my @list = @{ $self->{warp_these_objects} || [] };

    foreach my $ref (@list) {
        my ( $warped, $warp_index ) = @$ref;
        next unless defined $warped;    # $warped is a weak ref and may vanish

        # pure warp of object
        $logger->debug( "node trigger_warp: from '",
            $self->name, "' warping '", $warped->name, "'" );

        # FIXME: this does not trigger new registration (or removal thereof)...
        $warped->refresh_affected_registrations( $self->location );

        #$warped->refresh_values_from_master ;
        $warped->do_warp;
        $logger->debug( "node trigger_warp: from '",
            $self->name, "' warping '", $warped->name, "' done" );
    }
    return;
}

# FIXME: should we un-register ???

1;

# ABSTRACT: Node that change config class properties

__END__

=pod

=encoding UTF-8

=head1 NAME

Config::Model::WarpedNode - Node that change config class properties

=head1 VERSION

version 2.162

=head1 SYNOPSIS

 use Config::Model;

 my $model = Config::Model->new;
 foreach (qw/X Y/) {
    $model->create_config_class(
        name    => "Class$_",
        element => [ foo => {qw/type leaf value_type string/} ]
    );
 }
 $model->create_config_class(



( run in 0.470 second using v1.01-cache-2.11-cpan-39bf76dae61 )