package MooseX::AttributeHelpers::Composite::Trait;
use Moose::Role;
use MooseX::AttributeHelpers::MethodProvider;
use MooseX::AttributeHelpers::Meta::Method::Provided;

has provides => (
    is      => 'ro',
    isa     => 'HashRef',
    default => sub { {} },
);

after install_accessors => sub {
    my $attr  = shift;
    my $class = $attr->associated_class;

    my $provides = $attr->provides;

    foreach my $method_provider (keys %$provides) {
        my $typename = get_provider_type($method_provider);
        confess "Attribute must be of type $typename to use $method_provider"
            unless ($attr->has_type_constraint
                    && $attr->type_constraint->is_a_type_of($typename));
    
        my $spec = $provides->{$method_provider};
        my $factories = get_provider_methods($method_provider, $spec);

        foreach my $method_name (keys %$factories) {
            confess "$method_name already exists in class " . $class->name
                if $class->has_method($method_name);

            my $method = MooseX::AttributeHelpers::Meta::Method::Provided->wrap(
                $factories->{$method_name}->(
                    $attr, 
                    $attr->get_read_method_ref, 
                    $attr->get_write_method_ref
                ),
            );
            $attr->associate_method($method);
            $class->add_method($method_name => $method)
        }
    }
};

1;

__END__

=pod

=head1 NAME

MooseX::AttributeHelpers::Composite:Trait

=head1 SYNOPSIS

    package Foo;
    use Moose;
    use MooseX::AttributeHelpers;
    
    has foo => (
        #metaclass => 'Composite',
        traits    => ['MooseX::AttributeHelpers::Composite::Trait'],
        is        => 'ro',
        isa       => 'Int',
        default   => 0,
        provides  => {
            Counter => {
                inc   => 'inc_foo',
                reset => 'reset_foo',
            },
            Number => {
                mul   => 'mul_foo',
            },
            # My::Method::Provider => {
            #     some_method => 'foo_method',
            #},
        },
    );
    
    package main;
    
    my $foo = Foo->new;
    $foo->inc_foo;
    $foo->mul_foo(3);
    print $foo->foo . "\n";
    # 3

=head1 DESCRIPTION

This is an expansion on the basic L<MooseX::AttributeHelpers> idea, allowing you
to compose the methods provided by the various
L<MethodProviders|MooseX::AttributeHelpers::MethodProvider> without naming
conflicts.  In addition, this module provides a way to get these helper
methods without being locked into a particular
L<metaclass|MooseX::AttributeHelpers::Composite>, as it is simply a role with
a provides attribute and a method modifier.  It cannot, however, be used with
old-style AttributeHelpers - the 'provides' name will conflict.

=head1 ATTRIBUTES

=over 4

=item provides

The map that tells Composite which methods from which providers you would like
installed under which names.  It follows the format 

    ProviderName => {
        provided_method => desired_method_name,
        ...
    },
    AnotherProvider => {
        ...
    },
    ...

=back

=head1 BUGS

All complex software has bugs lurking in it, and this module is no
exception. If you find a bug please either email me, or add the bug
to cpan-RT.

=head1 AUTHOR

Paul Driver E<lt>frodwith@cpan.orgE<gt>

=cut
