be Groovie

Viewing posts for Perl

Oct 21 2005

Editing Myghty with TextMate

TextMate is a rather slick little text editor, with a bunch of cool automation stuff thats great for programmers. You’ve probably already seen it if you’ve watched any of those demo movies for some of the latest web frameworks.

Anyways, as I mainly use Myghty, I needed a syntax highlighting mode for its format. So I made a Myghty bundle for TextMate. This should also be useful for those using Mason as only a few minor adjustments regarding the underlying language highlighter need to be tweaked (Change source.python -> source.perl). This also has a few automation snippets to speed things up.

To install:

  • Unzip
  • Drag into ~/Library/Application Support/TextMate/Bundles/
  • Restart TextMate (Not absolutely sure this is needed though)

Enjoy!

Comments
Oct 18 2005

Hooked on Myghty

I’ve been programming web sites for many years, and have yet to come across a templating language as appealing as Mason / Myghty. To avoid confusion I’m going to talk about Myghty, but since its a direct port of Mason (plus some MVC stuff) all of my comments apply to Mason as well (unless otherwise noted). So if you find yourself stuck using Perl (or you prefer Perl) and something here sounds appealing, by all means use Mason as I did.

Despite Myghty only having come into existence approximately 14 months ago, the code-base is stable, very quick, and has been running in production environments for over 8 months. This is mainly because it started as a very direct port of Mason to Python, it then grew a few additional features that made it great for MVC use. The methodologies present in Mason (thus Myghty as well) are known to scale to very large and complex sites, as this list of Mason-powered sites shows. But it’s the little things added up that really make Myghty my template language of choice.

This is a rather lengthy post as I highlight and explain some core concepts of Myghty, please bear with me… also, if you’d like to follow along and try the examples out, its really easy to get started using Myghty with Paste.

Syntax

Template languages vary a lot in style, there are the very basic string replacement template languages all the way to more advanced template languages. Myghty definitely weighs in on the latter as it has many of its own concepts with regards to templating that produce a very robust and advanced templating system.

The syntax itself is also very appealing to me, as I’m a fan of templating languages that keep their guts inside < > signs. The only exception to this being if you need a quick line of Python, which is done just by having a % in front of it. Here’s what a loop would look like:


% for person in people:
   <b>Hi</b><% person %>
% #end

You’ll notice an additional line is needed to indicate the end of the loop. This is because Python uses white-space to determine blocks and Myghty needs to know when the indentation is over.

Components and Inheritance

In Myghty, each template is more properly referred to as a Component. When a component is directly called as a request (or sub-request), inheritance is applied. This is how a site’s skin is typically applied. Rather than having to specify in your template that it includes or extends some other template, in Myghty your component automatically inherits from an autohandler file above it.

An easier way to think of it is to consider your template directory layout as a Class, and all the templates in it are methods. Every directory inside that root one is another Class, and so on. The autohandler in this context acts much like your __init__ method. Here’s a little example:


	
  1. /autohandler



Sitename


% m.call_next()
Comments
Dec 18 2004

Fast CGI with HTML::Mason

I decided the other day for a variety of reasons, to switch from the mod_perl web-app style to using Fast CGI with HTML::Mason. I only found one application out there that uses Mason with Fast CGI, which was the RT Ticket tracking system. However, the way it was setup didn’t match my requirements, nor the way their handler was configured.

After scouring the Internet some more, I hobbled together a working config section for my Apache+mod_fastcgi along with a template for the mason handler. Since I haven’t seen anything going over these basic steps anywhere else, here’s how I did it.

First, the things you should have installed on your system (which I’m assuming is *nix):

  • HTML::Mason
  • CGI::Fast
  • Apache w/mod_fastcgi

Fast CGI runs your CGI application for you, and handles connections between your application, and the webserver. To configure your application, you just use one of the Fast CGI development kits for the response event loop within which your application will process requests.

Since we’re using Perl, there’s already a handy module available from CPAN that I chose to use called CGI::Fast. Then we just wrap our Mason call within a CGI::Fast loop to handle requests. This Perl script will be kept running persistently so that you get the advantage of not having to startup the Perl interpreter on every web page request.

Why Fast CGI instead of mod_perl?

  • You can use the connection feature of Fast CGI to run your app on a different machine than the webserver
  • Your application takes up only as much ram as Perl + your modules
  • It’s more portable, you don’t even need to use Apache, any webserver supporting Fast CGI will work
  • Less configuration files to maintain

Before showing my standard handler template, you should be aware of how I organize a Mason site using Fast CGI. Here’s what my directory structure looks like under the fictional GroovieWebapp:

  • GroovieWebapp/
    • site/
    • modules/
    • libs/
    • mdata/
    • mason-handler.fcgi

Site is where all of our Mason code (and images, css, etc.) is going to go. Modules is for putting any of your own Perl modules into that you made specifically for this webapp. libs for Mason libs, mdata for your Mason data dir, and finally the handler itself. This structure puts your whole webapp under one directory which is also useful under version control systems like Subversion.

Here’s what my standard handler template looks like (mason-handler.fcgi):


#!/usr/bin/perl
use FindBin qw($Bin);
use lib “$Bin/modules”;

use strict;
use HTML::Mason::CGIHandler;
use MIME::Lite; # Need this to e-mail the error

  1. Enter CGI::Fast mode, which should also work as a vanilla CGI script.

require CGI::Fast;

my $h;
my $show_error = 1; # Should we e-mail the error, or dump to the web?

if ($show_error) { $h = HTML::Mason::CGIHandler->new ( comp_root => [ [main => “/usr/local/www/GroovieWebapp/site”], [libs => “/usr/local/www/GroovieWebapp/libs”] ], data_dir => “/usr/local/www/GroovieWebapp/mdata”, allow_globals => [qw($Schema $Session)] );
} else { $h = HTML::Mason::CGIHandler->new ( comp_root => [ [main => “/usr/local/www/GroovieWebapp/site”], [libs => “/usr/local/www/GroovieWebapp/libs”] ], data_dir => “/usr/local/www/GroovieWebapp/mdata”, error_format => 'text’, error_mode => 'fatal’, allow_globals => [qw($Schema $Session)] );
}

  1. Setup our global vars for the request, preload our modules

{ package HTML::Mason::Commands; use Apache::Session::File (); # My favorite for session tracking use CGI::Cookie; # Also for session tracking use DBI; # It’s nice to load and establish our db connection in advance DBI->install_driver(“mysql”); # Put in whatever connection you use, etc. # This allows our $Schema variable to be accessed from anywhere in our Mason site our $Schema = DBI->connect_cached(“dbi:mysql:DB_NAME”,“DB_USER”, “DB_PASSWORD” ); }

  1. These two subroutines add Mason functionality that was lost by using CGIHandler instead
  2. of the ApacheHandler.

sub HTML::Mason::FakeApache::document_root { my $self = shift; return $ENV{'DOCUMENT_ROOT’};
}
sub HTML::Mason::FakeApache::param { my $self = shift; my $key = shift; my %args = HTML::Mason::Utils::cgi_request_args($self->query,$self->query->request_method); my @keys = (keys %args); if ($key) { return $args{$key}; } else { return @keys; } }
  1. For e-mailing the error

sub send_email { my $error = shift; my $cgi = shift; my $site = $cgi->virtual_host(); my $time = localtime; my $body = “————————————————————\n”; $body .= “———— ERROR OCCURRED\n”; $body .= “————————————————————\n”; $body .= “\n\n”; $body .= “WEBSITE INFO\n”; $body .= “Site: $site\n”; $body .= “Full URI Request: “.$ENV{'REQUEST_URI’}.”\n”; $body .= “Time: $time\n”; $body .= “\n\n”; $body .= “USER INFO\n”; $body .= “Referrer: “.$cgi->referer().”\n”; $body .= “User-agent: “.$cgi->user_agent().”\n”; $body .= “IP Address: “.$cgi->remote_host().”\n”; $body .= “Cookie info: “.$cgi->raw_cookie().”\n”; $body .= “\n\n”; $body .= “MASON ERROR\n”; $body .= $error; my $msg = MIME::Lite->new( From => 'YOUR SITE ', To => 'YOUR_EMAIL_ADDRESS’, Subject => “$site Mason Website Error occured at $time”, Data => $body, ); $msg->send('smtp’,'YOUR_SMTP_SERVER’); }

while (my $cgi = new CGI::Fast) { # the whole point of fastcgi requires the env to get reset here.. # So we must squash it again (This was copied from RT’s Fast CGI handler) $ENV{'PATH’} = ‘bin:/usr/bin’; $ENV{'CDPATH’} = '’ if defined $ENV{'CDPATH’}; $ENV{'SHELL’} = ‘bin/sh’ if defined $ENV{'SHELL’}; $ENV{'ENV’} = '’ if defined $ENV{'ENV’}; $ENV{'IFS’} = '’ if defined $ENV{'IFS’};

# The Mason $r->uri includes the script name unless we do this $ENV{'SCRIPT_NAME’} = '’; # This deals with someone entering yoursite.com/ to make sure it serves index.html if ( ( !$h->interp->comp_exists( $cgi->path_info ) ) && ( $h->interp->comp_exists( $cgi->path_info . “index.html” ) ) ) { $cgi->path_info( $cgi->path_info . “index.html” ); } #$cgi->header(-charset=>'utf-8’); # If your site uses utf-8 characters # Ping our db handle $HTML::Mason::Commands::Schema->ping; # Lets try and handle this… eval { $h->handle_cgi_object($cgi); }; # Something happened, if it couldn’t find the component, don’t fatal # we’ll re-process as a 404 if ($@) { if ($@ =~ /could not find component/) { # If you want Mason to handle the error so you can keep your site appearence, # this will call Mason to display your error page. If the error was in the # code that is called on every page, this will cause trouble. $cgi->path_info(’/errordocs/404.html’); $h->handle_cgi_object($cgi); } else { send_email($@,$cgi); } } }

This template has the option of either showing the Mason debugging output to the screen, or capturing the error, displaying a pretty 404 of your desire, and e-mailing you the error that occured.

Now for the Apache httpd.conf:


  1. Tell FastCGI to put its temporary files somewhere sane.

FastCgiIpcDir /tmp
  1. Increases processes if you have heavy loads to deal with

FastCgiServer /usr/local/www/GroovieWebapp/mason-handler.fcgi -idle-timeout 120 -processes 2

ServerAdmin webmaster@YOUR_SERVER ServerName YOUR_SERVER_NAME

AddHandler fastcgi-script fcgi ScriptAliasMatch (.*\.html$) /usr/local/www/GroovieWebapp/mason-handler.fcgi$1 ScriptAliasMatch (.*\/$) /usr/local/www/GroovieWebapp/mason-handler.fcgi$1 DocumentRoot /usr/local/www/GroovieWebapp

Restart apache, and check apache’s error_log to see that Fast CGI started up your application properly. Obviously, tailor these samples as needed. Another useful trick when running your webapp this way, is that if you kill the perl processes the apache Fast CGI process manager starts for you, it’ll re-spawn them. I find this a quick way to re-load individual webapps if I made changes to a module they’re using.

Enjoy!

Tags: Perl Code
Comments
Nov 26 2004

A Mason component to fill-in error messages

How often have you seen those sites with a form, and after you miss a field, it pops up a little message in red under the text box indicating what went wrong? I’m guessing a lot, and when writing web applications this can be a pain to code in.

Typically in Perl/PHP, you’d add this by going through your form, adding little bits of code under each and every form element to display the error on invalid input. I quickly got tired of this, and decided to simplify the process.

In examining HTML::FillInForm, I noticed I needed a slightly different tool to easily parse the HTML form. After a little bit of shopping about, I decided on HTML::Parser to do the heavy lifting. Here’s a snippet from a Mason page using my error_fill.mas component to toss in the error messages:


% if ($form_status eq 'errors') {
<&| /lib/error_fill.mas, errors => $errors_hash_ref &>
<p style="color: red; font-weight:bold;">Errors Found: Please correct the fields indicated.
<& /forms/myform.mas, %ARGS &>
</&>
% } else {
<& /forms/myform.mas, %ARGS &>
% }

$errors_hash_ref is a hash ref that is keyed by the form field name, with the value set to the error message you want displayed. Right now, error_fill.mas does not have custom pre/post-fix variables for you to tweak how the error message is inserted. It currently puts a <br> followed by a red span element containing your message.

myform.mas is the form I want to display, I prefer to split sections out in Mason to keep my web application modular and the sections of my pages more reusable.

Here’s error_fill.mas:




$errors
%args>
  1. $errors is a hash reference keyed as:
  2. 'field name’ > 'Error message’

use HTML::Parser;
my $form = $m->content;

my $p = HTML::Parser->new(api_version > 3);
$p->handler(default => sub { print _ }, "text"); $p->handler(end => sub { my ($tagname, $text, $attr) = _; if (($tagname eq ‘select’) && (exists $errors->{$attr->{name}})) { print $text; print ‘’; foreach my $err (@{$errors->{$attr->{name}}}) { print ‘
’.$err; } print ‘
’;

} else { print $text; } }, “tagname, text, attr”); $p->handler(start => sub { my ($tagname, $text, $attr) = _; if (($tagname eq 'input') && (exists $errors->{$attr->{name}})) { print $text; print '<span style="color:red;">'; foreach my $err ({$errors->{$attr->{name}}}) { print ‘
’.$err; } print ”; } else { print $text; } }, “tagname, text, attr”); $p->parse($form); %init>
Hopefully this will help some people out.
Tags: Perl Code
Comments
Page 1 of 1