Introduction
Ruby’s use of blocks, coupled with its parentheses-optional syntax, make it very easy to define iterator methods that look like and behave like control structures. One simple example is the loop method of the kernel. In this article, we will discuss some examples that uses ruby’s threading API.
Delaying and Repeating Execution: after and every
#
# Define Kernel methods after and every for deferring blocks of code.
# Examples:
#
# after 1 { puts "done" }
# every 60 { redraw_clock }
#
# Both methods return Thread objects. Call kill on the returned objects
# to cancel the execution of the code.
#
# Note that this is a very naive implementation. A more robust # implementation would use a single global timer thread for all tasks,
# would allow a way to retrieve the value of a deferred block, and would
# provide a way to wait for all pending tasks to complete.
#
# Execute block after sleeping the specified number of seconds. def after(seconds, &block) Thread.new do # In a new thread...
sleep(seconds) # First sleep
block.call # Then call the block
end # Return the Thread object right away
end
# Repeatedly sleep and then execute the block.
# Pass value to the block on the first invocation.
# On subsequent invocations, pass the value of the previous invocation.
def every(seconds, value=nil, &block)
Thread.new do # In a new thread...
loop do # Loop forever (or until break in block)
sleep(seconds) # Sleep
value = block.call(value) # And invoke block
end # Then repeat..
end # every returns the Thread
end
The example above contains global methods named after and every. Each takes a numeric argument that represents a number of seconds and should have a block associated with it. after creates a new thread and returns the Thread object immediately. The newly created thread sleeps for the specified number of seconds and then calls (with no arguments) the block you provided. every is similar, but it calls the block repeatedly, sleeping the specified number of seconds between calls. The second argument to every is a value to pass to the first invocation of the block. The return value of each invocation becomes the value passed for the next invocation. The block associated with every can use break to prevent any future invocations.