Given this calls:
Taskman.queue(2.5) { print 'world!' }
Taskman.queue(1.0) { print 'hello ' }
When we do this one:
Taskman.work
You get the output:
hello world
class Taskman | |
class << self | |
def queue(delay, &block) | |
store << [delay, block] | |
end | |
def work(thread_provider: Thread) | |
workers = [] | |
while (item = store.shift) do | |
delay,task = item | |
workers << thread_provider.new do | |
sleep delay | |
task.call | |
end | |
end | |
workers.each(&:join) | |
end | |
private | |
def store | |
@queue ||= [] | |
end | |
end | |
end | |
if $PROGRAM_NAME == __FILE__ | |
Taskman.queue(2.5) { print 'world!' } | |
Taskman.queue(1.0) { print 'hello ' } | |
Taskman.work # => hello world | |
end |
require "minitest/autorun" | |
require "minitest/pride" | |
require_relative "taskman" | |
class TaskmanTest < Minitest::Spec | |
subject { Taskman } | |
describe ".queue" do | |
it "stores a job" do | |
job = -> { true } | |
list = subject.queue(0, &job) | |
value(list[0][0]).must_equal(0) | |
value(list[0][1]).must_be_instance_of(Proc) | |
end | |
end | |
describe ".work" do | |
it "creates a thread" do | |
class ThreadMock | |
@instances = [] | |
class << self | |
attr_accessor :instances | |
end | |
def initialize | |
self.class.instances << self | |
end | |
attr_accessor :called_join # accessible for test | |
def join | |
@called_join = true # I was called! | |
end | |
end | |
subject.queue(1) { true } | |
subject.work(thread_provider: ThreadMock) | |
value(ThreadMock.instances.first.called_join).must_equal(true) | |
end | |
# This version suffers race conditions | |
# it "creates a thread" do | |
# job = -> { true } | |
# subject.queue(1, &job) | |
# thread_mock = Minitest::Mock.new | |
# r = Object.new | |
# def r.join;end | |
# thread_mock.expect(:new, r) | |
# subject.work(thread_provider: thread_mock) | |
# thread_mock.verify | |
# end | |
it "does the work" do | |
executed = false | |
job = -> { executed = true } | |
subject.queue(0, &job) | |
subject.work | |
value(executed).must_equal(true) | |
end | |
end | |
end |
And now with Ruby 3: