Little Things: Heredocs
At their simplest, they are merely a means of defining a (potentially) multi-line string, thus:
<<LOREM syntax introduces
LOREM as the delimiter for the heredoc, and the parser then reads all subsequent lines of text up to (but not including) the final
LOREM and treats them as a single string, including all whitespace. (You don’t have to use the word
LOREM, either–any valid identifier will do.)
With this syntax, the final delimiter (e.g.
LOREM) must appear on a line by itself with no leading whitespace, which can be kind of a bummer sometimes. (It tends to put a real cramp in one’s neatly indented program.) Fortunately, there’s a solution for that: prefix the first delimiter with a hyphen, and Ruby will ignore whitespace in front of the final delimiter.
This lets you indent the final delimiter…but remember that all whitespace is preserved inside the heredoc. If you indent the text inside the heredoc, those indentations will be in the final string. Sometimes you want that…other times, not so much.
This leads to a quirky (but oh, so useful!) little thing about heredocs: syntactically, the first delimiter represents the entire heredoc. That is to say, if you want to invoke a method on the string, you attach the method invocation to the first delimiter, not the last! Like this:
Note how the
gsub call is attached to the first delimiter. This will call gsub on the entire heredoc, stripping leading whitespace from each line of the string.
Quirky? Yes, perhaps, but really handy. Because that first delimiter can stand in for the entire heredoc, it lets you pass entire heredocs as arguments to methods:
See that? The first delimiter just drops right in as an argument, and the heredoc picks right up on the next line. You can even (though I don’t recommend it) pass multiple heredocs to a single method invocation. (Pardon the contrived example here…this really is something you’ll never want to do, but it’s fun to know that it can be done!)
Also, it’s worth noting that by default, heredocs in Ruby are subject to string interpolation, just as if they were double-quoted strings:
If you don’t want a heredoc to be string-interpolated (that is, you want to treat it like a single-quoted string), just single-quote the first delimiter:
You can use double-quotes, too, to get the default behavior (if you like being explicit). And if you use backticks, Ruby will execute each line in a shell and replace it with the output of that command:
Heredocs may not be a groundbreaking, game-changing feature of Ruby, but they certainly make me smile when I need them. Little things, I tell you!
(I’m sure there have got to be more tricks involving heredocs, ones I’ve never seen, so if you happen to have a favorite, please share it!)