wjw has asked for the wisdom of the Perl Monks concerning the following question:

Have been using Net::Whois::IP to gather info about break-in attempts on my server. I store the results in a db.
The whoisip_query returns a reference to a simple array. So one can call it like I do by simply saying
my $response = whoisip_query($ip);
Very handy.

There is of course the challenge that WhoIs responses are inconsistent, some having lots of information, others having much less. In fact the fields returned are not consistent. For example: Some records will return a key value pair for 'city', others don't.

Never-the-less, I have found a subset which seems to be there all the time, however the keys may be called out differently.
Again for example: email, e-mail, e_mail, abuse_email etc... .

Thus my delight when a google search for hashes with keys identified with regular expressions returned (from PM, mind you) Tie::Hash::Regex! And it works pretty nicely.(Thank you Mr. Cross!)

What I ended up doing to make it work however was to make a copy of the hash returned to my named reference($response) by 'whoisip_query' and tie to that copy. Again, this works, but I am wondering if there is a better way to do this. I tried tie-ing to '${%response}' to see if that would get me to the underlying hash, but that broke immediately. Following is what I tried:

#!/usr/bin/perl use strict; use warnings; use Tie::Hash::Regex; use Net::Whois::IP qw(whoisip_query); my %k_ip = ( "101.78.231.135" => 320, "103.23.141.141" => 300, "103.23.244.22" => 288 ); my $ref_r; #this works foreach my $ip ( keys %k_ip ) { print "$ip \n"; print "\t" . try1($ip) . "\n"; print "\t" . try2($ip) . "\n"; print "\t" . try3($ip) . "\n"; } print "all done\n"; sub try1 { my $ip = shift(@_); my %r; tie %r, 'Tie::Hash::Regex'; my $ref_r = whoisip_query($ip); %r = %{$ref_r}; my $email = $r{qr/mail/}; if( length($email) > 0 ) { return $email; } else { return "no email"; } } sub try2 { my $ip = shift(@_); my $ref_r = whoisip_query($ip); tie %{$ref_r}, 'Tie::Hash::Regex'; if( scalar( keys %{$ref_r} ) < 1 ) { return "tie did not work..emtied underling hash"; } my $email = %{$ref_r}{qr/mail/}; if( length($email) > 0 ) { return $email; } else { return "no email"; } } sub try3 { return "This blows up -> Can't locate object method TIESCALAR \t\tvia package Tie::Hash::Regex \t\tat /home/wjw/tmp/tie_hash_regex.pl line 56"; my $ip = shift(@_); my $ref_r = whoisip_query($ip); tie $ref_r, 'Tie::Hash::Regex'; if( scalar( keys %{$ref_r} ) < 1 ) { return "tie did not work.."; } my $email = %{$ref_r}{qr/mail/}; if( length($email) > 0 ) { return $email; } else { return "no email"; } }

Working with references is not my strong point(needless to say probably). My question(s) is/are:

Feel free to lecture me. My ignorance does not bother me... :-). It is Sunday morning and I am not all that analytic today.

...the majority is always wrong, and always the last to know about it...
Insanity: Doing the same thing over and over again and expecting different results...

Replies are listed 'Best First'.
Re: Tie::Hash::Regex to hash reference?
by Anonymous Monk on Apr 28, 2014 at 08:02 UTC

    Are there things that I did not try which would have been likely to succeed.

    Not really :) but see next part

    Is there a way to use that reference directly with Tie::Hash::Regex without making the copy?

    Its not really important :) but see next part

    #!/usr/bin/perl -- use strict; use warnings; use Tie::Hash::Regex; Main( @ARGV ); exit( 0 ); sub Tie::Hash::Regex::TIEHASH { my( $class, $ref ) = @_; $ref ||= {}; return bless $ref, $class; } sub Main { my $sing = bless setSome(), 'Tie::Hash::Regex'; my %song; tie %song, 'Tie::Hash::Regex', setSome(); print $sing->FETCH(qr/pe/i), "\n"; print $song{qr/by/i}, "\n"; #~ typeSome( \%song ); #~ typeSome( $sing ); } sub setSome { my( $song ) = @_;; $song ||= {}; $song->{Peter} = "I Am Peter, Hear Me Roar"; $song->{Byrne} = "When I have nothing to say, my lips are sealed." +; $song; } sub typeSome { my( $song ) = @_; while( my( $writer, $song ) = each %$song ){ print "$writer: $song\n"; } } __END__

    And this is the point you should consider perlobj :)