NAME
Util::H2O::More - provides baptise
, a drop-in replacement for bless
; like if bless
created accessors for you. This module also provides additional methods built using h2o
or o2h
from Util::H2O.
Util::H2O::More
also provides a wrapper method now, h3o
that will find and objectify all HASH
refs contained in ARRAY
s at any level, no matter how deep. This ability is very useful for dealing with modern services that return ARRAY
s of HASH
, traditional DBI queries, and other modules that can provide LIST
s of HASH
refs, such as Web::Scraper.
SYNOPSIS
It is easy to create an OOP module using baptise
instead of bless
, which means it includes accessors (thanks to Util::H2O::h2o
). In most cases, baptise
can be used as a drop-in replacement for bless
.
Below is an example of a traditional Perl OOP class constructor using baptise
to define a set of default accessors, in addition to any that are created by virtue of the %opts
passed.
use strict;
use warnings;
package Foo::Bar;
# exports 'h2o' also
use Util::H2O::More qw/baptise/;
sub new {
my $pkg = shift;
my %opts = @_;
# replaces bless, defines default constructures and creates
# constructors based on what's passed into %opts
my $self = baptise \%opts, $pkg, qw/bar haz herp derpes/;
return $self;
}
1;
Then on a caller script,
use strict;
use warnings;
use Foo::Bar;
my $foo = Foo::Bar->new(some => q{thing}, else => 4);
print $foo->some . qq{\n};
# set bar via default accessor
$foo->bar(1);
print $foo->bar . qq{\n};
# default accessors also available from the class defined
# above,
# $foo->haz, $foo->herp, $foo->derpes
# and from the supplied tuple,
# $foo->else
For more examples, please look at the classes created for the unit tests contained in t/lib
.
NB: There are other useful methods, so please read all of the POD. This section simply covers baptise
, which was the first method based on Util::H2O::h2o
presented in this module.
DESCRIPTION
The primary method, baptise
, essentially provides the same interface as the core keyword bless
with an additional slurpy third parameter where one may specify a list of default accessors.
Why Was This Created?
The really short answer: because h2o
doesn't play nice inside of the traditional Perl OOP constructor (new
) idiom. This is not h2o
's fault. This is my fault for wanting to use it to do something it was never meant to do.
Implied above is that I wanted to maintain the usage pattern of bless
, but extend it to include the generation of accessors. I wanted a better bless.
The long answer...
h2o
is a deceptively powerful tool that, above all, makes it easy and fun to add accessors to ad hoc hash references that many Perl developers like to use and that get emitted, unblessed by many popular modules. For example, HTTP::Tiny
, Web::Scraper
, and the more common select% methods DBI
flavors implement. In particular, any JSON
returned by a HTTP::Tiny
web request is not just ublessed, but still serialized.
Still more useful utilities may be built upon h2o
, e.g.; h3o
which is able to handle data structures that contain HASH
references buried or nested arbitrarily within ARRAY
references.
For example, h3o
cleans things up very nicely for dealing with web APIs:
my $response = h2o HTTP::Tiny->get($JSON_API_URL);
die if not $response->success;
my $JSON_data_with_accessors = h3o JSON::decode_json $response->content;
Finally, and what started this module; the usage pattern of h2o
begs it to be able to support being used as a drop in replacement for bless
. But is does a fine job as serving as the basis for a better bless.
METHODS
baptise $hash_ref, $pkg, LIST
-
Takes the same first 2 parameters as
bless
; with the addition of a list that defines a set of default accessors that do not rely on the top level keys of the provided hash reference. baptise -recurse, $hash_ref, $pkg, LIST
-
Like
baptise
, but creates accessors recursively for a nested hash reference. Usesh2o
's-recurse
flag.Note: The accessors created in the nested hashes are handled directly by
h2o
by utilizing the-recurse
flag. This means that they will necessarily be blessed using the unchangable behavior ofh2o
, which maintains the name space ofUtil::H2O::_$hash
even ifh2o
is passed with the-isa
and-class
flags, which are both utilized to achieve the effective outcome ofbaptise
andbastise -recurse
. opt2h2o LIST
-
Handy function for working with
Getopt::Long
, which takes a list of options meant forGetopt::Long
; and extracts the flag names so that they may be used to create default accessors without having more than one list. E.g.,use Getopt::Long qw//; my @opts = (qw/option1=s options2=s@ option3 option4=i o5|option5=s/); my $o = h2o {}, opt2h2o(@opts); Getopt::Long::GetOptionsFromArray( \@ARGV, $o, @opts ); # Note, @ARGV is passed by reference # now options are all available as accessors, e.g.: if ($o->option3) { do_the_thing(); }
Note: default values for options may still be placed inside of the anonymous hash being objectified via
h2o
. This will work perfectly well withbaptise
and friends.use Getopt::Long qw//; my @opts = (qw/option1=s options2=s@ option3 option4=i o5|option5=s/); my $o = h2o { option1 => q{foo} }, opt2h2o(@opts); Getopt::Long::GetOptionsFromArray( \@ARGV, $o, @opts ); # Note, @ARGV is passed by reference # ... # now $o can be used to query all possible options, even if they were # never passed at the commandline
o2h REF
-
Uses
Util::H2O::o2h
, so behaves identical to it. A new hash reference is returned, unlikeh2o
orbaptise
. SeeUtil::H2O
's POD for a lot more information.This method complements
h2o
orbaptise
very well in the sitution, e.g., when one is dealing with an ad hoc object that then needs to be sent as a serialzied JSON string. It's convenient to be able to get the un<bless>'d data structure most JSON encoding methods are expecting.Implementation note:
Access to
Util::H2O::o2h
, but adjusts$Util::H2O::_PACKAGE_REGEX
to accept package names that are generated bybaptise
. This effectively is an unbless.Historical Note:
Util::H2O::More::o2h
precededUtil::H2O::o2h
, and the author of the latter added it after seeing it's usefulness in cases where the ability to get a pureHASH
reference after having objectified was useful. A good example is the standard dislikeJSON
modules'encode_json
method implementations have for blessed references; this also affects environments like Dancer2 or Mojo that employ automatic serialization steps beyond route handlers. Returning a blessed reference would cause the underlying serialization routines to warn ordie
without usingo2h
to return a pureHASH
reference. h3o REF
-
This method is basically a wrapper around
h2o
that will traverse an arbitrarily complex Perl data structure, applyingh2o
to anyHASH
references along the way.A common usecase where
h3o
is useful is a web API call that returns some list ofHASH
references contained inside of anARRAY
reference.For example,
my $array_of_hashes = JSON::decode_json $json; h3o $array_of_hashes; my $co = $array_of_hashes->[3]->company->name;
Here,
$array_of_hashes
is anARRAY
reference that contains a set of elements that areHASH
references; a pretty common situation when dealing with records from an API or database call.[3]
, refers the 4th element, which is aHASH
reference. ThisHASH
reference has an accessor viah3o
, and this returns anotherHASH
that has an accessor calledname
.The structure of
$array_of_hashes
is based on JSON, e.g., that is of the form:[ { "id": 1, "name": "Leanne Graham", "username": "Bret", "email": "Sincere@april.biz", "address": { "street": "Kulas Light", "suite": "Apt. 556", "city": "Gwenborough", "zipcode": "92998-3874", "geo": { "lat": "-37.3159", "lng": "81.1496" } }, "phone": "1-770-736-8031 x56442", "website": "hildegard.org", "company": { "name": "Romaguera-Crona", "catchPhrase": "Multi-layered client-server neural-net", "bs": "harness real-time e-markets" } }, { "id": 2, "name": "Ervin Howell", "username": "Antonette", "email": "Shanna@melissa.tv", "address": { "street": "Victor Plains", "suite": "Suite 879", "city": "Wisokyburgh", "zipcode": "90566-7771", "geo": { "lat": "-43.9509", "lng": "-34.4618" } }, "phone": "010-692-6593 x09125", "website": "anastasia.net", "company": { "name": "Deckow-Crist", "catchPhrase": "Proactive didactic contingency", "bs": "synergize scalable supply-chains" } }, { "id": 3, "name": "Clementine Bauch", "username": "Samantha", "email": "Nathan@yesenia.net", "address": { "street": "Douglas Extension", "suite": "Suite 847", "city": "McKenziehaven", "zipcode": "59590-4157", "geo": { "lat": "-68.6102", "lng": "-47.0653" } }, "phone": "1-463-123-4447", "website": "ramiro.info", "company": { "name": "Romaguera-Jacobson", "catchPhrase": "Face to face bifurcated interface", "bs": "e-enable strategic applications" } } ] (* froms, https://jsonplaceholder.typicode.com/users)
ARRAY
vmethodsIt is still somewhat inconvenient, though idiomatic, to refer to
ARRAY
elements directly as in the example above. However, it is still inconsistent with idea ofUtil::H2O
. So,h3o
leans into its heavy nature by adding some "virtual" methods toARRAY
containers.all
-
Returns a LIST of all items in the
ARRAY
container.my @items = $root->some-barray->all;
get INDEX
-
Given an
ARRAY
container fromh3o
, returns the element at the given index. Seepush
example below for a practical example. push LIST
-
Pushes LIST onto ARRAY attached to the vmethod called; also applies the
h3o
method to anything pushed.my @added = $root->some->barray->push({ foo => 1 }, {foo => 2}); my $one = $root->some->barray->get(0)->foo; # returns 1 via "get" my $two = $root->some->barray->get(1)->foo; # returns 2 via "get"
pop
-
Pop's an element from
ARRAY
container available after applyingh3o
to a structure that hasARRAY
refs at any level.my $item = $root->some-barray->pop;
unshift LIST
-
Similar to
push
, just operates on the near end of theARRAY
. shift
-
Similar to
pop
, just operates on the near end of theARRAY
. scalar
-
Returns the number of items in the
ARRAY
container, which is more convenient that doing,my $count = scalar @{$root->some->barray->all};
o3h REF
-
Does for data structures objectified with
h3o
whato2h
does for objects created withh2o
.
EXTERNAL METHODS
h2o
-
Because
Util::H2O::More
exportsh2o
as the basis for its operations,h2o
is also available without needing to qualify its full name space.
DEPENDENCIES
Requires Util::H2O
because this module is effectively a wrapper around h2o
.
It also uses the state
keyword, which is only available in perls >= 5.10.
BUGS
No. I mean maybe. Buyer beware.
LICENSE AND COPYRIGHT
Perl/perl
ACKNOWLEDGEMENTS
Thank you to HAUKEX for creating Util::H2O and hearing me out on its usefulness for some unintended use cases.
AUTHOR
Oodler 577 <oodler@cpan.org>