What does gets.chomp do? - ruby

I was also wondering if I always have to put the exclamation point after .capitalize!
print "What's your first name? "
first_name = gets.chomp
first_name.capitalize!
print "What's your last name? "
last_name = gets.chomp
last_name.capitalize!
print "What city are you from? "
city = gets.chomp
city.capitalize!
print "What state or province are you from? "
state = gets.chomp
state.capitalize!.upcase!
puts "Your name is #{first_name} #{last_name} and you're from #{city}, #{state}!"

What does gets.chomp do?
If you type denisreturn then gets would return "denis\n" where \n is the line feed character from the return key. chomp removes such trailing newline:
"denis\n".chomp
#=> "denis"
I was also wondering if I always have to put the exclamation point after .capitalize!
In general, a bang method is a method like any other: (from the documentation for method names)
The bang methods (! at the end of method name) are called and executed just like any other method.
But:
[...] by convention, a method with an exclamation point or bang is considered dangerous.
Dangerous can mean various things, depending on the context. For built-in methods from Ruby's core library it usually means:
[...] that when a method ends with a bang (!), it indicates that unlike its non-bang equivalent, permanently modifies its receiver.
So capitalize! (with !) will modify first_name: (the method's receiver)
first_name = 'denis' #=> "denis"
first_name.capitalize! #=> "Denis"
first_name #=> "Denis"
capitalize! will also return nil if the string is already capitalized:
first_name = 'Denis' #=> "Denis"
first_name.capitalize! #=> nil
first_name #=> "Denis"
Whereas capitalize (without !) will always return a new (capitalized) string, leaving first_name unchanged:
first_name = 'denis' #=> "denis"
first_name.capitalize #=> "Denis"
first_name #=> "denis"
Apparently, the capitalize call above doesn't make much sense because the return value is not used anywhere. You usually want to do something with that new string like assigning it to a variable:
capitalized_first_name = first_name.capitalize
or passing it to a method:
puts "Your name is #{first_name.capitalize}"

chomp removes the linebreak character at the end of the string input.
Adding the ! will mutate the value of your variable. It is not required. It depends on your use case.
foo = 'foo'
foo.capitalize
print foo
=> 'foo'
bar = 'bar'
bar.capitalize!
print bar
=> 'Bar'

Of course you don't need the "!". Let's try to get by without them:
print "What's your first name? "
first_name = gets.chomp.capitalize
print "What's your last name? "
last_name = gets.chomp.capitalize
print "What city are you from? "
city = gets.chomp.capitalize
print "What state or province are you from? "
state = gets.chomp.upcase
puts "Your name is #{first_name} #{last_name} and you're from #{city}, #{state}!"
There you go. You can avoid mutation and just manipulate your strings with standard methods. No "!" methods need apply!
ps: capitalize followed by upcase is the same as just upcase.

Related

create comma separated string in the First element of an array Ruby

So this may seem odd, and I have done quite a bit of googling, however, I am not really a programmer, (sysops) and trying to figure out how to pass data to the AWS API in the required format, which does seem a little odd.
So, working with resources in AWS, I need to pass tags which are keys and values. The key is a string. The value is a comma separated string, in the first element of an array. So in Ruby terms, looks like this.
{env => ["stage,qa,dev"]}
and not
{env => ["stage","qa","dev"]}
I'm created an admittedly. not a very pretty little app that will allow me to run ssm documents on targeted instances in aws.
I can get the string into an array element using this class I created
class Tags
attr_accessor :tags
def initialize
#tags = {"env" => nil ,"os" => nil ,"group" => nil }
end
def set_values()
puts "please enter value/s for the following keys, using spaces or commas for multiple values"
#tags.each { |key,value|
print "enter #{key} value/s: "
#tags[key] = [gets.strip.chomp]
#tags[key] = Validate.multi_value(tags[key])
}
end
end
I then call this Validate.multi_value passing in the created Array, but it spits an array of my string value back.
class Validate
def self.multi_value(value)
if value.any?{ |sub_string| sub_string.include?(",") || sub_string.include?(" ") }
value = value[0].split(/[,\s]+/)
return value
else
return value
end
end
end
Using pry, I've seen it gets for example ["stage dev qa"] then the if statement does work, then it spits out ["stage","dev","qa"].
and I need it to output ["stage,dev,qa"] but for the life of me, I can't make it work.
I hope that's clear.
If you have any suggestions, I'd be most grateful.
I'm not hugely experienced at ruby and the may be class methods that I've missed.
If your arrays are always coming through in the format ["stage dev qa"] then first we need to split the one string into the parts we want:
arr = ["stage dev qa"]
arr.split(' ')
=> ["stage", "dev", "qa"]
Then we need to join them with the comma:
arr.split(' ').join(',')
=> "stage,dev,qa"
And finally we need to wrap it in an array:
[arr.first.split(' ').join(',')]
=> ["stage,dev,qa"]
All together:
def transform_array(arr)
[arr.first.split(' ').join(',')]
end
transform_array(['stage dev qa'])
=> ['stage,dev,qa']
More info: How do I convert an array of strings into a comma-separated string?
I see no point in creating a class here when a simple method would do.
def set_values
["env", "os", "group"].map do |tag|
puts "Please enter values for #{tag}, using spaces or commas"
print "to separate multiple values: "
gets.strip.gsub(/[ ,]+/, ',')
end
end
Suppose, when asked, the user enters, "stage dev,qa" (for"env"), "OS X" (for"OS") and "Hell's Angels" for "group". Then:
set_values
#=> ["stage,dev,qa", "OS,X", "Hell's,Angels"]
If, as I suspect, you only wish to convert spaces to commas for "env" and not for "os" or "group", write:
def set_values
puts "Please enter values for env, using spaces or commas"
print "to separate multiple values: "
[gets.strip.gsub(/[ ,]+/, ',')] +
["os", "group"].map do |tag|
print "Please enter value for #{tag}: "
gets.strip
end
end
set_values
#=> ["stage,dev,ga", "OS X", "Hell's Angels"]
See Array#map, String#gsub and Array#+.
gets.strip.gsub(/[ ,]+/, ',') merely chains the two operations s = gets.strip and s.gsub(/[ ,]+/, ','). Chaining is commonplace in Ruby.
The regular expression used by gsub reads, "match one or more spaces or commas", [ ,] being a character class, requiring one of the characters in the class be matched, + meaning that one or more of those spaces or commas are to be matched. If the string were "a , b,, c" there would be two matches, " , " and ",, "; gsub would convert both to a single comma.
Using print rather than puts displays the user's entry on the same line as the prompt, immediately after ": ", rather than on the next line. That is of course purely stylistic.
Often one would write gets.chomp rather than gets.strip. Both remove newlines and other whitespace at the end of the string, strip also removes any whitespace at the beginning of the string. strip is probably best in this case.
What do you think about this?, everything gets treated in the Validates method. I don't know if you wanted to remove repeated values, but, just in case I did, so a
"this string,, has too many,,, , spaces"
will become
"this,string,has,too,many,spaces"
and not
"this,,,,string,,,has,too,,many,,,,,,spaces"
Here's the code
class Tags
attr_accessor :tags
# initializes the class (no change)
#
def initialize
#tags = {"env" => nil ,"os" => nil ,"group" => nil }
end
# request and assign the values <- SOME CHANGES
#
def set_values
puts "please enter value/s for the following keys, using spaces or commas for multiple values"
#tags.each do |key,value|
print "enter #{key} value/s: "
#tags[key] = Validate.multi_value( gets )
end
end
end
class Validate
# Sets the array
#
def self.multi_value(value)
# Remove leading spaces, then remove special chars,
# replace all spaces with commas, then remove repetitions
#
[ value.strip.delete("\n","\r","\t","\rn").gsub(" ", ",").squeeze(",") ]
end
end
EDITED, thanks lacostenycoder

Ruby `downcase!` returns `nil`

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.
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!
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.
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"

How can I store my `gets` method in a variable?

I need to store a user input in a variable. This is my code:
puts "Hi! I'm HAL, what's your name?"
gets.strip
name = gets.strip
greeting(name)
This isn't working.
This may not be what you want, but it answers the question posed in the title.
You can hold the method Kernel#gets in a variable like so:
m = method(:gets)
#=> #<Method: Object(Kernel)#gets>
Now let's use it.
def greeting(name)
puts "Me? I'm #{name}"
end
puts "Hi! I'm HAL, what's your name?"
name = m.call.strip # "Dave Bowman" is entered
name holds the user's response, after the string is stripped of any enclosing whitespace and the trailing newline character.
greeting(name)
Me? I'm Dave Bowman
Try this:
puts "Hi! I'm HAL, what's your name?"
name = gets.strip
greeting(name)

setting variables equal to 'gets' in Ruby

I want to write a program that asks for two strings from the user and searches for one within the other, but I'm having some trouble making it work. The following returns "not" even when the given character is present within the string. Does anyone know what I'm doing wrong?
puts 'Enter the string that you would like to search'
content = gets
puts 'What character would you like to find?'
query = gets
if content.include? query
puts "here"
else
puts "not"
end
gets returns the string from the user including the newline character '\n' at the end. If the user enters "Hello world" and "Hello", then the strings really are:
"Hello World\n"
"Hello\n"
That makes it obvious, why your code does not find a match.
Use chomp to remove that newline characters from the end of the string.
puts 'Enter the string that you would like to search'
content = gets.chomp
puts 'What character would you like to find?'
query = gets.chomp
if content.include?(query)
puts "here"
else
puts "not"
end

Ruby: how to use/turn multi-word strings into symbols

Most hash keys are single word names. Let's use movie names and ratings as an example. That's easy to make a symbol:
my_hash = { Ferris_Bueller: 5}
What if I don't want to use an underscore in my key name, but need that string as a symbol?
I thought of doing this, but it doesn't work:
my_hash = { "Ferris Bueller": 5}
The issue is, I'm trying to prompt the user to name a movie, rate it, then add those values as a key/value pair in my_hash. People will input two-word movies normally, without the underscore. How do I get that key to store in the hash as a symbol? I.e.:
puts "Name a movie:"
name = gets.chomp
puts "Rate it 1-5:"
rating = gets.chomp
my_hash[name.to_sym] = rating
The user types a two-word movie, such as Robo Cop. Why wont this work?
You can make a multi-word symbol using this notation:
:"multi word symbol" => value
You can also use .gsub! to convert the _ to a space and then .gsub! again to convert it back. This way the code is still registered but the user never sees the underscore. Here's an example:
movies = {
The_Raven: 4,
I_Robot: 3
}
puts "Howdy, please select one of the following."
choice = gets.chomp
case choice
when "update"
puts "Please select which movie you'd like to update."
title = gets.chomp
title.gsub!(/ /, "_")
#By doing this, the user can type 'The Raven' and Ruby will be able to
#register it as a title in your movies hash.
if
movies[title.to_sym].nil?
puts "That movie doesn't exist in our inventory!"
else
puts "What would you like to change the rating to? (Rating must be 1 - 5)"
rating = gets.chomp
movies[title.to_sym] = rating.to_i
title.gsub!(/_/, " ")
#Then you convert it back from an underscore to a space. This way Ruby
#will display to the user the title without underscores.
puts "#{title} has been updated with a new rating of #{rating}."
end`enter code here`
In order to get that working you might need to use hash rockets actually...
my_hash = { :"Ferris Bueller" => 5}

Resources