use strict; use warnings; use Test::More; { package Foo; use Moose; use Moose::Util::TypeConstraints; subtype 'UCArray', as 'ArrayRef[Str]', where { !grep {/[a-z]/} @{$_}; }; coerce 'UCArray', from 'ArrayRef[Str]', via { [ map { uc $_ } @{$_} ]; }; has array => ( traits => ['Array'], is => 'rw', isa => 'UCArray', coerce => 1, handles => { push_array => 'push', set_array => 'set', }, ); our @TriggerArgs; has lazy => ( traits => ['Array'], is => 'rw', isa => 'UCArray', coerce => 1, lazy => 1, default => sub { ['a'] }, handles => { push_lazy => 'push', set_lazy => 'set', }, trigger => sub { @TriggerArgs = @_ }, clearer => 'clear_lazy', ); } my $foo = Foo->new; { $foo->array( [qw( A B C )] ); $foo->push_array('d'); is_deeply( $foo->array, [qw( A B C D )], 'push coerces the array' ); $foo->set_array( 1 => 'x' ); is_deeply( $foo->array, [qw( A X C D )], 'set coerces the array' ); } { $foo->push_lazy('d'); is_deeply( $foo->lazy, [qw( A D )], 'push coerces the array - lazy' ); is_deeply( \@Foo::TriggerArgs, [ $foo, [qw( A D )], ['A'] ], 'trigger receives expected arguments' ); $foo->set_lazy( 2 => 'f' ); is_deeply( $foo->lazy, [qw( A D F )], 'set coerces the array - lazy' ); is_deeply( \@Foo::TriggerArgs, [ $foo, [qw( A D F )], [qw( A D )] ], 'trigger receives expected arguments' ); } { package Thing; use Moose; has thing => ( is => 'ro', isa => 'Int', ); } { package Bar; use Moose; use Moose::Util::TypeConstraints; class_type 'Thing'; coerce 'Thing' => from 'Int' => via { Thing->new( thing => $_ ) }; subtype 'ArrayRefOfThings' => as 'ArrayRef[Thing]'; coerce 'ArrayRefOfThings' => from 'ArrayRef[Int]' => via { [ map { Thing->new( thing => $_ ) } @{$_} ] }; coerce 'ArrayRefOfThings' => from 'Int' => via { [ Thing->new( thing => $_ ) ] }; has array => ( traits => ['Array'], is => 'rw', isa => 'ArrayRefOfThings', coerce => 1, handles => { push_array => 'push', unshift_array => 'unshift', set_array => 'set', insert_array => 'insert', }, ); } { my $bar = Bar->new( array => [ 1, 2, 3 ] ); $bar->push_array( 4, 5 ); is_deeply( [ map { $_->thing } @{ $bar->array } ], [ 1, 2, 3, 4, 5 ], 'push coerces new members' ); $bar->unshift_array( -1, 0 ); is_deeply( [ map { $_->thing } @{ $bar->array } ], [ -1, 0, 1, 2, 3, 4, 5 ], 'unshift coerces new members' ); $bar->set_array( 3 => 9 ); is_deeply( [ map { $_->thing } @{ $bar->array } ], [ -1, 0, 1, 9, 3, 4, 5 ], 'set coerces new members' ); $bar->insert_array( 3 => 42 ); is_deeply( [ map { $_->thing } @{ $bar->array } ], [ -1, 0, 1, 42, 9, 3, 4, 5 ], 'insert coerces new members' ); } { package Baz; use Moose; use Moose::Util::TypeConstraints; subtype 'SmallArrayRef' => as 'ArrayRef' => where { @{$_} <= 2 }; coerce 'SmallArrayRef' => from 'ArrayRef' => via { [ @{$_}[ -2, -1 ] ] }; has array => ( traits => ['Array'], is => 'rw', isa => 'SmallArrayRef', coerce => 1, handles => { push_array => 'push', set_array => 'set', insert_array => 'insert', }, ); } { my $baz = Baz->new( array => [ 1, 2, 3 ] ); is_deeply( $baz->array, [ 2, 3 ], 'coercion truncates array ref in constructor' ); $baz->push_array(4); is_deeply( $baz->array, [ 3, 4 ], 'coercion truncates array ref on push' ); $baz->insert_array( 1 => 5 ); is_deeply( $baz->array, [ 5, 4 ], 'coercion truncates array ref on insert' ); $baz->push_array( 7, 8, 9 ); is_deeply( $baz->array, [ 8, 9 ], 'coercion truncates array ref on push' ); } done_testing;