Here's the description of the debounce function from Underscore.js:
Creates and returns a new debounced version of the passed function that will postpone its execution until after wait milliseconds have elapsed since the last time it was invoked. Useful for implementing behavior that should only happen after the input has stopped arriving. For example: rendering a preview of a Markdown comment, recalculating a layout after the window has stopped being resized, and so on.
Is there a simple way to implement such behavior using watchr? I'm editing database file, so I can't controll when it's saved. And I want to do something with ruby when I'm done editing.
Not so simple solution - with Thread:
class Debouncer
def initialize(seconds, &block)
#seconds = seconds
#block = block
end
def register_event
Thread.kill(#thread) unless #thread.nil?
#thread = Thread.new do
sleep #seconds
#block.call
end
end
end
debouncer = Debouncer.new(30) { do_thing }
watch( 'venus/database/(.*)' ) {|md| debouncer.register_event()}
Related
My app freezes when I use emit to update status on GUI.
I want to know the reason or how to avoid this freeze. Thanks for your review.
My test environment
Windows 7 x64
railsinstaller-3.0.0.exe(MD5 : 26889DE0029C01A45AD2AED873708057)
https://github.com/railsinstaller/railsinstaller-windows/releases/download/3.0.0-alpha.2/railsinstaller-3.0.0.exe
qtbindings (4.8.5.2 x86-mingw32)
qtbindings-qt (4.8.5 x86-mingw32)
The demo app is present below.
#!/usr/bin/env ruby
# encoding: UTF-8
#
require 'Qt'
class App < Qt::MainWindow
signals 'test()'
slots 'on_test()'
def initialize
super
#label = Qt::Label.new
self.centralWidget = #label
self.show
connect self, SIGNAL('test()'), SLOT('on_test()')
start_count
end
def start_count
Thread.new do
loop {
emit test()
}
end
end
def on_test()
#label.text = #label.text.to_i + 1
end
end
app = Qt::Application.new(ARGV)
App.new
app.exec
#hyde
Thank you for you answer.
Solution 2 of qtbindings seems to be no help.
connect self, SIGNAL('test()'), SLOT('on_test()')
=>
connect self, SIGNAL('test()'), SLOT('on_test()'), Qt::BlockingQueuedConnection
Solution 1 was tested and the app runs fluently.
The code of Solution 1:
#!/usr/bin/env ruby
# encoding: UTF-8
#
require 'Qt'
class App < Qt::MainWindow
slots 'on_test()'
def initialize
super
#label = Qt::Label.new
self.centralWidget = #label
self.show
#c = Qt::AtomicInt.new
start_count
start_timer
end
def start_count
Thread.new do
loop {
#c.fetchAndAddRelaxed(1)
}
end
end
def start_timer
t = Qt::Timer.new(self)
t.start(16)
connect t, SIGNAL('timeout()'), SLOT('on_test()')
end
def on_test()
#label.text = #c.fetchAndAddRelaxed(0) + 1
end
end
app = Qt::Application.new(ARGV)
App.new
app.exec
Speculation on reason: the Qt main thread event loop never gets to process application events, because it is too busy delivering queued signals. The signals are queued, because they are between threads, so slot gets called in the right thread, independent of the emitting thread (and they must be queued in this case, because slot manipulates GUI objects, which is only allowed from the main thread)
There are a few alternatives to solve this. I don't really know Ruby, or its Qt bindings, so here's just a rough outline:
Solution 1: let the thread loop go around as fast as it can:
Create an atomic variable. Either use some Ruby type, or QAtomicInt (I assume that's possible with the Ruby Qt bindings).
In your thread loop, just increment the atomic variable, instead of emitting a signal.
Add a QTimer for updating the #label.text at desired intervals. If the user is supposed to be able to read the number, I'd suggest something like 500 ms interval. Minimum sensible interval is something like 16 ms for ~60 fps update rate.
Connect the timer timeout to on_test and get the value of the atomic integer to update the text.
That way updating of the numeric value is independent of displaying it.
Solution 2: make the thread block until emitted signal is actually delivered:
Use connection type BlockingQueuedConnection (note: do not use with single thread). Add that connection type to the signal connection statement (however you do it with Ruby Qt). Then the emitting thread will block until the target slot is actually called, so the signals will only be emitted at the rate they can be processed, no faster.
Your application freezes cause you emit signals in the infinite loop but not cause of emit
I am writing an automated testing program which will test some web programs that are sometimes slow to load certain AJAX calls. For instance the user will click 'Query' which will result in a HTML 'loading' overlay for anywhere from 15 to 90 seconds. When the search completes, it will then update a table on the same page with the results.
So obviously I can increase the waiting time individually like so:
browser.td(:id => 'someId').when_present.some_action #=> will wait 30 seconds
browser.td(:id => 'someId').when_present(90).some_action #=> will wait *90* seconds
But is there a way to modify (in my case increase) the time so Watir-Webdriver always waits 90 seconds on .when_present like so:
browser.some_default = 90
browser.td(:id => 'someId').when_present.some_action #=> will wait *90* seconds
A few words of warning: Client timeout will not affect when_present. Nor will implicit wait.
Update: This monkey patch has been merged into watir-webdriver and so will no longer be needed in watir-webdriver v0.6.5. You will be able to set the timeout using:
Watir.default_timeout = 90
The wait methods are defined similar to:
def when_present(timeout = 30)
message = "waiting for #{selector_string} to become present"
if block_given?
Watir::Wait.until(timeout, message) { present? }
yield self
else
WhenPresentDecorator.new(self, timeout, message)
end
end
As you can see, the default timeout of 30 seconds is hard-coded. Therefore, there is no easy way to change it everywhere.
However, you could monkey patch the wait methods to use a default time and set it to what you want. The following monkey patch will set the default timeout to 90 seconds.
require 'watir-webdriver'
module Watir
# Can be changed within a script with Watir.default_wait_time = 30
#default_wait_time = 90
class << self
attr_accessor :default_wait_time
end
module Wait
class << self
alias old_until until
def until(timeout = Watir.default_wait_time, message = nil, &block)
old_until(timeout, message, &block)
end
alias old_while while
def while(timeout = Watir.default_wait_time, message = nil, &block)
old_while(timeout, message, &block)
end
end # self
end # Wait
module EventuallyPresent
alias old_when_present when_present
def when_present(timeout = Watir.default_wait_time, &block)
old_when_present(timeout, &block)
end
alias old_wait_until_present wait_until_present
def wait_until_present(timeout = Watir.default_wait_time)
old_wait_until_present(timeout)
end
alias old_wait_while_present wait_while_present
def wait_while_present(timeout = Watir.default_wait_time)
old_wait_while_present(timeout)
end
end # EventuallyPresent
end # Watir
Include the patch after the watir webdriver code is loaded.
I found another question very similar to mine with a solution that worked for me when I wrote it all in one simple script. I even wrote a second simple example sort of simulating what I'm trying to do, and it seemed to still work.
My simulation was:
class A
def looper(&block)
Thread.new do
loop do
exit if gets.chomp == 'q'
end
end
loop do
block.call
end
end
end
class B < A
def looper
super do
puts 'howddyyyy from B'
end
end
end
This works fine, exiting when you press q<Enter>. However, when I tried to implement this into my actual project, it fails to work. I'll post the code from the method in question in the child class, as the parent class is literally exactly the same as the example above.
def looper
super do
if obj = Object.first(:process_status => STATUS_UNPROCESSED)
puts "[Object ##{obj.id}] Processing..."
puts "-" * 60
obj.set_failed
if #obj.process(obj)
obj.set_processed
end
puts "-" * 60
puts "[Object ##{obj.id}] Finished!"
puts
puts
else
sleep 10
end
end
end
So, for some reason, this doesn't work. I put a puts into the new Thread (listening for q), and it seems to output the puts before every loop of block.call. Maybe it just isn't able to get the key, by which I mean, maybe the timeframe in which you have to enter q<Enter> is way too small? I'm not sure, which is why I'm asking some advice here. My only other guess is that it has something to do with the methods called within this method (process, or possible the Sequel calls to the database) blocking the other thread(s)?
I'm new to threading, so I have no clue.
Okay, everybody. I feel a little stupid for typing all that up, as I came to a solution not five minutes later (and one I had overlooked here on Stack Overflow).
For anyone facing a similar issue in the future, this is what I ended up doing (in the parent class):
def looper(&block)
interrupted = false
trap("INT") { interrupted = true }
until interrupted do
block.call
end
exit
end
This manages to achieve what I was essentially trying to do.
Thanks for reading!
I'm trying to do something like this, where I have two loops going in seperate threads. The problem I am having is that in the main thread, when I use gets and the script is waiting for user input, the other thread is stopped to wait as well.
class Server
def initialize
#server = TCPServer.new(8080)
run
end
def run
#thread = Thread.new(#server) { |server|
while true
newsock = server.accept
puts "some stuff after accept!"
next if !newsock
# some other stuff
end
}
end
end
def processCommand
# some user commands here
end
test = Server.new
while true do
processCommand(STDIN.gets)
end
The above is just a sample of what I want to do.
Is there a way to make the main thread block while waiting for user input?
You might want to take a look at using the select method of the IO class. Take a look at
good select example for handling select with asynchronous input. Depending upon what version of ruby you're using you might have issues with STDIN though, I'm pretty sure it always triggers the select in 1.8.6.
I'm not sure if this is what you are looking for, but I was looking for something similar and this example does exactly what I wanted. The thread will continue processing until the user hits enter, and then the thread will be able to handle your user input as desired.
user_input = nil
t1 = Thread.new do
while !user_input
puts "Running"
end
puts "Stopping per user input: #{user_input}"
end
user_input = STDIN.gets
t1.join
I need to perform some actions periodically on my GTK Ruby program and i am looking for the working example of using gobject.timeout_add() function.
here is a short example showing a timeout each second that prints the message foo. The true at the end of the timeout block means that you don't want to remove the timeout. Return false when you want the timeout to stop firing.
require 'glib2'
GLib::Timeout.add(1000) do
puts "foo"
true
end
mainloop = GLib::MainLoop.new
mainloop.run
I have found this solution, but I am not sure:
class MainWin
def initialize()
#window = Gtk::Window::new
....
periodic
end
def periodic
do_something
Glib::Timeout.add(100) { periodic }
end
end