Skip to content

Commit

Permalink
Combine monkey_patch and class_to_path in new Mojo::BaseUtil
Browse files Browse the repository at this point in the history
  • Loading branch information
okurz committed May 8, 2024
1 parent 3d767a6 commit b7002c7
Show file tree
Hide file tree
Showing 10 changed files with 108 additions and 87 deletions.
18 changes: 8 additions & 10 deletions lib/Mojo/Base.pm
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ use feature ':5.16';
use mro;

# No imports because we get subclassed, a lot!
use Carp ();
use Scalar::Util ();
use Mojo::MonkeyPatch ();
use Carp ();
use Scalar::Util ();
use Mojo::BaseUtil ();

# Role support requires Role::Tiny 2.000001+
use constant ROLES => !!(eval { require Role::Tiny; Role::Tiny->VERSION('2.000001'); 1 });
Expand All @@ -22,8 +22,6 @@ use constant ASYNC => $ENV{MOJO_NO_ASYNC}
# Protect subclasses using AUTOLOAD
sub DESTROY { }

sub class_to_path { join '.', join('/', split(/::|'/, shift)), 'pm' }

sub attr {
my ($self, $attrs, $value, %kv) = @_;
return unless (my $class = ref $self || $self) && $attrs;
Expand All @@ -41,7 +39,7 @@ sub attr {
ref $self->{$_} and Scalar::Util::weaken $self->{$_} for @$names;
return $self;
};
Mojo::MonkeyPatch::monkey_patch(my $base = $class . '::_Base', 'new', $sub);
Mojo::BaseUtil::monkey_patch(my $base = $class . '::_Base', 'new', $sub);
no strict 'refs';
unshift @{"${class}::ISA"}, $base;
}
Expand Down Expand Up @@ -90,7 +88,7 @@ sub attr {
else {
$sub = sub { return $_[0]{$attr} if @_ == 1; $_[0]{$attr} = $_[1]; $_[0] };
}
Mojo::MonkeyPatch::monkey_patch($class, $attr, $sub);
Mojo::BaseUtil::monkey_patch($class, $attr, $sub);
}
}

Expand All @@ -110,7 +108,7 @@ sub import {
# Role
elsif ($flag eq '-role') {
Carp::croak 'Role::Tiny 2.000001+ is required for roles' unless ROLES;
Mojo::MonkeyPatch::monkey_patch($caller, 'has', sub { attr($caller, @_) });
Mojo::BaseUtil::monkey_patch($caller, 'has', sub { attr($caller, @_) });
eval "package $caller; use Role::Tiny; 1" or die $@;
}

Expand All @@ -131,9 +129,9 @@ sub import {
# Module
elsif ($flag !~ /^-/) {
no strict 'refs';
require(class_to_path($flag)) unless $flag->can('new');
require(Mojo::BaseUtil::class_to_path($flag)) unless $flag->can('new');
push @{"${caller}::ISA"}, $flag;
Mojo::MonkeyPatch::monkey_patch($caller, 'has', sub { attr($caller, @_) });
Mojo::BaseUtil::monkey_patch($caller, 'has', sub { attr($caller, @_) });
}

elsif ($flag ne '-strict') { Carp::croak "Unsupported flag: $flag" }
Expand Down
77 changes: 77 additions & 0 deletions lib/Mojo/BaseUtil.pm
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package Mojo::BaseUtil;
# only using pure Perl as the only purpose of this module is to break a
# circular dependency involving Mojo::Base
use strict;
use warnings;

use Exporter qw(import);
use Sub::Util qw(set_subname);

our @EXPORT_OK = (qw(class_to_path monkey_patch));


sub class_to_path { join '.', join('/', split(/::|'/, shift)), 'pm' }

sub monkey_patch {
my ($class, %patch) = @_;
no strict 'refs';
no warnings 'redefine';
*{"${class}::$_"} = set_subname("${class}::$_", $patch{$_}) for keys %patch;
}

1;

=encoding utf8
=head1 NAME
Mojo::BaseUtil - Common utility functions used in Mojo::Base, re-exported in Mojo::Util.
=head1 SYNOPSIS
use Mojo::BaseUtil qw(class_to_patch monkey_path);
my $path = class_to_path 'Foo::Bar';
monkey_patch 'MyApp', foo => sub { say 'Foo!' };
=head1 DESCRIPTION
L<Mojo::BaseUtil> provides a C<class_to_path> and the C<monkey_patch> function
for L<Mojo>. The main purpose is to provide functions to both C<Mojo::Base>
and C<Mojo::Util> so that C<Mojo::Base> does not have to load the rest of
C<Mojo::Util>.
=head1 FUNCTIONS
L<Mojo::BaseUtil> only implements a limited number of functions. For forward
compatibility it should still be imported individually.
=head2 class_to_path
my $path = class_to_path 'Foo::Bar';
Convert class name to path, as used by C<%INC>.
# "Foo/Bar.pm"
class_to_path 'Foo::Bar';
# "FooBar.pm"
class_to_path 'FooBar';
=head2 monkey_patch
monkey_patch $package, foo => sub {...};
monkey_patch $package, foo => sub {...}, bar => sub {...};
Monkey patch functions into package.
monkey_patch 'MyApp',
one => sub { say 'One!' },
two => sub { say 'Two!' },
three => sub { say 'Three!' };
=head1 SEE ALSO
L<Mojolicious>, L<Mojolicious::Guides>, L<https://mojolicious.org>.
=cut
4 changes: 3 additions & 1 deletion lib/Mojo/Home.pm
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package Mojo::Home;
use Mojo::Base 'Mojo::File';

use Mojo::Util qw(class_to_path);

sub detect {
my ($self, $class) = @_;

Expand All @@ -9,7 +11,7 @@ sub detect {
if ($ENV{MOJO_HOME}) { $home = Mojo::File->new($ENV{MOJO_HOME})->to_array }

# Location of the application class (Windows mixes backslash and slash)
elsif ($class && (my $path = $INC{my $file = Mojo::Base::class_to_path $class})) {
elsif ($class && (my $path = $INC{my $file = class_to_path $class})) {
$home = Mojo::File->new($path)->to_array;
splice @$home, (my @dummy = split(/\//, $file)) * -1;
@$home && $home->[-1] eq $_ && pop @$home for qw(lib blib);
Expand Down
4 changes: 2 additions & 2 deletions lib/Mojo/Loader.pm
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use Mojo::Base -strict;
use Exporter qw(import);
use Mojo::Exception;
use Mojo::File qw(path);
use Mojo::Util qw(b64_decode);
use Mojo::Util qw(b64_decode class_to_path);

our @EXPORT_OK = qw(data_section file_is_binary find_modules find_packages load_class load_classes);

Expand Down Expand Up @@ -47,7 +47,7 @@ sub load_class {
return undef if $class->can('new') || eval "require $class; 1";

# Does not exist
return 1 if $@ =~ /^Can't locate \Q@{[Mojo::Base::class_to_path $class]}\E in \@INC/;
return 1 if $@ =~ /^Can't locate \Q@{[class_to_path $class]}\E in \@INC/;

# Real error
return Mojo::Exception->new($@)->inspect;
Expand Down
56 changes: 0 additions & 56 deletions lib/Mojo/MonkeyPatch.pm

This file was deleted.

4 changes: 2 additions & 2 deletions lib/Mojo/Util.pm
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use IO::Poll qw(POLLIN POLLPRI);
use IO::Uncompress::Gunzip;
use List::Util qw(min);
use MIME::Base64 qw(decode_base64 encode_base64);
use Mojo::MonkeyPatch qw(monkey_patch);
use Mojo::BaseUtil qw(class_to_path monkey_patch);
use Pod::Usage qw(pod2usage);
use Socket qw(inet_pton AF_INET6 AF_INET);
use Symbol qw(delete_package);
Expand Down Expand Up @@ -67,7 +67,7 @@ my $ENTITY_RE = qr/&(?:\#((?:[0-9]{1,7}|x[0-9a-fA-F]{1,6}));|(\w+[;=]?))/;
# Encoding and pattern cache
my (%ENCODING, %PATTERN);

# re-exporting MonkeyPatch::monkey_patch and Mojo::Base::class_to_path for backward compatibility
# re-exporting BaseUtil functions for backward compatibility
our @EXPORT_OK = (
qw(b64_decode b64_encode camelize class_to_file class_to_path decamelize decode deprecated dumper encode),
qw(extract_usage getopt gunzip gzip header_params hmac_sha1_sum html_attr_unescape html_unescape humanize_bytes),
Expand Down
6 changes: 3 additions & 3 deletions lib/Mojolicious/Command/Author/generate/app.pm
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package Mojolicious::Command::Author::generate::app;
use Mojo::Base 'Mojolicious::Command';

use Mojo::Util qw(class_to_file decamelize);
use Mojo::Util qw(class_to_file class_to_path decamelize);

has description => 'Generate Mojolicious application directory structure';
has usage => sub { shift->extract_usage };
Expand All @@ -15,15 +15,15 @@ sub run {
$self->chmod_rel_file("$name/script/$name", 0744);

# Application class
my $app = Mojo::Base::class_to_path $class;
my $app = class_to_path $class;
$self->render_to_rel_file('appclass', "$name/lib/$app", {class => $class});

# Config file (using the default moniker)
$self->render_to_rel_file('config', "$name/@{[decamelize $class]}.yml");

# Controller
my $controller = "${class}::Controller::Example";
my $path = Mojo::Base::class_to_path $controller;
my $path = class_to_path $controller;
$self->render_to_rel_file('controller', "$name/lib/$path", {class => $controller});

# Test
Expand Down
4 changes: 2 additions & 2 deletions lib/Mojolicious/Command/Author/generate/plugin.pm
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package Mojolicious::Command::Author::generate::plugin;
use Mojo::Base 'Mojolicious::Command';

use Mojo::Util qw(camelize getopt);
use Mojo::Util qw(camelize class_to_path getopt);

has description => 'Generate Mojolicious plugin directory structure';
has usage => sub { shift->extract_usage };
Expand All @@ -15,7 +15,7 @@ sub run {
my $name = $args[0] // 'MyPlugin';
my $class = $full ? $name : "Mojolicious::Plugin::$name";
my $dir = join '-', split(/::/, $class);
my $app = Mojo::Base::class_to_path $class;
my $app = class_to_path $class;
$self->render_to_rel_file('class', "$dir/lib/$app", {class => $class, name => $name});

# Test
Expand Down
9 changes: 0 additions & 9 deletions t/mojo/base.t
Original file line number Diff line number Diff line change
Expand Up @@ -143,13 +143,4 @@ subtest 'Weaken' => sub {
is $weak->four(25)->four, 25, 'right value';
};

subtest 'class_to_path' => sub {
is Mojo::Base::class_to_path('Foo::Bar'), 'Foo/Bar.pm', 'right path';
is Mojo::Base::class_to_path("Foo'Bar"), 'Foo/Bar.pm', 'right path';
is Mojo::Base::class_to_path("Foo'Bar::Baz"), 'Foo/Bar/Baz.pm', 'right path';
is Mojo::Base::class_to_path("Foo::Bar'Baz"), 'Foo/Bar/Baz.pm', 'right path';
is Mojo::Base::class_to_path("Foo::Bar::Baz"), 'Foo/Bar/Baz.pm', 'right path';
is Mojo::Base::class_to_path("Foo'Bar'Baz"), 'Foo/Bar/Baz.pm', 'right path';
};

done_testing();
13 changes: 11 additions & 2 deletions t/mojo/monkey_patch.t → t/mojo/base_util.t
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,17 @@ use Mojo::Base -strict;
use Test::More;
use Sub::Util qw(subname);

use Mojo::MonkeyPatch qw(monkey_patch);
use Mojo::BaseUtil qw(class_to_path monkey_patch);


subtest 'class_to_path' => sub {
is Mojo::BaseUtil::class_to_path('Foo::Bar'), 'Foo/Bar.pm', 'right path';
is Mojo::BaseUtil::class_to_path("Foo'Bar"), 'Foo/Bar.pm', 'right path';
is Mojo::BaseUtil::class_to_path("Foo'Bar::Baz"), 'Foo/Bar/Baz.pm', 'right path';
is Mojo::BaseUtil::class_to_path("Foo::Bar'Baz"), 'Foo/Bar/Baz.pm', 'right path';
is Mojo::BaseUtil::class_to_path("Foo::Bar::Baz"), 'Foo/Bar/Baz.pm', 'right path';
is Mojo::BaseUtil::class_to_path("Foo'Bar'Baz"), 'Foo/Bar/Baz.pm', 'right path';
};

subtest 'monkey_patch' => sub {
{
Expand Down Expand Up @@ -37,4 +47,3 @@ subtest 'monkey_patch (with name)' => sub {
};

done_testing();

0 comments on commit b7002c7

Please sign in to comment.