Mojo 0.9 released

| No Comments | No TrackBacks
Our biggest update so far, with many awesome new features like built in log file support and Modes. Mojolicious got even more userfriendly, take a look!
- Added modes to Mojolicious.
- Added Mojo::Log and log support for Mojo/Mojolicious.
- Changed MojoX::Renderer and Mojo::Template api to make catching errors easier, we now use a scalar ref for results like most template engines.
- Added MojoX::Context.
- Added multi level controller class support to Mojolicious.
- MojoX::Dispatcher::Routes should be able to fail.
- Added diagnostics functions to Mojo::HelloWorld.
- Made the env parser Apache compatible.
- Made Mojo::Server::FastCGI Apache compatible.
- Added namespace, class and method captures to MojoX::Dispatcher::Routes.
- Made url_for work for rebased applications.
- Added ctx, render, req, res and stash methods to Mojolicious controllers.
- Changed cookie, param and upload in Mojo::Parameters to return a list.
- Added support for templateless renderers to MojoX::Renderer.
- Added blacklist to MojoX::Dispatcher::Routes.
- Fixed Mojo::Date bugs. (vti)
- Fixed / routes matching too much.
- New Windows workaround in Mojo::Client and Mojo::Server::Daemon.
- Cleaned up Mojo::Transaction. (Ask Bjoern Hansen)
- Added .perltidyrc. (Ask Bjoern Hansen)
- Allow chains to be broken with return values in MojoX::Dispatcher::Routes.
- The stack in MojoX::Routes resets now.
- Renamed default_handler to default_format in MojoX::Renderer.
- Disallow actions beginning with _ in MojoX::Dispatcher::Routes.
- Preload application in servers. (Graham Barr)
- Renamed is_version to at_least_version. (Mark Stosberg)
- Added documentation. (Ch Lamprecht)
- Added param tests. (Mark Stosberg)
- Added documentation for Mojo::Log. (Mark Stosberg)
- Add test for MojoX::Renderer. (Mark Stosberg)
- When testing, allow servers a few seconds to stop. (Leon Brocard) - Fixed typos.

Small things that make a big difference

| 4 Comments | No TrackBacks
Mojolicious and Catalyst actions have always been very similar since i've basically cargo culted them both from Maypole. But we've never been happy with the idea of explicitly passing around the context object in Mojolicious.
sub list {
    my ($self, $c) = @_;
    $self->_list($c);
    $c->render;
}

sub _list {
    my ($self, $c) = @_;
    $c->stash(items => [qw/23 54/]);
}
Ask Bjoern Hansen recently proposed a small change to this which got a discussion started.
sub list {
    my $self = shift;
    $self->_list;
    $self->ctx->render;
}

sub _list {
    my $self = shift;
    $self->ctx->stash(items => [qw/23 54/]);
}
Making the context a controller attribute was a big step forward but still couldn't be considered beautiful. After some more unsuccessful tries Mark Stosberg popped up with some CGI::Application examples, and it totally made sense for us.
sub list {
    my $self = shift;
    $self->_list;
    $self->render;
}

sub _list {
    my $self = shift;
    $self->stash(items => [qw/23 54/]);
}
All we had to do to make it finally beautiful was adding the 4 most often used methods/attributes from the context to the controller.
sub test {
    my $self = shift;

    # Request
    my $req = $self->req;

    # Response
    my $res = $self->res;

    # Stash
    $self->stash(foo => 23);

    # Renderer
    $self->render;
}
It's incredible how much of a difference such a minor change can make usability wise.

Environments for Mojolicious

| 1 Comment | No TrackBacks
Back in the days when i was working on Catalyst, i thought it would be a great idea to have a special debug environment. You could activate it with a simple -Debug flag in the import list. But what if your development process has more stages than development and production? Right, you are screwed. That's why we've decided to use a more ambitious concept we call Modes in Mojolicious, where you can have an unlimited number of different environments.
package MyApp;
use base 'Mojolicious';

sub production_mode {
    my $self = shift;

    # Production templates
    $self->renderer->root('/Users/production/templates');
}

sub development_mode {
    my $self = shift;

    # Development templates
    $self->renderer->root('/Users/dev/templates');
}

sub startup {
    my $self = shift;

    # Default templates for everything else
    $self->renderer->root('/Users/defaul/templates');
}

1;
As you can see we've chosen a very minimalistic approach that feels in line with the rest of Mojolicious. Switching between modes is as easy as changing a environment variable.
% MOJO_MODE=production bin/my_app daemon

Mojo review

| No Comments | No TrackBacks
Mark Stosberg just reviewed Mojo, take a look!

Mojo and HTTP::Engine

| 1 Comment | No TrackBacks
Update: This benchmark was in fact not very fair towards HTTP::Engine, since i've exploited a design flaw. The reason was that i wanted to make a point and show how useless this kind of benchmark is. :)

Kazuhiro Osawa did a quite interesting benchmark comparing Mojo and HTTP::Engine performance. What he forgot to mention was that the HTTP::Engine backend he used was a minimal server that barely understands HTTP 1.0, while the Mojo server had full HTTP 1.1 support.

Now i thought activating some more features in HTTP::Engine like keep-alive would make this benchmark way more interesting.

HTTP::Engine code
use strict;
use warnings;
use HTTP::Engine;
use HTTP::Engine::Response;

HTTP::Engine->new(
    interface => {
        module          => 'Standalone',
        args => { port => 8081, keepalive => 1, fork => 1 },
        request_handler => sub {
            my $req = shift;
            HTTP::Engine::Response->new(
                body => 'Congratulations, your Mojo is working!',
            );
        },
    }
)->run;
Mojo code
use strict;
use warnings;
use Mojo::Server::Daemon::Prefork;

my $daemon = Mojo::Server::Daemon::Prefork->new;
$daemon->port(8082);
$daemon->run;
HTTP::Engine result
Macintosh:~ sri$ ab -n 10000 -c 100 http://127.0.0.1:8081/
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking 127.0.0.1 (be patient)
Completed 1000 requests
Completed 2000 requests
Completed 3000 requests
Completed 4000 requests
Completed 5000 requests
Completed 6000 requests
Completed 7000 requests
Completed 8000 requests
Completed 9000 requests
Completed 10000 requests
Finished 10000 requests


Server Software:        
Server Hostname:        127.0.0.1
Server Port:            8081

Document Path:          /
Document Length:        38 bytes

Concurrency Level:      100
Time taken for tests:   282.980 seconds
Complete requests:      10000
Failed requests:        0
Write errors:           0
Total transferred:      1710000 bytes
HTML transferred:       380000 bytes
Requests per second:    35.34 [#/sec] (mean)
Time per request:       2829.797 [ms] (mean)
Time per request:       28.298 [ms] (mean, across all concurrent requests)
Transfer rate:          5.90 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   1.0      0      23
Processing:    84 2816 178.0   2830    3066
Waiting:       84 2813 178.0   2827    3061
Total:         89 2816 177.7   2830    3066

Percentage of the requests served within a certain time (ms)
  50%   2830
  66%   2860
  75%   2878
  80%   2889
  90%   2917
  95%   2940
  98%   2970
  99%   2993
 100%   3066 (longest request)
Mojo result
Macintosh:~ sri$ ab -n 10000 -c 100 http://127.0.0.1:8082/
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking 127.0.0.1 (be patient)
Completed 1000 requests
Completed 2000 requests
Completed 3000 requests
Completed 4000 requests
Completed 5000 requests
Completed 6000 requests
Completed 7000 requests
Completed 8000 requests
Completed 9000 requests
Completed 10000 requests
Finished 10000 requests


Server Software:        
Server Hostname:        127.0.0.1
Server Port:            8082

Document Path:          /
Document Length:        38 bytes

Concurrency Level:      100
Time taken for tests:   15.234 seconds
Complete requests:      10000
Failed requests:        0
Write errors:           0
Total transferred:      1591431 bytes
HTML transferred:       380342 bytes
Requests per second:    656.41 [#/sec] (mean)
Time per request:       152.344 [ms] (mean)
Time per request:       1.523 [ms] (mean, across all concurrent requests)
Transfer rate:          102.01 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0   40  28.2     39     128
Processing:     3  111  37.2    114     358
Waiting:        1   80  32.0     81     294
Total:         10  151  33.3    152     365

Percentage of the requests served within a certain time (ms)
  50%    152
  66%    157
  75%    163
  80%    168
  90%    192
  95%    211
  98%    231
  99%    249
 100%    365 (longest request)
Note that none of the HTTP::Engine backends comes (not even remotely) close to the number of features present in Mojo, so take these benchmarks with a grain of salt, even though Mojo destroyed HTTP::Engine. Maybe once they add at least one backend that speaks HTTP 1.1 we can have a real benchmark.

Want Mojo documentation?

| No Comments | No TrackBacks
I've submitted a grant proposal to the Perl Foundation, you can leave a comment there to show them your interest, every comment counts!

Mojo website launched!

| No Comments | No TrackBacks
What is a web framework without a pretty website? Today we have finally launched http://mojolicious.org, yay! Lets see if we can start a new trend of good looking Perl sites. :)

Mojo 0.8 released (full Windows compatibility)

| No Comments | No TrackBacks
Today is a great day for Mojo, the last big milestone has been reached, we are now 100% Windows compatible. Kudos to all who have helped! And here is the complete changelog.
- Fixed Mojo::Server::Daemon windows support.
- Generated applications now have individually named executables.
- Cleaned up Mojo::Home.
- Changed Mojolicious default application templates to something more sane.
- Mojo::Base accessors don't take multiple arguments anymore, this results in a 25% speed increase.
- Added MOJO_MAX_MEMORY_SIZE environment variable.
- Added prepare_parser and prepare_builder callbacks to Mojo::Message.
- Added done and is_done to Mojo::Stateful.
- Fixed many win32 related bugs.
- Fixed keep alive related bugs in daemon and client. (Pedro Melo)
- Allow default in Mojo::Base to have false values. (Pedro Melo)
- Fixed chmod_rel_file in Mojo::Script. (Shu Cho).
- Mojo::Base attributes can't start with a digit. (Shu Cho).
- Fixed Content-Length header for empty messages.
- Removed warning from Mojo.pm.
- Renamed gate to bridge in MojoX::Routes.
- Added waypoint() to MojoX::Routes.
- Added named url_for to MojoX::Routes and Mojolicious.
- Added Mojolicious documentation. (vti)
- Fixed documentation links.
- Fixed some typos.

Mojo::Base beats all non xs accessor generators

| 6 Comments | No TrackBacks
Marcel Gruenauer did some interesting benchmarks comparing the most popular accessor generators.
Raw get/set performance was most important for me and i'm glad Mojo::Base did beat the competition.

All accessor generators besides Moose suck

| 4 Comments | No TrackBacks
Once you start using Moose all of a sudden the old accessor generators such as Class::Accessor feel very clumsy.
But adding a whole meta obect system just to generate accessors seems a bit of overkill for smaller projects.
Thats why i've written Mojo::Base, it's fast, simple, without any hidden magic, and won't get in your way if you decide to "upgrade" to Moose later on.
package Server;
use base 'Mojo::Base';

__PACKAGE__->attr('name');
__PACKAGE__->attr('port', default => 2);
__PACKAGE__->attr([qw/min_processes max_processes/],
    chained => 1,
    default => sub { 2 }
);
 __PACKAGE__->attr('transaction', weak => 1);

package main;
use Server;

my $s = Server->new;
print $s->port;
print $s->max_processes(5)->port;

my $s = Server->new(port => 3000);
print $s->min_processes(3)->min_processes;

my $t = MyTransaction->new;
$s->transaction($t);