Posts Tagged ‘catalyst’

How to prevent some components to be loaded by Catalyst

Thursday, June 25th, 2009

Let’s say you have a “large” Catalyst application, with a lot of compoments. When you deploy your application, or when you want to test it while your developping, you may not want to have some of thoses components loaded (you don’t have all the dependencies, they are incompatible, etc…). Catalyst use Module::Pluggable to load the components, so you can easily configure this. In your application’s configuration, add:

setup_components:
  except:
    - MyApp::Model::AAAA
    - MyAPP::Model::BBBB::REST
    ...

Module::Pluggable have some other interesting features. You may have a second Catalyst application, and want to use one or more components from this one. You can easily do this:

setup_components:
  search_path:
    - MyApp
    - MyOtherApp::Model

CatalystX::Dispatcher::AsGraph

Saturday, May 30th, 2009

This morning I saw this post from marcus ramberg about MojoX::Routes::AsGraph. I liked the idea. But as I Catalyst instead of Mojo, I thought I could give a try and do the same thing for Catalyst dispatcher, and I’ve coded CatalystX::Dispatcher::AsGraph. For the moment only private actions are graphed.

routes

You use it like this:

perl bin/catalyst_graph_dispatcher.pl --appname Arkham --output routes.png

You can create a simple script to output as text if you prefer:

#!/usr/bin/perl -w             
use strict;
use CatalystX::Dispatcher::AsGraph;
 
my $graph = CatalystX::Dispatcher::AsGraph->new_with_options();
$graph->run;
print $graph->graph->as_txt;

The code is on github for the moment.

For thoses who are interested by visualization, I’ll publish soon some (at least I think) really nice visualisations about CPAN, Perl, and his community, that we have created at $work.

A simple feed aggregator with modern Perl - part 4.1

Monday, May 18th, 2009

You can thanks bobtfish for being such a pedantic guy, ’cause now you will have a better chained examples. He forked my repository from github and fix some code that I’ll explain here.

lib/MyFeedReader.pm

 package MyFeedReader;
+use Moose;
+use namespace::autoclean;
 
-use strict;
-use warnings;
-
-use Catalyst::Runtime '5.70';
+use Catalyst::Runtime '5.80';
 
-use parent qw/Catalyst/;
+extends 'Catalyst';

You can see that he use Moose, so we can remove use strict; use warnings; and have a more elegant way to inherit from Catalyst with extends 'Catalyst' instead of use parent qw/Catalyst/. He also have updated the Catalyst::Runtime version, and added namespace::autoclean. The purpose of this module is to keep imported methods out of you namespace. Take a look at the documenation it’s easy to understand how and why it’s usefull.

lib/MyFeedReader/Controller/Root.pm

-use strict;
-use warnings;
-use parent 'Catalyst::Controller';
+use Moose;
+use namespace::autoclean;
+BEGIN { extends 'Catalyst::Controller' }
 
-sub index :Path :Args(0) {
+sub root : Chained('/') PathPart() CaptureArgs(0) {}
+
+sub index : Chained('root') PathPart('') Args(0) {
     my ( $self, $c ) = @_;
 
     # Hello World
     $c->response->body( $c->welcome_message );
 }
 
-sub default :Path {
+sub default : Private {
     my ( $self, $c ) = @_;
     $c->response->body( 'Page not found' );
     $c->response->status(404);

A new method, root, that will be the root path for our application. All our methods will be chained from this action. If start you catalyst server and go to http://localhost:3000/ you will be served with the Catalyst’s welcome message as before.

lib/MyFeedReader/Controller/Entry.pm

-use warnings;
+use Moose;
 use MyAggregator::Entry;
-use parent 'Catalyst::Controller';
-
-__PACKAGE__->config->{namespace} = 'entry';
+use namespace::autoclean;
+BEGIN { extends 'Catalyst::Controller'; }
 
-sub view : Chained('/') : PathPart('entry') : Args(1) {
+sub view : Chained('/root') : PathPart('entry') : Args(1) {
     my ( $self, $c, $id ) = @_;
 
     $c->stash->{entry} = $c->model('KiokuDB')->lookup($id);
 }
 
-1;
-
+__PACKAGE__->meta->make_immutable;

We extends the Catalyst::Controller in a Moose way, and the make_immutable instruction is a Moose recommanded best practice (you can alsa add no Moose after the make_immutable).

lib/MyFeedreader/Controller/Feed.pm

+use Moose;
+use namespace::autoclean;
+BEGIN { extends 'Catalyst::Controller' }
 
-use strict;
-use warnings;
-use parent 'Catalyst::Controller';
+sub feed : Chained('/root') PathPart('feed') CaptureArgs(0) {}
 
-__PACKAGE__->config->{namespace} = 'feed';
-
-sub index : Path : Args(0) {
+sub index : Chained('feed') PathPart('') Args(0) {
     my ( $self, $c ) = @_;
 
     $c->stash->{feeds}
         = [ $c->model('MyModel')->resultset('Feed')->search() ];
 }
 
-sub view : Chained('/') : PathPart('feed/view') : Args(1) {
+sub view : Chained('feed') : PathPart('view') : Args(1) {
     my ( $self, $c, $id ) = @_;
 
     $c->stash->{feed}
         = $c->model('MyModel')->resultset('Feed')->find($id);
 }
 
-1;
+__PACKAGE__->meta->make_immutable;

We got feed which is chained to root. index is chained to feed, and take no arguments. This method display the list of our feeds. And we got the view method, chained to feed too, but with one argument, that display the content of an entry.

If you start the application, you will see the following routes:

.-------------------------------------+--------------------------------------.
| Path Spec                           | Private                              |
+-------------------------------------+--------------------------------------+
| /root/entry/*                       | /root (0)                            |
|                                     | => /entry/view                       |
| /root/feed                          | /root (0)                            |
|                                     | -> /feed/feed (0)                    |
|                                     | => /feed/index                       |
| /root/feed/view/*                   | /root (0)                            |
|                                     | -> /feed/feed (0)                    |
|                                     | => /feed/view                        |
| /root                               | /root (0)                            |
|                                     | => /index                            |
'-------------------------------------+--------------------------------------'

I hope you got a better idea about chained action in catalyst now. And again, thanks to bobtfish for the code.

A simple feed aggregator with modern Perl - part 4

Wednesday, May 13th, 2009

We have the model, the aggregator (and some tests), now we can do a basic frontend to read our feed. For this I will create a webapp using Catalyst.

Catalyst::Devel is required for developping catalyst application, so we will install it first:

    cpan Catalyst::Devel

Now we can create our catalyst application using the helper:

    catalyst.pl MyFeedReader

This command initialise the framework for our application MyFeedReader. A number of files are created, like the structure of the MVC directory, some tests, helpers, …

We start by creating a view, using TTSite. TTSite generate some templates for us, and the configuration for this template. We will also have a basic CSS, a header, footer, etc.

    cd MyFeedReader
    perl script/myfeedreader_create.pl view TT TTSite

TTSite files are under root/src and root/lib. A MyAggregator/View/TT.pm file is also created. We edit it to make it look like this:

    __PACKAGE__->config({
        INCLUDE_PATH => [
            MyFeedReader->path_to( 'root', 'src' ),
            MyFeedReader->path_to( 'root', 'lib' )
        ],
        PRE_PROCESS  => 'config/main',
        WRAPPER      => 'site/wrapper',
        ERROR        => 'error.tt2',
        TIMER        => 0,
        TEMPLATE_EXTENSION => '.tt2',
    });

Now we create our first template, in root/src/index.tt2

    to <a href="/feed/">your feeds</a>

If you start the application (using perl script/myfeedreader_server.pl) and point your browser on http://localhost:3000/, this template will be rendered.

We need two models, one for KiokuDB and another one for MyModel:

lib/MyFeedReader/Model/KiokuDB.pm

    package MyFeedReader::Model::KiokuDB;
    use Moose;
    BEGIN { extends qw(Catalyst::Model::KiokuDB) }
    1;

we edit the configuration file (myfeedreader.conf), and set the dsn for our kiokudb backend

    <Model KiokuDB>
        dsn dbi:SQLite:../MyAggregator/foo.db
    </Model>

lib/MyFeedReader/Model/MyModel.pm

    package MyFeedReader::Model::MyModel;
    use base qw/Catalyst::Model::DBIC::Schema/;
    1;

and the configuration:

    <Model MyModel>
        connect_info dbi:SQLite:../MyModel/model.db
        schema_class MyModel
    </Model>

We got our view and our model, we can do the code for the controller. We need 2 controller, one for the feed, and one for the entries. The Feed controller will list them and display entries titles for a given feed. The Entry controller will just display them.

lib/MyFeedReader/Controller/Feed.pm

    package MyFeedReader::Controller::Feed;
    use strict;
    use warnings;
    use parent 'Catalyst::Controller';
 
    __PACKAGE__->config->{namespace} = 'feed';
 
    sub index : Path : Args(0) {
        my ( $self, $c ) = @_;
        $c->stash->{feeds}
            = [ $c->model('MyModel')->resultset('Feed')->search() ];
    }
 
    sub view : Chained('/') : PathPart('feed/view') : Args(1) {
        my ( $self, $c, $id ) = @_;
        $c->stash->{feed}
            = $c->model('MyModel')->resultset('Feed')->find($id);
    }
 
    1;

The function index list the feeds, while the function view list the entries for a give feed. We use the chained action mechanism to dispatch this url, so we can have
urls like this /feed/*

We create our 2 templates (for index and view):

root/src/feed/index.tt2

    <ul>
        [% FOREACH feed IN feeds %]
            <li><a href="/feed/view/[% feed.id %]">[% feed.url %]</a></li>
        [% END %]
    </ul>

root/src/feed/vew.tt2

    <h1>[% feed.url %]</h1>
 
    <h3>entries</h3>
    <ul>
        [% FOREACH entry IN feed.entries %]
            <li><a href="/entry/[% entry.id %]">[% entry.permalink %]</a></li>
        [% END %]
    </ul>

If you point your browser to http://localhost:3000/feed/ you will see this:

list_feed

Now the controller for displaying the entries:

    package MyFeedReader::Controller::Entry;
    use strict;
    use warnings;
    use MyAggregator::Entry;
    use parent 'Catalyst::Controller';
 
    __PACKAGE__->config->{namespace} = 'entry';
 
    sub view : Chained('/') : PathPart('entry') : Args(1) {
        my ( $self, $c, $id ) = @_;
        $c->stash->{entry} = $c->model('KiokuDB')->lookup($id);
    }
 
    1;

The function view fetch an entry from the kiokudb backend, and store it in the stash, so we can use it in our template.

root/src/entry/view.tt2

    <h1><a href="[% entry.permalink %]">[% entry.title %]</a></h1>
    <span>Posted [% entry.date %] by [% entry.author %]</span>
    <div id="content">
        [% entry.content %]
    </div>

If you point your browser to an entry (something like http://localhost:3000/entry/somesha256value), you will see an entry:

show_entry

Et voila, we are done with a really basic feed reader. You can add methods to add or delete feed, mark an entry as read, …

The code is available on github.

belgian perl workshop 09

Sunday, March 8th, 2009

last weekend my co-workers and I went to the Belgian Perl Workshop 09. I attended the following presentations:

  • kiokudb, by nothingmuch. Slides are available here. We were able to talk with him during the afternoon, we might we use it at work.
  • Painless XSLT with Perl, by andrew shitov.
    Was interesting, even if I don’t do any XSLT anymore. Again, some ideas might be used for work.
  • What are you pretending to be?, by liz. That’s a hell of a hack. The module is available on the cpan.
  • Regular Expressions and UniCode Guru, by abigail. Feel better to know that I’m not the only one suffering with unicode in Perl ;). Learn some stuff like how to create a custom character classe, etc.
  • Catalyst, by matt trout. Ok, we’re using Catalyst at work for our webservices. So we allready know about catalyst, but we were curious. And as i was hoping, we learn some nice tweaks. We discovered Catalyst::Adaptor, so we don’t have to do some horrible stuff in our Controller any more, and some other interesting stuff were put in this talk. And matt is a really good speaker, manage to keep an audiance amused and interested.
  • Catalyst & AWS, by matt trout. Once again, a really good talk by matt. Some good advices, and a lot of fun.

We didn’t stay long for the social event in the evening; we had booked a hotel in bruxelles. But i’m glad that we were able to get to this perl workshop, it was well-organised, good talks, meet nice people, and learn some stuff. All in all, a good day :)

some photos are available on on my flickr account.