|
NAMEHash::MultiValue - Store multiple values per keySYNOPSISuse Hash::MultiValue; my $hash = Hash::MultiValue->new( foo => 'a', foo => 'b', bar => 'baz', ); # $hash is an object, but can be used as a hashref and DWIMs! my $foo = $hash->{foo}; # 'b' (the last entry) my $foo = $hash->get('foo'); # 'b' (always, regardless of context) my @foo = $hash->get_all('foo'); # ('a', 'b') keys %$hash; # ('foo', 'bar') not guaranteed to be ordered $hash->keys; # ('foo', 'foo', 'bar') guaranteed to be ordered DESCRIPTIONHash::MultiValue is an object (and a plain hash reference) that may contain multiple values per key, inspired by MultiDict of WebOb.RATIONALEIn a typical web application, the request parameters (a.k.a CGI parameters) can be single value or multi values. Using CGI.pm style "param" is one way to deal with this problem (and it is good, as long as you're aware of its list context gotcha), but there's another approach to convert parameters into a hash reference, like Catalyst's "$c->req->parameters" does, and it sucks.Why? Because the value could be just a scalar if there is one value and an array ref if there are multiple, depending on user input rather than how you code it. So your code should always be like this to be defensive: my $p = $c->req->parameters; my @maybe_multi = ref $p->{m} eq 'ARRAY' ? @{$p->{m}} : ($p->{m}); my $must_single = ref $p->{m} eq 'ARRAY' ? $p->{m}->[0] : $p->{m}; Otherwise you'll get a random runtime exception of Can't use string as an ARRAY ref or get stringified array ARRAY(0xXXXXXXXXX) as a string, depending on user input and that is miserable and insecure. This module provides a solution to this by making it behave like a single value hash reference, but also has an API to get multiple values on demand, explicitly. HOW THIS WORKSThe object returned by "new" is a blessed hash reference that contains the last entry of the same key if there are multiple values, but it also keeps the original pair state in the object tracker (a.k.a inside out objects) and allows you to access the original pairs and multiple values via the method calls, such as "get_all" or "flatten".This module does not use "tie" or overload and is quite fast. Yes, there is Tie::Hash::MultiValue and this module tries to solve exactly the same problem, but using a different implementation. UPDATING CONTENTSWhen you update the content of the hash, DO NOT UPDATE using the hash reference interface: this won't write through to the tracking object.my $hash = Hash::MultiValue->new(...); # WRONG $hash->{foo} = 'bar'; delete $hash->{foo}; # Correct $hash->add(foo => 'bar'); $hash->remove('foo'); See below for the list of updating methods. METHODS
WHY LAST NOT FIRST?You might wonder why this module uses the last value of the same key instead of first. There's no strong reasoning on this decision since one is as arbitrary as the other, but this is more consistent to what Perl does:sub x { return ('a', 'b', 'c'); } my $x = x(); # $x = 'c' my %a = ( a => 1 ); my %b = ( a => 2 ); my %m = (%a, %b); # $m{a} = 2 When perl gets a list in a scalar context it gets the last entry. Also if you merge hashes having a same key, the last one wins. NOTES ON refIf you pass this MultiValue hash object to some upstream functions that you can't control and does things like:if (ref $args eq 'HASH') { ... } because this is a blessed hash reference it doesn't match and would fail. To avoid that you should call "as_hashref" to get a finalized (= non-blessed) hash reference. You can also use UNIVERSAL::ref to make it work magically: use UNIVERSAL::ref; # before loading Hash::MultiValue use Hash::MultiValue; and then all "ref" calls to Hash::MultiValue objects will return HASH. THREAD SAFETYPrior to version 0.09, this module wasn't safe in a threaded environment, including win32 fork() emulation. Versions newer than 0.09 is considered thread safe.AUTHORTatsuhiko Miyagawa <miyagawa@bulknews.net>Aristotle Pagaltzis Hans Dieter Pearcey Thanks to Michael Peters for the suggestion to use inside-out objects instead of tie. LICENSEThis library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.SEE ALSO
Visit the GSP FreeBSD Man Page Interface. |