Skip to content

Commit

Permalink
improve Mojo::Base role support with shorthands, so "MyClass->with_ro…
Browse files Browse the repository at this point in the history
…les('MyClass::Role::Foo')" becomes "MyClass->with_roles('+Foo')"
  • Loading branch information
kraih committed Aug 16, 2017
1 parent f7a0b66 commit 87030e6
Show file tree
Hide file tree
Showing 7 changed files with 48 additions and 19 deletions.
3 changes: 3 additions & 0 deletions Changes
@@ -1,5 +1,8 @@

7.42 2017-08-16
- Improved Mojo::Base role support with shorthands, so
"MyClass->with_roles('MyClass::Role::Foo')" becomes
"MyClass->with_roles('+Foo')".

7.41 2017-08-15
- Added with_roles method to Mojo::ByteStream, Mojo::Collection, Mojo::DOM and
Expand Down
18 changes: 11 additions & 7 deletions lib/Mojo/Base.pm
Expand Up @@ -106,8 +106,10 @@ sub tap {
}

sub with_roles {
return Role::Tiny->create_class_with_roles(@_) if ROLES;
Carp::croak 'Role::Tiny 2.000001+ is required for roles';
Carp::croak 'Role::Tiny 2.000001+ is required for roles' unless ROLES;
my $class = shift;
return Role::Tiny->create_class_with_roles($class,
map { /^\+(.+)$/ ? "${class}::Role::$1" : $_ } @_);
}

1;
Expand Down Expand Up @@ -247,14 +249,16 @@ spliced or tapped into) a chained set of object method calls.
=head2 with_roles
my $new_class = SubClass->with_roles('Foo::Role1', 'Bar::Role2');
my $new_class = SubClass->with_roles('SubClass::Role::One');
my $new_class = SubClass->with_roles('+One', '+Two');
Create and return a new class that extends the given class with one or more
L<Role::Tiny> roles. Note that role support depends on L<Role::Tiny>
(2.000001+).
L<Role::Tiny> roles. For roles following the naming scheme
C<MyClass::Role::RoleName> you can use the shorthand C<+RoleName>. Note that
role support depends on L<Role::Tiny> (2.000001+).
# Create a new class with roles and instantiate it
my $new_class = SubClass->with_roles('Foo::Role1', 'Foo::Role2');
# Create a new class with the role "SubClass::Role::Foo" and instantiate it
my $new_class = SubClass->with_roles('+Foo');
my $object = $new_class->new;
=head1 SEE ALSO
Expand Down
3 changes: 2 additions & 1 deletion lib/Mojo/ByteStream.pm
Expand Up @@ -332,7 +332,8 @@ L<Mojo::Util/"url_unescape">.
=head2 with_roles
my $new_class = Mojo::ByteStream->with_roles('Foo::Role1', 'Bar::Role2');
my $new_class = Mojo::ByteStream->with_roles('Mojo::ByteStream::Role::One');
my $new_class = Mojo::ByteStream->with_roles('+One', '+Two');
Alias for L<Mojo::Base/"with_roles">.
Expand Down
3 changes: 2 additions & 1 deletion lib/Mojo/Collection.pm
Expand Up @@ -371,7 +371,8 @@ callback/method.
=head2 with_roles
my $new_class = Mojo::Collection->with_roles('Foo::Role1', 'Bar::Role2');
my $new_class = Mojo::Collection->with_roles('Mojo::Collection::Role::One');
my $new_class = Mojo::Collection->with_roles('+One', '+Two');
Alias for L<Mojo::Base/"with_roles">.
Expand Down
5 changes: 3 additions & 2 deletions lib/Mojo/DOM.pm
Expand Up @@ -13,7 +13,7 @@ use Carp 'croak';
use Mojo::Collection;
use Mojo::DOM::CSS;
use Mojo::DOM::HTML;
use Scalar::Util qw(blessed weaken);
use Scalar::Util 'weaken';

sub all_text { _text(_nodes(shift->tree), 1) }

Expand Down Expand Up @@ -950,7 +950,8 @@ if none could be found.
=head2 with_roles
my $new_class = Mojo::DOM->with_roles('Foo::Role1', 'Bar::Role2');
my $new_class = Mojo::DOM->with_roles('Mojo::DOM::Role::One');
my $new_class = Mojo::DOM->with_roles('+One', '+Two');
Alias for L<Mojo::Base/"with_roles">.
Expand Down
3 changes: 2 additions & 1 deletion lib/Mojo/File.pm
Expand Up @@ -450,7 +450,8 @@ Stringify the path.
=head2 with_roles
my $new_class = Mojo::File->with_roles('Foo::Role1', 'Bar::Role2');
my $new_class = Mojo::File->with_roles('Mojo::File::Role::One');
my $new_class = Mojo::File->with_roles('+One', '+Two');
Alias for L<Mojo::Base/"with_roles">.
Expand Down
32 changes: 25 additions & 7 deletions t/mojo/roles.t
Expand Up @@ -7,7 +7,7 @@ BEGIN {
unless Mojo::Base->ROLES;
}

package Mojo::RoleTest::LOUD;
package Mojo::RoleTest::Role::LOUD;
use Role::Tiny;

sub yell {'HEY!'}
Expand All @@ -19,7 +19,7 @@ sub hello {
return $self->yell . ' ' . uc($self->name) . '!!!';
}

package Mojo::RoleTest::quiet;
package Mojo::RoleTest::Role::quiet;
use Role::Tiny;

requires 'name';
Expand All @@ -29,7 +29,7 @@ sub whisper {
return 'psst, ' . lc($self->name);
}

package Mojo::RoleTest::Base;
package Mojo::RoleTest;
use Mojo::Base -base;

has name => 'bob';
Expand All @@ -52,22 +52,40 @@ use Mojo::DOM;
use Mojo::File;

# Plain class
my $obj = Mojo::RoleTest::Base->new(name => 'Ted');
my $obj = Mojo::RoleTest->new(name => 'Ted');
is $obj->name, 'Ted', 'attribute';
is $obj->hello, 'hello Ted', 'method';

# Single role
my $obj2 = Mojo::RoleTest::Base->with_roles('Mojo::RoleTest::LOUD')->new;
my $obj2 = Mojo::RoleTest->with_roles('Mojo::RoleTest::Role::LOUD')->new;
is $obj2->hello, 'HEY! BOB!!!', 'role method';
is $obj2->yell, 'HEY!', 'another role method';

# Single role (shorthand)
my $obj4 = Mojo::RoleTest->with_roles('+LOUD')->new;
is $obj4->hello, 'HEY! BOB!!!', 'role method';
is $obj4->yell, 'HEY!', 'another role method';

# Multiple roles
my $obj3 = Mojo::RoleTest::Base->with_roles('Mojo::RoleTest::quiet',
'Mojo::RoleTest::LOUD')->new(name => 'Joel');
my $obj3 = Mojo::RoleTest->with_roles('Mojo::RoleTest::Role::quiet',
'Mojo::RoleTest::Role::LOUD')->new(name => 'Joel');
is $obj3->name, 'Joel', 'base attribute';
is $obj3->whisper, 'psst, joel', 'method from first role';
is $obj3->hello, 'HEY! JOEL!!!', 'method from second role';

# Multiple roles (shorthand)
my $obj5 = Mojo::RoleTest->with_roles('+quiet', '+LOUD')->new(name => 'Joel');
is $obj5->name, 'Joel', 'base attribute';
is $obj5->whisper, 'psst, joel', 'method from first role';
is $obj5->hello, 'HEY! JOEL!!!', 'method from second role';

# Multiple roles (mixed)
my $obj6 = Mojo::RoleTest->with_roles('Mojo::RoleTest::Role::quiet', '+LOUD')
->new(name => 'Joel');
is $obj6->name, 'Joel', 'base attribute';
is $obj6->whisper, 'psst, joel', 'method from first role';
is $obj6->hello, 'HEY! JOEL!!!', 'method from second role';

# Classes that are not subclasses of Mojo::Base
my $stream = Mojo::ByteStream->with_roles('Mojo::RoleTest::Hello')->new;
is $stream->hello, 'hello mojo!', 'right result';
Expand Down

0 comments on commit 87030e6

Please sign in to comment.