package Role::Tiny;
sub _getglob { \*{$_[0]} }
+sub _getstash { \%{"$_[0]::"} }
use strict;
use warnings FATAL => 'all';
our %APPLIED_TO;
our %COMPOSED;
+# inlined from Moo::_Utils - update that first.
+
sub _load_module {
- return 1 if $_[0]->can('can');
(my $proto = $_[0]) =~ s/::/\//g;
- require "${proto}.pm";
+ return 1 if $INC{"${proto}.pm"};
+ # can't just ->can('can') because a sub-package Foo::Bar::Baz
+ # creates a 'Baz::' key in Foo::Bar's symbol table
+ return 1 if grep !/::$/, keys %{_getstash($_[0])||{}};
+ { local $@; require "${proto}.pm"; }
return 1;
}
+{ # \[] is REF, not SCALAR. \v1 is VSTRING (thanks to doy for that one)
+ my %reftypes = map +($_ => 1), qw(SCALAR REF VSTRING);
+ sub _is_scalar_ref { $reftypes{ref($_[0])} }
+}
+
sub import {
my $target = caller;
- my $me = $_[0];
+ my $me = shift;
strictures->import;
return if $INFO{$target}; # already exported into this package
# get symbol table reference
# install before/after/around subs
foreach my $type (qw(before after around)) {
*{_getglob "${target}::${type}"} = sub {
- require Class::Method::Modifiers;
+ { local $@; require Class::Method::Modifiers; }
push @{$INFO{$target}{modifiers}||=[]}, [ $type => @_ ];
};
}
die "Only one role supported at a time by with" if @_ > 1;
$me->apply_role_to_package($target, $_[0]);
};
- # grab all *non-constant* (ref eq 'SCALAR') subs present
+ # grab all *non-constant* (stash slot is not a scalarref) subs present
# in the symbol table and store their refaddrs (no need to forcibly
# inflate constant subs into real subs) - also add '' to here (this
# is used later)
@{$INFO{$target}{not_methods}={}}{
- '', map { *$_{CODE}||() } grep !(ref eq 'SCALAR'), values %$stash
+ '', map { *$_{CODE}||() } grep !ref($_), values %$stash
} = ();
# a role does itself
$APPLIED_TO{$target} = { $target => undef };
die "No roles supplied!" unless @roles;
- my $new_name = join('+', $superclass, my $compose_name = join '+', @roles);
+ my $new_name = join(
+ '__WITH__', $superclass, my $compose_name = join '__AND__', @roles
+ );
+
return $new_name if $COMPOSED{class}{$new_name};
foreach my $role (@roles) {
die "${role} is not a Role::Tiny" unless my $info = $INFO{$role};
}
- if ($] > 5.010) {
- require mro;
+ if ($] >= 5.010) {
+ { local $@; require mro; }
} else {
- require MRO::Compat;
+ { local $@; require MRO::Compat; }
}
my @composable = map $me->_composable_package_for($_), reverse @roles;
) {
push @mod_base, "sub ${modified} { shift->next::method(\@_) }";
}
- eval(my $code = join "\n", "package ${base_name};", @mod_base);
- die "Evaling failed: $@\nTrying to eval:\n${code}" if $@;
+ {
+ local $@;
+ eval(my $code = join "\n", "package ${base_name};", @mod_base);
+ die "Evaling failed: $@\nTrying to eval:\n${code}" if $@;
+ }
$me->_install_modifiers($composed_name, $modifiers);
$COMPOSED{role}{$composed_name} = 1;
return $composed_name;
my $code = *{$stash->{$_}}{CODE};
# rely on the '' key we added in import for "no code here"
exists $not_methods->{$code||''} ? () : ($_ => $code)
- } grep !(ref($stash->{$_}) eq 'SCALAR'), keys %$stash
+ } grep !ref($stash->{$_}), keys %$stash
};
};
}
# determine already extant methods of target
my %has_methods;
@has_methods{grep
- +((ref($stash->{$_}) eq 'SCALAR') || (*{$stash->{$_}}{CODE})),
+ +(ref($stash->{$_}) || *{$stash->{$_}}{CODE}),
keys %$stash
} = ();
package Some::Class;
- require Role::Tiny;
+ use Role::Tiny::With;
# bar gets imported, but not foo
- Role::Tiny->apply_role_to_package('Some::Role', __PACKAGE__);
+ with 'Some::Role';
sub foo { ... }
Role::Tiny->apply_role_to_package('Some::Package', 'Some::Role');
-Composes role with package
+Composes role with package. See also L<Role::Tiny::With>.
=head2 apply_roles_to_object
See L<< Class::Method::Modifiers/after method(s) => sub { ... } >> for full
documentation.
+=head1 AUTHORS
+
+See L<Moo> for authors.
+
+=head1 COPYRIGHT AND LICENSE
+
+See L<Moo> for the copyright and license.
+
+=cut