=pod =head1 ============================================================================ =head1 MULTIDEMENSIONAL HASH-ARRAY FUNCTIONS =head1 ---------------------------------------------------------------------- =head2 deep_defined ( <\%hash or $hash_ref>, <@key_list or $key_string> ) OBJECTIVE: Return the value defined for a $mixedHashArray{$key}[$combination]{$set}, without invoking autovivification. (with more flexability than deep_defined_action.) PREMIS: Prevent "$mixedHashArray{key}[combination]" from being instantiated when effectively testing if "$mixedHashArray{key}[combination]{set}" is defined or while getting it's value. This function is flexible enough to accept args in a list format, or a format that is more condusive to copying the keys directly from the instantiation... EX: Instantiation: (w/ autovivification) $hash{key}{combination}{set} = "some_value"; Test: if ($value = &deep_defined(\%hash, qq( {key}{combination}{set} ) ) ){ print "$value"; #prints "some_value"... } But Notice that if you test an undefined key combination set, no autovivification occurs. EX: Test: if ($value = &deep_defined(\%hash, qq( {undefined}{key}{combination}{set} ) ) ){ ### test fails; no autovivification } You can also specify the key combination set as a list if you find that more practical: EX: Test: if ($value = &deep_defined(\%hash, "key", "combination", "set")){ ... } It also handles $hash_refs instead and arrays and mixed hash-array combinations... EX: Instantiation: (w/ autovivification) $hash{key}{combination}{set}[2]{and_key_for_hash_in_second_list_position} = "some_value"; $hash_ref = /%hash; Test: if ($value = &deep_defined($hash_ref, qq( {key}{combination}{set}[2]{and_key_for_hash_in_second_list_position} ) ) ){ print "$value"; #prints "some_value"... } ADDITIONAL INFO: This function is simply a wrapper for the sub deep_defined_action(), which does the actual combinational testing... It takes the second argument and parses it as a string into a list in wich deep_defined_action will accept. =cut sub deep_defined { my( $possible_ref, @keys ) = @_ ; if (ref($possible_ref) eq "HASH" or ref($possible_ref) eq "ARRAY"){ ### now look at the keys to see what they are: my $first_key = @keys[0]; $first_key =~s/\s+//g; #get rid of spaces $first_key =~s/^(\{|\[)//g; #get rid of the leading bracket or brace $first_key =~s/(\}|\])$//g; #get rid of the trailing bracket or brace #my @list = split(m/\}\{|\]\[|\]\{|\}\[|\{|\}|\[|\]/, $first_key); ### these are kind of ordered... my @list = split(m/\}\{|\]\[|\]\{|\}\[/, $first_key); ### these are kind of ordered... if (@list > 1){ my @new_list = (); foreach my $item (@list){ if (&is_int($item)){ @new_list = (@new_list, int($item)); }else{ push (@new_list, $item); } } ### then the second argument was a string containing the keys in typical form for autovivification... return &deep_defined_action($possible_ref, @new_list); }else{ ### then the arguments following the first are probably already keys, so lets just plug 'em in. return &deep_defined_action($possible_ref, @keys); } }else{ warn "Invalid arguments passed into sub deep_defined. args: @_ \n"; warn "The first arg should be a ref to a hash or array...\n"; return; } } =pod =head1 ---------------------------------------------------------------------- =head2 deep_defined_action ( <\%hash or $hash_ref>, @key_list ) OBJECTIVE: Return the value defined for a $mixedHashArray{$key}[$combination]{$set}, without invoking autovivification. (used by the more flexable sub deep_defined) PREMIS: Prevent "$mixedHashArray{key}[combination]" from being instantiated when effectively testing if "$mixedHashArray{key}[combination]{set}" is defined or while getting it's value. Specify the key combination set as a list: EX: Test: if ($value = &deep_defined(\%hash, "key", "combination", "set")){ print "$value" } ADDITIONAL INFO: This subroutine basically came from www.sysarch.com/Perl/autoviv.txt and was originally called deep_defined, but the return value has been modified to return the defined value of a multidimensional hash ref combination rather than just a boolean. To be used in combination with deep_defined; it is meant only to be used as an @EXPORT_OK or private function and to be included in the same module in which sub deep_defined is located. =cut sub deep_defined_action { my( $ref, @keys ) = @_ ; unless ( @keys ) { warn "deep_defined_action: no keys" ; return ; } foreach my $key ( @keys ) { if( ref $ref eq 'HASH' ) { # fail when the key doesn't exist at this level return unless defined( $ref->{$key} ) ; $ref = $ref->{$key} ; next ; } if( ref $ref eq 'ARRAY' ) { # fail when the index is out of range or is not defined return unless 0 <= $key && $key < @{$ref} ; return unless defined( $ref->[$key] ) ; $ref = $ref->[$key] ; next ; } # fail when the current level is not a hash or array ref return ; } #return 1 ; #changed this to return the actual value instead of just a boolean: Isn't that more useful? return $ref ; } =pod =head1 ============================================================================ =head1 SCALAR_TEST FUNCTIONS =head1 ---------------------------------------------------------------------- =head2 is_int ($scalar) returns true if a scalar is an integer, otherwise undef. =cut sub is_int{ ###### returns true if a scalar is an integer: my ($thing) = @_; if (int($thing) eq $thing){ return 1; }else{ return; } }