2

This is the closest I've found but it deals with booleans instead of numbers: DRY up Ruby ternary

I'm trying to avoid a divide by 0 scenario in Ruby, while keeping the code shorter and easier to read.

I want to make the following bit of code more concise:

number_to_percentage ((percent_complete.nan? ? 0 : (percent_complete * 100)), :precision => 0)

or

number_to_percentage ((percent_complete.nan? ? 0 : percent_complete) * 100, :precision => 0)

It just seems really hard to read right now. There's more chaining involved so the percent_complete is actually quite a bit longer. I'm also returning this value from a method, so it gets longer yet again.

I'd like to avoid using temporary variables or shortening the method names, so was hoping to learn of another way.

If I can avoid having to type "percent_complete" twice then that pretty much solves it.

Community
  • 1
  • 1
Zhao Li
  • 4,936
  • 8
  • 33
  • 51
  • Can you change `percent_complete` to end up as `nil` rather than NaN? Then you could exploit `nil.to_i == 0`. – mu is too short Feb 24 '12 at 20:41
  • @mu is too short: Thanks for the suggestion. I'm not sure if I can change it to nil; I'll have to look into that. Currently, percent_complete is a float divided by a float. – Zhao Li Feb 24 '12 at 21:16
  • Personally, on the stylistic front, I'd prefer to not see the ternary statement inside the parameter list to a method. – the Tin Man Feb 24 '12 at 21:47
  • @theTinMan: I definitely agree it's hard to read. I'd love to hear how you style this code. – Zhao Li Feb 27 '12 at 20:04

2 Answers2

4

Why don't you define a new method on Numeric?

class Numeric
  def safe_to_f
    self.nan? ? 0.0 : self.to_f
  end
end

If you like you could also add:

class NilClass
  def safe_to_f
    0.0
  end
end

Here's another idea:

class Object
  # substitute a different object if 'predicate' is true
  # if 'predicate' is :nil?, this is just like ||
  def guard(predicate,substitute)
    send(predicate) ? substitute : self
  end
end

Which would allow you to write:

percent_complete.guard(:nan?, 0)
Alex D
  • 29,755
  • 7
  • 80
  • 126
  • Thanks for the suggestion. I was hoping there was something more "built-in"-ish, but that can definitely work. Thanks again! – Zhao Li Feb 24 '12 at 21:17
  • 1
    @ALi, this is one of the great things about Ruby -- there are so many ways you can "bend" the language, that you're not stuck with only what comes built-in. Get used to extending the core classes; if you do it well, it's a powerful technique which can make your code more concise and elegant in *many* situations. – Alex D Feb 24 '12 at 21:45
  • Thanks again for all those great suggestions! It's hard to decide which one to go with. – Zhao Li Feb 27 '12 at 20:06
1

I'd just add a custom helper that deals with NaN in the desired way.

# in app/helpers/extra_number_helper.rb
module ExtraNumberHelpers
    def number_or_nan_to_percentage(number, options = { })
        number = 0 if(number.respond_to(:nan?) && number.nan?)
        number_to_percentage(number, options)
    end
end

Then use number_or_nan_to_percentage when you need special NaN handling. This also has the happy side effect of telling the people working on your code that you are explicitly dealing with NaN as a possible value.

mu is too short
  • 426,620
  • 70
  • 833
  • 800