I'm a big fan of declarative programming, that is, describing what I want to happen and letting the computer figure out how to achieve this. Thus, mapping schemes like mapping from URLs or CGI queries to Perl code interest me. I'm searching for a language that has the expressiveness of Perls regular expressions yet works for URLs. Simple regular expressions don't cut it because I want to be largely independent from the order of the CGI parameters. The following are some musings that came to my mind and I'm seeking other prior art, ideas and feedback on and faults with my ideas.

Here's my idea of integrating (CGI) parameter validation and dispatch, with some advantages and some disadvantages:

The basic format is:

url { # some Perl code to be invoked on receiving the URL }

That's pretty abstract, so some more example to flesh it out a bit:

/edit?node=(\w+);... { print "You're trying to edit '$node'"; }; /create?name=(\w+);... { print "You're trying to create '$name' but gave no code to fill it +"; }; /create?name=(\w+);code=(.*) { print "Created as sub $name { $code }"; }; /(.*) { print "Don't know how to handle " . $q->query_path; };

The Perl side would "simply" parse each rule (and the code attached to the rule) into subroutines like this:

# /edit?node=(\w+);... { # print "You're trying to edit '$node'"; # }; sub edit_node { my ($q) = @_; return if ($q->param('node') !~ /^(\w+)$/; my $node = $1; print "You're trying to edit '$node'"; };

The advantages are obvious (to me at least):

  1. Implicit validation of the named parameters
  2. Extraction of the named parameters into (lexical, named) variables, enabling some kind of strictness for your URLs

The disadvantages I see so far are:

  1. No sensible support for parameters with multiple values
  2. Anonymous/unnamed parameters get eaten by the ... declaration at the end, and it's not clear whether these should be passed through or ignored/hidden from the called code.
  3. Some effort must go into ordering the rules/specifications from most specific to least specific, and that effort must be completely automatic and be able to warn of conflicts
  4. Is it sensible at all to couple code and associated rules like this, or should any such rule reflect onto a named subroutine anyway?
  5. The way to declare optional parameters with defaults, using ; as the magic "default" delimiter doesn't seem sound. The ";" was chosen because it is otherwise used to delimit query parameters and thus is unlikely to occur within parameters.
  6. The scheme doesn't work for more complex validation, like making sure that a parameter actually exists as a key in a database table (;user=5348 for example) - either some fancy plugin syntax is needed or plain old manual Perl coding in the called routine.
  7. The order of query parameters possibly gets lost. The order of query parameters is important, for example the ;op= sequences on PM.
  8. The nice integration into the model that Catalyst provides needs to be hacked on to my syntax by inspecting the package of the caller and adding the correct prefixes - but tight coupling to a specific model is not what I want anyway.

There are currently two other declarative schemes I know of, but I didn't find their documentation too elucidating:

Catalyst has a URL mapping scheme similar to the one I propose below, but it can only map on the query path, not on the query parameters.

Jifty also has a mapping scheme, but I didn't find any documentation besides some uncommented example template on it.

CGI::Application::Dispatch mimics a dispatching scheme that Ruby (on Rails?) has - I've added another column to the table. It has some features that the other systems do not, but also lacks parameter based dispatch.

While formalizing my wishes, I have thought about abstract parameter specifications which don't fit within regex-style "oneliners" but allow me to think about an isomorphic terser syntax. I came up with the following commands and the equivalent formulations in Catalyst and Jifty:

Abstract name and parametersCatalystJiftyMy ownRuby/CGI::Application::Dispatch
named-path-capture $specindex-based captures are possible via :Regex('^/(...)/(...)')???/(?<name1>\w+)/(?<name2>\w+)/:name1/:name2/ gets turned into { name1 => $value1, name2 => $value2 }
optional-path-capture $specIndex access via :Regex('^/(...)(/...)?') (unconfirmed)???/(?<name1>\w+)/(?<name2>\w*)/:name1/:name2? gets turned into { name1 => $value1, name2 => $value2 } (if there is a second path segment)
path-matches $re:Regex('^/.../')n/am!^/.../!Substring via '...'
path-equals $str:Path('/.../')|/...//.../
param-equals $key $valcustom handler???;key=val/.../
param-present $keycustom handler???;key=(.*)n/a
param-matches $key $recustom handler???;key=(\d+)n/a
param-default $key $re $valcustom handler???;key=(\d+;0)n/a

My central question to you is, have you seen anything like this, or can you fill out the missing pieces for Catalyst, Jifty or whatever path matching language you have? Should I pursue this at all or have you followed that path and found it littered with the dead carcasses of those who came before you?

20060720 Added Ruby/CGI::Application::Dispatch information

20060721 Added (slightly modified) Regexp::NamedCaptures syntax for (named) captures of path elements


In reply to Mapping URLs to code - in search of perlish dispatch schemes by Corion

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.