user1513388
user1513388

Reputation: 7441

Ruby check if nil before calling method

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

Upvotes: 70

Views: 52541

Answers (10)

user513951
user513951

Reputation: 13612

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.

Upvotes: 138

tanius
tanius

Reputation: 16749

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

Upvotes: 1

3limin4t0r
3limin4t0r

Reputation: 21110

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.

Upvotes: 3

Michael Kohl
Michael Kohl

Reputation: 66837

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

Upvotes: 11

sawa
sawa

Reputation: 168071

If you want to avoid the error that appears in the question:

s.to_s.strip

Upvotes: 2

megas
megas

Reputation: 21791

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 }

Upvotes: 17

ksol
ksol

Reputation: 12235

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.

Upvotes: 2

Victor Moroz
Victor Moroz

Reputation: 9225

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) }

Upvotes: 2

lukad
lukad

Reputation: 17843

I guess the easiest method would be the following:

s.strip if s

Upvotes: 9

Eugene
Eugene

Reputation: 4879

Simply put:

s = s.nil? ? s : s.strip

Tl;dr Check if s is nil, then return s, otherwise, strip it.

Upvotes: 0

Related Questions