It took me a little while to figure this one out so I thought I post it here, partly to make it easier for myself to find it next time ;-)

I write software for biological applications and I use Moose. My modules often take biological sequence data as input, so I create a subtype for strings that fulfill a regex for valid DNA sequences (in this case I only allow the letters A,G,T, C and N). This is in a package MyApp::MooseX::MyTypes:

subtype 'DNAString' => as Str => where { $_ && $_=~/^[AGCTN]+$/i} => message {"Not a DNA string: only AGCT or N allowed and cannot be +empty"};
Now my modules can define attributes like this:
use MyApp::MooseX::MyTypes: has sequence => ( isa => 'DNAString', );
So far so good, but sequences in biological applications in Perl often exist in the form of Bio::Seq objects and I thought it would be nice if my DNAString type could automatically get the sequence string from such objects. However, you can only coerce from Moose built-in types, so I wanted to say: coerce from an incoming object into a sequence string, if that object has a 'seq' method (which returns the sequence as a string in BioPerl).
Turns out that this can be done like this (in MyApp::MooseX::MyTypes again):
coerce 'DNAString' => from duck_type( ['seq'] ) => via { $_->seq };
And then you need to tell the constructor that you want to use coercions for this attribute by adding the 'coerce' switch:
use MyApp::MooseX::MyTypes: has sequence => ( isa => 'DNAString', coerce => 1, );
Now all my modules that used to only accept sequence strings, automatically except Bio::Seq objects as well.

Replies are listed 'Best First'.
Re: Of moose and ducks (or: how to coerce from non-Moose type objects)
by stvn (Monsignor) on Jan 08, 2011 at 00:59 UTC

    You could have also done this ...

    class_type('Bio::Seq'); coerce 'DNAString' => from 'Bio::Seq' => via { $_->seq };
    Moose class types are not restricted to Moose created classes, you can make one for any plain old Perl class. Of course the version you have is more flexible, assuming you know you can trust the seq method.

    -stvn
      Ah, ok - I didn't know the class_type construct. That's a useful one. But in this case, I think my version is more suitable because there are many BioPerl classes that implement a 'seq' method, so ducktyping is indeed more flexible.