Reputation:
I have this code:
settings[:base_name].gsub! /[\x00\/\\:\*\?\"<>\|]/, ''
When I run the script it throws an error:
gsub!': can't modify frozen String (RuntimeError)
I have changed the code to this:
settings[:base_name] = settings[:base_name].gsub /[\x00\/\\:\*\?\"<>\|]/, ''
The code above works, but I don't like at all, is there a way to properly use gsub! in this case?
Upvotes: 4
Views: 12736
Reputation: 1530
@pabloelices,
The issue is that the String
object referenced by settings[:base_name]
has been frozen and is now effectively immutable. You can check this by:
settings[:base_name].frozen? # => will return 'true'
You could clean up the code and intent somewhat by doing the following:
my_setting = settings[:base_name].dup # Create a duplicate of the setting.
settings[:base_name] = my_setting.gsub /[\x00\/\\:\*\?\"<>\|]/, ''
But the original String
object will not allow gsub!
to be invoked on it.
Upvotes: 5
Reputation: 35803
No. Apparently, the API providing the string has frozen it, which means any method that modifies it will fail. Because gsub!
modifies the string it is called on, a frozen object can not use gsub!
. However, the variable that contains a frozen object can still be set to a non-frozen object, which is why your second code snippet works.
The API probably froze the object because it is a constant string that all of the instances share, and so one instance shouldn't be able to ruin the string. But they do define a setter method, so you can set the value.
Upvotes: 7