Config-Model

 view release on metacpan or  search on metacpan

lib/Config/Model/CheckList.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::CheckList 2.162;

use Mouse;
use 5.020;

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

use Config::Model::Exception;
use Config::Model::IdElementReference;
use Config::Model::Warper;
use List::MoreUtils qw/any none/;
use Carp;
use Log::Log4perl qw(get_logger :levels);
use Storable qw/dclone/;

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

with "Config::Model::Role::WarpMaster";
with "Config::Model::Role::Grab";
with "Config::Model::Role::HelpAsText";
with "Config::Model::Role::ComputeFunction";
with "Config::Model::Role::Utils";

my $logger = get_logger("Tree.Element.CheckList");
my $user_logger   = get_logger("User");

my @introspect_params = qw/refer_to computed_refer_to/;

my @accessible_params = qw/default_list upstream_default_list choice ordered/;
my @allowed_warp_params = ( @accessible_params, qw/level/ );

has [qw/backup data preset layered/] => ( is => 'rw', isa => 'HashRef', default => sub { {}; } );
has computed_refer_to => ( is => 'rw', isa => 'Maybe[HashRef]' );
has [qw/refer_to/]            => ( is => 'rw', isa => 'Str' );
has [qw/ordered_data choice/] => ( is => 'rw', isa => 'ArrayRef', default => sub { []; } );
has [qw/ordered/]             => ( is => 'ro', isa => 'Bool' );

has [qw/warp help/] => ( is => 'rw', isa => 'Maybe[HashRef]' );

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

sub BUILD {
    my $self = shift;

    if ( defined $self->refer_to or defined $self->computed_refer_to ) {
        $self->submit_to_refer_to();
    }

    $self->set_properties();    # set will use backup data

    if ( defined $self->warp ) {
        my $warp_info = $self->warp;
        $self->{warper} = Config::Model::Warper->new(
            warped_object => $self,
            %$warp_info,
            allowed => \@allowed_warp_params
        );
    }

    $self->cl_init;

    $logger->info( "Created check_list element " . $self->element_name );
    return $self;
}

sub cl_init {
    my $self = shift;

    $self->warp if ( $self->{warp} );

    if ( defined $self->{ref_object} ) {
        my $level = $self->parent->get_element_property(
            element  => $self->{element_name},
            property => 'level',
        );
        $self->{ref_object}->get_choice_from_referred_to if $level ne 'hidden';
    }
    return;
}

sub name {
    my $self = shift;
    my $name = $self->{parent}->name . ' ' . $self->{element_name};
    return $name;
}

sub value_type { return 'check_list'; }

# warning : call to 'set' are not cumulative. Default value are always
# restored. Lest keeping track of what was modified with 'set' is
# too hard for the user.
sub set_properties ($self, @args) {
    # cleanup all parameters that are handled by warp
    for (@allowed_warp_params) {
        delete $self->{$_};
    }

    if ( $logger->is_trace() ) {
        my %h = @args;
        my $keys = join( ',', keys %h );
        $logger->trace("set_properties called on $self->{element_name} with $keys");
    }

    # merge data passed to the constructor with data passed to set
    my %args = ( %{ $self->{backup} }, @args );

    # these are handled by Node or Warper
    for (qw/level/) {
        delete $args{$_}
    }

    $self->{ordered} = delete $args{ordered} || 0;

    if ( defined $args{choice} ) {
        my @choice = @{ delete $args{choice} };
        $self->{default_choice} = \@choice;
        $self->setup_choice(@choice);
    }

    if ( defined $args{default} ) {
        $logger->warn($self->name, ": default param is deprecated, use default_list");
        $args{default_list} = delete $args{default};
    }

    if ( defined $args{default_list} ) {
        $self->{default_list} = delete $args{default_list};
    }

    # store default data in a hash (more convenient)
    $self->{default_data} = { map { $_ => 1 } @{ $self->{default_list} } };

    if ( defined $args{upstream_default_list} ) {
        $self->{upstream_default_list} = delete $args{upstream_default_list};
    }

    # store upstream default data in a hash (more convenient)
    $self->{upstream_default_data} =
        { map { $_ => 1 } @{ $self->{upstream_default_list} } };

    Config::Model::Exception::Model->throw(
        object => $self,
        error  => "Unexpected parameters :" . join( ' ', keys %args ) ) if scalar keys %args;

    if ( $self->has_warped_slaves ) {
        my $hash = $self->get_checked_list_as_hash; # force scalar context
        $self->trigger_warp($hash, $self->fetch);
    }
    return;
}

sub setup_choice ($self, @args) {
    my @choice = ref $args[0] ? @{ $args[0] } : @args;

    $logger->trace("CheckList $self->{element_name}: setup_choice with @choice");

    # store all enum values in a hash. This way, checking
    # whether a value is present in the enum set is easier
    delete $self->{choice_hash} if defined $self->{choice_hash};
    for (@choice) {
        $self->{choice_hash}{$_} = 1;
    }

    $self->{choice} = \@choice;

    # cleanup current preset and data if it does not fit current choices

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


    return;
}

sub get_info {
    my $self = shift;

    my @items = ('type: check_list');
    if ( defined $self->refer_to ) {
        push @items, "refer_to: " . $self->refer_to;
    }
    push @items, "ordered: " . ( $self->ordered ? 'yes' : 'no' );
    return @items;
}

sub clear {
    my $self = shift;
    # also triggers notify changes
    for my $item ($self->get_choice) {
        $self->clear_item($item);
    }
    return;
}

sub clear_values { goto &clear; }

sub clear_layered {
    my $self = shift;
    $self->{layered} = {};
    return;
}

my %old_mode = ( built_in_list => 'upstream_default_list', );

sub get_checked_list_as_hash ($self, @args) {
    my %args = _resolve_arg_shortcut(\@args, 'mode');
    my $mode = $args{mode} || '';

    foreach my $k ( keys %old_mode ) {
        next unless $mode eq $k;
        $mode = $old_mode{$k};
        carp $self->location, " warning: deprecated mode parameter: $k, ", "expected $mode\n";
    }

    if ( my $err = $self->is_bad_mode($mode)) {
        croak "get_checked_list_as_hash: $err";
    }

    my $dat = $self->{data};
    my $pre = $self->{preset};
    my $def = $self->{default_data};
    my $lay = $self->{layered};
    my $ud  = $self->{upstream_default_data};

    # fill empty hash result
    my %h = map { $_ => 0 } $self->get_choice;

    my %predef = ( %$def, %$pre );
    my %std = ( %$ud, %$lay, %$def, %$pre );

    # use _std_backup if all data values are null (no checked items by user)
    my %old_dat = ( none { $_; } values %$dat ) ? %{ $self->{_std_backup} || {} } : %$dat;

    if ( not $mode and any { $_; } values %predef and none { $_; } values %old_dat ) {

        # changed from nothing to default checked list that must be written
        $self->{_std_backup} = { %$def, %$pre };
        $self->notify_change( note => "use default checklist" );
    }

    # custom test must compare the whole list at once, not just one item at a time.
    my %result =
        $mode eq 'custom' ? ( ( grep { $dat->{$_} xor $std{$_} } keys %h ) ? ( %$pre, %$dat ) : () )
        : $mode eq 'preset'           ? (%$pre)
        : $mode eq 'layered'          ? (%$lay)
        : $mode eq 'upstream_default' ? (%$ud)
        : $mode eq 'default'          ? (%$def)
        : $mode eq 'standard'         ? %std
        : $mode eq 'user'             ? ( %h, %std, %$dat )
        :                               ( %predef, %$dat );

    return wantarray ? %result : \%result;
}

sub get_checked_list ($self, @args) {
    my %h          = $self->get_checked_list_as_hash(@args);
    my @good_order = $self->{ordered} ? @{ $self->{ordered_data} } : sort keys %h;
    my @res        = grep { $h{$_} } @good_order;
    return wantarray ? @res : \@res;
}

sub fetch ($self, @args) {
    return join( ',', $self->get_checked_list(@args) );
}

sub fetch_custom {
    my $self = shift;
    return join( ',', $self->get_checked_list('custom') );
}

sub fetch_preset {
    my $self = shift;
    return join( ',', $self->get_checked_list('preset') );
}

sub fetch_layered {
    my $self = shift;
    return join( ',', $self->get_checked_list('layered') );
}

sub get ($self, $path, @args){
    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 {
    my ($self, $path, $list, %args) = @_;

    my $check_validity = $self->_check_check( $args{check} );
    if ($path) {
        Config::Model::Exception::User->throw(
            object  => $self,



( run in 2.648 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )