.\" Automatically generated by Pod::Man 4.14 (Pod::Simple 3.40) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. \*(C+ will .\" give a nicer C++. Capital omega is used to do unbreakable dashes and .\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, .\" nothing in troff, for use with C<>. .tr \(*W- .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` "" . ds C' "" 'br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' . ds C` . ds C' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is >0, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .\" .\" Avoid warning from groff about undefined register 'F'. .de IX .. .nr rF 0 .if \n(.g .if rF .nr rF 1 .if (\n(rF:(\n(.g==0)) \{\ . if \nF \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . if !\nF==2 \{\ . nr % 0 . nr F 2 . \} . \} .\} .rr rF .\" ======================================================================== .\" .IX Title "List::Objects::WithUtils 3pm" .TH List::Objects::WithUtils 3pm "2021-01-21" "perl v5.32.0" "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH "NAME" List::Objects::WithUtils \- List objects, kitchen sink included .SH "SYNOPSIS" .IX Header "SYNOPSIS" .Vb 2 \& ## A small sample; consult the description, below, for links to \& ## extended documentation \& \& # Import all object constructor functions: \& # array immarray array_of immarray_of \& # hash immhash hash_of immhash_of \& use List::Objects::WithUtils; \& \& # Import all of the above plus autoboxing: \& use List::Objects::WithUtils \*(Aq:all\*(Aq; \& # Same as above, but shorter: \& use Lowu; \& \& # Most methods returning lists return new objects; chaining is easy: \& array(qw/ aa Ab bb Bc bc /) \& \->grep(sub { /^b/i }) \& \->map(sub { uc }) \& \->uniq \& \->all; # ( \*(AqBB\*(Aq, \*(AqBC\*(Aq ) \& \& # Useful utilities from other list modules are available: \& my $want_idx = array( \& +{ id => \*(Aq400\*(Aq, user => \*(Aqbob\*(Aq }, \& +{ id => \*(Aq600\*(Aq, user => \*(Aqsuzy\*(Aq }, \& +{ id => \*(Aq700\*(Aq, user => \*(Aqfred\*(Aq }, \& )\->first_index(sub { $_\->{id} > 500 }); \& \& my $itr = array( 1 .. 7 )\->natatime(3); \& while ( my @nextset = $itr\->() ) { \& ... \& } \& \& my $meshed = array(qw/ a b c d /) \& \->mesh( array(1 .. 4) ) \& \->all; # ( \*(Aqa\*(Aq, 1, \*(Aqb\*(Aq, 2, \*(Aqc\*(Aq, 3, \*(Aqd\*(Aq, 4 ) \& \& my ($evens, $odds) = array( 1 .. 20 ) \& \->part(sub { $_[0] & 1 }) \& \->all; \& \& my $sorted = array( \& +{ name => \*(Aqbob\*(Aq, acct => 1 }, \& +{ name => \*(Aqfred\*(Aq, acct => 2 }, \& +{ name => \*(Aqsuzy\*(Aq, acct => 3 }, \& )\->sort_by(sub { $_\->{name} }); \& \& # array() objects are mutable: \& my $mutable = array(qw/ foo bar baz /); \& $mutable\->insert(1, \*(Aqquux\*(Aq); \& $mutable\->delete(2); \& \& # ... or use immarray() immutable arrays: \& my $static = immarray( qw/ foo bar baz / ); \& $static\->set(0, \*(Aqquux\*(Aq); # dies \& $static\->[0] = \*(Aqquux\*(Aq; # dies \& push @$static, \*(Aqquux\*(Aq; # dies \& \& # Construct a hash: \& my $hash = hash( foo => \*(Aqbar\*(Aq, snacks => \*(Aqcake\*(Aq ); \& \& # You can set multiple keys in one call: \& $hash\->set( foobar => \*(Aqbaz\*(Aq, pie => \*(Aqcherry\*(Aq ); \& \& # ... which is useful for merging in another (plain) hash: \& my %foo = ( pie => \*(Aqpumpkin\*(Aq, snacks => \*(Aqcheese\*(Aq ); \& $hash\->set( %foo ); \& \& # ... or another hash object: \& my $second = hash( pie => \*(Aqkey lime\*(Aq ); \& $hash\->set( $second\->export ); \& \& # Retrieve one value as a simple scalar: \& my $snacks = $hash\->get(\*(Aqsnacks\*(Aq); \& \& # ... or retrieve multiple values as an array\-type object: \& my $vals = $hash\->get(\*(Aqfoo\*(Aq, \*(Aqfoobar\*(Aq); \& \& # Take a hash slice of keys, return a new hash object \& # consisting of the retrieved key/value pairs: \& my $slice = $hash\->sliced(\*(Aqfoo\*(Aq, \*(Aqpie\*(Aq); \& \& # Arrays inflate to hash objects: \& my $items = array( qw/ foo bar baz/ )\->map(sub { $_ => 1 })\->inflate; \& if ($items\->exists(\*(Aqfoo\*(Aq)) { \& # ... \& } \& \& # Hashes inflate to simple objects with accessors: \& my $obj = $hash\->inflate; \& $snacks = $obj\->snacks; \& \& # Methods returning multiple values typically return new array\-type objects: \& my @match_keys = $hash\->keys\->grep(sub { m/foo/ })\->all; \& my @match_vals = $hash\->values\->grep(sub { m/bar/ })\->all; \& \& my @sorted_pairs = hash( foo => 2, bar => 3, baz => 1) \& \->kv \& \->sort_by(sub { $_\->[1] }) \& \->all; # ( [ baz => 1 ], [ foo => 2 ], [ bar => 3 ] ) \& \& # Perl6\-inspired Junctions: \& if ( $hash\->keys\->any_items == qr/snacks/ ) { \& # ... hash has key(s) matching /snacks/ ... \& } \& if ( $hash\->values\->all_items > 10 ) { \& # ... all hash values greater than 10 ... \& } \& \& # Type\-checking arrays via Type::Tiny: \& use Types::Standard \-all; \& my $int_arr = array_of Int() => 1 .. 10; \& \& # Type\-checking hashes: \& use Types::Standard \-all; \& my $int_hash = hash_of Int() => (foo => 1, bar => 2); \& \& # Native list types can be autoboxed: \& use List::Objects::WithUtils \*(Aqautobox\*(Aq; \& my $foo = [ qw/foo baz bar foo quux/ ]\->uniq\->sort; \& my $bar = +{ a => 1, b => 2, c => 3 }\->values\->sort; \& \& # Autoboxing is lexically scoped like normal: \& { no List::Objects::WithUtils::Autobox; \& [ 1 .. 10 ]\->shuffle; # dies \& } .Ve .SH "DESCRIPTION" .IX Header "DESCRIPTION" A set of roles and classes defining an object-oriented interface to Perl hashes and arrays with useful utility methods, junctions, type-checking ability, and optional autoboxing. Originally derived from Data::Perl. .SS "Uses" .IX Subsection "Uses" The included objects are useful as-is but are largely intended for use as data container types for attributes. This lends a more natural object-oriented syntax; these are particularly convenient in combination with delegated methods, as in this example: .PP .Vb 3 \& package Some::Thing; \& use List::Objects::WithUtils; \& use Moo; \& \& has items => ( \& is => \*(Aqro\*(Aq, \& builder => sub { array }, \& handles => +{ \& add_items => \*(Aqpush\*(Aq, \& get_items => \*(Aqall\*(Aq, \& items_where => \*(Aqgrep\*(Aq, \& }, \& ); \& \& # ... later ... \& my $thing = Some::Thing\->new; \& $thing\->add_items(@more_items); \& # Operate on all positive items: \& for my $item ($thing\->items_where(sub { $_ > 0 })\->all) { \& ... \& } .Ve .PP List::Objects::Types provides Type::Tiny\-based types & coercions matching the list objects provided by this distribution. These integrate nicely with typed or untyped list objects: .PP .Vb 3 \& package Accounts; \& use List::Objects::Types \-types; \& use Moo 2; \& \& has usergroups => ( \& is => \*(Aqro\*(Aq, \& # +{ $group => [ [ $usr => $id ], ... ] } \& # Coerced to objects all the way down: \& isa => TypedHash[ TypedArray[ArrayObj] ], \& coerce => 1, \& builder => sub { +{} }, \& ); \& \& # ... later ... \& my $users_in_grp = $accts\->usergroups \& \->get($some_group) \& \->grep(sub { $_[0]\->get(0) }); .Ve .SS "Objects" .IX Subsection "Objects" \fIArrays\fR .IX Subsection "Arrays" .PP \&\fBarray\fR (List::Objects::WithUtils::Array) provides basic mutable ARRAY-type objects. Behavior is defined by List::Objects::WithUtils::Role::Array; look there for documentation on available methods. .PP \&\fBimmarray\fR is imported from List::Objects::WithUtils::Array::Immutable and operates much like an \fBarray\fR, except methods that mutate the list are not available; using immutable arrays promotes safer programming patterns. .PP \&\fBarray_of\fR provides Type::Tiny\-compatible type-checking array objects that can coerce and check their values as they are added; see List::Objects::WithUtils::Array::Typed. .PP \&\fBimmarray_of\fR provides immutable type-checking arrays; see List::Objects::WithUtils::Array::Immutable::Typed. .PP \fIHashes\fR .IX Subsection "Hashes" .PP \&\fBhash\fR is the basic mutable HASH-type object imported from List::Objects::WithUtils::Hash; see List::Objects::WithUtils::Role::Hash for documentation. .PP \&\fBimmhash\fR provides immutable (restricted) hashes; see List::Objects::WithUtils::Hash::Immutable. .PP \&\fBhash_of\fR provides Type::Tiny\-compatible type-checking hash objects; see List::Objects::WithUtils::Hash::Typed. .PP \&\fBimmhash_of\fR provides immutable type-checking hashes; see List::Objects::WithUtils::Hash::Immutable::Typed. .SS "Importing" .IX Subsection "Importing" A bare import list (\f(CW\*(C`use List::Objects::WithUtils;\*(C'\fR) will import all of the object constructor functions described above; they can also be selectively imported, e.g.: .PP .Vb 1 \& use List::Objects::WithUtils \*(Aqarray_of\*(Aq, \*(Aqhash_of\*(Aq; .Ve .PP Importing \fBautobox\fR lexically enables List::Objects::WithUtils::Autobox, which provides List::Objects::WithUtils::Array or List::Objects::WithUtils::Hash methods for native \s-1ARRAY\s0 and \s-1HASH\s0 types. .PP Importing \fBall\fR or \fB:all\fR will import all of the object constructors and additionally turn \fBautobox\fR on; \f(CW\*(C`use Lowu;\*(C'\fR is a shortcut for importing \&\fBall\fR. .SS "Debugging" .IX Subsection "Debugging" Most methods belonging to these objects are heavily micro-optimized \*(-- at the cost of useful error handling. .PP Since there are few built-in argument checks, a mistake in your code can frequently lead to slightly cryptic errors from the perl side: .PP .Vb 3 \& > my $pos; # whoops, I\*(Aqm still undefined later: \& > if ($arr\->exists($pos)) { ... } \& Use of uninitialized value in numeric le (<=) at $useless_lib_lineno .Ve .PP \&... in which case Devel::Confess is likely to improve your quality of life by providing a real backtrace: .PP .Vb 3 \& $ perl \-d:Confess my_app.pl \& Use of uninitialized value in numeric le (<=) at ... \& [...]::Array::exists(ARRAY(0x8441068), undef) called at ... .Ve .SS "Subclassing" .IX Subsection "Subclassing" The importer for this package is somewhat flexible; a subclass can override import to pass import tags and a target package by feeding this package's \&\f(CW\*(C`import()\*(C'\fR a \s-1HASH:\s0 .PP .Vb 12 \& # Subclass and import to target packages (see Lowu.pm f.ex): \& package My::Defaults; \& use parent \*(AqList::Objects::WithUtils\*(Aq; \& sub import { \& my ($class, @params) = @_; \& $class\->SUPER::import( \& +{ \& import => [ \*(Aqautobox\*(Aq, \*(Aqarray\*(Aq, \*(Aqhash\*(Aq ], \& to => scalar(caller) \& } \& ) \& } .Ve .PP Functionality is mostly defined by Roles. For example, it's easy to create your own array class with new methods: .PP .Vb 5 \& package My::Array::Object; \& use Role::Tiny::With; \& # Act like List::Objects::WithUtils::Array: \& with \*(AqList::Objects::WithUtils::Role::Array\*(Aq, \& \*(AqList::Objects::WithUtils::Role::Array::WithJunctions\*(Aq; \& \& # One way to add your own functional interface: \& use Exporter \*(Aqimport\*(Aq; our @EXPORT = \*(Aqmy_array\*(Aq; \& sub my_array { _\|_PACKAGE_\|_\->new(@_) } \& \& # ... add/override methods ... .Ve .PP \&... in which case you may want to also define your own hash subclass that overrides \f(CW\*(C`array_type\*(C'\fR to produce your preferred arrays: .PP .Vb 3 \& package My::Hash::Object; \& use Role::Tiny::With; \& with \*(AqList::Objects::WithUtils::Role::Hash\*(Aq; \& \& use Exporter \*(Aqimport\*(Aq; our @EXPORT = \*(Aqmy_hash\*(Aq; \& sub my_hash { _\|_PACKAGE_\|_\->new(@_) } \& \& sub array_type { \*(AqMy::Array::Object\*(Aq } \& \& # ... add/override methods ... .Ve .SH "SEE ALSO" .IX Header "SEE ALSO" List::Objects::WithUtils::Role::Array for documentation on the basic set of \&\f(CW\*(C`array()\*(C'\fR methods. .PP List::Objects::WithUtils::Role::Array::WithJunctions for documentation on \f(CW\*(C`array()\*(C'\fR junction-returning methods. .PP List::Objects::WithUtils::Array::Immutable for more on \f(CW\*(C`immarray()\*(C'\fR immutable arrays. .PP List::Objects::WithUtils::Array::Typed for more on \f(CW\*(C`array_of()\*(C'\fR type-checking arrays. .PP List::Objects::WithUtils::Array::Immutable::Typed for more on \&\f(CW\*(C`immarray_of()\*(C'\fR immutable type-checking arrays. .PP List::Objects::WithUtils::Role::Hash for documentation regarding \f(CW\*(C`hash()\*(C'\fR methods. .PP List::Objects::WithUtils::Hash::Immutable for more on \f(CW\*(C`immhash()\*(C'\fR immutable hashes. .PP List::Objects::WithUtils::Hash::Typed for more on \f(CW\*(C`hash_of()\*(C'\fR type-checking hashes. .PP List::Objects::WithUtils::Hash::Immutable::Typed for more on \&\f(CW\*(C`immhash_of()\*(C'\fR immutable type-checking hashes. .PP List::Objects::WithUtils::Autobox for details on autoboxing. .PP The Lowu module for a convenient importer shortcut. .PP List::Objects::Types for relevant Type::Tiny types. .PP MoopsX::ListObjects for integration with Moops class-building sugar. .SH "AUTHOR" .IX Header "AUTHOR" Jon Portnoy .PP Licensed under the same terms as Perl. .PP The original Array and Hash roles were derived from Data::Perl by Matthew Phillips (\s-1CPAN: MATTP\s0), haarg, and others. .PP Immutable array objects were originally inspired by Const::Fast by Leon Timmermans (\s-1CPAN: LEONT\s0), but now use \f(CW\*(C`tie\*(C'\fR. .PP Junctions are adapted from Perl6::Junction by Carl Franks (\s-1CPAN: CFRANKS\s0) .PP Most of the type-checking code and other useful additions were contributed by Toby Inkster (\s-1CPAN: TOBYINK\s0) .PP A significant portion of this code simply wraps other widely-used modules, especially: .PP List::Util .PP List::UtilsBy .PP Type::Tiny .PP Inspiration for a few pieces comes from the \*(L"classic\*(R" (version 0.33) List::MoreUtils.