liveBook · Manning

Gsub!

As explained in The Well-Grounded Rubyist, Fourth Edition

gsub! globally replaces matching substrings in a string in place and returns the modified string or nil when no replacement occurs.

Use `gsub!` when every match in a string needs replacing and the original string should change. Like `gsub`, it substitutes throughout the string; unlike `gsub`, it saves the changes in the receiver. By contrast, `sub` makes at most one substitution. section 11.7.3 section 13.2.1

>> string = "Hello there!"
=> "Hello there!"
>> string.gsub!(/e/, "E")
=> "HEllo thErE!"        1
>> string
=> "HEllo thErE!"        2

The returned string and the variable both show the replacements: `gsub!` changed the original object. section 13.2.1

A replacement can be a string or a block. With a block, each matched substring is passed in for replacement; parenthetical captures are also available through numbered capture variables. In a replacement string, backslash-number notation refers to captures, with `\0` representing the whole match. Avoid interpolating `$1` into the replacement string ahead of time: it may contain a capture from an earlier match instead. section 11.7.3

>> string = "Hello there!"
=> "Hello there!"
>> string.gsub!(/zzz/, "xxx")
=> nil
>> string
=> "Hello there!"

When the pattern has no match, `gsub!` returns `nil` and leaves the string unchanged. section 13.2.1

That return value makes `gsub!` useful as a condition: a truthy result signals that substitution occurred. It also makes chaining risky. If there is no match, a following method receives `nil`, not the string. When the next operation must run either way, make separate calls or use `tap` to keep the string as the chain’s value. Do not redefine `String#gsub!` merely to make it always return the string; other code may rely on its `nil` result. section 13.2.1

>> states = { "NY" => "New York", "NJ" => "New Jersey", "ME" => "Maine" } 
=> {"NY"=>"New York", "NJ"=>"New Jersey", "ME"=>"Maine"} 1
>> string = "Eastern states include NY, NJ, and ME."  2
=> "Eastern states include NY, NJ, and ME."
>> if string.gsub!(/\b([A-Z]{2})\b/) { states[$1] } 3
>>   puts "Substitution occurred"
>> else
>>   puts "String unchanged"
>> end
Substitution occurred  4

A conditional uses `gsub!` both to expand matching abbreviations in place and to test whether any substitution occurred. section 13.2.1

How The Well-Grounded Rubyist, Fourth Edition covers it

How deep it goes
Works through mutation, successful and unmatched returns, replacement forms, and chaining risks; does not examine implementation internals.
Examples
Shows vowel replacement, state-abbreviation expansion, unmatched substitution, and a method chain that fails after a `nil` return.
What it assumes
Assumes familiarity with Ruby strings and method calls while illustrating regexp matching, replacement blocks, and capture references.
What you can do after
Apply `String#gsub!` to edit a string in place, test for substitution, and avoid chaining through a possible `nil` return.
How it connects
Connects `gsub!` with regular expressions, `sub`, `gsub`, replacement blocks, captures, method chaining, and `tap`.

This explainer was generated by Manning's knowledge graph from the text of The Well-Grounded Rubyist, Fourth Edition. The section links point to the parts of the book it draws on.