Reputation: 76976
I am using the following code to check if a variable is not nil and not zero
if(discount != nil && discount != 0)
...
end
Is there a better way to do this?
Upvotes: 324
Views: 625654
Reputation: 5727
In modern rails I like using positive?
in this context. positive? returns a boolean, but nonzero?
returns either nil
or a value.
if(discount&.positive?)
...
end
Examples:
With nonzero?
[nil,0, 1].map{|v| v&.nonzero?}
=> [nil, nil, 1]
And with positive?
[nil,0, 1].map{|v| v&.positive?}
=> [nil, false, true]
Upvotes: 0
Reputation: 127
Yes, we do have a clean way in ruby.
discount.to_f.zero?
This check handles good amount of cases i.e. discount may be nil, discount may be int 0, discount may be float 0.0, discount may be string "0.0", "0".
Upvotes: 3
Reputation: 6964
I prefer using a more cleaner approach :
val.to_i.zero?
val.to_i
will return a 0
if val is a nil
,
after that, all we need to do is check whether the final value is a zero.
Upvotes: 2
Reputation: 16435
ok, after 5 years have passed....
if discount.try :nonzero?
...
end
It's important to note that try
is defined in the ActiveSupport gem, so it is not available in plain ruby.
Upvotes: 35
Reputation: 139
Alternative solution is to use Refinements, like so:
module Nothingness
refine Numeric do
alias_method :nothing?, :zero?
end
refine NilClass do
alias_method :nothing?, :nil?
end
end
using Nothingness
if discount.nothing?
# do something
end
Upvotes: -1
Reputation: 10121
if discount.nil? || discount == 0
[do something]
end
Upvotes: 0
Reputation: 1571
def is_nil_and_zero(data)
data.blank? || data == 0
end
If we pass "" it will return false whereas blank? returns true. Same is the case when data = false blank? returns true for nil, false, empty, or a whitespace string. So it's better to use blank? method to avoid empty string as well.
Upvotes: 2
Reputation: 36101
From Ruby 2.3.0 onward, you can combine the safe navigation operator (&.
) with Numeric#nonzero?
. &.
returns nil
if the instance was nil
and nonzero?
- if the number was 0
:
if discount&.nonzero?
# ...
end
Or postfix:
do_something if discount&.nonzero?
Upvotes: 37
Reputation: 4201
When dealing with a database record, I like to initialize all empty values with 0, using the migration helper:
add_column :products, :price, :integer, default: 0
Upvotes: 1
Reputation: 57
You can take advantage of the NilClass
provided #to_i
method, which will return zero for nil
values:
unless discount.to_i.zero?
# Code here
end
If discount
can be fractional numbers, you can use #to_f
instead, to prevent the number from being rounded to zero.
Upvotes: 2
Reputation: 794
You can convert your empty row to integer value and check zero?.
"".to_i.zero? => true
nil.to_i.zero? => true
Upvotes: 11
Reputation: 17793
if discount and discount != 0
..
end
update, it will false
for discount = false
Upvotes: 3
Reputation: 529
I believe the following is good enough for ruby code. I don't think I could write a unit test that shows any difference between this and the original.
if discount != 0
end
Upvotes: -7
Reputation: 49656
class Object
def nil_zero?
self.nil? || self == 0
end
end
# which lets you do
nil.nil_zero? # returns true
0.nil_zero? # returns true
1.nil_zero? # returns false
"a".nil_zero? # returns false
unless discount.nil_zero?
# do stuff...
end
Beware of the usual disclaimers... great power/responsibility, monkey patching leading to the dark side etc.
Upvotes: 42
Reputation: 176645
You could do this:
if (!discount.nil? && !discount.zero?)
The order is important here, because if discount
is nil
, then it will not have a zero?
method. Ruby's short-circuit evaluation should prevent it from trying to evaluate discount.zero?
, however, if discount
is nil
.
Upvotes: 25
Reputation: 124622
You could initialize discount to 0 as long as your code is guaranteed not to try and use it before it is initialized. That would remove one check I suppose, I can't think of anything else.
Upvotes: 0