Stringifying URI objects to relative URIs by default

Aristotle on 2008-08-05T19:11:35

You only need a trivial subclass of URI::WithBase:

{
	package URI::WithBase::Rel;
	our @ISA = qw( URI::WithBase );
	use overload '""' => sub { shift->rel->as_string(@_) }, fallback => 1;
}

If you stringify objects of this class URI::WithBase::Rel, the stringified URI will always come out relative to the base URI of the object. (If you happen to need a non-relative URI out of it, you can call the as_string method explicitly.)

Next, if you happen to be using Catalyst, put something like this in your MyApp.pm:

sub uri_for {
	my $c = shift;
	return URI::WithBase::Rel->new( $c->NEXT::uri_for( @_ ), $c->req->uri );
}

Now all the unadorned uri_for calls in your templates will produce nice relative URIs.

(The alternative would be to install URI::SmartURI and Catalyst::Plugin::SmartURI… but for this very simple use case of “relative URIs nearly all the time,” the amount of code in those modules alone, much less the huge pile of code they pull in via prerequisites, seems completely unjustifiable.)