Recently in Catalyst Category

YAPC this year was great.

I met a lot of people I only knew on the interwebs, went to some great talks, and got my ass heckled. I enjoyed every moment of it.

Matt Trout gave a great ironman forfeit talk, Stevan Little gave a great keynote on Tuesday, Nick Perez gave (6) great talks, 2 of which I was able to attend, Jesse Leuhrs showed me how to extend Moose like a boss, Chris Prather told me why MooseX::POE sucks and why I shouldn't use it, and I learned some Klingon from Paul Fenwick. Jay Shirley talked about a sensible way to use templates to control your UI, keeping designers AND programmers happy, and Cory Watson talked about selling Moose to your bosses and managing your data verification stack with Data::Manager.

My talks went mostly okay. Intro to Catalyst was a bit of a farce, but hey! We all learned something that day: Catalyst makes things get done faster. Thumbit was fun to talk about, and I actually got a good deal of hacking done on the code to make it (almost) work. Google Summer of Code will always be near and dear to my heart, my first talk, which is about my first dip into the magical waters of open source development.

I bid YAPC2010 a fond farewell, and shout outs to every one I met and everyone I got to hang out with after hours.

Until next year!

I've finally been able to play with the massively fun toy that is Bread::Board.

What is it, you say?

Bread::Board is basically a way to wire application components up in a DRY, and efficient manner. This is extremely useful for application configuration, and application setup (database handles/connection pooling, configuration file location, logger class setup, etc.).

The example I have put together involves the above, with a relatively sane method for setting up a configuration API so it's reusable and not a TOTAL pain in the ass.

Basically, I looked at blawd and stole the configuration bits and mangled them into something I could use.

Check it out (this comes from my minimal CMS Deimos:

package Deimos::ConfigContainer;
use Moose;
use namespace::autoclean;
use Bread::Board;
use Data::Dumper;
use Deimos::Schema; 
use Config::JFDI;
use Template;

has 'log_file_name' => (
  is      => 'ro',
  isa     => 'Str',
  default => "deimos.conf"
);

has 'config' => (
  is => 'ro',
  lazy_build => 1,
);

sub _build_config {
  my $self = shift;
  my $cfg = Config::JFDI->new( path => $something . $self->log_file_name );
  return $cfg->get;
}

sub build {
  my ($self, $service) = @_;
  my $cfg = $self->config;
  my $c = container Deimos => as {

    service 'site_title' => (
        block => sub {
            my $self = shift;
            return $self->config->{'site_title'};
        },
        dependencies => [ depends_on('config') ],
    );

    service 'log_file' => $self->log_file_name;

    service 'config' => $cfg;

    service 'schema' => (
        lifecycle => "Singleton",
        block => sub {
            warn "config: " . Dumper $cfg;
           return Deimos::Schema->connect(
               @{ $cfg->{'Database'}->{'connect_info'} },
            );
          }
    );

    service 'templates' => ( 
        block => sub {
            return Template->new($cfg->{'templates'});
        }
    );

    service 'application' => (
        class        => 'Deimos',
        dependencies => {
            schema     => depends_on('schema'),
            config     => depends_on('config'),
            site_title => depends_on('site_title'),
        }
    );
};

    return $c->fetch($service)->get;
}

 __PACKAGE__->meta->make_immutable;
1;

Basically, this allows you to either use your configcontainer, or, like I plan to, create a role, and apply it as needed and do $self->config->fetch('service_name');

This makes life MUCH much easier on the configuration front.

I hope this helps someone out there like it helped me when I finally got it figured out.

Why use LeakTracker?

You have a Catalyst application that is consuming more and more memory over time. You would like to find out what classes are involved and where you may have cyclic references. Why not try out nothingmuch's handy dandy Catalyst::Controller::LeakTracker.

Full Article

Bracket is a web application that manages a group of players and their picks in the national college basketball tournament. It was written to provide an open source bracket system for the tourney that is fast, simple and ad free.

(update: sorry for the post-march madness post, this is all dhoss's fault)

Many of you will have run into this problem: You want to stash a callback in Catalyst that will build you the URL for an action. It’s supposed to be a callback, because you want to dynamically pass an ID or other argument to the URL.

As nice as this sounds, you have to be careful so you don’t create a circular reference. I’ll discuss the current best practice for this problem below and will propose another kind of solution.

Abstract

There is more than one way to handle forms in your Catalyst/DBIC application. This paper speaks to the HTML::FormHandler way. Let's start with a simple example of building a registration form to allow new users to register with your website application1. We will look at how to build a registration form object and use it in a Catalyst controller. Furthermore, the form will integrate with a DBIC connected database to persist the registration information submitted via the form.

Data::Manager is a really fantastic marriage of two very well thought out and uncoupled modules, Data::Verifier and Message::Stack. Data::Verifier does exactly what its name says, which is verifies data. You give it a hashref of constraints to verify against, and call ->validate on your data that you've passed in, and boom, data is verified with errors and filters. Messages::Stack is again, another very aptly named module. It gives you a programmatic interface to creating a stack of messages with a syslog flavor to them with regards to message level, scope, id, etc. You can then, after creating a stack of messages, retrieve messages matching a scope, or a block of messages pertaining to a certain attribute of your data, search through the messages and grab the ones that match your search criteria, or get all of the messages.

I've never really liked dealing with creating forms. You have to write a butt load of tedious HTML, validate it, and then return error messages as needed. If you want it to be fancy and pretty, you have to write a bunch of CSS to put your error messages where you want and make them shiny. Luckily, there are things to handle this.

Being a Moose fanatic, I am most partial to the latter, HTML::FormHandler. It's extremely easy to use, and requires zero configuration file crap. You get validation as Moose types/constraints, it's very cool.

So, back to me hating having to build forms. This includes building a form for something that already has enough information to build a form from, say, a database schema. My dream has been to be able to read a database schema (preferably DBIx::Class), and generate a form based on the data types specified in said schema. This is completely doable! Heck, even I drafted up some code to get some preliminary form fields from a database. The following is from the CMS I'm working on, using HTML::FormHandler and DBIx::Class to get things done. This is extremely proof of concept code, and doesn't actually have any logic to determine what kind of form element a given schema entity should be. That, however, should be fairly trivial and I will undoubtedly be writing a follow up to that effect. Go here to check out the source: http://gist.github.com/230652. Enjoy.

Recently while working on getting tests done for Catalyst::Devel so it could be shipped, and I absolutely could not figure out how to get the test for the development server to work. So, I queried #catalyst-dev about it, and my good friend mst told me to use strace to figure out what was going on behind the scenes. In this case, I used dtruss since I'm a Mac user and for some reason the usual *nix tool doesn't work on the Mac platform.

Basically, what went down was this:

  1. sudo dtruss -f prove -l t/author/optional_http-server.t
  2. a whole load of rather cryptic output (see below for a snippet)
  3. analysis and correction

What I found was that since the Catalyst development server is chock full of system calls that are chock full of information on what's going on (and going wrong) behind the scenes, dtruss was the perfect tool for grabbing messages being relayed between processes and not necessarily being spewed out to my terminal. Here's a small snippet of the problem area I (well, mst actually) discovered:

46665/0x117e04: stat64("/opt/local/lib/perl5/vendorperl/Catalyst/ScriptRunner.pm\0", 0x7FFF5FBFEE90, 0xFFFFFFFFFFFFFFFF) = -1 Err#2 46665/0x117e04: stat64("/opt/local/lib/perl5/5.8.9/darwin-2level/Catalyst/ScriptRunner.pmc\0", 0x7FFF5FBFEF20, 0x0) = -1 Err#2 46665/0x117e04: stat64("/opt/local/lib/perl5/5.8.9/darwin-2level/Catalyst/ScriptRunner.pm\0", 0x7FFF5FBFEE90, 0xFFFFFFFFFFFFFFFF) = -1 Err#2 46665/0x117e04: stat64("/opt/local/lib/perl5/5.8.9/Catalyst/ScriptRunner.pmc\0", 0x7FFF5FBFEF20, 0x0) = -1 Err#2 46665/0x117e04: stat64("/opt/local/lib/perl5/5.8.9/Catalyst/ScriptRunner.pm\0", 0x7FFF5FBFEE90, 0xFFFFFFFFFFFFFFFF) = -1 Err#2 46665/0x117e04: stat64("./Catalyst/ScriptRunner.pmc\0", 0x7FFF5FBFEF20, 0x0) = -1 Err#2 46665/0x117e04: stat64("./Catalyst/ScriptRunner.pm\0", 0x7FFF5FBFEE90, 0xFFFFFFFFFFFFFFFF) = -1 Err#2 46665/0x117e04: writenocancel(0x2, "Can't locate Catalyst/ScriptRunner.pm in @INC (@INC contains: /Users/dhoss/web-devel/Cat-Runtime-5.8/t/author/../../lib /Users/dhoss/web-devel/Cat-Runtime-5.8/lib /opt/local/lib/perl5/siteperl/5.8.9/darwin-2level /opt/local/lib/perl5/siteperl/5.8.9 /opt/", 0x2D0)

That's just a snippet. Somewhat cryptic, but it's all right there. Check out this line: 46665/0x117e04: writenocancel(0x2, "Can't locate Catalyst/ScriptRunner.pm in @INC (@INC contains: /Users/dhoss/web-devel/Cat-Runtime-5.8/t/author/../../lib /Users/dhoss/web-devel/Cat-Runtime-5.8/lib /opt/local/lib/perl5/siteperl/5.8.9/darwin-2level /opt/local/lib/perl5/site_perl/5.8.9 /opt/", 0x2D0). Derp! I was running this test in Catalyst::Runtime trunk/ that doesn't have my ScriptRunner classes merged yet. So, I reran this test (using dtruss -f again) under my branch, found out that the options being passed to the development server were incorrect, corrected, svn committed, and can now take another step (finally) toward shipping Catalyst::Devel!

There's a new kid on the block for web application development, and it's called Plack. I'm not going to go into depth on explaining it here, as the website listed previously does a stellar job of that, but I'm going to explain and talk about what got me started on it, and what made me love it.

I've been a pretty avid MovableType fan since I first got it running. It Just Works(tm). I've always ran it under Apache, however, so when I made the big and permanent transition to nginx, I was befuddled as to how to get it to run under my new toy. A kind sir by the name of Jay Shirley recommended I use Plack to get my old love running under nginx. I talked to the creator of this mystical new being, Tatsuhiko Miyagawa on its IRC channel, #plack. We went back and forth for a few iterations until w(h)e got his mt.psgi script (listed here) working so that MT would be okay with new installs.

The result: A mostly working MovableType installation! The only problem is, I have a MT database dump from MySQL that I either A) need to convert the data portion of the dump to something PostgreSQL (what I've converted to for life) will like, or B) suck it up and set up a MySQL instance for this one app. MT itself runs just fine, it's completely my fault that anything on the database side doesn't work. Miyagawa reports that previous installations work just fine with this, so, as I said, I will need to investigate which route I want to take to get this data into a database for MT.

Either way, my experience was fantastic. Plack is really easy to set up. All the work is done for you, and you can still run things under FastCGI (if you're so inclined). It's a great bridge between server software and a web application, so we're not stranded somewhere in between holding on to the connecting ends of a bridge screaming "HOLY FUCK THIS HURTS AND GOD I HOPE IT HOLDS TOGETHER IF WE HAVE TO CHANGE ANYTHING".

Kudos to you miyagawa, I'm pretty sold on using this from here on out for web apps I write in the future (mostly Catalyst based, for which we have Catalyst::Engine::PSGI!)

UPDATE: Here's the configuration I'm using for nginx: http://wiki.catalyzed.org/codesamples/dhoss/placknginxconf

Sponsored By


Ionzero: Rescue your dev project.
OpenID accepted here Learn more about OpenID

Following

Not following anyone

Note to spammers: all comments are moderated. Don't waste your time