Using blessed CodeRefs with Moose type constraints

533 views Asked by At

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.

2

There are 2 answers

0
ikegami On BEST ANSWER

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:

  • Unblessed code references.
  • Blessed code references.
  • Objects that pretend to be code references (i.e. those that overload &{}).

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;
0
Axeman On

Do you know enough to get from Scalar::Util::reftype?