1

With this code:

input = gets.chomp.downcase!
puts input

if there is at least one uppercase letter in the input, the input will be put on screen, freed of its uppercases. But if the input has no uppercase letter, it will put nil, like if nothing was written.

I want my input to be fully downcased; if it is a string with no uppercase letter, it should return the same string.

I thought about something like this:

input = gets.chomp
if input.include(uppercase) then input.downcase! end

But this doesn't work. I hope someone has an idea on how I should do this.

sawa
  • 165,429
  • 45
  • 277
  • 381
nounoursnoir
  • 671
  • 2
  • 10
  • 25
  • 4
    A lot of these dark mysteries are explained by *reading the documentation*. That's what it's there for. This is a reasonable question, but it's also one you could've answered yourself. – tadman Jan 23 '17 at 01:53
  • 1
    The correct way to use `downcase!` is: `input = gets.chomp` then `input.downcase!` and finally `puts input` – Stefan Jan 23 '17 at 08:16
  • 1
    Can you explain which specific part of the documentation is unclear to you? That way, the Ruby developers can improve the documentation to help future Rubyists. – Jörg W Mittag Jan 23 '17 at 09:55
  • What is your question? – sawa Jan 23 '17 at 11:16
  • Can someone explain the LOGIC of why "whopper".downcase! returns nil rather than just "whopper"? Or is this question worth making a new post for? – pgblu May 16 '18 at 14:27

3 Answers3

8

According to the docs for String: (emphasis is mine added)

downcase

Returns a copy of str with all uppercase letters replaced with their lowercase counterparts. The operation is locale insensitive—only characters “A” to “Z” are affected. Note: case replacement is effective only in ASCII region.

downcase!

Downcases the contents of str, returning nil if no changes were made. Note: case replacement is effective only in ASCII region.

Basically it says that downcase! (with exclamation mark) will return nil if there is no uppercase letters.

To fix your program:

input = gets.chomp.downcase
puts input

Hope that helped!

notme1560
  • 346
  • 4
  • 14
5

This will work:

input = gets.chomp.downcase
puts input

String#downcase

Returns a modified string and leaves the original unmodified.

str = "Hello world!"
str.downcase # => "hello world!"
str          # => "Hello world!"

String#downcase!

Modifies the original string, returns nil if no changes were made or returns the new string if a change was made.

str = "Hello world!"
str.downcase! # => "hello world!"
str           # => "hello world!"
str.downcase! # => nil

! (bang) methods

It's common for Ruby methods with ! / non-! variants to behave in a similar manner. See this post for an in-depth explanation why.

Community
  • 1
  • 1
1

The reason that downcase! returns nil is so you know whether or not the object was changed. If you're assigning the modified string to another variable, like you are here, you should use downcase instead (without the bang !).

If you're not familiar, the standard library bang methods typically act on the receiver directly. That means this:

foo = "Hello"
foo.downcase!
foo #=> "hello"

Versus this:

foo = "Hello"
bar = foo.downcase
foo #=> "Hello"
bar #=> "hello"
coreyward
  • 77,547
  • 20
  • 137
  • 166
  • "the standard library bang methods typically act on the caller directly" – Do you have any example of this? Many bang methods mutate the *receiver*, some have other "interesting" effects (e.g. `Process::exit!` vs `Process::exit`), but I am not aware of any that act on the caller. In fact, barring deep metaprogramming magic, getting access to the caller at all is pretty much impossible. – Jörg W Mittag Jan 23 '17 at 09:54
  • @JörgWMittag Whoops. Silly mistake. Fixed. – coreyward Jan 23 '17 at 15:26