Ruby: String interpolation prints the function first when called second - ruby

Here is my short program
def def1()
x = 1
puts x
end
def def2()
y = 2
puts y
end
puts "some text #{def1}"
puts "some text #{def2}"
The outcome of this example...
1
some text
2
some text
I don't understand why this puts in this order and not "sometext" first.

Because the string is created first, which means calling def1, and then the whole string is passed into puts.
We can expand puts "some text #{def1}" out to understand.
string = "some text " + def1.to_s
puts string
As you can see, def1 is called to create the string. def1 prints out 1 itself, it does not return anything (it returns nil). Then the whole string is printed.
That's how all function calls work. The arguments are evaluated, the the function is called.
You'd need to call def1 after printing the prefix.
print "some text "
def1
This is a reason why it's often better to have a function return a value rather than print it itself.

In order to print the string, puts has to know what the string is. In order to know what the string is in this particular line:
puts "some text #{def1}"
Ruby has to call def1 first. def1, in turn, calls puts to print something.

Related

Why is user input in Ruby different from a given string already inside the code? [duplicate]

This question already has answers here:
Why does Ruby's 'gets' includes the closing newline?
(5 answers)
Closed 3 years ago.
My Ruby program evaluates strings in a function called func1. It asks for user input when it runs. The string comparison if statement
does not work on user input no matter what. I can interactively enter the string that should be the same as the program-defined variable constant. But the function interprets the two strings differently. I have added extra debugging steps to verify the string is correct. But I still fail to see why the func1 sees user input different from the way I, a human, sees the input. I expect func1 to receive the user-inputted string foobar and recognize it. This is not what is happening. What am I doing wrong?
Here is my Ruby program:
def func1(x)
if x == 'foobar' then
print "you gave this function foobar"
puts " "
else
print "you did NOT give this function foobar"
end
end
def prompt(*args)
print("Enter a string: ")
coolstring = gets
return coolstring
end
func1("foobar")
y = prompt
print(y)
func1(y)
Here is some output that shows I entered the string "foobar":
you gave this function foobar
Enter a string: foobar
foobar
you did NOT give this function foobar
When you call gets the newline that ends the input is stored in the variable:
pry(main)> gets
qwe
# => "qwe\n"
To remove it, use String#chomp. It removes a separator (by default a newline) from the end of the string:
pry(main)> a = gets
asd
#=> "asd\n"
pry(main)> a.chomp
#=> "asd"
And in your case:
def prompt(*args)
print("Enter a string: ")
coolstring = gets.chomp # <<<<<<<<<<<< here
return coolstring
end

Loop until answer is a string

I'm trying to loop this question until the user's input is a string value:
Question: What is your name?
I don't want the user to just press enter and leave the name blank.
I don't want the user's input to be numeric/numbers.
Please see my code below:
name1 = gets.chomp.to_s
loop do
print "Please enter your name "
name1 = gets.chomp.to_s
if name1.empty?
puts "No input."
else name1.to_i
puts "Illegal character ':'"
end
end
With this code, I can't proceed to the next question even if I input a string value. Please help.
Your code has several issues:
Your input and output is out of order. You gather input before prompting and that input (from your first line) is never used:
name1 = gets.chomp.to_s # <- Ruby is waiting for input
loop do
print "Please enter your name " # <- user is prompted to enter name
name1 = gets.chomp.to_s # <- previous input is overwritten
# ...
end
The first line should probably be deleted.
gets might return nil, but chomp always returns a string. Calling to_s afterwards is therefore superfluous.
Your if-else construct is actually:
if name1.empty?
puts "No input."
else
name1.to_i
puts "Illegal character ':'"
end
So whenever the input is not empty?, you convert it to an integer (discarding the result) and print an error message. You probably want an elsif instead (/.../ is a regexp and \d matches a digit):
if name1.empty?
puts 'No input.'
elsif name1.match? /\d/
puts 'Digits not allowed.'
end
You could also use a case expression:
case name1
when ''
puts 'No input.'
when /\d/
puts 'Digits not allowed.'
end
You never break out of your loop. The code keeps looping even if no error was found. This can be fixed by adding a break statement in an else branch (to either if or case):
# ...
else
break
end
gets.chomp will always return a string, and as such there is no need to call to_s on the method.
If you don't want the user to be able to input any integers, you could use the following for a clean solution:
name.count("0-9") > 0
If this returns true, then you know that the user's input contains at least one number.

Why is the method output printed first?

I wrote the following:
greeting="i am awesome"
puts("I was saying that #{greeting}")
# => I was saying that i am awesome
When I change it to this:
def showman
print("I am awesome ")
end
puts("I was saying that #{showman}")
# => I am awesome I was saying that
why is the method output printed first, and then the string? Why is it not printing like "I was saying that I am awesome"? What can I do to make the output be as such?
If I modify the showman function to:
def showman
return ("I am awesome ")
end
then it gives the desired output. Why is the use of return in this way making difference to the output?
In first output why method output is printed first and then the string.
In order to evaluate the string, showman is evaluated before the whole string is evaluated, which prints "I am awesome ".
Why its not printing like "I was saying that I am awesome"
Because print returns nil, and interpolating nil in a string evaluates to an empty string ("#{showman}" → "#{nil}" → ""). Without print, the showman method returns the string "I am awesome ".
Why is the use of return in this way making difference to the output?
It is not the use of return that is making the difference. It is the absence of print that is making the difference.

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

How to use "gets" and "gets.chomp" in Ruby

I learned that gets creates a new line and asks the user to input something, and gets.chomp does the same thing except that it does not create a new line. gets must return an object, so you can call a method on it, right? If so, lets name that object returned by gets as tmp, then you can call the chomp method of tmp. But before gets returns tmp, it should print a new line on the screen. So what does chomp do? Does it remove the new line after the gets created it?
Another way to re-expound my question is: Are the following actions performed when I call gets.chomp?
gets prints a new line
gets returns tmp
tmp.chomp removes the new line
User input
Is this the right order?
gets lets the user input a line and returns it as a value to your program. This value includes the trailing line break. If you then call chomp on that value, this line break is cut off. So no, what you have there is incorrect, it should rather be:
gets gets a line of text, including a line break at the end.
This is the user input
gets returns that line of text as a string value.
Calling chomp on that value removes the line break
The fact that you see the line of text on the screen is only because you entered it there in the first place. gets does not magically suppress output of things you entered.
The question shouldn't be "Is this the right order?" but more "is this is the right way of approaching this?"
Consider this, which is more or less what you want to achieve:
You assign a variable called tmp the return value of gets, which is a String.
Then you call String's chomp method on that object and you can see that chomp removed the trailing new-line.
Actually what chomp does, is remove the Enter character ("\n") at the end of your string. When you type h e l l o, one character at a time, and then press Enter gets takes all the letters and the Enter key's new-line character ("\n").
1. tmp = gets
hello
=>"hello\n"
2. tmp.chomp
"hello"
gets is your user's input. Also, it's good to know that *gets means "get string" and puts means "put string". That means these methods are dealing with Strings only.
chomp is the method to remove trailing new line character i.e. '\n' from the the string.
whenever "gets" is use to take i/p from user it appends new line character i.e.'\n' in the end of the string.So to remove '\n' from the string 'chomp' is used.
str = "Hello ruby\n"
str = str.chomp
puts str
o/p
"Hello ruby"
chomp returns a new String with the given record separator removed from the end of str (if present).
See the Ruby String API for more information.
"gets" allows user input but a new line will be added after the string (string means text or a sequence of characters)
"gets.chomp" allows user input as well just like "gets", but there is
not going to be a new line that is added after the string.
Proof that there are differences between them:
Gets.chomp
puts "Enter first text:"
text1 = gets.chomp
puts "Enter second text:"
text2 = gets.chomp
puts text1 + text2
Gets:
puts "Enter first text:"
text1 = gets
puts "Enter second text:"
text2 = gets
puts text1 + text2
Copy paste the code I gave you, run and you will see and know that they are both different.
For example:
x = gets
y = gets
puts x+y
and
x = gets.chomp
y = gets.chomp
puts x+y
Now run the two examples separately and see the difference.

Resources