Removing values from strings in a while loop for Ruby - ruby

So I'm learning yet ANOTHER new language cause apparently my company thinks we should support every thing conceivable under the sun. Next week I suspect a memo about FORTRAN, automatonization, and punch cards. But that's neither her nor there. My question is, I'm running a loop (in this particular case a while loop) and have it collecting a string from the user. Name of pet. This while loop continues to repeat until the user breaks it. However on the second time around I start receiving messages from Ruby telling me that the values have already been preassigned. It doesn't really cause issues as the program continues to run, but it doesn't look good.
Is there any way to clear the values so that it all returns to nil except the values I want, or would it be better to just put everything in functions so that there's no chance of regurgitation?
sample:
while moonies > 0
print "Would you like to punch a kitty? y or n"
y = gets()
if y = 'y'
print "Which kitty would you like to punch?"
slap = gets()
if slap == Tom
print "You spent 50 dollars punching a kitten."
....
else
print "Is there something else you'd like to kick or did you want to spend no money today?"
and so on and so on.
The problem is that when it gets back around to y is when the messages start to appear. thanks for the assistance.

Well...
if y = 'y'
is an assignment, not a comparison for equality. y='y' is always true. Should be
if y == "y\n" #note the newline, you got it from "gets"
if slap == Tom
This is a comparison, but Tom is a constant (it starts with a capital). I'm guessing you reassign a value to it, somewhere in your loop. Ruby complains about it. The newline issue will be here again. slap=gets.chomp will get rid of it.

Related

Why is my Ruby code not executing as I expect it to?

I'm learning Ruby through the book Learn to Program by Chris Pine. In the book, there's an exercise which says:
Write a Deaf Grandma program. Whatever you say to grandma (whatever you type in), she should respond with HUH?! SPEAK UP, SONNY!, unless you shout it (type in all capitals). If you shout, she can hear you (or at least she thinks so) and yells back, NO, NOT SINCE 1938! To make your program really believable, have grandma shout a different year each time; maybe any year at random between 1930 and 1950. (This part is optional, and would be much easier if you read the section on Ruby's random number generator at the end of the methods chapter.) You can't stop talking to grandma until you shout BYE.
Hint: Don't forget about chomp! 'BYE'with an Enter is not the same as 'BYE' without one!
Hint 2: Try to think about what parts of your program should happen over and over again. All of those should be in your while loop.
I have written my code and it doesn't work as expected. Basically, when I input information, it follows the order in which the code was written. For example if I input "HELLO" it'll reply "HUH?! SPEAK UP, SONNY! but really it should be writing back "NO, NOT SINCE 1938!".
When I input 'BYE' nothing will come up unless I follow the order in which the code was written in (I hope that makes sense).
I have tried a lot of things, like not using the break (for the loop). I have tried to write it as one long piece of code without any ifs or else's.
Here is the code I have written:
puts 'Go speak to Grandma, she\'s in the kitchen!'
speaking = gets.chomp
if speaking == speaking.downcase
puts 'HUH?! SPEAK UP, SONNY!'
gets.chomp
while speaking == 'BYE'
puts 'BYE! COME AGAIN SOON!'
gets.chomp
break
end
else speaking == speaking.upcase
puts 'NO, NOT SINCE 1983!'
gets.chomp
end
I expect when I write HELLO to get the appropriate answer of 'NO, NOT SINCE 1983!'. Also, I expect the conversation to keep going because I have used gets.chomp on all pieces of the code. Sp why is the code stopping?
Problem in the code is that if ... else condition not wrapped within loop, so it would no be executed repeatedly.
Hint 2: Try to think about what parts of your program should happen
over and over again. All of those should be in your while loop
To make loop works you need wrap all repeatable lines within loop.
In your case loop should break only when input will be BYE
puts 'Go speak to Grandma, she\'s in the kitchen!'
speaking = gets.chomp
until speaking == 'BYE'
if speaking == speaking.upcase
puts 'NO, NOT SINCE 1983!'
else
puts 'HUH?! SPEAK UP, SONNY!'
end
# Get input before next loop
speaking = gets.chomp
end
puts 'BYE! COME AGAIN SOON!'
You don't need to check for downcase explicitly, only you care about is "does input contains only upper case characters"

Case statement don't work

I'm learning Ruby from "Programming Ruby, The Pragmatic Programmers(2nd, 2005)" and I'm stuck in the Case statement chapter.
So i copy-paste some code in my version from book:
def kind
puts "Type year and I'll tell you genre: "
ask = gets.chomp
kind = case ask
when 1850..1889 then "Blues"
when 1890..1909 then "Ragtime"
when 1910..1929 then "New Orleans Jazz"
when 1930..1939 then "Swing"
when 1940..1950 then "Bebop"
else "Jazz"
end
puts "You typed year #{ask}. Genre of music in that period is
#{kind}."
end
kind
Hence, whatever year I'm put, output is "Jazz"...What am I working incorrectly?
gets.chomp returns a string, and you are comparing that with integers.
You can inspect ask after you assigned it:
ask = gets.chomp
p ask
When you run the script and enter a number (e.g. 1940), you should see "1940" printed in the terminal. The quotes around the number show you that the variable holds a string, not a number. (FYI don't use puts here, since it won't show the quotes.)
As mudasobwa wrote in his comment, the way to fix this is to cast the input to a number before you compare it:
ask = gets.chomp.to_i
If you add p ask again, you should now see that only the number is printed to the terminal, without any " surrounding it. This shows you that the variable holds an integer.

Count the number of sentences in a paragraph using Ruby

I have gotten to the point where I can split and count sentences with simple end of sentence punctuation like ! ? .
However, I need it to work for complex sentences such as:
"Learning Ruby is a great endeavor!!!! Well, it can be difficult at times..."
Here you can see the punctuation repeats itself.
What I have so far, that works with simple sentences:
def count_sentences
sentence_array = self.split(/[.?!]/)
return sentence_array.count
end
Thank you!
It's pretty easy to adapt your code to be a little more forgiving:
def count_sentences
self.split(/[.?!]+/).count
end
There's no need for the intermediate variable or return.
Note that empty strings will also be caught up in this, so you may want to filter those out:
test = "This is junk! There's a space at the end! "
That would return 3 with your code. Here's a fix for that:
def count_sentences
self.split(/[.?!]+/).grep(/\S/).count
end
That will select only those strings that have at least one non-space character.
class String
def count_sentences
scan(/[.!?]+(?=\s|\z)/).size
end
end
str = "Learning Ruby is great!!!! The course cost $2.43... How much??!"
str.count_sentences
#=> 3
(?=\s|\z)/) is a positive lookahead, requiring the match to be immediately followed by a whitespace character or the end of the string.
String#count might be easiest.
"Who will treat me to a beer? I bet, alexnewby will!".count('.!?')
Compared to tadman's solution, no intermediate array needs to be constructed. However it yields incorrect results if, for instance, a run of periods or exclamation mark is found in the string:
"Now thinking .... Ah, that's it! This is what we have to do!!!".count('.!?')
=> 8
The question therefore is: Do you need absolute, exact results, or just approximate ones (which might be sufficient, if this is used for statistical analysis of, say, large printed texts)? If you need exact results, you need to define, what is a sentence, and what is not. Think about the following text - how many sentences are in it?
Louise jumped out of the ground floor window.
"Stop! Don't run away!", cried Andy. "I did not
want to eat your chocolate; you have to believe
me!" - and, after thinking for a moment, he
added: "If you come back, I'll buy you a new
one! Large one! With hazelnuts!".
BTW, even tadman's solution is not exact. It would give a count of five for the following single sentence:
The IP address of Mr. Sloopsteen's dishwasher is 192.168.101.108!

Selecting key words in a string (that are included in an Array) to change their format in Ruby

Select key words in a string to change their format in Ruby
I have a big string (text) and an Array of strings (key_words) as below:
text = 'So in this election, we cannot sit back and hope that everything works out for the best. We cannot afford to be tired or frustrated or cynical. No, hear me. Between now and November, we need to do what we did eight years ago and four years ago…'
key_words = ['frustrated', 'tired', 'hope']
My objective is to print each word in ‘text’ while changing the colour and case of the words that are included in key_words. I’ve been able to do that by doing:
require 'colorize'
text.split(/\b/).each do |x|
if key_words.include?(x.downcase) ; print '#{x}'.colorize(:red)
else print '#{x}' end
end
However, since I don’t want to include many words in key_words I want to make the selection more sensitive going beyond an exact match. Such as if, for example:
key_words = ['frustrat', 'tire', 'hope'] => the algorithm would select both 'Frustration', 'Frustrated' or 'Tiring' and 'Tired' or 'Hope' and 'Hopeful'.
I’ve tried playing with word lengths in both the string and the array as below but it’s seems very inefficient solution and I’m getting very confused with the usage of .any? and .include? methods in this scenario.
key_words = ['frustrated', 'tired', 'hope']
key_words_abb = []
key_words.each { |x| key_words_abb << x.downcase[0][0..x.length-2]}
text.split(/\b/).each do |x|
if key_words_abb.include?(x.downcase[0][0..x.length-2]); print '#{x}'.colorize(:red)
else print x
end
end
Since I can’t find a specific solution online I would appreciate your help.
It's worth noting that when doing repeated substitutions on strings, especially longer ones, you'll want your substitution method to be as efficient as possible. Spinning through an array of things to switch out is painfully expensive, especially as that list grows.
Here's a variation on your approach:
replacement = Regexp.new('\b%s\b' % [ Regexp.union(key_words) ])
replaced = text.gsub(replacement) do |s|
s.colorize(:red)
end
puts replaced
If you're using that substitution repeatedly you should persist the Regexp object into a constant. That avoids having to compile it for each string you're adjusting. If the list changes based on factors hard to predict, leave it like this and produce it dynamically.
One thing to note about using Ruby is it's often best to express your code as a series of transformations with output as a final step. Putting things like print in the middle of a loop complicates things unnecessarily. If you want to add an additional step to your loop you have to do a lot of extra work to move that print to a later stage. With the approach here you can just chain on the end and do whatever you want.

When using rand() to generate numbers how can I verify that 'if' and 'else' statements guarantee me a correct answer?

I am attempting an exercise from a book that doesn't show any example code for a correct answer, so I'm not sure where I may have strayed. I've written what I felt was a good bit of code, but now I'm not sure if my code will return my statement for a correct guess.
The code:
prng = rand(10)
puts "What's your guess (1-9)?"
user_guess = gets.chomp
if user_guess == prng
puts "You guessed correctly!"
else
puts "Try again!"
end
I feel as though my if statement might be the issue here, because when I run the code it always returns my else statement. I've also tried narrowing the range of numbers so that my guess is more likely correct and I still didn't trigger the if statement's puts.
Any help is appreciated!
rand(10) returns an integer. gets returns a string. A string (in ruby) is never equal to an integer.
You need to either convert your input to an integer (gets.chomp.to_i) or your integer to a string: (rand(10).to_s) before you compare them.
Edit: If you need to debug further, you should check what the values actually are:
puts "The answer was #{prng.inspect} and you guessed #{user_guess.inspect}"

Resources