30

I'm looking for a way to convert an empty string to nil in place using Ruby. If I end up with a string that is empty spaces I can do

 "    ".strip!

This will give me the empty string "".

What I would like to be able to do is something like this.

"    ".strip!.to_nil!

This will get an in place replacement of the empty string with nil. to_nil! would change the string to nil directly if it is .empty? otherwise if the string is not empty it would not change.

The key here is that I want it to happen directly rather than through an assignment such as

f = nil if f.strip!.empty?
Timur Shtatland
  • 12,024
  • 2
  • 30
  • 47
bigtunacan
  • 4,873
  • 8
  • 40
  • 73
  • Maybe I'm missing something... but what would the point be to do something to a string first and then set it to nil? Might as well set the string to nil in the first place, right? – summea Mar 14 '13 at 20:21
  • It cannot be done inplace. Are you interested only in in-place modifications? I created an answer with `String#presence` but it's not in-place (note that both inplace/rebindings are -usually- a bad practice). – tokland Mar 14 '13 at 20:47
  • I agree that they are usually a bad practice, I'm essentially trying to go around a road block that this type of solution would make it very easy. – bigtunacan Mar 14 '13 at 20:58

4 Answers4

76

The clean way is using presence.

Let's test it.

'    '.presence
# => nil


''.presence
# => nil


'text'.presence
# => "text"


nil.presence
# => nil


[].presence
# => nil


{}.presence
# => nil

true.presence
# => true

false.presence
# => nil

Please note this method is from Ruby on Rails v4.2.7 https://apidock.com/rails/Object/presence

NOTE: Not work on IRB, work with Ruby on Rails!

Martin K.
  • 1,168
  • 15
  • 16
4

That isn't possible.

String#squeeze! can work in place because it's possible to modify the original object to store the new value. But the value nil is an object of a different class, so it cannot be represented by an object of class String.

qqx
  • 18,947
  • 4
  • 64
  • 68
  • That really goes to the heart of what I'm trying to do. I essentially want to do an in place change that is changing types. With all of the other magic surrounding Ruby with __send__, eval, etc... I was thinking there might be a way to essentially find the object by object_id and switch it out from underneath itself. – bigtunacan Mar 14 '13 at 20:31
  • That would be especially difficult with `nil` which is an immediate value. It always has 4 as the object_id. – qqx Mar 14 '13 at 20:51
  • Agreed; I guess what I'm really getting at is trying to trick the system into pointing from one object_id to another. In the same way we can bypass private using send. – bigtunacan Mar 14 '13 at 20:56
3

I know I am bit late but you can write your own method for the String class, and run code in initializers:

class String
  def to_nil
    present? ? self : nil
  end
end

and then you will get:

'a'.to_nil
=> "a"
''.to_nil
=> nil

Of course you can also strip the string before checking if thats suits for you

sudo
  • 1,581
  • 1
  • 10
  • 11
1

Regex to the rescue! We can use string[regexp] which returns a new_string if there is a match or nil if the regex doesn't match (see documentation String).

''[/.+/] 
# => nil

'text'[/.+/] 
# => 'text'

# Caution 1: This doesn't work for strings which are just spaces
'   '[/.+/] 
# => '   '

# In these cases you can strip...
'   '.strip[/.+/] 
# => nil

# ...or use a more complicated regex:
'   '[/.*\S.*/]
# => nil
Christopher Oezbek
  • 23,994
  • 6
  • 61
  • 85