include works with if but not else - ruby

I doing a Ruby botcamp. I'm supposed to write code that replaces all user input of 's' with 'th' so it reads like Daffy Duck is speaking. If I enter an s it will be replaced with th. That works! But If I don't enter an 's' it's supposed to print that none were included in my elsif statemnt. Instead I'm getting the error 'undefined method `include?' for nil:NilClass'. Other than that error, the interpretor is telling me the code is good.
print "Input a string: "
user_input=gets.chomp.downcase!
if user_input.include?"s"
user_input.gsub!(/s/, "th")
puts "Your string is #{user_input}!"
elsif
puts "There are no s's in your string!"
end
Any ideas on what I need to change?

You need to be careful with built-in ruby methods that end with an exclamation point (!). A lot of them will return nil if no changes were made:
'test'.downcase! # => nil
'Test'.downcase! # => "test"
Since you are assigning the result to a variable, there's no need to use the exclamation point method, since those modify in-place, you can just use the normal downcase method.
'test'.downcase # => "test"
You also later on have an elsif with no condition, that should probably just be an else. It's actually executing the first line of the "body" of the elsif as the conditional:
if false
puts "a"
elsif
puts "b" # recall that `puts` returns `nil`
puts "c"
else
puts "d"
end
This results in
b
d
being output

Related

if-elsif without conditions not branching correctly in Ruby

When I run the following code:
if
puts "A"
elsif
puts "B"
end
I get the output:
A
B
Why does it not warn or raise any errors? And why does it execute both branches?
an if-elsif without conditions
Here's where you're wrong. The puts are the conditions. There are no bodies in that snippet, only the conditions.
Here's your code, properly formatted.
if puts "A"
elsif puts "B"
end
And why it executes both branches?
puts returns nil, a falsey value. That's why it tries both branches. If this code had an else, it'd be executed too.
In other words :
if # this is the condition :
puts "A" # an expression which prints A and returns nil
# hence it's like "if false", try elsif ...
then
puts 'passes in then'
elsif # this is another condition :
puts "B" # puts prints B and returns nil
else # no condition satisfied, passes in else :
puts 'in else'
end
Execution :
$ ruby -w t.rb
A
B
in else

Calling method isn't returning string

I created a method to count a substring 'e' in a string passed as an argument. If there isn't a substring 'e' in the string, it should return "There is no \"e\"." I am trying to achieve this:
How many times 'e' is in a string.
If given string doesn't contain any "e", return "There is no "e"."
if given string is empty, return empty string.
if given string is nil, return nil.
This is my code:
def find_e(s)
if !s.include?("e")
"There is no \"e\"."
elsif s.empty?
""
else s.nil?
nil
end
s.count("e").to_s
end
find_e("Bnjamin")
It skips the if statement and it still uses the method count. Why is this?
To achieve what you want you could move your string.count to the else statement in your if, because actually you're making your method return the quantity of e passed in the count method over your string, but what happens inside the if isn't being used:
def find_e(s)
if s.nil?
nil
elsif s.empty?
''
elsif !s.include?("e")
"There is no \"e\"."
else
s.count("e").to_s
end
end
p find_e("Bnjamin") # => "There is no \"e\"."
p find_e("Benjamin") # => "1"
p find_e(nil) # => nil
p find_e('') # => ""
And also your validations must be in order, first check nil values, then empty values, and then the rest, if you don't then you'll get some undefined method ___ for nil:NilClass errors.
You might have a hard time using the method you wrote. In the next method, you'll need a new case statement to test if find_e returned nil, an empty string, a string with a number or "no e".
This method would be a bit more consistent:
def count_e(string_or_nil)
count = string_or_nil.to_s.count("e")
if count == 0
"There is no \"e\"."
else
count
end
end
puts count_e("Covfefe")
# 2
puts count_e("Bnjamin")
# There is no "e".
puts count_e("")
# There is no "e".
puts count_e(nil)
# There is no "e".
But really, if there's no e in the input, just returning 0 would be the most logical behaviour.
You need to put your count method in a branch of the if/else statement, or else it will be evaluated last every time. Without an explicit return statement Ruby will return the last statement, so putting the method outside the if/else branch on the last line guarantees it will always be hit. Also, nil can be converted to an empty string by calling #to_s, so you can remove one of your branches by converting s.to_s, calling empty? and returning s
def find_e(s)
if s.to_s.empty?
s
elsif !s.include?("e")
"There is no \"e\"."
else
s.count("e").to_s
end
end
If you just return 0 whether you get nil, an empty string, or a string without e, you can make it one line
def find_e(s)
s.to_s.count("e").to_s
end
If it were me I'd probably return an Integer, which can always be converted to a String later. puts and "#{}" will implicitly call to_s for you anway. Then you can use that integer return in your presentation logic.
def count_e(input)
input.to_s.count("e")
end
def check_for_e(input)
count = count_e(input)
count > 0 ? count.to_s : "There's no \"e\"."
end
check_for_e("Covfefe") # => "2"
check_for_e("Bnjamin") # => "There's no \"e\"."
check_for_e(nil) # => "There's no \"e\"."
check_for_e("") # => "There's no \"e\"."
In Ruby, methods return the last statement in their body. Your method's last statement is always s.count("e").to_s, since that lies outside of the if statements.

How can I make script work in Ruby?

I am new to Ruby.
I need to make this script work:
puts "Do you like cats?"
ask = gets
def ask(n)
if ask == yes
return "I do too"
end
if ask == no
return "Dogs are better"
end
end
puts "#{ask(n)}"
Error message is :
pracif.rb:15:in <main>': undefined local variable or methodn' for
main: Object (NameError)
Here's a script that would work for you :
puts "Do you like cats?"
answer = gets
def ask(n)
if n == 'yes'
return "I do too"
end
if n == 'no'
return "Dogs are better"
end
end
puts ask(answer.downcase.chomp)
Explaination
As the error said you were trying to pass in a variable n which was not defined
Secondly you have a method name ask same as variable name. I've renamed the variable to answer instead
Thirdly, enclose yes and no in quotes
And finally, since you are using gets a \n gets appended like yes\n so none of your conditions would match. So i've used chomp to remove \n. And also used downcase to make input case insensitive.
EDIT
As mentioned by #Jordan in the comments, there is no reason to use string interpolation for the puts statement. So it's enough to call the method directly.
There are a bunch of issues with your code. Try something more like:
def reply(response)
return 'I do too' if response == 'yes'
return 'Dogs are better' if response == 'no'
'Invalid response!'
end
puts 'Do you like cats?'
response = gets().chomp()
puts reply(response)
Pay attention to the variable names. If you keep them descriptive, it is easier to spot mistakes.
Your script has no n local variable defined that you are passing to your ask(n) method at the end.
Rename your ask variable that your script gets from user to answer for example and pass it to your ask method at the end like so:
Updated code to fix other problem I did not see in the first run.
puts "Do you like cats?"
answer = gets.chomp
def ask(n)
(n == 'yes') ? "I do too" : "Dogs are better"
end
puts "#{ask(answer)}"

Strange result in Ruby with "end if"

I expect this code to execute the code block and result in the output "x" and "y", or just to throw a syntax error:
if true
puts "x"
end if
puts "y"
However, the interpreter ignores the if true block and only executes puts "y". If I instead enter the following code:
if true
puts "x"
end if
the interpreter exits with an end-of-input syntax error. Is there a reason why the first snippet is valid code but somehow executing wrong? It would seem to me that there is some error in the parser.
I've confirmed this in Ruby 2.1.2 as well as Ruby 2.1.5.
There are two things playing together here:
The return value of the puts is nil
Ruby is usually clever enough to read the next line if the current command hasn't ended yet.
That means:
if true
puts "x"
end if
puts "y"
is the same than:
if true
puts "x"
end if (puts "y")
Ruby evaluates puts "y" to nil:
if true
puts "x"
end if nil
What leads Ruby to not evaluate the if true block, because if nil acts like if false.
Or in other words: Your example is the same as:
if puts("y") # evaluates to nil (aka is falsey)
if true
puts "x"
end
end
I think what you mean to write is
if true
puts "x"
end
puts "y"
That would produce the output you expect.
Your code is incorrect. The correct code is:
if true
puts "x"
end
puts "y"
Your code tells Ruby to execute the if true ... end block if puts "y" returns true.
puts returns nil, which amounts to false in a condition check, leading to the block not being executed at all.
Your code is effectively saying only to execute the if true block only if puts "y" returns true. Unfortunately, puts returns nil. To end an if statement in Ruby, you simple have to use end. Unlike in Shell Scripting or Visual Basic, there is no specific end statements for different blocks.
Change
if true
puts "x"
end if
puts "y"
to
if true
puts "x"
end
puts "y"
And you'll be golden.

how to re-ask a user for input if none was given the first time?

My current code is this:
print "Feed me input."
def get_input
input_value=gets.chomp
if !input_value
print "you didn't type anything"
else
input_value.downcase!
if input_value.include? "s"
input_value.gsub!(/s/,"th")
else
print "You entered a string but it had no 's' letters."
end
end
return input_value
end
get_input()
if !get_input
get_input
else
puts "#{get_input}"
end
I'm not sure why it isn't working. When I run it I get prompted for input then when I press enter after entering none I get the "You entered a string but it had no 's' letters", not the "you didn't type anything" that I wanted.
Every object except false and nil is treated as false if they are used as predicates. Even empty string is treated as true:
s = ""
puts true if s # => true
Use String#empty? to check if it is empty string.
As you said When I run it I get prompted for input then when I press enter after entering none - It means what happened acctually is
input_value="\n".chomp #( you gets methods take only `\n` as input)
"\n".chomp # => ""
so your input_value variable holds and empty string object. Now in Ruby every object has true value, except nil and false. Said that "" is also true,but you did !input_value,which means you are making it false explicitly. That's the reason in the below if-else block, else part has been executed and you didn't see the expected output "you didn't type anything".
if !input_value
print "you didn't type anything"
else
input_value.downcase!
if input_value.include? "s"
#.. rest code.
So I would suggest you in such a context replace the line if !input_value to if input_value.empty?, Which will make your code to behave as you are expecting. I didn't take your logic as a whole,but tries to show you how to code to meet your needs:
print "Feed me input."
def get_input
input_value=gets.chomp
if input_value.empty?
puts "you didn't type anything"
false
else
puts "found value"
input_value.downcase!
end
end
until input = get_input
# code
end
puts input
output
kirti#kirti-Aspire-5733Z:~/Ruby$ ruby test.rb
Feed me input.
you didn't type anything
you didn't type anything
you didn't type anything
HH
found value
hh
kirti#kirti-Aspire-5733Z:~/Ruby$

Resources