NAME

Types::Capabilities - don't care what type of data you are given, just what you can do with it

SYNOPSIS

Using Greppable in a method signature:

use experimental qw( signatures );

package LineFilter {
  use Moo;
  use Type::Params 'signature_for';
  use Types::Capabilities 'Greppable';
  use Types::Standard 'RegexpRef';
  
  has regexp => ( is => 'ro', isa => RegexpRef, required => 1 );
  
  signature_for print_matching_lines => (
    method     => 1,
    positional => [ Greppable ],
  );
  
  sub print_matching_lines ( $self, $source ) {
    my $re = $self->regexp;
    for my $line ( $source->grep( sub { /$re/ } ) ) {
      print $line, "\n";
    }
  }
}

my $greetings = LineFilter->new( regexp => qr/Hello/ );
$greetings->print_matching_lines( [ 'Hello world', 'Goodbye' ] );

Using Enqueueable and Dequeueable in an attribute type constraint:

use experimental qw( signatures try );

package TaskQueue {
  use Moose;
  use Types::Capabilities qw( +Enqueueable +Dequeueable );
  use Types::Common qw( +CodeRef );
  
  has queue => (
    is        => 'ro',
    isa       => Enqueueable & Dequeueable,
    default   => sub { [] },
    handles   => [ qw/ enqueue dequeue / ],
  );
  
  sub run_next ( $self ) {
    
    my $task = assert_CodeRef( $self->dequeue or return $self );
    
    try {
      $task->();
    }
    catch ( $e ) {
      warn "Error running task: $e, sending to back of queue";
      $self->enqueue( $task );
    }
    
    return $self;
  }
}

my $q = TaskQueue->new;
$q->enqueue( sub { ... } );
$q->enqueue( sub { ... } );
$q->run_next->run_next->run_next;

DESCRIPTION

This module allows you to indicate when you are designing your API that you don't care exactly what type of object is passed to you, as long as it's "greppable" or "sortable" or some other capability you want from the object.

In particular, in the "SYNOPSIS" example, the signature is checking that whatever value is provided for $source, it must offer a grep method. Exactly what the grep method does isn't checked by the type constraint, but the expected behaviour is that it must accept a coderef and, in list context, return the values matching the grep as a list.

The key feature that this module provides is that if $source is not an object with a grep method, but is an array ref or an object which overloads @{}, then it will be coerced into an object with a grep method.

CONSTRAINTS

This module is a Type::Library-based type constraint library and provides the following constraints.

Constraints for Collection-Like Objects

Mappable

An object which provides a map method.

The expectation is that the method should accept a coderef which transforms a single item in a collection. Called in list context, it should return the result of applying that to all items in that collection. The results of calling map in scalar context are not specified, but it may return another collection-like object which further operations can be carried out on.

Can be coerced from ArrayRef, Greppable, Eachable, ArrayLike, CodeRef, FileHandle, or File. (Files are read by line.)

Greppable

An object which provides a grep method.

The expectation is that the method should accept a coderef which returns a boolean for each item in a collection. Called in list context, it should return items in that collection where the coderef returned true. The results of calling grep in scalar context are not specified, but it may return another collection-like object which further operations can be carried out on.

Can be coerced from ArrayRef, Mappable, Eachable, ArrayLike, CodeRef, FileHandle, or File. (Files are read by line.)

Sortable

An object which provides a sort method.

The expectation is that the method should accept a coderef which compares two items, returning 1 if they are in the correct order, -1 if they are in the wrong order, and 0 if the two items are of equivalent order. Called in list context, it should return all the items in the collection sorted according to the coderef. The results of calling sort in scalar context are not specified, but it may return another collection-like object which further operations can be carried out on.

Can be coerced from ArrayRef, Mappable, Greppable, Eachable, CodeRef, FileHandle, or File. (Files are read by line.)

Reversible

An object which provides a reverse method.

The expectation is that when the method is called in list context, it should return all the items in the collection in reverse order. The results of calling reverse in scalar context are not specified, but it may return another collection-like object which further operations can be carried out on.

Can be coerced from ArrayRef, Mappable, Greppable, Eachable, ArrayLike, FileHandle, or File. (Files are read by line.)

Countable

An object which provides a count method.

The expectation is that when the method is called in scalar context, it should return the number of items in the collection.

Can be coerced from ArrayRef, Mappable, Greppable, Eachable, ArrayLike, FileHandle, or File. (Files are read by line.)

Joinable

An object which provides a join method.

The expectation is that when the method is called in scalar context, it should return a single item that is caused by joining all the items in the collection together, typically via string concatenation. The method may be passed a value to use as a separator; if no separator is given, the method may use a default separator, typically something like "," or the empty string.

Can be coerced from ArrayRef, Mappable, Greppable, Eachable, ArrayLike, FileHandle, or File. (Files are read by line.)

Eachable

An object which provides an each method.

The expectation is that when the method is called in void context and passed a coderef, it should call the coderef for each item in the collection.

Can be coerced from ArrayRef, Mappable, Greppable, ArrayLike, CodeRef, FileHandle, or File. (Files are read by line.).

Constraints for Queue-Like Objects

Enqueueable

An object which provides an enqueue method.

The expectation is that the method can be called with a single item to add that item to the end of the collection.

Can be coerced from ArrayRef, Mappable, Greppable, Eachable, ArrayLike, or CodeRef.

Note that if you coerce a Enqueueable object from a ArrayRef, then pushing onto the coerced object will also push onto the original array. In theory this should work for ArrayLike too, though it depends on how the original array-like object implemented overloading.

Dequeueable

An object which provides a dequeue method.

The expectation is that when the method is called in a scalar context, it will remove an item from the front of the collection and return it.

Can be coerced from ArrayRef, Mappable, Greppable, Eachable, ArrayLike, or CodeRef.

Note that if you coerce a Dequeueable object from a ArrayRef, then shifting from the coerced object will also shift from the original array. In theory this should work for ArrayLike too, though it depends on how the original array-like object implemented overloading.

Peekable

An object which provides a peek method.

The expectation is that when the method is called in a scalar context, it will return an item from the collection without altering the collection.

When used with a queue-like collection, it is expected to return the item at the front/start of the collection; the item which would be returned by dequeue. When used with a stack-like collection, it is expected to return the item at the back/end of the collection; the item which would be returned by pop. Otherwise, which item it returns is unspecified.

Can be coerced from ArrayRef, Mappable, Greppable, Eachable, or ArrayLike.

Constraints for Stack-Like Objects

Pushable

An object which provides a push method.

The expectation is that the method can be called with a single item to add that item to the end of the collection. (This behaviour is essentially the same as enqueue.)

Can be coerced from ArrayRef, Mappable, Greppable, Eachable, ArrayLike, or CodeRef.

Note that if you coerce a Pushable object from a ArrayRef, then pushing onto the coerced object will also push onto the original array. In theory this should work for ArrayLike too, though it depends on how the original array-like object implemented overloading.

Poppable

An object which provides a pop method.

The expectation is that when the method is called in a scalar context, it will remove an item from the end of the collection and return it.

Can be coerced from ArrayRef, Mappable, Greppable, Eachable, ArrayLike, or CodeRef.

Note that if you coerce a Pushable object from a ArrayRef, then popping from the coerced object will also pop from the original array. In theory this should work for ArrayLike too, though it depends on how the original array-like object implemented overloading.

Peekable

See description above.

Combined Capabilities

It is possible to specify that you need an object to provide multiple capabilities:

has task_queue => (
  is      => 'ro',
  isa     => Enqueueable & Dequeueable & Countable & Peekable,
  coerce  => 1,
);

General collection-like capabilities (like Eachable and Countable) may be combined with queue-like and stack-like capabilities.

Combining Conflicting Capabilities

Combining queue-like and stack-like capabilities with each other will work, but the coercion feature will stop working and you will need to design your own class to implement those capabilities.

has task_queue => (
  is      => 'ro',
  isa     => ( Enqueueable & Poppable )
               ->plus_coercions( ArrayRef, sub { MyClass->new($_) } ),
  coerce  => 1,
);

Coercion from CodeRef

Coderefs can be used as iterators to be coerced into Eachable, Mappable, and Greppable objects. The each, map, and grep methods will call the coderef in list context to return one or more items. The empty list should be returned to indicate that the iterator has been exhausted.

Coderefs can also be coerced to Dequeueable objects. The coderef will be is expected to dequeue and return a single item.

Coderefs can also be coerced to Enqueueable objects. The coderef will be called with a single item to enqueue.

Coderefs can also be coerced to Poppable objects. The coderef will be is expected to pop and return a single item.

Coderefs can also be coerced to Pushable objects. The coderef will be called with a single item to push.

Here is a simple implementation of a FIFO queue.

use v5.10;

# If an item is on @_, then enqueue it.
# Otherwise, it's a dequeue operation.
my $q = ( Enqueueable & Dequeueable )->coerce( sub {
  state $list = [];
  return push @$list, $_[0] if @_;
  return if !@$list;
  shift @$list;
} );

$q->enqueue( 'first' );
$q->enqueue( 'second' );
say $q->dequeue;   # first
$q->enqueue( 'third' );
say $q->dequeue;   # second
say $q->dequeue;   # third

Coercion from FileHandle and File

File handles opened for input can be coerced into Mappable, Greppable, Sortable, Reversible, Countable, Joinable, and Eachable objects.

Files are treated as lists of lines using "\n" as the line separator. Lines are chomped to remove the trailing "\n". seek($fh, 0, 0) at the start of each method.

Path::Tiny objects representing files will also work. They will be opened in UTF-8 mode.

The following variables can tweak how this coercion works, though be wary of changing them as it can have global effects.

$Types::Capabilities::CoercedValue::FILEHANDLE::INPUT_RECORD_SEPARATOR

Defaults to "\n".

$Types::Capabilities::CoercedValue::FILEHANDLE::AUTO_SEEK

Defaults to true.

$Types::Capabilities::CoercedValue::FILEHANDLE::AUTO_CHOMP

Defaults to true.

$Types::Capabilities::CoercedValue::FILEHANDLE::PATHTINY_FH_OPTIONS

Defaults to { locked => 1 }.

$Types::Capabilities::CoercedValue::FILEHANDLE::PATHTINY_FH_BINMODE

Defaults to ":utf8".

Note that the values of these variables at the time of coercion are what is important.

use Types::Capabilities qw( to_Eachable );

my $eachable = do {
  local $Types::Capabilities::CoercedValue::FILEHANDLE::INPUT_RECORD_SEPARATOR = "\r\n";
  to_Eachable( $fh );
};

$Types::Capabilities::CoercedValue::FILEHANDLE::INPUT_RECORD_SEPARATOR = "something else";

# Iterates through file using "\r\n" as the line ending.
$eachable->each( sub {
  ...;
} );

BUGS

Please report any bugs to https://github.com/tobyink/p5-types-capabilities/issues.

SEE ALSO

Largely inspired by: Data::Collection.

Sub::HandlesVia, Hydrogen::Autobox.

ArrayRef, CodeRef, and FileHandle are defined in Types::Standard.

ArrayLike is defined in Types::TypeTiny.

File is defined in Types::Path::Tiny.

AUTHOR

Toby Inkster <tobyink@cpan.org>.

COPYRIGHT AND LICENCE

This software is copyright (c) 2025-2026 by Toby Inkster.

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.

DISCLAIMER OF WARRANTIES

THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.