MooseでList::RubyLike

List::RubyLikeをMoose::Autobox用に移植してみました。
まだ足りないメソッドはありますが、おいおい追加していきます。

コード

package Moose::Autobox::Array::RubyLike;
use Moose::Role;
use Moose::Autobox;
use List::Util;
use Carp qw/croak/;

our $VERSION = '0.01';

sub find {
    my ( $array, $cond ) = @_;
    my $code
        = ( ref $cond and ref $cond eq 'CODE' )
        ? $cond
        : sub { $_ eq $cond };

    for (@$array) { &$code and return $_ }
    return;
}

sub delete_at {
    my ( $array, $pos ) = @_;
    my $last_index = $array->_last_index;
    return if $pos > $last_index;
    my $result;
    $_ == $pos
        ? $result
        = $array->shift
        : $array->push( $array->shift )
        for 0 .. $last_index;
    return $result;
}

sub delete_if {
    my ( $array, $code ) = @_;
    croak "Argument must be a code" unless ref $code eq 'CODE';
    my $last_index = $array->_last_index;
    for ( 0 .. $last_index ) {
        my $item = $array->shift;
        local $_ = $item;
        $array->push($item) if $code->($_);
    }
    return $array;
}

sub _last_index {
    my $array = CORE::shift;
    $array->length ? $array->length - 1 : 0;
}

sub each {
    my ( $array, $code ) = @_;
    croak "Argument must be a code" unless ref $code eq 'CODE';
    my @copied = @{$array};
    $code->($_) for @copied;
    $array;
}

sub compact {
    my $array = shift;
    $array->grep( sub {defined} );
}

sub is_empty {
    !$_[0]->length;
}

sub sum {
    List::Util::sum @{ $_[0] };
}

*collect = \↦

1;

__END__

テスト

#!/usr/bin/perl
use strict;
use warnings;

use Test::More tests => 15;

BEGIN {
    use_ok('Moose::Autobox');
}

use Moose::Autobox;
Moose::Autobox->mixin_additional_role( 'ARRAY',
    'Moose::Autobox::Array::RubyLike' );

#find
my $list = [ 1 .. 3 ];
is $list->find( sub { $_ == 1 } ), 1, 'contain 1';
is $list->find( sub { $_ == 2 } ), 2, 'contain 2';
is $list->find( sub { $_ == 3 } ), 3;
is $list->find( sub { $_ == 4 } ), undef;
is $list->find(1), 1;
is $list->find(2), 2;
is $list->find(3), 3;
is $list->find(4), undef;

# delete_at
$list = [ 1, 2, 3, 4, 5 ];
ok not $list->delete_at(5);
is_deeply( $list->delete_at(2), 3 );
is_deeply( $list->delete_at(0), 1 );

# delete_if
$list = [ 1, 2, 3, 4, 5 ];
is_deeply( $list->delete_if( sub { $_ < 3 ? 1 : 0 } ), [ 1, 2 ] );

# each
$list = [ &#39;foo&#39;, &#39;bar&#39;, &#39;baz&#39; ];
my @resulsts;
my $ret = $list->each( sub { s!^ba!!; push @resulsts, $_ } );
is_deeply \@resulsts, [ &#39;foo&#39;, &#39;r&#39;,   &#39;z&#39; ];
is_deeply $ret,       [ &#39;foo&#39;, &#39;bar&#39;, &#39;baz&#39; ];

# 微妙にメソッドが足りないのは後で追加する予定。githubにでもいれとくかなぁ。
# 本当はMoose::Autobox::Listのほうに追加したいんだけど、ちとMoose::Autobox::List, Moose::Autobox::Arrayを結構変更しないといけない。