Beefy Boxes and Bandwidth Generously Provided by pair Networks
No such thing as a small change
 
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
Replies are listed 'Best First'.
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 romping around the Monastery: (18)
As of 2015-07-28 15:32 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    The top three priorities of my open tasks are (in descending order of likelihood to be worked on) ...









    Results (257 votes), past polls