68

How do I write this multi-line, complex condition if statement in Ruby?

  if ( (aa != nil && self.prop1 == aa.decrypt)   
      || (bb != nil && self.prop2 == bb.decrypt)  
    ) && (self.id.nil? || self.id != id) 
    return true
  end

I'm getting Syntax error; unexpected tOROP.

In Java, I could write

if (
     ( (aa != null && aa.prop1.equals(aa.decrypt()))
     || (bb != null && bb.prop2.equals(bb.decrypt()))
     )
     && (this.id != id)
   ) {

   return true;
}
Chloe
  • 25,162
  • 40
  • 190
  • 357

2 Answers2

122

The short answer is the operator needs to be at the end of the line in order to tell Ruby to continue reading the next line as part of the statement, so this would work:

if ( (aa != nil && self.prop1 == aa.decrypt) ||
   (bb != nil && self.prop2 == bb.decrypt) ) &&
   (self.id.nil? || self.id != id)
  return true
end

That being said, you can probably reduce the logic by throwing exceptions based on input values, and removing some redundant checks (I'm making some jumps here about what your variables will look like, but you get the idea.)

raise 'aa must support decrypt' unless aa.respond_to? :decrypt
raise 'bb must support decrypt' unless bb.respond_to? :decrypt
if prop1 == aa.decrypt || prop2 == bb.decrypt
  if self.id != id
    return true
  end
end
Kyle Smith
  • 2,300
  • 1
  • 17
  • 10
30

You need to escape whitespace with the backslash character, it's ugly but you need it if you want to split conditions to multiple lines. Either that or leave the boolean operator on the previous line. So either of these will work:

if ( (aa != nil && self.prop1 == aa.decrypt)\
      || (bb != nil && self.prop2 == bb.decrypt)\
    ) && (self.id.nil? || self.id != id) 
    return true
  end

or:

if ( (aa != nil && self.prop1 == aa.decrypt) || 
      (bb != nil && self.prop2 == bb.decrypt)) &&
    (self.id.nil? || self.id != id) 
    return true
  end

Personally I usually decide to put each or all conditions in a method that self documents what's being decided:

def everythings_cool?
  ( (aa != nil && self.prop1 == aa.decrypt) || 
          (bb != nil && self.prop2 == bb.decrypt)) &&
        (self.id.nil? || self.id != id) 
end

then:

if everythings_cool?
  # do stuff
DiegoSalazar
  • 13,361
  • 2
  • 38
  • 55
  • I like the 2nd way. I don't like extracting methods unless it will be used in multiple locations, otherwise you have to pass variables to it and track it down to find out what it's doing when you look back at the if statement. – Chloe Jan 28 '14 at 22:10
  • 5
    I too prefer extracting even marginally complex boolean checks in self-documenting methods ending with a question mark. Improves sanity. – Epigene Jul 11 '17 at 08:27
  • Cool, thanks. This lets me keep operators on a separate line like in other languages, which I find to be much more readable to "future me" with fewer comprehension errors when quickly scanning code. – Bill McGonigle Mar 18 '23 at 15:12