Ruby provides ! to change state of some object in place. Hence if you see some functions have ! appended, it means the state of the caller of the function is expected to be changed. This is a very interesting Ruby feature. But sometimes one should be cautious when using this kind of functions because you would get unexpected behavior if using improperly.
Let's take an example of String#downcase!. According to the documentation.
Downcases the contents of str, returning nil if no changes were made. Note: case replacement is effective only in ASCII region.
If there is a String platform = "Suse", after calling platform.downcase!, the platform should become "suse". This is exactly what we expected. How about the return value? It's also "suse" and that's fine. In some cases, we would call platform.downcase! in some comparison conditions.
For example, below code snippet is to check the platform and action accordingly based on different platforms.
platform = "Suse" case platform.downcase! when 'aix' puts "For AIX" when 'suse' puts "For suse" end
The output will be "For suse". What if we change the code a bit.
platform = "suse" case platform.downcase! when 'aix' puts "For AIX" when 'suse' puts "For suse" end
Now nothing is printed out. "For suse" is not printed at all. What's going on? Reading the documentation one more time. It says that nil will be returned if the content is not changed. This means if the string to be downcased is already in lowercase, nothing will be changed and nil will be returned. Hence, platform.downcase! will return nil and no when condition is matched with nil and nothing will be printed.
The general advice is to avoid calling xxx! if you don't expect state change in place and if you are using them in comparison conditions.