use Scalar::Util 'blessed';
use Carp 'confess', 'croak', 'cluck';
+use List::MoreUtils qw( first_index );
use Sub::Exporter;
use Class::MOP;
}
);
+ sub _strip_traits {
+ my $at = shift;
+
+ my $idx = first_index { $_ eq '-traits' } @{ $at };
+
+ return unless $idx && $#{ $at } >= $idx + 1;
+
+ my $traits = $at->[ $idx + 1 ];
+
+ splice @{ $at }, $idx, 2;
+
+ return $traits;
+ }
+
# 1 extra level because it's called by import so there's a layer of indirection
sub _get_caller{
my $offset = 1;
: caller($offset);
}
+ sub _apply_meta_traits {
+ my ( $class, $traits ) = @_;
+
+ return
+ unless $traits && @{ $traits };
+
+ for my $trait ( @{ $traits } ) {
+ $trait->meta()->apply_to_metaclass_instance( $class->meta() );
+ }
+ }
+
sub import {
+ my $traits = _strip_traits(\@_);
+
$CALLER = _get_caller(@_);
# this works because both pragmas set $^H (see perldoc perlvar)
init_meta( $CALLER, 'Moose::Object' );
+ _apply_meta_traits( $CALLER, $traits );
+
goto $exporter;
}
}
}
+sub apply_to_metaclass_instance {
+ my ($self, $meta, @args) = @_;
+
+ $meta->isa('Moose::Meta::Class')
+ || confess "You must pass in a Moose::Meta::Class instance";
+
+ require Moose::Meta::Role::Application::ToMetaclassInstance;
+ return Moose::Meta::Role::Application::ToMetaclassInstance->new(@args)->apply($self, $meta);
+}
+
sub combine {
my ($class, @role_specs) = @_;
=item B<apply>
+=item B<apply_to_metaclass_instance>
+
=item B<combine>
=back
--- /dev/null
+package Moose::Meta::Role::Application::ToMetaclassInstance;
+
+use strict;
+use warnings;
+use metaclass;
+
+use Scalar::Util 'blessed';
+
+our $VERSION = '0.55';
+our $AUTHORITY = 'cpan:STEVAN';
+
+use base 'Moose::Meta::Role::Application::ToClass';
+
+__PACKAGE__->meta->add_attribute('rebless_params' => (
+ reader => 'rebless_params',
+ default => sub { {} }
+));
+
+my %ANON_CLASSES;
+
+sub apply {
+ my ($self, $role, $meta) = @_;
+
+ my $class = (blessed $meta)->create_anon_class(
+ superclasses => [ blessed($meta) ]
+ );
+
+ $self->SUPER::apply($role, $class);
+
+ $class->rebless_instance($meta, %{$self->rebless_params});
+}
+
+1;
+
+__END__
+
+=pod
+
+=head1 NAME
+
+Moose::Meta::Role::Application::ToInstance - Compose a role into an instance
+
+=head1 DESCRIPTION
+
+=head2 METHODS
+
+=over 4
+
+=item B<new>
+
+=item B<meta>
+
+=item B<apply>
+
+=item B<rebless_params>
+
+=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
+
+Stevan Little E<lt>stevan@iinteractive.comE<gt>
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright 2006-2008 by Infinity Interactive, Inc.
+
+L<http://www.iinteractive.com>
+
+This library is free software; you can redistribute it and/or modify
+it under the same terms as Perl itself.
+
+=cut
+
--- /dev/null
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use Test::More tests => 6;
+
+{
+ package My::SimpleTrait;
+
+ use Moose::Role;
+
+ sub simple { return 5 }
+}
+
+{
+ package Foo;
+
+ use Moose -traits => [ 'My::SimpleTrait' ];
+}
+
+can_ok( Foo->meta(), 'simple' );
+is( Foo->meta()->simple(), 5,
+ 'Foo->meta()->simple() returns expected value' );
+
+{
+ package My::SimpleTrait2;
+
+ use Moose::Role;
+
+ # This needs to happen at begin time so it happens before we apply
+ # traits to Bar
+ BEGIN {
+ has 'attr' =>
+ ( is => 'ro',
+ default => 'something',
+ );
+ }
+
+ sub simple { return 5 }
+}
+
+{
+ package Bar;
+
+ use Moose -traits => [ 'My::SimpleTrait2' ];
+}
+
+can_ok( Bar->meta(), 'simple' );
+is( Bar->meta()->simple(), 5,
+ 'Bar->meta()->simple() returns expected value' );
+can_ok( Bar->meta(), 'attr' );
+is( Bar->meta()->attr(), 'something',
+ 'Bar->meta()->attr() returns expected value' );