A piggy bank of commands, fixes, succinct reviews, some mini articles and technical opinions from a (mostly) Perl developer.

Jump to

Quick reference

Showing posts with label mojo. Show all posts
Showing posts with label mojo. Show all posts

Mojolicious version 9 cheat sheet

Mojo 9 changes:

s/over/requires/

s/route/any/

s/via/methods/


Mojo::UserAgent request format

The get(), post(), etc. methods are both too magic, and not magic enough.

They do what I mean, but only if I remember the order or parameters. Luckily Perl has an easy solution to this problem: Named parameters! AKA Passing a hash, like a normal person.


Recording HTTP responses with Perl

There are two main ways. If your HTTP requests are being done in a different way, you will need to build your own solution.

The LWP way:

use LWP::UserAgent::Mockable;

BEGIN {
    # Options: record|playback|passthrough
    $ENV{LWP_UA_MOCK}      ||= 'playback';
    $ENV{LWP_UA_MOCK_FILE} ||= "$0-lwp-mock.out";
}

END {
    LWP::UserAgent::Mockable->finished();
}

# You might be able to normalise the requests using the callbacks

The Mojo way:

use Mojo::UserAgent::Mockable;

my $mock_ua = Mojo::UserAgent::Mockable->new(
    mode        => $ENV{MOJO_UA_MOCK},
    file        => "$0-mojo-ua-mock.out",
#    ignore_body => 1,
# or:
    request_normalizer => sub {
        my ( $req, $recorded_req ) = @_; 

        my ($time) = $recorded_req->body =~ m{};
        my ($hash) = $recorded_req->body =~ m{(.*)};

        my $body = $req->body;
        $body =~ s{}{};
        $body =~ s{.*}{$hash};

        $req->body($body);
    },  

);

END {
    $mock_ua->save if $ENV{MOJO_UA_MOCK} eq 'record';
}

ok my $t = Test::Mojo->new("My::App");

$t->app->mock( useragent => sub { $mock_ua } );

# Configure the proxy in record/passthrough mode only
if ( $MODE =~ /record|passthrough/ ) { 
    local $ENV{HTTPS_PROXY} = $t->app->config->{http_proxy};
    local $ENV{HTTP_PROXY}  = $t->app->config->{http_proxy};
    my $proxy = Mojo::UserAgent::Proxy->new;
    $proxy->detect;
    $mock_ua->proxy( $proxy );
}

Add headers or cookies to request in Mojolicious tests

When using Test::Mojo, sometimes you want to modify the request to add a cookie or custom headers.

.

How to disable Mojo debug logging

When setting MOJO_LOG_LEVEL does not work... Make the following hacks:

removing debug output

~ ============================================================================ Tuesday 12th February 2019

~~~ FIXES FOR OLD VERSION OF MOJO (Supervillain 8.03)

../local/lib/perl5/Mojolicious.pm
132:    $self->log->debug(qq{$method "$path" ($id)}) if $ENV{BB_DEBUG} || $ENV{MOJO_DEBUG};

../local/lib/perl5/Mojolicious/Controller.pm
209:      $app->log->debug("$code $msg (${elapsed}s, $rps/s)") if $ENV{BB_DEBUG} || $ENV{MOJO_DEBUG};

../local/lib/perl5/Mojolicious/Plugin/EPLRenderer.pm
18:    $c->app->log->debug("Rendering cached @{[$mt->name]}") if $ENV{BB_DEBUG} || $ENV{MOJO_DEBUG};
30:      $c->app->log->debug(qq{Rendering inline template "$name"}) if $ENV{BB_DEBUG} || $ENV{MOJO_DEBUG};
40:        $c->app->log->debug(qq{Rendering template "$name"}) if $ENV{BB_DEBUG} || $ENV{MOJO_DEBUG};
46:        $c->app->log->debug(qq{Rendering template "$name" from DATA section}) if $ENV{BB_DEBUG} || $ENV{MOJO_DEBUG};

../local/lib/perl5/Mojolicious/Routes.pm
95:  $app->log->debug('Routing to a callback') if $ENV{BB_DEBUG} || $ENV{MOJO_DEBUG};
150:    $log->debug(qq{Routing to application "$class"}) if $ENV{BB_DEBUG} || $ENV{MOJO_DEBUG};
164:      $log->debug(qq{Routing to controller "$class" and action "$method"}) if $ENV{MOJO_DEBUG} || $ENV{BB_DEBUG};

~ ============================================================================ Thursday 7th March 2019

local/lib/perl5/Mojolicious.pm
123:          #return unless $ENV{MOJO_DEBUG}; # WS hack

local/lib/perl5/Mojolicious/Controller.pm
187:      return unless $ENV{MOJO_DEBUG};

local/lib/perl5/Mojolicious/Routes.pm
103:  $app->log->debug('Routing to a callback') if $ENV{MOJO_DEBUG};
170:      $log->debug(qq{Routing to controller "$class" and action "$method"}) if $ENV{MOJO_DEBUG};

x
491:>> /Users/will/dev/ats-broadcast-hub/local/lib/perl5/Mojolicious/Routes.pm:103:   $app->log->debug('Routing to a callback') if $ENV{MOJO_DEBUG};

~~~~ AND ~~~~

To fix CODE(0x7fde03335ca0) now:

vi local/lib/perl5/Mojolicious.pm +122

~~~ OLD VERSION OF MOJO

local/lib/perl5/Mojolicious.pm

  60 our $CODENAME = 'Supervillain';
  61 our $VERSION  = '8.03';

 119   # Start timer (ignore static files)
 120   my $stash = $c->stash;
 121   unless ($stash->{'mojo.static'} || $stash->{'mojo.started'}) {
 122     my $req    = $c->req;
 123     my $method = $req->method;
 124     my $path   = $req->url->path->to_abs_string;
 125     my $id     = $req->request_id;
 126     $self->log->debug(qq{$method "$path" ($id)});
 127     $c->helpers->timing->begin('mojo.timer');
 128   }

~~~ NEW VERSION OF MOJO

 119   # Start timer (ignore static files)
 120   my $stash = $c->stash;
 121   $self->log->debug(sub {
 122     my $req    = $c->req;
 123     my $method = $req->method;
 124     my $path   = $req->url->path->to_abs_string;
 125     my $id     = $req->request_id;
 126     $c->helpers->timing->begin('mojo.timer');
 127     return qq{$method "$path" ($id)};
 128   }) unless $stash->{'mojo.static'};
 129 

~~~ FIX FOR NEW VERSION (8.12)

vi local/lib/perl5/Mojolicious.pm

  61 our $CODENAME = 'Supervillain';
  62 our $VERSION  = '8.12';

 119   # Start timer (ignore static files)
 120   my $stash = $c->stash;
 121     my $req    = $c->req;
 122     my $method = $req->method;
 123     my $path   = $req->url->path->to_abs_string;
 124     my $id     = $req->request_id;
 125     $c->helpers->timing->begin('mojo.timer');
 126 if ($ENV{MOJO_DEBUG}) {
 127     $self->log->debug(qq{$method "$path" ($id)}) unless $stash->{'mojo.static'};
 128 }

vi local/lib/perl5/Mojolicious/Controller.pm

184     # Disable auto rendering and stop timer
185     my $app = $self->render_later->app;
186 #    $app->log->debug(sub {
187       my $timing  = $self->helpers->timing;
188       my $elapsed = $timing->elapsed('mojo.timer') // 0;
189       my $rps     = $timing->rps($elapsed) // '??';
190       my $code    = $res->code;
191       my $msg     = $res->message || $res->default_message($code);
192 #      return "$code $msg (${elapsed}s, $rps/s)";
193 #    }) unless $stash->{'mojo.static'};
194 if ($ENV{MOJO_DEBUG}) {
195       $app->log->debug("$code $msg (${elapsed}s, $rps/s)") unless $stash->{'mojo.static'}; # MOJO_DEBUG
196 }



Reserved keywords - Do Not Use these in your code

Do not use these names, you will get confusing errors...

Perl:

  • sub import


Mojolicious:

  • stash('data', ...)



Mojolicious basics

How to do common stuff.

Run an app:

MOJO_USERAGENT_DEBUG=1 perl -I lib ~/path/to/morbo --verbose --watch lib --watch local bin/app.pl

View existing routes:

perl -I lib bin/app.pl routes

Find the code that defines the routes:

grep -r '$r->get' .
grep -r '$r->post' .

Install database:

perl -I lib bin/app.pl dbic_migration --action=install

Write a script that uses the app config, etc:

See Mojolicious::Command

Debug Test::Mojo:

print $t->tx->res->body; # See also guide to debugging

Catch unexpected exceptions:

Dump out 2nd-level routes:
my @routes = sort map { $_->to_string } map { @{ $_->children } }
    grep { $_->name eq 'distro' || $_->name eq 'candidates' }
    @{ $t->app->routes->children };

Guide to debugging Mojolicious applications

When MOJO_MODE=development or is not set, you should see exceptions rendered in the browser. But if you don't, try creating a templates/exception.html.ep template that contains this: %= $exception

You can also create error templates for different environments:
  • templates/exception.production.html.ep
  • templates/exception.development.html.ep

Mojo provides useful hooks that can be used to dump out debugging info: