Last Updated: February 25, 2016
·
1.961K
· rmg

Ruby's URI strips slashes when there's no host

Some URI schemes (the protocol portion of an address) don't require a hostname or network portion. For example

file:///home/rmg/scratchpad

According to the RFC, you can skip the // if there's no host.

file:/home/rmg/scratchpad

Unfortunately, not everyone knows this, and therefore not every piece of software handles this!

The constant-named URI() method in Ruby's URI lib likes to strip the // for you. How helpful!

As I've discovered, Subversion is one of those pieces of software that doesn't handle this.

I took a look at the source code and found a way to fake things without resorting to monkey patching URI and without re-writing large portions of the functionality.

uri = URI('file:///foo/bar/baz')
uri.to_s          #=> 'file:/foo/bar/baz'
uri.send(:set_host, '')
uri.to_s          #=> 'file:///foo/bar/baz'

It does require using #send to invoke a protected method, though. Works for now, though, and I was able to wrap it up in a single well-tested method that does what I need so that I can at least refactor it later if it becomes a problem with newer versions.

require 'uri'
require 'pathname'

def clean_url(*parts)
  uri = URI(parts.join('/'))
  uri.path = Pathname(uri.path).cleanpath.to_s
  uri.send(:set_host, '') unless uri.host
  uri.to_s
end