Stacking methods


I’ve just started the Ruby course and am having difficulty understanding how various methods stack and why they don’t always work.

At the start of Exercise 2: “Thith Meanth War” the original code reads:

print "Thtring, pleathe!: "
user_input = gets.chomp

if user_input.include? "s"
user_input.gsub!(/s/, “th”)
puts "Nothing to do here!"

puts “Your string is: #{user_input}”

If I stack the two user_inputs methods onto a single line as:

user_input = gets.chomp.downcase!

I get a return of:

Thtring, pleathe!: seven
undefined method `include?’ for nil:NilClass

But only when my answer begins with lower case. If I start with a capital letter, the programs runs normally.
However, if I replace .downcase! with .downcase, then the program works, regardless of whether my answer is capitalized, or not.

Can anyone explain why the two ways of stacking behave differently, please? As I understand it, .capitalize! modifies the string permanently, but I don’t get why it behaves differently when stacked as compared to getting it’s own line.


When a method is written with a bang (!) modifier, the mutation is done in-place. Ruby does not make a hard copy of the original, but a transient one in memory upon which it applies the declared modification and places the result back into the original variable. There is a catch, though… If no change takes place, the original is discarded. and the variable is left empty, hence, nil, which has no attributes.

Try it…

a = gets.chomp.downcase!
puts a.nil?
=> nil
 > a
=> nil
=> nil
 > a
=> "something"

Note: The printed nil after true and false is not a's value, but the return value of the puts method. a's value follows.


a = gets.chomp.downcase!
  1. gets (get stiing) executes
  2. .chomp removes whitespace from the input string
  3. .downcase! immediately modifies the string if it has at least one capital letter.
  4. the final result is assigned to a.


Thanks, mtf.
So, in this example, by stacking the methods the string gets a value of nil because no changes took place, and since the original is gone the program fails.
However, by using

user_input = gets.chomp

on separate lines, it allows for a backup string to default to if no changes occur during .capitalize!?


Whether on separate lines or method chained, the effect is the same. By writing it as two lines, the string assignment is made to the variable, unchanged except for removing of whitespace.

a = gets.chomp
puts a           # -> will be input string, truncated
a.capitalize!    # -> will be CAPITALS or nil

Note that a changes in place.

When there is no bang, Ruby creates a copy of the original string, mutates it (or not) and assigns it to the variable. The value will be a string, changed or not, not nil. If we do not provide a variable assignment, we don’t see the result as the original is unchanged.

a = gets.chomp.downcase


Cool, thanks for taking the time to explain things to me.


This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.