8

I often have a situation where I want to do some conditional logic and then return a part of the condition. How can I do this without repeating the part of the condition in the true or false expression?

For example:

ClassName.method.blank? ? false : ClassName.method

Is there any way to avoid repeating ClassName.method?

Here is a real-world example:

PROFESSIONAL_ROLES.key(self.professional_role).nil? ? 
    948460516 : PROFESSIONAL_ROLES.key(self.professional_role)
Reed G. Law
  • 3,897
  • 1
  • 41
  • 78
  • 2
    DRY is one of those things that makes a lot of sense when you're repeating blocks of code, or long sequences of chained methods or just doing something that the repetition could be reducing your code quality some how. I don't think it makes sense when you're doing something simple and having to jump through a hoop to become DRY-er. We can easily get seduced into chasing the DRY dragon and lose track of "good enough". In your example, if you're going to loop over it millions of times then add a temp variable or do the `||` thing @sepp2k said, otherwise don't worry about it too much. – the Tin Man Jan 07 '11 at 23:54

3 Answers3

10

Assuming you're okay with false being treated the same way as nil, you use ||:

PROFESSIONAL_ROLES.key(self.professional_role) || 948460516

This will return 948460516 if key returns nil or false and the return value of the call to key otherwise.

Note that this will only return 948460516 if key returns nil or false, not if it returns an empty array or string. Since you used nil? in your second example, I assume that's okay. However you used blank? in the first example (and blank? returns true for empty arrays and strings), so I'm not sure.

sepp2k
  • 363,768
  • 54
  • 674
  • 675
3

If you just want to DRY, then you can use a temp variable:

x = ClassName.method
x.blank? ? false : x

x = PROFESSIONAL_ROLES.key(self.professional_role)
x.nil? ? 948460516 : x

If you don't want to use a temp variable, you can use a block:

Proc.new do |x| x.blank? ? false : x end.call(ClassName.method)
Proc.new do |x| x.nil? ? 948460516 : x end.call(PROFESSIONAL_ROLES.key(self.professional_role))

For the cases you describe (where you just want to use the original value when a default-check fails), it'd be straightforward to write a helper method:

def x_or_default(x, defval, checker = :nil?)
  if x.send(checker) then defval else x end
end
x_or_default(ClassName.method, false, :blank?)
x_or_default(PROFESSIONAL_ROLES.key(self.professional_role), 94840516)

which is very similar to the || method described, but would also work with your blank? example.

I usually use temporary variables for this sort of thing.

Aidan Cully
  • 5,457
  • 24
  • 27
0

I know this doesn't look too pretty, but it does make things a bit DRYer.

a = "ABC"
b = (temp = a.downcase).length < 3 ? "---" : temp

If you don't want to create temp variable for whatever reason, you could reuse something that already exists like $_.

detunized
  • 15,059
  • 3
  • 48
  • 64