Author image Hauke D
and 1 contributors

Name

Util::H2O - Hash to Object: turns hashrefs into objects with accessors for keys

Synopsis

 use Util::H2O;
 
 my $hash = h2o { foo => "bar", x => "y" }, qw/ more keys /;
 print $hash->foo, "\n";           # accessor
 $hash->x("z");                    # change value
 $hash->more("quz");               # additional keys
 
 my $struct = { hello => { perl => "world!" } };
 h2o -recurse, $struct;            # objectify nested hashrefs as well
 print $struct->hello->perl, "\n";
 
 my $obj = h2o -meth, {            # code references become methods
     what => "beans",
     cool => sub {
         my $self = shift;
         print $self->what, "\n";
     } };
 $obj->cool;                       # prints "beans"
 
 h2o -classify=>'Point', {         # whip up a class
         angle => sub { my $self = shift; atan2($self->y, $self->x) }
     }, qw/ x y /;
 my $one = Point->new(x=>1, y=>2);
 my $two = Point->new(x=>3, y=>4);
 printf "%.3f\n", $two->angle;     # prints 0.927

Description

This module allows you to turn hashrefs into objects, so that instead of $hash->{key} you can write $hash->key, plus you get protection from typos. In addition, options are provided that allow you to whip up really simple classes.

You can still use the hash like a normal hashref as well, as in $hash->{key}, keys %$hash, and so on, but note that by default this function also locks the hash's keyset to prevent typos there too.

This module exports a single function by default.

h2o @opts, $hashref, @additional_keys

@opts

If you specify an option with a value multiple times, only the last one will take effect.

-recurse

Nested hashes are objectified as well. Note that none of the other options will be applied to the nested hashes, including @additional_keys. Nested arrayrefs are not recursed into.

-meth

Any code references present in the hash at the time of this function call will be turned into methods. Because these methods are installed into the object's package, they can't be changed later by modifying the hash.

To avoid confusion when iterating over the hash, the hash entries that were turned into methods are removed from the hash. The key is also removed from the "allowed keys" (see the -lock option), unless you specify it in @additional_keys. In that case, you can change the value of that key completely independently of the method with the same name.

-class => classname

Specify the class name into which to bless the object (as opposed to the default: a generated, unique package name in Util::H2O::).

Note: If you use this option, -clean defaults to false, meaning that the package will stay in Perl's symbol table and use memory accordingly, and since this function installs the accessors in the package every time it is called, if you re-use the same package name, you will get "redefined" warnings. Therefore, if you want to create multiple objects in the same package, you should probably use -new.

-classify => classname

Short form of the options -new, -meth, -class => classname.

-new

Generates a constructor named new in the package. The constructor works as a class and instance method, and dies if it is given any arguments that it doesn't know about. If you want more advanced features, like required arguments, validation, or other initialization, you should probably switch to something like Moo instead.

-clean => bool

Whether or not to clean up the generated package when the object is destroyed. Defaults to false when -class is specified, true otherwise. If this is false, be aware that the packages will stay in Perl's symbol table and use memory accordingly.

-lock => bool

Whether or not to use Hash::Util's lock_ref_keys to prevent modifications to the hash's keyset. Defaults to true.

Keysets of objects created by the constructor generated by the -new option are not locked.

Note that on really old Perls, that is, before Perl v5.8.9, Hash::Util and its lock_ref_keys are not available, so the hash is never locked on those versions of Perl. Versions of this module before v0.06 did not lock the keyset.

-nolock

Short form of the option lock=>0.

$hashref

You must supply a plain (unblessed) hash reference here. Be aware that this function does modify the original hashref(s) by blessing it and locking its keyset (the latter can be disabled with the -lock option).

An accessor will be set up for each key in the hash; note that the keys must of course be valid Perl identifiers for you to be able to call the method normally.

When -clean is true (the default, unless you use -class), the hash may not contain a key named DESTROY. When -new is used, the hash may not contain a key named new.

@additional_keys

Methods will be set up for these keys even if they do not exist in the hash.

Returns

The (now blessed and optionally locked) $hashref.

See Also

Inspired in part by lock_keys from Hash::Util.

Many, many other modules exist to simplify object creation in Perl. This one is mine ;-P

Similar modules include Object::Adhoc, Object::Anon, Hash::AsObject, Object::Result, and Hash::Wrap, the latter of which also contains a comprehensive list of similar modules.

For real OO work, I like Moo and Type::Tiny.

Author, Copyright, and License

Copyright (c) 2020 Hauke Daempfling (haukex@zero-g.net).

This library is free software; you can redistribute it and/or modify it under the same terms as Perl 5 itself.

For more information see the Perl Artistic License, which should have been distributed with your copy of Perl. Try the command perldoc perlartistic or see http://perldoc.perl.org/perlartistic.html.