Skip to content

Commit

Permalink
deprecated Mojolicious::Routes->namespace in favor of Mojolicious::Ro…
Browse files Browse the repository at this point in the history
…utes->namespaces
  • Loading branch information
kraih committed Dec 19, 2012
1 parent 9526ba6 commit 6cce3a2
Show file tree
Hide file tree
Showing 12 changed files with 103 additions and 46 deletions.
4 changes: 3 additions & 1 deletion Changes
@@ -1,5 +1,7 @@

3.69 2012-12-19
3.69 2012-12-20
- Deprecated Mojolicious::Routes->namespace in favor of
Mojolicious::Routes->namespaces.
- Added color_field helper to Mojolicious::Plugin::TagHelpers.
- Added date_field helper to Mojolicious::Plugin::TagHelpers.
- Added datetime_field helper to Mojolicious::Plugin::TagHelpers.
Expand Down
2 changes: 1 addition & 1 deletion lib/Mojolicious.pm
Expand Up @@ -67,7 +67,7 @@ sub new {
push @{$self->static->paths}, $home->rel_dir('public');

# Default to application namespace
my $r = $self->routes->namespace(ref $self);
my $r = $self->routes->namespaces([ref $self]);

# Hide controller attributes/methods and "handler"
$r->hide(qw(AUTOLOAD DESTROY app cookie finish flash handler on param));
Expand Down
6 changes: 3 additions & 3 deletions lib/Mojolicious/Guides/Routing.pod
Expand Up @@ -313,10 +313,10 @@ The C<controller> is always appended to the C<namespace> if available.
# /hey -> MyApp::Controller::Foo::Bar->hey
$r->route('/hey')->to('Foo::Bar#hey', namespace => 'MyApp::Controller');

You can also change the default namespace for all routes in the application
with the router attribute L<Mojolicious::Routes/"namespace">.
You can also change the default namespaces for all routes in the application
with the router attribute L<Mojolicious::Routes/"namespaces">.

$r->namespace('MyApp::Controller');
$r->namespaces(['MyApp::Controller']);

=head2 Route to callback

Expand Down
2 changes: 1 addition & 1 deletion lib/Mojolicious/Lite.pm
Expand Up @@ -24,7 +24,7 @@ sub import {
my $app = $class->new;

# Initialize routes
my $routes = $app->routes->namespace('');
my $routes = $app->routes->namespaces([]);

# Default static and template class
$app->static->classes->[0] = $app->renderer->classes->[0] = $caller;
Expand Down
99 changes: 63 additions & 36 deletions lib/Mojolicious/Routes.pm
Expand Up @@ -11,8 +11,8 @@ use Scalar::Util 'weaken';
has base_classes => sub { [qw(Mojolicious::Controller Mojo)] };
has cache => sub { Mojo::Cache->new };
has [qw(conditions shortcuts)] => sub { {} };
has hidden => sub { [qw(attr has new tap)] };
has 'namespace';
has hidden => sub { [qw(attr has new tap)] };
has namespaces => sub { [] };

sub add_condition {
my ($self, $name, $cb) = @_;
Expand Down Expand Up @@ -82,6 +82,18 @@ sub dispatch {

sub hide { push @{shift->hidden}, @_ }

# DEPRECATED in Rainbow!
sub namespace {
warn <<EOF;
Mojolicious::Routes->namespace is DEPRECATED in favor of
Mojolicious::Routes->namespaces!
EOF
my $self = shift;
return $self->namespaces->[0] unless @_;
$self->namespaces->[0] = shift;
return $self;
}

sub route {
shift->add_child(Mojolicious::Routes::Route->new(@_))->children->[-1];
}
Expand All @@ -95,32 +107,58 @@ sub _callback {
}

sub _class {
my ($self, $field, $c) = @_;
my ($self, $c, $field) = @_;

# Application instance
return $field->{app} if ref $field->{app};

# Namespace and class
my $namespace = $field->{namespace};
# Application class
my @classes;
my $class = camelize $field->{controller} || '';
return undef unless $class || $namespace;
$class = length $class ? "${namespace}::$class" : $namespace
if length($namespace //= $self->namespace);
if ($field->{app}) { push @classes, $field->{app} }

# Specific namespace
elsif (defined(my $namespace = $field->{namespace})) {
if ($class) { push @classes, $namespace ? "${namespace}::$class" : $class }
elsif ($namespace) { push @classes, $namespace }
}

# All namespaces
elsif ($class) { push @classes, "${_}::$class" for @{$self->namespaces} }

# Try to load all classes
my $log = $c->app->log;
for my $class (@classes) {

# Check if it looks like a class
return $class =~ /^[a-zA-Z0-9_:]+$/ ? $class : undef;
# Failed
unless (my $found = $self->_load($class)) {
next unless defined $found;
$log->debug(qq{Class "$class" is not a controller.});
return undef;
}

# Success
return $class->new($c);
}

# Nothing found
$log->debug(qq{Controller "$classes[-1]" does not exist.}) if @classes;
return @classes ? undef : 0;
}

sub _controller {
my ($self, $c, $field, $staging) = @_;

# Load and instantiate controller/application
return 1 unless my $app = $field->{app} || $self->_class($field, $c);
return undef unless $self->_load($c, $app);
$app = $app->new($c) unless ref $app;
my $app;
unless ($app = $self->_class($c, $field)) { return defined $app ? 1 : undef }

# Application
my $continue;
my $class = ref $app;
my $log = $c->app->log;
if (my $sub = $app->can('handler')) {
$c->app->log->debug(qq{Routing to application "$class".});
$log->debug(qq{Routing to application "$class".});

# Try to connect routes
if (my $sub = $app->can('routes')) {
Expand All @@ -132,8 +170,7 @@ sub _controller {
}

# Action
elsif (my $method = $self->_method($field, $c)) {
my $log = $c->app->log;
elsif (my $method = $self->_method($c, $field)) {
$log->debug(qq{Routing to controller "$class" and action "$method".});

# Try to call action
Expand All @@ -150,29 +187,19 @@ sub _controller {
}

sub _load {
my ($self, $c, $app) = @_;
my ($self, $app) = @_;

# Load unless already loaded or application
return 1 if $self->{loaded}{$app} || ref $app;
if (my $e = Mojo::Loader->new->load($app)) {

# Doesn't exist
$c->app->log->debug(qq{Controller "$app" does not exist.})
and return undef
unless ref $e;

# Error
die $e;
}
# Load unless already loaded
return 1 if $self->{loaded}{$app};
if (my $e = Mojo::Loader->new->load($app)) { ref $e ? die $e : return undef }

# Check base classes
$c->app->log->debug(qq{Class "$app" is not a controller.}) and return undef
unless first { $app->isa($_) } @{$self->base_classes};
return 0 unless first { $app->isa($_) } @{$self->base_classes};
return ++$self->{loaded}{$app};
}

sub _method {
my ($self, $field, $c) = @_;
my ($self, $c, $field) = @_;

# Hidden
$self->{hiding} = {map { $_ => 1 } @{$self->hidden}} unless $self->{hiding};
Expand Down Expand Up @@ -302,12 +329,12 @@ Contains all available conditions.
Controller methods and attributes that are hidden from routes, defaults to
C<attr>, C<has>, C<new> and C<tap>.
=head2 C<namespace>
=head2 C<namespaces>
my $namespace = $r->namespace;
$r = $r->namespace('Foo::Bar::Controller');
my $namespaces = $r->namespaces;
$r = $r->namespaces(['Foo::Bar::Controller']);
Namespace used by C<dispatch> to search for controllers.
Namespaces used by C<dispatch> to search for controllers.
=head2 C<shortcuts>
Expand Down
6 changes: 6 additions & 0 deletions t/mojolicious/app.t
Expand Up @@ -239,6 +239,12 @@ $t->get_ok('/test8' => {'X-Test' => 'Hi there!'})->status_is(200)
->header_is('X-Powered-By' => 'Mojolicious (Perl)')
->content_is("Class works!\n");

# MojoliciousTest3::Bar::index (controller class in development namespace)
$t->get_ok('/test9' => {'X-Test' => 'Hi there!'})->status_is(200)
->header_is(Server => 'Mojolicious (Perl)')
->header_is('X-Powered-By' => 'Mojolicious (Perl)')
->content_is('Development namespace works!');

# 404
$t->get_ok('/' => {'X-Test' => 'Hi there!'})->status_is(404)
->header_is(Server => 'Mojolicious (Perl)')
Expand Down
2 changes: 1 addition & 1 deletion t/mojolicious/dispatch.t
Expand Up @@ -87,7 +87,7 @@ $c->app->log->path(undef);
$c->app->log->level('fatal');
my $d = Mojolicious::Routes->new;
ok $d, 'initialized';
$d->namespace('Test');
$d->namespaces(['Test']);
$d->route('/')->over([])->to(controller => 'foo', action => 'home');
$d->route('/foo/(capture)')->to(controller => 'foo', action => 'bar');

Expand Down
2 changes: 1 addition & 1 deletion t/mojolicious/embedded_lite_app.t
Expand Up @@ -78,7 +78,7 @@ package main;
# /foo/* (plugin app)
plugin 'PluginWithEmbeddedApp';

app->routes->namespace('MyTestApp');
app->routes->namespaces(['MyTestApp']);

# Mount full external application a few times
my $external = "$FindBin::Bin/external/myapp.pl";
Expand Down
9 changes: 8 additions & 1 deletion t/mojolicious/lib/MojoliciousTest.pm
Expand Up @@ -12,6 +12,9 @@ sub development_mode {

# Static root for development
unshift @{$self->static->paths}, $self->home->rel_dir('public_dev');

# Development namespace
push @{$self->routes->namespaces}, 'MojoliciousTest3';
}

sub startup {
Expand All @@ -25,7 +28,8 @@ sub startup {
push @{$self->commands->namespaces}, 'MojoliciousTest::Command';

# Plugins in custom namespace
unshift @{$self->plugins->namespaces}, $self->routes->namespace . '::Plugin';
unshift @{$self->plugins->namespaces},
$self->routes->namespaces->[0] . '::Plugin';
$self->plugin('test-some_plugin2');
$self->plugin('UPPERCASETestPlugin');

Expand Down Expand Up @@ -124,6 +128,9 @@ sub startup {
# /test8 (controller class)
$r->route('/test8')->to(controller => 'Foo::Bar', action => 'test');

# /test9 (controller in additional namespace)
$r->route('/test9')->to('bar#index');

# /withblock (template with blocks)
$r->route('/withblock')->to('foo#withblock');

Expand Down
9 changes: 9 additions & 0 deletions t/mojolicious/lib/MojoliciousTest3/Bar.pm
@@ -0,0 +1,9 @@
package MojoliciousTest3::Bar;
use Mojo::Base 'Mojolicious::Controller';

sub index {
my $self = shift;
$self->render(text => 'Development namespace works!');
}

1;
6 changes: 6 additions & 0 deletions t/mojolicious/production_app.t
Expand Up @@ -120,4 +120,10 @@ $t->get_ok('/just/some/template')->status_is(200)
->header_is('X-Powered-By' => 'Mojolicious (Perl)')
->content_is("Production template with low precedence.\n");

# MojoliciousTest3::Bar::index (controller class in development namespace)
$t->get_ok('/test9' => {'X-Test' => 'Hi there!'})->status_is(404)
->header_is(Server => 'Mojolicious (Perl)')
->header_is('X-Powered-By' => 'Mojolicious (Perl)')
->content_like(qr/Page not found/);

done_testing();
2 changes: 1 addition & 1 deletion t/pod_coverage.t
Expand Up @@ -8,4 +8,4 @@ plan skip_all => 'Test::Pod::Coverage 1.04 required for this test!'
unless eval 'use Test::Pod::Coverage 1.04; 1';

# DEPRECATED in Rainbow!
all_pod_coverage_ok({also_private => ['raw_message']});
all_pod_coverage_ok({also_private => [qw(namespace raw_message)]});

0 comments on commit 6cce3a2

Please sign in to comment.