I'm using Ruby 2.0, Cygwin, and Windows 8. The following program produces no output; it will loop forever and not puts the time.
hi = Thread.new do
while true do
puts Time.now # or call tick function
sleep 1
end
end
hi.join
Am I missing something?
I want the functionality to be:
Do something
Wait for 3-10 seconds
Do it again etc.
Seems like your output is buffered ($stdout.sync defaults to false). To flush all output immediately, start your script with:
$stdout.sync = true
Related
I have an unstoppable Ruby script that I need to be able to stop. Here is the following code:
require 'win32ole'
wsh = WIN32OLE.new("WScript.Shell")
def fileToArray(file)
x = []
File.foreach("#{file}") do |line|
x << line.to_s.split('')
end
return x.flatten!
end
tests = fileToArray("C:\\xampp\\htdocs\\x\\Script\\includes\\classes.php")
sleep 10
x = 0
y = tests.length
while x <= y do
send = tests[x]
speed = 0.025
if x == y
print "Test Complete"
break()
#You guys don't need to see this code, it's just detecting what keys are
#in the array and reading them to the file. But important to know that it is incrementing based on sent keys
else
x += 1
end
end
My problem is that the classes.php it is reading from is 4,000 lines long and takes a long time to get through. If it messes up, I have to wait until it is finished. There is no way for me to stop this loop from running until it is finished unless I completely log out from everything, CTRL+ALT+DEL Option: Logout. I've tried curses I've tried gets on exit. CTRL^C doesn't work either. I'd much rather have a written in solution, but otherwise I wouldn't mind knowing a few keys to killswitch the process a.k.a. "Kill it, kill it with keys"
You read each byte in an array, how long does your array get if you let in run till the end ? Filling an array of hundreds of thousands takes a long time indeed. Should see the rest of your code to decide if there is no better way, and why the win32ole object ?
If the standard windows keys to interrupt the jog don't word (Ctrl-c or Ctrl-break) and you can't use taskmanager, surely the console will still be responsive.
Here a script that does what you do. I put it in an endless loop so that I have to terminate it. The Process.pid shows the process id.
In advance you open a console and when you want to terminate the script you enter the following
taskkill /f /pid 5532
The /f is for forcing to terminate, the number is the pid you get from your script
# encoding:utf-8
STDOUT.sync = true
s1 = File.read __FILE__
puts Process.pid
class String
def to_a
while true # endless loop just for testing the kill
each_byte.inject([]){|result, char| result << char}
end
end
end
p s1.to_a
Tested with Windows 7 and Ruby MRI 1.9.3
EDIT:
based on your comment here another way to send keys to a program
If I understand correctly what you want to do you also don't need to split the string in advance.
require 'win32ole'
#for this script Autoit3 must be installed
s1 = "a string of thousands of characters"
# activate the correct window with the appclass
ai.Opt("WinTitleMatchMode", 4)
appClass = "[CLASS:xxxxxxxx]" # retrieved with AutoIt Window Info
ai = WIN32OLE.new("AutoItX3.Control")
ai.WinActivate(appClass)
# or with the handle
handle = "[HANDLE:#{ai.wingethandle(appClass)}]"
ai.WinActivate(handle)
# send keys, controlkeys or words to the program
ai.Send('{HOME}') #you can send control keys like that
s1.each_byte{|char| ai.Send(char); sleep 1} #to send everything char after char
s1[0..10].each_byte{|char| ai.Send(char); sleep 1} #to send the first 10 chars
I am doing android app test automation using Cucumber-Appium in ruby.
I want to write a wait function which should wait till the next page is shown.
I tried few ways but it is not working.
The code:
And (/^I wait till '(.*)' appears$/) do |next_page|
$i=1
while $i==1 do
if ObjectSpace.const_get('next_page').new.identity?
$current_page = $current_page.change_page('next_page')
$i=0
else
wait_secs(1)
end
end
Can any one suggest something?
Whenever I write a timeout method, I like to pass the block until it times out or resolves to true. Basically, I want it to look like this:
timer { ObjectSpace.const_get('NextPage').new.identity? }
So my method looks like:
def timer(t = 5, &block)
timeout = Time.now + t
until Time.now > timeout
result = yield
return result if result
sleep 0.5
end
raise "Timer failed after #{t} seconds"
end
This method loops over my block until yield returns truthy. It will sleep for a half a second and timeout after t seconds, which defaults to 5. If you wanted it to return false instead of raising an error, you just need to change the last line to false.
I'm not familiar enough with appium to write the block to check for your next page, but I imagine it would look similar to my first code example above.
Is there a way in Ruby to have it print the __LINE__ number of code (at my script level, not required gems) it's working on if taking longer than 9 seconds (adjustable)?
For debugging I am getting it to print verbose output of what it's trying to do, where it is in the code etc., rather than silently sitting for long periods of time.
A flaky situation makes it unpredicable how far it gets before something times out, so successive advancing doesn't apply here.
EDIT
Something like a trap would work, such that:
The original line number and hopefully code get remembered (both benchmark and timeout gems lose track of __LINE__ for instance.... Maybe there is a way to push it off to another .rb file to manipulate the stack to include my file & line of interest?)
When the overtime warning prints, execution still continues as if nothing had changed.
require 'timeout'
def do_something
Timeout::timeout(9) do
sleep 10
end
rescue Timeout::Error => e
puts "Something near line #{__LINE__} is taking too long!"
# or, count backwards in method
puts "Line #{__LINE__ - 5} is taking too long!"
end
do_something
This will stop execution if the timeout block runs out of time and raise a Timeout error.
If you want to continue execution, you might do better with benchmark:
require 'benchmark'
time = Benchmark.realtime do
sleep 10
end
puts "Line #{__LINE__ - 2} is slow" if time > 9
One benchmark block can have multiple timers:
Benchmark.bm do |b|
b.report('sleeping:') { sleep 3 }
b.report('chomping:') { " I eat whitespace ".chomp }
end
See more about benchmark here:
http://ruby-doc.org/stdlib-1.9.3/libdoc/benchmark/rdoc/Benchmark.html
If you want to keep track of the line number being executed, why don't you try passing it in to a custom method like so:
def timethis(line, &block)
if Benchmark.realtime(&block) > 2
puts "Line #{line} is slow"
end
end
timethis(__LINE__) { sleep 1 }
Why does this code work (I see the output 1 2 3):
for i in 1..3
Thread.new{
puts i
}
end
However, the following code does not produce the same output (I do not see the output 1 2 3)?
for i in 1..3
Thread.new{
sleep(5)
puts i
}
end
When you hit the end of the script, Ruby exits. If you add sleep 10 after the final loop, you can see the output show up. (Albeit, as 3 each time, because the binding to i reflects the value at the end of processing, and the sleep causes a thread switch back to the loop.)
You might want something like:
threads = []
for i in 1..3
threads << Thread.new {
sleep 5
puts i
}
end
threads.map {|t| t.join }
That will wait for all the threads to terminate before exiting.
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