Ruby check if nil before calling method - ruby

I have a string in Ruby on which I'm calling the strip method to remove the leading and trailing whitespace. e.g.
s = "12345 "
s.strip
However if the string is empty nil I get the following error.
NoMethodError: undefined method `strip' for nil:NilClass
I'm using Ruby 1.9 so whats the easiest way to check if the value is nil before calling the strip method?
Update:
I tried this on an element in an array but got the same problem:
data[2][1][6].nil? ? data[2][1][6] : data[2][1][6].split(":")[1].strip

Ruby 2.3.0 added a safe navigation operator (&.) that checks for nil before calling a method.
s&.strip
If s is nil, this expressions returns nil instead of raising NoMethodError.

You can use method try from ActiveSupport (Rails library)
gem install activesupport
require 'active_support/core_ext/object/try'
s.try(:strip)
or you can use my gem tryit which gives extra facilities:
gem install tryit
s.try { strip }

If you don't mind the extra object being created, either of these work:
"#{s}".strip
s.to_s.strip
Without extra object:
s && s.strip
s.strip if s

I guess the easiest method would be the following:
s.strip if s

I'd opt for a solution where s can never be nil to start with.
You can use the || operator to pass a default value if some_method returns a falsy value:
s = some_method || '' # default to an empty string on falsy return value
s.strip
Or if s is already assigned you can use ||= which does the same thing:
s ||= '' # set s to an empty string if s is falsy
s.strip
Providing default scenario's for the absence of a parameters or variables is a good way to keep your code clean, because you don't have to mix logic with variable checking.

Method which works for me (I know, I should never pollute pristine Object space, but it's so convenient that I will take a risk):
class Object
def unless_nil(default = nil, &block)
nil? ? default : block[self]
end
end
p "123".unless_nil(&:length) #=> 3
p nil.unless_nil("-", &:length) #=> "-"
In your particular case it could be:
data[2][1][6].unless_nil { |x| x.split(":")[1].unless_nil(&:strip) }

ActiveSupport comes with a method for that : try. For example, an_object.try :strip will return nil if an_object is nil, but will proceed otherwise. The syntax is the same as send. Cf active_support_core_extensions.html#try.

If you want to avoid the error that appears in the question:
s.to_s.strip

To complete the options shown here, there is the "Existence Check Shorthand", recommended in the Ruby Style Guide:
Use &&= to preprocess variables that may or may not exist. Using &&= will change the value only if it exists [means, is not nil], removing the need to check its existence with if.
So in your case you would do:
s = "12345 "
s &&= s.strip

Simply put:
s = s.nil? ? s : s.strip
Tl;dr Check if s is nil, then return s, otherwise, strip it.

Related

What is the meaning of `!!empty?`?

ActiveSupport extends Object with an instance method blank?:
class Object
def blank?
respond_to?(:empty?) ? !!empty? : !self
end
end
Could !!empty? be written as empty? instead? Is this a stylistic choice so that it reads easily as a method returning a boolean? Or is there something else?
The reason for this is that !! coerces the response from empty to a boolean. Empty can be defined differently on different objects so it is possible that someone in rails could have defined .empty? to not return a boolean. Since .blank? needs to return a boolean the !! is needed to ensure that a boolean is returned.
It is a common way to convert a truthy versus falesy value into strict true and false.
It is a common approach in Ruby to call !!(something). The result of the calculation will be boolean, not nil or something else:
!!(true) # true
!!(false) # false
!!(nil) # false
!! is used to force falsey/truthy values to false/true:
irb(main):001:0> !!nil == false
=> true
In fact, it used to be empty?. Here's the commit that changed it to !!empty?: https://github.com/rails/rails/commit/126dc47665c65cd129967cbd8a5926dddd0aa514
From the comments:
Bartuz:
Why double !! ? It returns the TrueClass / FalseClass anynway
fxn:
Because it is a dynamic language and subject to polymorphism, you just can't rely on empty? returning singletons, what you need to guarantee is that you return one no matter what.
The "improved" implementation however is incomplete, because you could just as well implement ! to return a non-boolean value:
class Foo
def !
nil
end
end
Foo.new.blank? #=> nil
To handle both methods (empty? and !), it should be implemented as:
!!(respond_to?(:empty?) ? empty? : !self)

Checking if variable is nil or empty in a single line using or operator

I have absolutely no experience in Ruby, but am trying to debug an issue in FPM. Sometimes, when running FPM, I get the following stack trace:
output': undefined method `empty?' for nil:NilClass (NoMethodError)
I traced this error back to this line (rpm.rb, line 419):
if #epoch.nil? or #epoch.empty?
#logger.warn("no value for epoch is set, defaulting to nil")
return nil
end
This blog post says the following about the or operator:
The best way to think about the chains constructed with or is as
series of fallbacks: try this, if that fails try this, and so on
This leads me to believe that in the above code fragment, if epoch.nil? evaluates to true, it will not attempt to check epoch.empty?, but a simple codepad shows that to be wrong (http://codepad.org/qI7rLvBX)
str = nil
puts str.nil? or str.empty?
Output:
Line 2: undefined method `empty?' for nil:NilClass (NoMethodError)
true
if I change it the operator to ||, then the short-circuiting works correctly - if epoch.nil? evaluates to true, it does not attempt to evaluate epoch.empty?.
Am I misunderstanding something about the or operator? And is the way FPM is checking for nil or empty incorrect?
You could skip the whole problem by noting that nil.to_s is an empty string:
NilClass#to_s → ""
Always returns the empty string.
Given that, you could say:
if #epoch.to_s.empty?
This is a useful trick for avoiding a bunch of noisy nil? tests when dealing with strings.
It's a matter of operator precedence. || has a higher precedence than or.
You should write it like:
str = nil
puts (str.nil? or str.empty?)
puts str.nil? || str.empty?
See more in Difference between "or" and || in Ruby?
For the issue of FPM, I have tried under Ruby 1.8.6, 1.9.3, 2.0.0, and did not get error with or expression.

Built in method for testing either nil or empty array?

How can I tell if an array is either empty or nil?
Without Rails or ActiveSupport,
array.to_a.empty?
There's no built-in Ruby method that does this, but ActiveSupport's blank does:
>> require "active_support/core_ext/object/blank" #=> true
>> nil.blank? #=> true
>> [].blank? #=> true
You can just use the Array#empty? and Object#nil? methods in conjunction with an OR.
arr.nil? || arr.empty?
This will return true of array is empty or the array value is nil.
To check whether array is empty one can use 'empty?' inbuilt method as follows,
array.empty? # returns true/false
To check whether array is nil (If not initialized or set to nil)
array.nil? # returns true/false

ruby syntactic sugar: dealing with nils

probably asked already but I couldn't find it.. here are 2 common situation (for me while programming rails..) that are frustrating to write in ruby:
"a string".match(/abc(.+)abc/)[1]
in this case I get an error because the string doesn't match, therefore the [] operator is called upon nil. What I'd like to find is a nicer alternative to the following:
temp="a string".match(/abc(.+)abc/); temp.nil? ? nil : temp[1]
in brief, if it didn't match simply return nil without the error
The second situation is this one:
var = something.very.long.and.tedious.to.write
var = something.other if var.nil?
In this case I want to assign something to var only if it's not nil, in case it's nil I'll assign something.other..
Any suggestion?
Thanks!
In Ruby on Rails you have the try method available on any Object. According to the API:
Invokes the method identified by the symbol method, passing it any arguments and/or the block specified, just like the regular Ruby Object#send does.
Unlike that method however, a NoMethodError exception will not be raised and nil will be returned instead, if the receiving object is a nil object or NilClass.
So for the first question you can do this:
"a string".match(/abc(.+)abc/).try(:[], 1)
And it will either give you [1] or nil without error.
Forget that Python atavism!
"a string"[/abc(.+)abc/,1] # => nil
"a string"[/abc(.+)abc/, 1]
# => nil
"abc123abc"[/abc(.+)abc/, 1]
# => "123"
And:
var = something.very.long.and.tedious.to.write || something.other
Please note that or has a different operator precedence than || and || should be preferred for this kind of usage. The or operator is for flow control usage, such as ARGV[0] or abort('Missing parameter').
For the first I'd recommend ick's maybe (equivalent to andand)
"a string".match(/abc(.+)abc/).maybe[1]
I am not sure I understand the second one, you want this?
var = something.very.long.and.tedious.to.write || something.other
"a string".match(/foo(bar)/).to_a[1]
NilClass#to_a returns an empty array, and indexing outside of it gives you nil values.
Alternatively (what I do) you can splat the matches:
_, some, more = "a string".match(/foo(bar)(jim)/).to_a
For the first question, I think Bob's answer is good.
For the second question,
var = something.very.long.and.tedious.to.write.instance_eval{nil? ? something.other : self}

Is There a Better Way of Checking Nil or Length == 0 of a String in Ruby?

Is there a better way than the following to check to see if a string is nil OR has a length of 0 in Ruby?
if !my_string || my_string.length == 0
return true
else
return false
end
In C# there's the handy
string.IsNullOrEmpty(myString)
Anything similar to that in Ruby?
When I'm not worried about performance, I'll often use this:
if my_string.to_s == ''
# It's nil or empty
end
There are various variations, of course...
if my_string.to_s.strip.length == 0
# It's nil, empty, or just whitespace
end
If you are willing to require ActiveSupport you can just use the #blank? method, which is defined for both NilClass and String.
I like to do this as follows (in a non Rails/ActiveSupport environment):
variable.to_s.empty?
this works because:
nil.to_s == ""
"".to_s == ""
An alternative to jcoby's proposal would be:
class NilClass
def nil_or_empty?
true
end
end
class String
def nil_or_empty?
empty?
end
end
As it was said here before Rails (ActiveSupport) have a handy blank? method and it is implemented like this:
class Object
def blank?
respond_to?(:empty?) ? empty? : !self
end
end
Pretty easy to add to any ruby-based project.
The beauty of this solution is that it works auto-magicaly not only for Strings but also for Arrays and other types.
variable.blank? will do it.
It returns true if the string is empty or if the string is nil.
nil? can be omitted in boolean contexts. Generally, you can use this to replicate the C# code:
return my_string.nil? || my_string.empty?
First of all, beware of that method:
As Jesse Ezel says:
Brad Abrams
"The method might seem convenient, but most of the time I have found that this situation arises from trying to cover up deeper bugs.
Your code should stick to a particular protocol on the use of strings, and you should understand the use of the protocol in library code and in the code you are working with.
The NullOrEmpty protocol is typically a quick fix (so the real problem is still somewhere else, and you got two protocols in use) or it is a lack of expertise in a particular protocol when implementing new code (and again, you should really know what your return values are)."
And if you patch String class... be sure NilClass has not been patch either!
class NilClass
def empty?; true; end
end
Every class has a nil? method:
if a_variable.nil?
# the variable has a nil value
end
And strings have the empty? method:
if a_string.empty?
# the string is empty
}
Remember that a string does not equal nil when it is empty, so use the empty? method to check if a string is empty.
Another option is to convert nil to an empty result on the fly:
(my_string||'').empty?
Konrad Rudolph has the right answer.
If it really bugs you, monkey patch the String class or add it to a class/module of your choice. It's really not a good practice to monkey patch core objects unless you have a really compelling reason though.
class String
def self.nilorempty?(string)
string.nil? || string.empty?
end
end
Then you can do String.nilorempty? mystring
Check for Empty Strings in Plain Ruby While Avoiding NameError Exceptions
There are some good answers here, but you don't need ActiveSupport or monkey-patching to address the common use case here. For example:
my_string.to_s.empty? if defined? my_string
This will "do the right thing" if my_string is nil or an empty string, but will not raise a NameError exception if my_string is not defined. This is generally preferable to the more contrived:
my_string.to_s.empty? rescue NameError
or its more verbose ilk, because exceptions should really be saved for things you don't expect to happen. In this case, while it might be a common error, an undefined variable isn't really an exceptional circumstance, so it should be handled accordingly.
Your mileage may vary.
If you are using rails, you can use #present?
require 'rails'
nil.present? # ==> false (Works on nil)
''.present? # ==> false (Works on strings)
' '.present? # ==> false (Works on blank strings)
[].present? # ==> false(Works on arrays)
false.present? # ==> false (Works on boolean)
So, conversely to check for nil or zero length use !present?
!(nil.present?) # ==> true
!(''.present?) # ==> true
!(' '.present?) # ==> true
!([].present?) # ==> true
!(false.present?) # ==> true
Have you tried Refinements?
module Nothingness
refine String do
alias_method :nothing?, :empty?
end
refine NilClass do
alias_method :nothing?, :nil?
end
end
using Nothingness
return my_string.nothing?
In rails you can try #blank?.
Warning: it will give you positives when string consists of spaces:
nil.blank? # ==> true
''.blank? # ==> true
' '.blank? # ==> true
'false'.blank? # ==> false
Just wanted to point it out. Maybe it suits your needs
UPD. why am i getting old questions in my feed?
Sorry for necroposting.
For code golfers:
if my_string=~/./
p 'non-empty string'
else
p 'nil or empty string'
end
Or if you're not a golfer (requires ruby 2.3 or later):
if my_string&.size&.positive?
# nonzero? also works
p 'non-empty string'
else
p 'nil or empty string'
end

Resources