New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Mojo::Base::with_roles patch #1120
Conversation
lib/Mojo/Base.pm
Outdated
@@ -61,6 +61,10 @@ sub attr { | |||
} | |||
} | |||
|
|||
sub can_roles { | |||
return !!(eval 'require Role::Tiny' && $Role::Tiny::VERSION >= 2.000005); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be a constant and the can_roles
method is just for exposure outside of the class. C.f. https://github.com/kraih/mojo/blob/be50b20ae6c80df78a2594fdd198c19364f649ad/lib/Mojo/IOLoop/Client.pm#L13-L15
lib/Mojo/Base.pm
Outdated
@@ -101,6 +105,16 @@ sub tap { | |||
return $self; | |||
} | |||
|
|||
sub with_roles { | |||
if ($_[0]->can_roles()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Within the class, it should use the constant (see above), since this will be constant folded at compile time and not introduce overhead on each with_roles call
lib/Mojo/Base.pm
Outdated
@@ -61,6 +61,10 @@ sub attr { | |||
} | |||
} | |||
|
|||
sub can_roles { | |||
return !!(eval 'require Role::Tiny' && $Role::Tiny::VERSION >= 2.000005); | |||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not consistent with our other optional dependencies.
lib/Mojo/Base.pm
Outdated
@@ -101,6 +105,16 @@ sub tap { | |||
return $self; | |||
} | |||
|
|||
sub with_roles { | |||
if ($_[0]->can_roles()) { | |||
Carp::croak "class and roles must be package names" if !!grep { ref $_ } @_; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a good reason that argument validation is required here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
create_class_with_roles will error if anything other than a valid role name is passed, so probably not needed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It may be worthwhile checking that the invocant is not an object though, there's no explicit check for that in Role::Tiny and it could lead to weird things being loaded based on object stringification
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll change it to only check the invocant.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's not something we normally do.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll remove it and see how cryptic the error is in the tests...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, my error is nice, but if you try to invoke with_roles on an object, you get a terrifying exception, so I'm fine with that (something like "Can't locate Mojo/RoleTest/Base__WITH__Mojo/RoleTest/LOUD=HASH(0x17e56b0).pm in @inc", or whatever)
lib/Mojo/Base.pm
Outdated
return Role::Tiny->create_class_with_roles(@_); | ||
} | ||
else { | ||
Carp::croak "Role::Tiny 2.000005 is required for with_roles method"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we really require 2.000005
, or would a nicer looking 2.0
work too?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would recommend at least 2.000001 for an important fix to created class names. https://rt.cpan.org/Public/Bug/Display.html?id=103310
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll change it to 2.000001+
lib/Mojo/Base.pm
Outdated
|
||
my $roles_ok = Mojo::Base->can_roles() | ||
|
||
True if L<Role::Tiny> 2.000005+ is installed and roles are supported in Mojo::Base |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mojo::Base
is not a link.
lib/Mojo/Base.pm
Outdated
@@ -210,6 +224,13 @@ executed at accessor read time if there's no set value, and gets passed the | |||
current instance of the object as first argument. Accessors can be chained, that | |||
means they return their invocant when they are called with an argument. | |||
|
|||
=head2 can_roles | |||
|
|||
my $roles_ok = Mojo::Base->can_roles() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We write my $bool = ...
for methods that return booleans.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also missing semicolon.
lib/Mojolicious/Command/version.pm
Outdated
@@ -27,6 +28,7 @@ OPTIONAL | |||
IO::Socket::Socks 0.64+ ($socks) | |||
IO::Socket::SSL 1.94+ ($tls) | |||
Net::DNS::Native 0.15+ ($nnr) | |||
Role::Tiny 2.000005+ ($roles) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indentation.
t/mojo/roles.t
Outdated
use Mojo::Base -strict; | ||
use Test::More; | ||
|
||
plan skip_all => "Role::Tiny required for roles" unless Mojo::Base->can_roles; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is inconsistent with other tests for optional dependencies.
t/mojo/roles.t
Outdated
|
||
# First test derived from sri's comment here: | ||
# https://github.com/kraih/mojo/pull/1118#issuecomment-320930345 | ||
# TODO: make this a subtest |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't use these kinda comments.
t/mojo/roles.t
Outdated
package Test::Mojo::Role::Location; | ||
|
||
use Role::Tiny; | ||
use Test::More; # for is() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Used twice.
t/mojo/roles.t
Outdated
$t->get_ok('http://mojolicio.us') | ||
->status_is(301) | ||
->location_is('http://mojolicious.org/') | ||
->or(sub { diag 'doh!' }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this is a good test case, keep it simple.
t/mojo/roles.t
Outdated
|
||
use Test::Mojo; | ||
|
||
plan tests => 3; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't use plans.
t/mojo/roles.t
Outdated
plan tests => 3; | ||
|
||
my $t = Test::Mojo->with_roles('Test::Mojo::Role::Location')->new(); | ||
$t->get_ok('http://mojolicio.us') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tests shouldn't require an internet connection.
Don't forget to squash your commits. |
lib/Mojo/Base.pm
Outdated
@@ -15,6 +15,10 @@ use IO::Handle (); | |||
my $NAME | |||
= eval { require Sub::Util; Sub::Util->can('set_subname') } || sub { $_[1] }; | |||
|
|||
# Role support requires Role::Tiny 2.000001+ | |||
use constant ROLES => | |||
!!(eval 'require Role::Tiny' && $Role::Tiny::VERSION >= 2.000001); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why not eval 'use Role::Tiny 2.000001 (); 1';
like at https://github.com/kraih/mojo/blob/master/lib/Mojo/IOLoop/TLS.pm#L11 ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually the best method would be eval { require Role::Tiny; Role::Tiny->VERSION('2.000001'); 1 }
String eval is unnecessary for this, and the ->VERSION method (same as used by use) is the correct way to check a module's version.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That does look much better.
lib/Mojolicious/Command/version.pm
Outdated
@@ -27,6 +28,7 @@ OPTIONAL | |||
IO::Socket::Socks 0.64+ ($socks) | |||
IO::Socket::SSL 1.94+ ($tls) | |||
Net::DNS::Native 0.15+ ($nnr) | |||
Role::Tiny 2.000005+ ($roles) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
2.000001+
t/mojo/roles.t
Outdated
|
||
BEGIN { | ||
# bail in a BEGIN block, so we can use Role::Tiny in inline classes below | ||
use Test::More; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Move the use Test::More
outside the block and remove the comment.
lib/Mojolicious/Command/version.pm
Outdated
@@ -27,6 +28,7 @@ OPTIONAL | |||
IO::Socket::Socks 0.64+ ($socks) | |||
IO::Socket::SSL 1.94+ ($tls) | |||
Net::DNS::Native 0.15+ ($nnr) | |||
Role::Tiny 2.000001+ ($roles) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indentation is still wrong.
eb3cca3
to
4700660
Compare
Support extending Mojo::Base classes with roles, using Role::Tiny (optional dependency)
Summary
Add with_roles method to Mojo::Base, per the specs described here:
https://irclog.perlgeek.de/mojo/2017-08-08#i_14984146
Motivation
Allow multiple developers to extend key Mojolicious classes (Test::Mojo, Mojo::UserAgent, etc)
using Role::Tiny (optional dependency)
References
https://irclog.perlgeek.de/mojo/2017-08-08#i_14984146