ruby - how do I get input while print to somewhere else? - ruby

I wrote ruby script like below.
puts a and echo of gets are mixed.
how can I arrange print value 'a' on terminal position 0,0
and gets on position y=10, x=0?
thanks.
Thread.new do
a = 1
loop do
puts a
a += 1
sleep 0.5
end
end
loop do
gets
end

Related

ruby how to stop a loop with user input?

I'm new to ruby and I'm trying to make a loop that outputs a random number between 0 and 1 every second until user hits any key. Then, output the total number of random numbers generated and the average value of the numbers generated. However, I can't make the loop to stop at all, is there anything like break to stop the loop in ruby?
def random
ran = []
puts "Press 1 and 'enter' to start and 2 to stop \n"
s = gets.chomp
ran << Random.rand(0.0...1.1)
ran.each do|i|
ran << Random.rand(0.0...1.1)
puts i
sleep(1)
end
puts "The total number of random numbers generated is: #{ran.length}"
end
random
You don't really need another thread.
numbers = []
puts 'Press ENTER to start'
puts 'Press Ctrl-C to stop'
gets
loop do
numbers << rand
sleep 1
rescue Interrupt
puts
printf "Count: %d\n", numbers.size
printf "Mean: %f\n", numbers.sum / numbers.size
exit
end
Requires Ruby >= 2.5

Restarting a loop from the top

I have the following:
text_counter = 0
MAXTEXT_COUNTER = 10
puts "hello, this will start"
loop do
puts "hello"
text_counter += 1
sleep(2)
if text_counter >= MAXTEXT_COUNTER
break
end
end
sleep(7200)
print "ended test"
Once the break has happened, how can I get it to start again from the top?
I'm now thinking I could nest this loop in an until loop with the condition of text_counter == 1000. This would break, then sleep for 2 hours, then start again until it hits 1000.
It looks like you need a loop within a loop where you repeat one N times, the other M times:
MAXTEXT_COUNTER = 10
puts "hello, this will start"
loop do
MAXTEXT_COUNTER.times do
puts "hello"
sleep(2)
end
print "ended test"
sleep(7200)
end
The outer loop is perpetual. The inner one runs a certain number of times and stops using the times method.
You're looking for next
It functions similarly to break, but returns control back to the top of the loop. It's great for creating flat control flow.
For example
0.upto(100) do |i|
if i % 7 == 0
puts "#{i} is a multiple of 7"
next
end
puts i
end
There is a retry keyword which repeats the loop from top, just what you've asked.
Or you can wrap your loop into a method and continuously call that method.

Printing an ASCII spinning "cursor" in the console

I have a Ruby script that does some long taking jobs. It is command-line only and I would like to show that the script is still running and not halted. I used to like the so called "spinning cursor" in the old days and I managed to reproduce it in Ruby under Windows.
Question: does this work in the other OS's? If not, is there an OS-independent way to accomplish this?
No IRB solutions please.
10.times {
print "/"
sleep(0.1)
print "\b"
print "-"
sleep(0.1)
print "\b"
print "\\"
sleep(0.1)
print "\b"
print "|"
sleep(0.1)
print "\b"
}
Yes, this works on Windows, OS X, and Linux. Improving on Niklas' suggestion, you can make this more general like so:
def show_wait_cursor(seconds,fps=10)
chars = %w[| / - \\]
delay = 1.0/fps
(seconds*fps).round.times{ |i|
print chars[i % chars.length]
sleep delay
print "\b"
}
end
show_wait_cursor(3)
If you don't know how long the process will take, you can do this in another thread:
def show_wait_spinner(fps=10)
chars = %w[| / - \\]
delay = 1.0/fps
iter = 0
spinner = Thread.new do
while iter do # Keep spinning until told otherwise
print chars[(iter+=1) % chars.length]
sleep delay
print "\b"
end
end
yield.tap{ # After yielding to the block, save the return value
iter = false # Tell the thread to exit, cleaning up after itself…
spinner.join # …and wait for it to do so.
} # Use the block's return value as the method's
end
print "Doing something tricky..."
show_wait_spinner{
sleep rand(4)+2 # Simulate a task taking an unknown amount of time
}
puts "Done!"
This one outputs:
Doing something tricky...|
Doing something tricky.../
Doing something tricky...-
Doing something tricky...\
(et cetera)
Doing something tricky...done!
# First define your chars
pinwheel = %w{| / - \\}
# Rotate and print as often as needed to "spin"
def spin_it
print "\b" + pinwheel.rotate!.first
end
EDIT from peter: here a working version
def spin_it(times)
pinwheel = %w{| / - \\}
times.times do
print "\b" + pinwheel.rotate!.first
sleep(0.1)
end
end
spin_it 10
I wrote a gem spin_to_win that displays a spinner while yielding a block. For example:
SpinToWin.with_spinner('Zzzz') do |spinner|
spinner.banner('sleepy')
sleep 1
end
Zzzz \ [sleepy]
It can also track work pending vs. work completed:
SpinToWin.with_spinner('Zzzz') do |spinner|
spinner.increment_todo!(3)
spinner.banner('snore')
sleep 1
spinner.increment_done!
spinner.banner('dream')
sleep 1
spinner.increment_done!
spinner.banner('wake up!')
sleep 1
spinner.increment_done!
end
Zzzz \ 3 of 3 [wake up!]
I use rainbow gem to print color-changing string to indicate the code is working.
require 'rainbow'
def self.print_with_random_color
content = "I am still working on it. Please wait..."
colors = ["aqua","chartreuse","crimson","fuchsia","gold","lawngreen","palegoldenrod","powderblue","sandybrown","deepskyblue"]
loop do
print Rainbow("[#{Time.now}] " + content).send(colors.sample)
(content.length + 1).times {print "\r"}
sleep 0.3
end
end

Take a number input, iterate up to the top of a given range and output numbers into a file

I'm hoping to get my Ruby script to start at an inputted number, say 100, and itterate all the way up to the end of the range; 1000. Having all the numbers in between saved to a file.
This is a code I have so far:
#!/usr/bin/env ruby
if ARGV.length ==0;
puts "Enter the start number"
else puts ARGV.size
ARGV.each do |a|
for i in 0..1000 do
puts i;
end
end
end
To run it I'm typing:
ruby increment.rb 100 > increment.txt
However, it ignores the input number and starts at 1 regardless.
What am I doing wrong?
It starts at 0 because you're giving it the range 0..1000, which starts at 0. If you want to use the numeric value of a as the starting point, use a.to_i instead of 0.
ARGV is an array and the first argument is stored in ARGV[0] second in ARGV[1] etc
if ARGV[0]
start = ARGV[0].to_i
else
puts "Enter the start number"
start = gets.to_i
end
(start .. 1000).each do |i|
puts i
end

Reading a file N lines at a time in ruby

I have a large file (hundreds of megs) that consists of filenames, one per line.
I need to loop through the list of filenames, and fork off a process for each filename. I want a maximum of 8 forked processes at a time and I don't want to read the whole filename list into RAM at once.
I'm not even sure where to begin, can anyone help me out?
File.foreach("large_file").each_slice(8) do |eight_lines|
# eight_lines is an array containing 8 lines.
# at this point you can iterate over these filenames
# and spawn off your processes/threads
end
It sounds like the Process module will be useful for this task. Here's something I quickly threw together as a starting point:
include Process
i = 0
for line in open('files.txt') do
i += 1
fork { `sleep #{rand} && echo "#{i} - #{line.chomp}" >> numbers.txt` }
if i >= 8
wait # join any single child process
i -= 1
end
end
waitall # join all remaining child processes
Output:
hello
goodbye
test1
test2
a
b
c
d
e
f
g
$ ruby b.rb
$ cat numbers.txt
1 - hello
3 -
2 - goodbye
5 - test2
6 - a
4 - test1
7 - b
8 - c
8 - d
8 - e
8 - f
8 - g
The way this works is that:
for line in open(XXX) will lazily iterate over the lines of the file you specify.
fork will spawn a child process executing the given block, and in this case, we use backticks to indicate something to be executed by the shell. Note that rand returns a value 0-1 here so we are sleeping less than a second, and I call line.chomp to remove the trailing newline that we get from line.
If we've accumulated 8 or more processes, call wait to stop everything until one of them returns.
Finally, outside the loop, call waitall to join all remaining processes before exiting the script.
Here's Mark's solution wrapped up as a ProcessPool class, might be helpful to have it around (and please correct me if I made some mistake):
class ProcessPool
def initialize pool_size
#pool_size = pool_size
#free_slots = #pool_size
end
def fork &p
if #free_slots == 0
Process.wait
#free_slots += 1
end
#free_slots -= 1
puts "Free slots: #{#free_slots}"
Process.fork &p
end
def waitall
Process.waitall
end
end
pool = ProcessPool.new 8
for line in open('files.txt') do
pool.fork { Kernel.sleep rand(10); puts line.chomp }
end
pool.waitall
puts 'finished'
The standard library documentation for Queue has
require 'thread'
queue = Queue.new
producer = Thread.new do
5.times do |i|
sleep rand(i) # simulate expense
queue << i
puts "#{i} produced"
end
end
consumer = Thread.new do
5.times do |i|
value = queue.pop
sleep rand(i/2) # simulate expense
puts "consumed #{value}"
end
end
consumer.join
I do find it a little verbose though.
Wikipedia describes this as a thread pool pattern
arr = IO.readlines("filename")

Resources