NAME
List::Objects::WithUtils - List objects with useful methods
SYNOPSIS
## A small sample; consult the description, below, for links to
## extended documentation
# Import selectively:
use List::Objects::WithUtils 'array';
# Import 'array()', 'immarray()', 'hash()' object constructors:
use List::Objects::WithUtils;
# Import all functions:
use List::Objects::WithUtils ':functions';
# Import all of the above plus autoboxing:
use List::Objects::WithUtils ':all';
# Same, but via convenience shortcut:
use Lowu;
# Some simple chained array operations, eventually returning a plain list
# 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; # ( 'BB', 'BC' )
# Useful utilities from other list modules are available:
my $wanted = array(
+{ id => '200', user => 'bob' },
+{ id => '400', user => 'suzy' },
+{ id => '600', user => 'fred' },
)->first(sub { $_->{id} > 500 });
my $sum = array( 1, 2, 3 )->reduce(sub { $_[0] + $_[1] }); # 6
my $itr = array( 1 .. 7 )->natatime(3);
while ( my @nextset = $itr->() ) {
...
}
my $meshed = array(qw/ a b c d /)
->mesh( array(1 .. 4) )
->all; # ( 'a', 1, 'b', 2, 'c', 3, 'd', 4 )
my ($evens, $odds) = array( 1 .. 20 )
->part(sub { $_[0] & 1 })
->all;
my $sorted = array(
+{ name => 'bob', acct => 1 },
+{ name => 'fred', acct => 2 },
+{ name => 'suzy', acct => 3 },
)->sort_by(sub { $_->{name} });
# array() objects are mutable:
my $mutable = array(qw/ foo bar baz /);
$mutable->insert(1, 'quux');
$mutable->delete(2);
# ... or use immarray() immutable arrays:
my $static = immarray( qw/ foo bar baz / );
$static->set(0, 'quux'); # dies
$static->[0] = 'quux'; # dies
push @$static, 'quux'; # dies
# Simple hash operations; construct a hash:
my $hash = hash( foo => 'bar', snacks => 'cake' );
# You can set multiple keys in one call:
$hash->set( foobar => 'baz', pie => 'cherry' );
# ... which is useful for merging in another (plain) hash:
my %foo = ( pie => 'pumpkin', snacks => 'cheese' );
$hash->set( %foo );
# ... or another hash object:
my $second = hash( pie => 'key lime' );
$hash->set( $second->export );
# Retrieve one value as a simple scalar:
my $snacks = $hash->get('snacks');
# ... or retrieve multiple values as an array-type object:
my $vals = $hash->get('foo', 'foobar');
# Take a hash slice of keys, return a new hash object
# consisting of the retrieved key/value pairs:
my $slice = $hash->sliced('foo', 'pie');
# Chained method examples; methods that return 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 eq 'snacks' ) {
...
}
if ( $hash->values->all_items > 10 ) {
...
}
# Type-checking arrays:
use List::Objects::WithUtils 'array_of';
use Types::Standard -all;
my $int_arr = array_of( Int, 1 .. 10 );
# Type-checking hashes:
use List::Objects::WithUtils 'hash_of';
use Types::Standard -all;
my $int_hash = hash_of( Int, foo => 1, bar => 2 );
# Hashes can be inflated to objects:
my $obj = $hash->inflate;
$snacks = $obj->snacks;
# Native list types can be autoboxed:
use List::Objects::WithUtils 'autobox';
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
}
DESCRIPTION
A set of roles and classes defining an object-oriented interface to Perl hashes and arrays with useful utility methods, junctions, and optional autoboxing.
Originally derived from Data::Perl.
array is imported from List::Objects::WithUtils::Array and creates a new ARRAY-type object. Behavior is defined by List::Objects::WithUtils::Role::Array; look there for documentation on available methods.
immarray is imported from List::Objects::WithUtils::Array::Immutable and operates much like an array, except methods that mutate the list are not available and the backing ARRAY is marked read-only; using immutable arrays promotes safer functional patterns.
hash is imported from List::Objects::WithUtils::Hash; see List::Objects::WithUtils::Role::Hash for documentation.
Importing autobox lexically enables List::Objects::WithUtils::Autobox, providing methods for native ARRAY and HASH types.
A bare import list (use List::Objects::WithUtils;
) will import the array
, immarray
, and hash
functions.
Importing array_of gives you Type::Tiny-compatible type-checking array objects; see List::Objects::WithUtils::Array::Typed.
Importing hash_of gives you Type::Tiny-compatible type-checking hash objects; see List::Objects::WithUtils::Hash::Typed.
Importing functions or :functions will import all of the above.
Importing all or :all will import all of the above and additionally turn autobox on, as will the shortcut use Lowu;
(as of 1.003).
Why another object-oriented list module?
There are a fair few object-oriented approaches to lists on CPAN, none of which were quite what I needed. Data::Perl comes the closest -- but is primarily targetting MooX::HandlesVia and cannot guarantee a stable API at the time this was written (plus, I don't need the other data types).
This module aims to provide a consistent, natural interface to hashes and arrays exclusively, with convenient access to common tools. The interface is expected to remain stable; methods may be added but are not expected to be removed (or experience incompatible interface changes, barring serious bugs).
SEE ALSO
List::Objects::WithUtils::Role::Array for documentation on the basic set of array()
methods.
List::Objects::WithUtils::Role::WithJunctions for documentation on array()
junction-returning methods.
List::Objects::WithUtils::Role::Hash for documentation regarding hash()
methods.
List::Objects::WithUtils::Array::Immutable for more on immarray()
immutable arrays.
List::Objects::WithUtils::Array::Typed for more on array_of()
type-checking arrays.
List::Objects::WithUtils::Hash::Typed for more on hash_of()
type-checking hashes.
List::Objects::WithUtils::Autobox for details on autoboxing.
The Lowu module for a convenient importer shortcut.
List::Objects::Types for relevant Type::Tiny types.
MoopsX::ListObjects for integration with Moops class-building sugar.
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 import()
a HASH:
# Subclass and import to target packages (see Lowu.pm f.ex):
package My::Defaults;
use parent 'List::Objects::WithUtils';
sub import {
my ($class, @params) = @_;
$class->SUPER::import(
+{
import => [ 'autobox', 'array', 'hash' ],
to => scalar(caller)
}
)
}
Functionality is mostly defined by Roles. For example, it's easy to create your own array class with new methods:
package My::Array::Object;
use Role::Tiny::With;
with 'List::Objects::WithUtils::Role::Array',
'List::Objects::WithUtils::Role::WithJunctions';
# An easy way to add your own functional interface:
use Exporter 'import'; our @EXPORT = 'my_array';
sub my_array { __PACKAGE__->new(@_) }
# ... add/override methods ...
... in which case you may want to also define your own hash subclass that overrides array_type
to produce your preferred arrays:
package My::Hash::Object;
use Role::Tiny::With;
with 'List::Objects::WithUtils::Role::Hash';
use Exporter 'import'; our @EXPORT = 'my_hash';
sub my_hash { __PACKAGE__->new(@_) }
sub array_type { 'My::Array::Object' }
# ...
AUTHOR
Jon Portnoy <avenj@cobaltirc.org>
Licensed under the same terms as Perl.
The original Array and Hash roles were derived from Data::Perl by Matthew Phillips (CPAN: MATTP), haarg, and others.
Immutable array objects were inspired by Const::Fast.
Junctions are adapted from Perl6::Junction by Carl Franks.
Many of the useful type-checking bits were contributed by Toby Inkster (CPAN: TOBYINK).
Much of this code simply wraps other widely-used modules, including: