Ruby: edit thread program to enter function upon termination - ruby

Basically in my search for code which will loop, and terminate upon user input, i managed to find code here, and after some alteration, produced this:
#desired destination method, however loop persists!!
def desired_method
print "method entered"
end
Thread.new do
while line = STDIN.gets
break if line.chomp == "" # code detects user input
end
desired_method
end
# program will loop here until user presses enter
loop do
puts "foo"
sleep 1
end
This code is brilliant, and will enter the method 'desired_method' when i hit enter, however the loop persists!! printing 'foo' perpetually after "method entered"!!. I have done some research prior to posting this question on how to kill threads, which i believe may hold the answer. My attempts included naming the thread and using the 'thread.exit' function to kill it, however these techniques have remained unsuccessful.
Can anyone illustrate how i might enter the 'desired_method' method without the persisting "foo" print?
Thanks in advance, and greatly appreciated.

An easy solution here is to use semaphore, signalling between threads with a variable access to both places:
# This will be out stop flag, for signalling between threads.
#time_to_stop = false
def desired_method
print "method entered"
# Here we want the loop in the other thread to stop.
#time_to_stop = true
end
Thread.new do
while line = STDIN.gets
break if line.chomp == "" # code detects user input
end
desired_method
end
# program will loop here until user presses enter
loop do
puts "foo"
sleep 1
# only continue if the stop flag is not set.
break if #time_to_stop
end
Hope this helps.

Related

I am unable to break a loop that repeatedly asks for user input. Anyone know how to solve this?

I am trying to create a loop that will ask the user for an integer and will then print "hi" an integer number of times and then ask for input again. I then want the loop to break if the user inputs "bye".
my code so far:
def hi_hi_goodbye
loop do
number = gets
(number.to_i).times do
print "hi"
end
break if
gets == "bye"
end
end
My code so far will not loop. It receives the integer and prints "hi" a given amount of times. However, I am unable to break the loop.
Try
break if gets.chomp == "bye"
This is so because your input would be something like bye\n, so your condition always false, because gets takes even the enter.

Why does the first iteration of this not wait for user input from STDIN?

I'm finding this a bit odd. I would expect each iteration of parse_line(ARGF.read_line) here to wait for input from STDIN. What actually is happening is the first iteration skips waiting for user input, but subsequent iterations do wait. My temporary workaround is just to iterate an extra time.
def parse_line(line)
line.split(" ").map(&:to_i)
end
def get_number_of_slices
parse_line(ARGF.readline(1)).first
end
def get_all_slice_dimensions(number_of_slices)
number_of_slices += 1 # for some reason the first read doesn't wait for user input...
number_of_slices.times.collect { puts "iter"; parse_line(ARGF.readline) }
end
def main
puts (get_all_slice_dimensions get_number_of_slices)
end
main
Added code so that it is a full working program. I found that when I changed readline(1) to readline in get_number_of_slices, I did not need to add 1 to number_of_slices in get_all_slice_dimensions any longer, but I would still like to know the reason why this affects the behavior. If you pay attention to the output, iter will print twice the first time.

ruby debugging user prompt

I need a way to pause the program's flow because there are a lot of print statements that I want to check first. is there a way to do this with ruby, stop the program's flow and continue only if the user has entered yes or stop if it has entered no ? thanks
Yes. In your code, put gets. Then the code will pause at that point until the user inputs Enter. You don't need to do anything special to terminate because, if you want to, you can just do Ctrl+C.
Don't forget to chomp off the newline from the return value of gets.
n, m = 0, 1
repeat = 10
loop do
repeat.times do
print "#{m}, "
n, m = m, n + m
end
puts "\nContinue (yes/no)?"
answer = gets.chomp
exit if answer == "no"
end
Also check out Pry.
# test.rb
require 'pry'
class A
def hello() puts "hello world!" end
end
a = A.new
# start a REPL session
binding.pry
# program resumes here (after pry session)
puts "program resumes here."

Terminating Loop on Input

I'm trying to find a way to terminate a loop when the user hits 'x'+Enter. I want the loop to just keep running in the background until the user cancels it.
Something along these lines:
while gets.chomp != 'x'
puts 'looping...'
sleep 1
end
I'm a beginner with programming and have searched far and wide for how to do this so any help would be deeply appreciated.
You have to use threads for this:
Thread.new do
while line = STDIN.gets
break if line.chomp == 'x'
end
exit
end
# whatever you want to do in the background
# (or rather in the foreground, actually)
loop do
puts "foo"
sleep 1
end
The problem is that STDIN.gets blocks, so you can't do something else at the same time without parallelizing the program by using a background thread that only checks for input.

How do I listen to STDIN input without pausing my script?

I have a while loop consistently listening to incoming connections and outputting them to console. I would like to be able to issue commands via the console without affecting the output. I've tried:
Thread.new do
while true
input = gets.chomp
puts "So I herd u sed, \"#{input}\"."
#Commands would be in this scope
end
end
However, that seems to pause my entire script until input is received; and even then, some threads I have initiated before this one don't seem to execute. I've tried looking at TCPSocket's select() method to no avail.
Not sure where are the commands you want to "continue running" in your example. Try this small script:
Thread.new do
loop do
s = gets.chomp
puts "You entered #{s}"
exit if s == 'end'
end
end
i = 0
loop do
puts "And the script is still running (#{i})..."
i += 1
sleep 1
end
Reading from STDIN is done in a separate thread, while the main script continues to work.
Ruby uses green threads, so blocking system calls will block all threads anyway. An idea:
require 'io/wait'
while true
if $stdin.ready?
line = $stdin.readline.strip
p "line from stdin: #{line}"
end
p "really, I am working here"
sleep 0.1
end

Resources