package NACL::MatcherValue; use CR::Setup::Constants; use Data::Dumper; use Params::Validate qw(:all); use Scalar::Util qw(blessed); use NATE::Log qw(log_global); my $Log = log_global(); my $may_enter = $Log->may_enter(); my $may_exit = $Log->may_exit(); =head2 new Initializes a new MatcherValue which is a container object for values that is used to standardize the API used for matchers. =cut my $new_validate_spec = { value => { default => undef }, }; sub new { my %params = validate( @{[@_[1..$#_]]}, $new_validate_spec ); my $self = \%params; bless $self, $_[0]; $self; } =head2 make_matcher_value_if_not_already Conditionally wrap the value in a MatcherValue and perform optional processing and validation on it. =cut my $make_matcher_value_if_not_already_validate_spec = { value => { default => undef }, value_spec => { default => $TRUE }, value_validation => { type => BOOLEAN, default => $FALSE }, decoderef => { type => BOOLEAN, default => $TRUE }, }; sub make_matcher_value_if_not_already { my %params = validate( @{[@_[1..$#_]]}, $make_matcher_value_if_not_already_validate_spec ); my $calling_function = (caller(1))[3]; if (_is_value_a_matcher_value($params{'value'})) { # Already a MatcherValue } else { # MatcherValue It $params{'value'} = $_[0]->new( value => $params{'value'} ); } if ( $params{'decoderef'} ) { $params{'value'}->decoderef(); } if ( $params{'value_validation'} ) { my @for_validation = ( 'value' => $params{'value'}->value()); validate_with( params => \@for_validation, spec => { value => $params{'value_spec'}, }, allow_extra => $FALSE, called => $calling_function, ); } $params{'value'}; } =head2 value Returns the value after dereferencing all code refs in the raw value stored. =cut sub value { validate_pos(@{[@_[1..$#_]]}); _handle_code_refs($_[0]->value_raw()); } =head2 value_raw Returns the raw value stored in the MatcherValue. =cut sub value_raw { validate_pos(@{[@_[1..$#_]]}); $_[0]->{'value'}; } =head2 decoderef Dereferences all code refs for the raw value and stores that into the MatcherValue. =cut sub decoderef { validate_pos(@{[@_[1..$#_]]}); $_[0]->{'value'} = _handle_code_refs( $_[0]->{'value'} ); } sub _is_value_a_matcher_value { validate_pos(@{[@_[1..$#_]]}); ( defined $_[0] && blessed($_[0]) && $_[0]->isa('NACL::MatcherValue') ) ? $TRUE : $FALSE; } # XXX: This sub is incredibly performance critical, in order to prevent as much time # as possible being spent in the the validate, it removes it from the validation, especially # because it is an absolutely arbitrary value. Because of this failures when passing extra # parameters will be off by 1 in the error message. sub _handle_code_refs { validate_pos(@{[@_[1..$#_]]}); if ( ref( $_[0] ) eq 'CODE' ) { _handle_code_refs( &{$_[0]} ); } elsif ( _is_value_a_matcher_value($_[0]) ) { $_[0]->value(); } else { $_[0]; } } 1;