Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 797
angelixd Avatar asked Oct 08 '22 21:10

angelixd


1 Answers

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;
like image 148
ikegami Avatar answered Oct 13 '22 10:10

ikegami