List::oo - object interface to list (array) methods


List-oo documentation Contained in the List-oo distribution.

Index


Code Index:

NAME

Top

List::oo - object interface to list (array) methods

SYNOPSIS

Top

Connecting multiple list functions together "reads" from right to left (starting with the data input way over on the right.)

This module provides a chainable method interface to array objects, which can be a bit more readable when multiple operations are involved.

This

  print join(' ', map({"|$_|"} qw(a b c))), "\n";

becomes:

  use List::oo qw(L);
  print L(qw(a b c))->map(sub {"|$_|"})->join(' '), "\n";

There is definitely some cost of execution speed. This is just an experiment. Comments and suggestions welcome.

Constructors

Top

new

  $l = List::oo->new(@array);

L

  $l = L(@array);

Strange Constructors

Top

This is only here because you so frequently need to start with a string op and L(split(...)) is ugly.

Aside: I'm not sure I really like this as an interface point. The need to use qr// is at least a little annoying.

Split

  my $l = Split(qr/\s+/, $string);

Convenience Functions

Top

F

Declare a subroutine.

  F{...};

See also lambda, which lets you use λ{} instead.

About the sub {...} syntax

Sadly, perl5 does not allow prototypes on methods. Thus, we cannot use the undecorated block syntax as with

  map({...} @list);

Rather, you must use the explicit sub {...} syntax

  $l->map(sub {...});

Or, use the F{} or λ{} shortcuts.

  use List::oo qw(F);
  ...
  $l->map(F{...});

With lambda

  use lambda;
  ...
  $l->map(λ{...});

(If the above doesn't render as the greek character lambda, your pod viewer is not playing nice.)

List Methods

Top

These methods are mostly analogous to the perl builtins. Where the builtin would return a list, we return a List::oo object. Where the builtin returns a scalar or some data which was not the primary list (e.g. push, pop, splice, etc.), you'll find some ifoo() methods (the 'i' prefix is for 'inline'.)

grep

  $l = $l->grep(sub {...});

map

  $l = $l->map(sub {...});

reverse

  $l = $l->reverse;

dice

Does things that can't be done with map.

  $l2 = $l->dice(sub {my @a = @_; ... return(@a);});

Feeds @$l into sub, which should return a perl list. Puts the results in a new List::oo object.

The purpose is simply to allow you to write an unbroken chain when you need to feed the entire list through some function which doesn't operate per-element.

Without this, you would have to break the chain of thought

  L(that_function($l->map(\&fx)->l))->map(\&fy);

With dice, simply insert it where it is needed.

  $l->map(\&fx)->dice(sub {that_function(@_)})->map(\&fy);

Note that in contrast to map() and grep() methods, dice() does not define the $_ variable.

What sort of functions need the whole list? Say you want to reverse the front and back half of a list, or maybe break a list of 20 items into 5 references of 4 items each. See the tests for examples.

sort

A lot like CORE::sort.

  $l->sort;

  $l->sort(sub {$a <=> $b});

Unfortunately, we don't get the sort $a/$b package variable magic. So, I set your package's $a and $b just like sort would. This means you might get "used only once" warnings, but you can silence these with:

  use List::oo qw($a $b);

The $a and $b imports have no other effect.

splice

Splices into @$l and returns the removed elements (or last element in scalar context) ala CORE::splice.

  $l->splice($offset, $length, @list);

With no replacement:

  $l->splice($offset, $length);

Remove everything from $offset onward

  $l->splice($offset);

Empties the list

  $l->splice;

Head and Tail Methods

Top

push

Returns the new length of the list.

  $l->push(@stuff);

pop

Removes and returns the last item.

  $l->pop;

shift

Removes and returns the first item.

  $l->shift;

unshift

Prepends @stuff to @$l and returns the new length of @$l.

  $l->unshift(@stuff);

Inlined Methods

Top

If you want to keep chaining calls together (and don't need to retrieve the pop/shift/splice data.)

ipush

  $l->map(sub {...})->ipush($val)->map(sub {...});

ipop

  $l->map(sub {...})->ipop->map(sub {...});

ishift

  $l->map(sub {...})->ishift->map(sub {...});

iunshift

  $l->map(sub {...})->iunshift($val)->map(sub {...});

isplice

  $l->map(sub {...})->isplice($offset, ...)->map(sub {...});

wrap

Add new values to the start and end.

  $l = $l->wrap($head,$tail);

Is just:

  $l->iunshift($head)->ipush($tail);

Additions to List::MoreUtils

Top

The lack of prototypes means I can't do everything that List::MoreUtils does in exactly the same way. I've chosen to make the bindings to multi-list methods take only single lists and added mfoo() methods here.

mmesh

Meshes @$l, @a, @b, @c, ...

  my $l = $l->mmesh(\@a, \@b, \@c, ...);

meach_array

Just the binding to List::MoreUtils::each_arrayref;

  my $iterator = $l->meach_array(\@a, \@b, \@c);

Give Me Back My List

Top

You can wrap the call chain in @{} or use one of the following methods.

flatten

If you really like to type.

  @list = $l->flatten;

l

The l is pretty flat and is the lowercase (less special) version of our terse constructor L().

  @list = $l->l;

Scalar Result Methods

Top

These only work at the end of a chain.

join

  $string = $l->join("\n");

length

Length of the list.

  $l->length;

List::Util / List::MoreUtils

Top

The following method documentation is autogenerated along with the wrappers of functions from List::Util and List::MoreUtils. The supported usage is shown (in some cases, these methods only support a subset of the function usage (due to the lack of method prototype support.)

The clusters of sigils (e.g. l=&l) are included as a shorthand reference. These sigils are what drive the code generation (see the source of List::oo::Extras and the build_extras.pl tool in the source repository for the dirty details.) The sigil on the left of the '=' represents the return value, the sigils on the right of the '=' represent what is passed to the wrapped function.

  l - a List::oo object (the $self when found on the right)
  L - an array of List::oo objects
  $ - a scalar
  @ - an array
  & - a subroutine reference (λ)

See List::Util and List::MoreUtils for more info.

INSERT_AUTODOC (if you find this in the .pod file, something went wrong)

AUTHOR

Top

Eric Wilhelm @ <ewilhelm at cpan dot org>

http://scratchcomputing.com/

Thanks to

Jim Keenan for contributions to the test suite.

BUGS

Top

If you found this module on CPAN, please report any bugs or feature requests through the web interface at http://rt.cpan.org. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.

If you pulled this development version from my /svn/, please contact me directly.

COPYRIGHT

Top

NO WARRANTY

Top

Absolutely, positively NO WARRANTY, neither express or implied, is offered with this software. You use this software at your own risk. In case of loss, no person or entity owes you anything whatsoever. You have been warned.

LICENSE

Top

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

SEE ALSO

Top

  EO::Array


List-oo documentation Contained in the List-oo distribution.
package List::oo;
$VERSION = v0.2.1;

use warnings;
use strict;

use Carp;

use List::oo::Extras;

require Exporter;
*{import} = \&Exporter::import;

our @EXPORT_OK = qw(
  L
  Split
  F
  $a
  $b
  );

# XXX now I need tags

sub new {
  my $caller = CORE::shift;
  my $class = ref($caller) || $caller;
  my $self = [@_];
  bless($self, $class);
  return($self);
} # end subroutine new definition
########################################################################

sub L {
  return(List::oo->new(@_));
} # end subroutine L definition
########################################################################

sub Split {
  my ($regex, $string) = @_;
  ## warn "$regex, $string\n";
  UNIVERSAL::isa($regex, 'Regexp') or
    croak("First argument to Split must be a regular expression");
  return(List::oo->new(split($regex, $string)));
} # end subroutine Split definition
########################################################################

sub F (&) {
  my $sub = CORE::shift(@_);
  @_ and croak;
  UNIVERSAL::isa($sub, 'CODE') and return($sub);
  eval($sub->isa('List::oo')) and croak 'not a method';
  croak('why bother');
} # end subroutine F definition
########################################################################

sub grep {
  my $self = CORE::shift;
  my $sub = CORE::shift;
  return($self->new(CORE::grep({$sub->($_)} @$self)));
} # end subroutine grep definition
########################################################################

sub map {
  my $self = CORE::shift;
  my $sub = CORE::shift;
  return($self->new(CORE::map({$sub->($_)} @$self)));
} # end subroutine map definition
########################################################################

sub reverse {
  my $self = CORE::shift;
  return($self->new(CORE::reverse(@$self)));
} # end subroutine reverse definition
########################################################################

sub dice {
  my $self = CORE::shift;
  my $sub = CORE::shift;
  return($self->new($sub->(@$self)));
} # end subroutine dice definition
########################################################################

sub sort {
  my $self = CORE::shift;
  my $sub = CORE::shift;
  # XXX should these be in-place methods or not?
  if( $sub) {
    my $caller = caller;
    my ($ca, $cb) = map({eval('\\$'.$caller.'::'.$_)} qw(a b));
    return($self->new(CORE::sort(
      # sort sets my package vars, so I have to set them into
      # caller's here to make this work
      {($$ca, $$cb)=($a,$b); $sub->();}
      @$self))
    );
    # THE OTHER OPTION {{{
    # my @list = eval("package $caller; CORE::sort(\$sub \@\$self)");
    # return($self->new(@list));
    # }}}
  }
  else {
    return($self->new(CORE::sort(@$self)));
  }
} # end subroutine sort definition
########################################################################

sub splice {
  my $self = CORE::shift;
  if(@_ >= 3) {
    my ($o, $l) = (CORE::shift(@_), CORE::shift(@_));
    return CORE::splice(@$self, $o, $l, @_);
  }
  elsif(@_ == 2) {
    return CORE::splice(@$self, $_[0], $_[1]);
  }
  elsif(@_ == 1) {
    return CORE::splice(@$self, $_[0]);
  }
  else {
    return CORE::splice(@$self);
  }
} # end subroutine splice definition
########################################################################

sub push {
  my $self = CORE::shift;
  CORE::push(@$self, @_);
} # end subroutine push definition
########################################################################

sub pop {
  my $self = shift;
  pop(@$self);
} # end subroutine pop definition
########################################################################

*{List::oo::shift} = sub { # declaring like that makes CORE::shift() not needed
  my $self = CORE::shift;
  CORE::shift(@$self);
}; # end subroutine shift definition
########################################################################

sub unshift {
  my $self = shift;
  CORE::unshift(@$self, @_);
} # end subroutine unshift definition
########################################################################

foreach my $method (qw(push pop shift unshift splice)) {
  no strict 'refs';
  *{__PACKAGE__ . "::i$method"} = sub {
    my $self = CORE::shift;
    $self->$method(@_);
    return($self);
  };
}

sub wrap {
  my $self = CORE::shift;
  my ($head, $tail) = @_;
  $self->unshift($head);
  $self->push($tail);
  return($self);
} # end subroutine wrap definition
########################################################################

sub mmesh {
  my $self = shift;
  my (@lists) = @_;
  return($self->new(&List::MoreUtils::mesh($self, @lists)));
} # end subroutine mmesh definition
########################################################################

sub meach_array {
  goto &List::MoreUtils::each_arrayref;
} # end subroutine meach_array definition
########################################################################

sub flatten {
  my $self = CORE::shift;
  return(@$self);
} # end subroutine l definition
########################################################################
sub l {shift->flatten;}

sub join {
  my $self = CORE::shift;
  my $char = CORE::shift;
  return(CORE::join($char, @$self));
} # end subroutine join definition
########################################################################

sub length {
  my $self = CORE::shift;
  return(scalar(@$self));
} # end subroutine length definition
########################################################################

# if 'no Carp;' would work...
delete($List::oo::{$_}) for(qw(carp croak confess));

# these aren't methods either
#delete($List::oo::{$_}) for(qw(L F));

1;
# vim:ts=2:sw=2:et:sta:encoding=utf8