Beefy Boxes and Bandwidth Generously Provided by pair Networks
"be consistent"
 
PerlMonks  

Create Read-Accessors for a given hash

by voj (Acolyte)
on Feb 28, 2013 at 08:43 UTC ( #1021019=perlquestion: print w/ replies, xml ) Need Help??
voj has asked for the wisdom of the Perl Monks concerning the following question:

Given a hash reference I want to access values from, I am tired of writing say $h->{foo}, $h->{bar}, $h->{doz}; but I want say $h->foo, $h->bar, $h->doz; What is the easiest way to do so, without creating a copy of the hash? I managed it with a single line:
sub GET::AUTOLOAD { $GET::AUTOLOAD =~ /::(\w+)$/; $_[0]->{ $1 }; } my $h = { foo => 1, bar => 2, doz => 3 }; bless $h, 'GET'; say $h->foo, $h->bar, $h->doz;
But I'd prefer a solution that works with nested JSON-like structures (blessing all nested hashrefs, not blessing array references but hashrefs in arrayrefs etc.), to do:
my $h = { foo => 1, bar => [ 2, { doz => 3 } ] }; getter($h); say $h->foo->[1]->doz; # 3
Is there a CPAN module that provides such a simple getter method? P.S: One could write it, but I prefer to use a module:
use Scalar::Util qw(); sub GET::AUTOLOAD { $GET::AUTOLOAD =~ /::(\w+)$/; $_[0]->{ $1 }; } sub getter { my $h = $_[0]; my $r = Scalar::Util::reftype($h) or return; if ($r eq 'ARRAY') { getter($_) for @$h; } elsif ($r eq 'HASH') { bless $h, 'GET'; getter($h->{$_}) for keys %$h; } $h; }

Comment on Create Read-Accessors for a given hash
Select or Download Code
Re: Create Read-Accessors for a given hash
by Corion (Pope) on Feb 28, 2013 at 09:05 UTC

    You can do so with operator overloading and tie-ing. Doing so will incur quite some overhead though. You can see the technique applied in MozRepl::RemoteObject, but I don't think the amount of code and the complexity don't warrant the tiny gains (if any).

    package Getter; use overload '%{}' => 'Getter::as_hash', '@{}' => 'Getter::as_array', ; sub as_hash { my ($self) = @_; # return tied hash }; sub as_array { my ($self) = @_; # return tied array }; sub AUTOLOAD { # Map to hash access } package Getter::TiedArray; # Copy the code from MozRepl::RemoteObject and gut the remote function +ality package Getter::TiedHash; # Copy the code from MozRepl::RemoteObject and gut the remote function +ality
Re: Create Read-Accessors for a given hash
by tobyink (Abbot) on Feb 28, 2013 at 09:05 UTC

    I can't think of a CPAN module that goes this recursively, but it's only a few more lines of code to do so...

    use v5.12; sub autobless ($) { ref $_[0] eq 'HASH' and bless $_[0] => 'Hash'; ref $_[0] eq 'ARRAY' and bless $_[0] => 'Array'; return $_[0]; } sub Hash::AUTOLOAD { return unless $Hash::AUTOLOAD =~ /::(\w+)$/; autobless $_[0]{$1}; } sub Array::AUTOLOAD { return unless $Array::AUTOLOAD =~ /::_([0-9]+)$/; autobless $_[0][$1]; } my $h = { foo => 1, bar => 2, doz => 3, quux => [ 4, {quuux => 5} ]}; autobless $h; say for $h->foo, $h->bar, $h->doz; say $h->quux->_0; say $h->quux->_1->quuux;
    package Cow { use Moo; has name => (is => 'lazy', default => sub { 'Mooington' }) } say Cow->new->name

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1021019]
Approved by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others chanting in the Monastery: (7)
As of 2014-12-28 03:28 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    Is guessing a good strategy for surviving in the IT business?





    Results (178 votes), past polls