perlmoosemoosex-types

Using blessed CodeRefs with Moose type constraints


We use Moose classes that serialize iterators into various output formats. We describe the iterator as an attribute:

has iterator => (
    is => 'ro',
    isa => 'CodeRef',
    required => 1,
);

This has worked fine so far, but we have lately been using Iterator::Simple to prepare iterators for later consumption. This means that we can go about writing this:

has iterator => (
    is => 'ro',
    isa => 'CodeRef|Iterator::Simple::Iterator',
    required => 1,
);

And allow our serializers to accept the iterator class correctly. However, that seems to be a incomplete solution.

Is there a way in Moose to specify the constraint that the attribute must be callable? I suspect it may be possible with Moose::Util::TypeConstraints and using overload::Overloaded on &{} to check, but I'd like to know if anyone has created a module to do this already or if there is a Moose-standard way to test for this.


Solution

  • CodeRef only allows unblessed code references. Fortunately, it's easy to make your own types.

    Define Callable as shown below, then use it instead of CodeRef. It allows the following:

    use Moose::Util::TypeConstraints;
    use overload     qw( );
    use Scalar::Util qw( );
    
    subtype 'Callable'
        => as 'Ref'
        => where {
              Scalar::Util::reftype($_) eq 'CODE'
                 ||
              Scalar::Util::blessed($_) && overload::Method($_, "&{}")
           }
    
        # Written such that parent's inline_as needs not be prepended.
        => inline_as {'(
              (Scalar::Util::reftype('.$_[1].') // "") eq 'CODE'
                 ||
              Scalar::Util::blessed('.$_[1].') && overload::Method('.$_[1].', "&{}")
           )'};
    
    no Moose::Util::TypeConstraints;