The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
package MooseX::Iterator::Meta::Iterable;
use Moose;
use MooseX::Iterator::Array;

use Carp 'confess';

our $VERSION   = '0.11';
our $AUTHORITY = 'cpan:RLB';

extends 'Moose::Meta::Attribute';

has iterate_over => ( is => 'ro', isa => 'Str', default => '' );

before '_process_options' => sub {
    my ( $class, $name, $options ) = @_;

    #if ( defined $options->{is} ) {
    #    confess "Can not use 'is' with the Iterable metaclass";
    #}
    $options->{is} = 'bare';
    $class->meta->add_attribute( iterate_name => ( is => 'ro', isa => 'Str', default => $name ) );
};

after 'install_accessors' => sub {
    my ($self) = @_;
    my $class = $self->associated_class;

    my $iterate_name    = $self->iterate_name;
    my $collection_name = $self->iterate_over;

    my $type       = $class->get_attribute($collection_name)->type_constraint->name;
    my $collection = $class->get_attribute($collection_name)->get_read_method;

    my $iterator_class_name = $self->_calculate_iterator_class_for_type($type);

    confess "Invalid iterator class given" if !$iterator_class_name;
    confess "$iterator_class_name does not implement MooseX::Iterator::Role" if !$iterator_class_name->does('MooseX::Iterator::Role');

    $class->add_method(
        $iterate_name => sub {
            my ($self) = @_;
            $iterator_class_name->new( collection => $self->$collection );
        }
    );
};

sub _calculate_iterator_class_for_type {
    my ( $self, $type ) = @_;

    if ( $type eq 'ArrayRef' ) {
        return 'MooseX::Iterator::Array';
    }
    elsif ( $type eq 'HashRef' ) {
        return 'MooseX::Iterator::Hash';
    }
}

no Moose;

package Moose::Meta::Attribute::Custom::Iterable;
sub register_implementation { 'MooseX::Iterator::Meta::Iterable' }

1;