On Wed, Jan 14, 2009 at 1:06 PM, Howe, Tom (IT) <tom.h...@morganstanley.com> wrote: > I have something like this: > > subtype 'Thing' > => as 'Object' > => where { $_->isa('ThingClass') }; > > coerce 'Thing' > => from 'Str' > => via { ThingClass->new ( xyz=> $_ ) }; > > > has 'things' => ( > is=>'rw', > isa=>'ArrayRef[Thing]', > lazy=>1, > coerce=>1, > auto_deref=>1, > default => sub { [] }, > }; > > > But if I pass in a list of strings to convert to Things, I get the error: > > "Cannot coerce without a type coercion" > > I've managed to get around it by defining a type 'ArrayRef[Thing]' > > Eg > Subtype 'ArrayRef[Thing]' > => as 'ArrayRef' > => where { > foreach (@{$_} .... > }; > > Coerce 'ArrayRef[Thing]' > => from 'ArrayRef' > > But this means > A) I'm essentially reimplementing ArrayRef each time. > B) It always coerces!
isa => 'Arrayref[Thing]' is setting up the subtype for you, so you don't need to do that explicitly You will need to create the coercion however, and yes every time you enable coerce => 1 Moose will look for an applicable coercion (for example: from ArrayRef to ArrayRef[Thing]) and apply it. > It should ideally check before it coerces... > > Anything I can do to improve on this? What are you hoping it will check? Moose doesn't do any kind of "Deep Coercion" because the edge cases become far to messy to handle in an elegant way ... or at least so far as anybody has thought of. What you are doing seems to be the right solution ... with my comments about the "subtype ArrayRef[Thing]" statment being optionally implicit. > Also, I'd like to be able to declare something like > > has 'foo' => ( is=>'rw', delegate=> sub { Foo->instance }, handles =>[qw/x y > z/] ) > > Where, if no value is passed in to foo() on construction, the accessor > created for foo() will always trigger the delegate sub but will not store > anything in the object in the way default does. > > > I tried this .. > > has 'foo' => ( is=>'rw', isa=>'Object', handles=> [qw/meth1 meth2 meth3/]); > > around 'foo' => sub { > my ($next,$self,@args) = @_; > if (@args) { > return $self->$next(@args); > } else { > return $self->$next() || Foo->instance(); > } > }; > > But got error: > > Cannot delegate meth1 to meth1 because the value of foo is not defined... > > > Is there some way to do this? Uh ... not if I'm understanding what you're asking for properly. You want an attribute accessor to sometimes store and Object, and sometimes just call a Class Method on some random class if the attribute isn't set? You'll have to write that yourself: has foo => ( is => 'rw', predicate => '_has_foo', handles => [qw(one two three)] ); around [qw(one two three)] => sub { my ($next, $self) = (shift, shift); return Foo->instance->$next(@_) unless $self->_has_foo; return $self->$next(@_); }; You could probably wrap this up in a MooseX module with some sugar if you find your using it a lot, but I don't understand why you'd want to do that in the first place. -Chris