Bob Aman

Multi-line Boolean Control Flow in Ruby

Over the years, I’ve frequently found myself implementing systems that follow Postel’s Law on a fairly regular basis. An extremely common scenario that comes up when building such liberal systems and parsers is a short-circuited sequence of searches.

Often, these search sequences will involve long if chains that repeatedly check for nil. However, this is both inefficient and inelegant. I’ve just (re-)discovered that Ruby has a much better way of accomodating this style of branching logic.

Take, for example, a particularly liberal feed parser that needs to return the title of a feed:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
def feed_node
  @feed_node ||= (
    root.xpath(
      '/atom:feed',
      'atom' => 'http://www.w3.org/2005/Atom'
    ).first or
    root.xpath('/feed').first or
    root.xpath(
      '/rdf:RDF/rdf:channel',
      'rdf' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'
    ).first or
    root.xpath('/rss/channel').first
  )
end

def title
  @title ||= (
    begin
      node = feed_node.xpath('title').first
      node.text if node
    end or
    begin
      node = feed_node.xpath(
        'dc:title',
        'dc' => 'http://purl.org/dc/elements/1.1/'
      ).first
      node.text if node
    end or
    begin
      node = feed_node.xpath(
        'rdf:title',
        'rdf' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'
      ).first
      node.text if node
    end
  )
end

Admittedly, the example above would allow for completely mental mixes of RSS, Atom, and ancient RDF, and it’s perhaps a bit contrived, but hopefully it illustrates how much cleaner you can make this kind of logic with some well-placed control-flow or’s. Because both or and and have extremely low operator precedence, there’s little risk of accidentally doing something unintended, and the use of begin; end allows for longer blocks of short-circuited logic. Additionally, instead of begin; end, you can also use method calls when chunks of logic start to get too long or unwieldy.

Of course, neither or nor and are anything new, but I rarely see them used across multiple lines, and it turns out that they’re really useful in longer expressions.