I’ve been planning this post for a long time, and Magnus Holme’s recent article on overriding unary operators gives me the perfect lead-in.
Ruby has great syntax sugar for quoting strings. You’ve got your single- and double-quotes; you’ve got slashes for Regexps and you’ve got a whole menagerie of %-quotes, such as %r for regular expressions: %r(/.*/)
.
But Ruby is a bit uptight about its quotes; if there’s a special kind of quoting you want to do that Matz didn’t think of, there’s no way to add it to the language. For instance, what if you wanted a way to quote URIs and have them be immediately parsed into URI objects, something like this:
uri = %u(http://google.com) # Doesn't work!
We can’t do anything like that… can we?
Well, maybe we can. You know how backtick quoting works, right? Put a string in backticks and you get the result of that string evaluated as a shell command:
`uname -srm` # => "Linux 2.6.36-1-lowlatency x86_64n"
What you might not know is that the backtick, unlike other quotes, is technically an operator defined in Kernel. And what is defined in Kernel can be overridden:
require 'uri' module BacktickURI def `(uri) URI.parse(uri) end end include BacktickURI `http://google.com` # => #<uri::http:0x7f4d30c3e7c0 URL:http://google.com>
And there you have it – your own custom backtick quotes.
Is this a good idea? Probably not. I certainly don’t recommend overriding the backticks at the root level as I’m doing here – this is a technique best limited to certain DSL contexts. But for better or for worse, now you know that even (some) quotes are overridable in Ruby.
This is interesting. It makes me wonder what other characters can be a method name.
Most (but not all) operators can be overridden in Ruby. The backtick is a special case – quotation marks aren't usually seen as an “operator” in most languages, but Ruby treats the backtick (and only the backtick) as an operator.
i just don't understand why
<a href="http://www.google.com" rel="nofollow">http://www.google.com</a>
needs two backticks ” ` “.And something nifty you didn't mention: the backtick method is called on the implicit receiver (that is, “self”). That means that you can do this:
require 'net/http'
class Google
include BacktickURI
def search_page_html
url =
<a href="http://www.google.com" rel="nofollow">http://www.google.com</a>/
res = Net::HTTP.start(url.host, url.port) {|http|
http.get('/')
}
res.body
end
end
Still not a great practice in general, but you can limit the damage to a single class instead of changing the meaning of backticks everywhere. As you say, it could find a nice use in some sort of DSL.
Good point. Your example code is how I'd use a backtick override in real life, if I ever thought it was warranted.