Given this calls:
Taskman.queue(2.5) { print 'world!' }
Taskman.queue(1.0) { print 'hello ' }When we do this one:
Taskman.workYou 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: