Dallaylaen has asked for the wisdom of the Perl Monks concerning the following question:

Hello dear esteemed monks,

I just tried to implement mojo-like path info handling in my own toy framework:

get '/from/:foo/to/:bar' => sub { my $req = shift; return { -content => "foo=".$req->param("foo", '\d+') }; };

It kind of works, but wasn't yet committed to master and/or CPAN.

The thing is, my param() method has a mandatory regex filter (much like perl's own -T switch). There's also a built-in way to impose such filter upon the URI tail (parameter called path_info_regex).

This made me think of combining the two and specifying parameter regex right in the URI. I've come up with the following variants:

Maybe there is a more compact and readable way?

Thank you!

  • Comment on Adding regexps to named URI parameters aka /from/:foo/to/:bar - can it get better than this?
  • Download Code

Replies are listed 'Best First'.
Re: Adding regexps to named URI parameters aka /from/:foo/to/:bar - can it get better than this?
by roboticus (Chancellor) on Aug 30, 2017 at 13:24 UTC

    Dallaylaen:

    I agree that compact and readable are worthwhile goals. I also agree that the third goal you alluded to (but didn't state) is worthwhile--unsurprising. Until you actually build some larger cases yourself, though, it'll be a bit difficult to judge which approach best meets your goals.

    I often hit the same snag and try to 'optimize' those goals before I'm ready. My suggestion would be to do one of:

    • Add a TODO comment to your code with your current question and postpone it for now
    • Build all three of them, with a large enough example to see if any of them are obviously better

    Presenting the issue to us is a good idea, too, as someone may have a good suggestion, but in this case, I think I'd more fully show your alternatives so that we don't have to dream up our own test cases. The problem with letting us come up with our own internalized test cases is that it's too easy to miss cases when you're thinking of test cases rather than writing them down as an example. So working up your own examples may make it rather more obvious to you what the better approach would be. (Kinda like the debugging technique "Rubber Duck Debugging"2 "Talking to the Teddy Bear" (or whatever it was, I forget what the standard name for it is).)

    Anyway, while typing this up I had the thought (dunno if it would be useful or not, or even work1) of using a quoted regex for the first get parameter (i.e., let perl do the heavy lifting), and then you could possibly let the named parameters come free from perls regex handler:

    get qr/(?<greet>hi|hello)/ => sub { print $+{greet}, " there!\n"; }

    Update: Added note below (and marker above).

    Note 1: I haven't used named captures very often ... often enough to know they exist, but infrequently enough that I'm always having to read the documentation on them and give it a few tries before I can use with without tripping over the syntax...

    Note 2: Fixed debugging method name, thanks pryrt!

    Note 3: I'm off work today, and I got curious whether I could make it work or not, so I gave it a try:

    $ cat pm_1198334.pl #!env perl my @handlers; sub get { my ($key, $action) = @_; push @handlers, [ $key, $action ]; } sub handle { my $request = shift; for my $rh (@handlers) { my ($key, $action) = @$rh; if ("Regexp" eq ref $key) { return $action->($request) if $request =~ $key; } elsif ("" eq ref $key) { return $action->($request) if $key eq $request; } else { print "How do I handle <", ref($key), ">?\n"; } } print "Sorry, I don't know what <$request> means!\n"; } get foo => sub { print "Pizza time!\n" }; get qr/(?<greet>hi|hello)/ => sub { print $+{greet}, " there!\n" }; handle("foo"); handle("hi robot!"); handle("helloooooooo Nurse!"); Roboticus@Waubli ~ $ perl pm_1198334.pl Pizza time! hi there! hello there!

    Success!

    ...roboticus

    When your only tool is a hammer, all problems look like your thumb.

      Thank you, roboticus.

      Despite my post being a case of "rubber duck debugging", my duck didn't tell me anything, so I had no choice but to submit it.

      Your answer was quite insightful though. I realized that if I used an actual regexp I would most likely use something like my ($foo, $bar) = $line =~ qr/.../; instead of named captures. I think I'll just add a method to extract unnamed captures from path_info.

      As for the use cases, IMHO mapping fancy URLs to query parameters is not at all a framework's responsibility. A proxy should do it. However, Mojo and Dancer and Kelp have it and I have to match if I want to ever take off.

      Thanks again.

        To match add dependency on standalone cpan module that does it