cron.before and cron.after now return a clock

This commit is contained in:
kikito 2013-09-25 18:40:12 +02:00
parent d7b075a076
commit c4f205460f
2 changed files with 92 additions and 115 deletions

View File

@ -28,8 +28,6 @@ local cron = {
-- Private functions
local entries -- initialized in cron.reset
local function isCallable(callback)
local tc = type(callback)
if tc == 'function' then return true end
@ -40,67 +38,61 @@ local function isCallable(callback)
return false
end
local function checkTimeAndCallback(time, callback)
assert(type(time) == "number" and time > 0, "time must be a positive number")
assert(isCallable(callback), "callback must be a function")
local function checkPositiveInteger(name, value)
if type(value) ~= "number" or value < 0 then
error(name .. " must be a positive number")
end
end
local function newEntry(time, callback, update, ...)
local entry = {
local Clock = {}
local Clock_mt = {__index = Clock}
local function newClock(time, callback, update, ...)
checkPositiveInteger('time', time)
assert(isCallable(callback), "callback must be a function")
return setmetatable({
time = time,
callback = callback,
args = {...},
running = 0,
update = update
}
entries[entry] = entry
return entry
}, Clock_mt)
end
local function updateTimedEntry(self, dt) -- returns true if expired
local function updateAfterClock(self, dt) -- returns true if expired
checkPositiveInteger('dt', dt)
if self.running >= self.time then return true end
self.running = self.running + dt
if self.running >= self.time then
self.callback(unpack(self.args))
cron.cancel(self)
return true
end
return false
end
local function updatePeriodicEntry(self, dt)
local function updateEveryClock(self, dt)
checkPositiveInteger('dt', dt)
self.running = self.running + dt
while self.running >= self.time do
self.callback(unpack(self.args))
self.running = self.running - self.time
end
end
-- Public functions
function cron.cancel(id)
entries[id] = nil
return false
end
function cron.after(time, callback, ...)
checkTimeAndCallback(time, callback)
return newEntry(time, callback, updateTimedEntry, ...)
return newClock(time, callback, updateAfterClock, ...)
end
function cron.every(time, callback, ...)
checkTimeAndCallback(time, callback)
return newEntry(time, callback, updatePeriodicEntry, ...)
return newClock(time, callback, updateEveryClock, ...)
end
function cron.update(dt)
assert(type(dt) == "number" and dt >= 0, "dt must be a non-negative number")
for _, entry in pairs(entries) do entry:update(dt) end
end
function cron.reset()
entries = {}
end
cron.reset()
return cron

View File

@ -2,7 +2,7 @@ local cron = require 'cron'
describe( 'cron', function()
local counter = 0
local counter
local function count(amount)
amount = amount or 1
counter = counter + amount
@ -11,41 +11,25 @@ describe( 'cron', function()
before_each(function()
counter = 0
cron.reset()
end)
describe('.update', function()
describe('clock', function()
describe(':update', function()
it('throws an error if dt is a negative number', function()
assert.error(function() cron.update() end)
assert.error(function() cron.update(-1) end)
assert.not_error(function() cron.update(1) end)
local clock = cron.every(1, count)
assert.error(function() clock:update() end)
assert.error(function() clock:update(-1) end)
assert.not_error(function() clock:update(1) end)
end)
end)
describe('.reset', function()
it('Cancels all timed actions', function()
cron.after(1, count)
cron.after(2, count)
cron.update(1)
assert.equal(counter, 1)
cron.reset()
cron.update(1)
assert.equal(counter, 1)
end)
it('Cancels all periodical actions', function()
cron.every(1, count)
cron.update(1)
assert.equal(counter, 1)
cron.reset()
cron.update(1)
assert.equal(counter, 1)
end)
end)
describe('.after', function()
it('Throws error if time is not a positive number, or callback is not callable', function()
it('checks parameters', function()
assert.error(function() cron.after('error', count) end)
assert.error(function() cron.after(2, 'error') end)
assert.error(function() cron.after(-2, count) end)
@ -54,28 +38,45 @@ describe( 'cron', function()
assert.not_error(function() cron.after(2, countable) end)
end)
it('Executes timed actions only once, at the right time', function()
cron.after(2, count)
cron.after(4, count)
cron.update(1)
it('produces a clock that executes actions only once, at the right time', function()
local c1 = cron.after(2, count)
local c2 = cron.after(4, count)
-- 1
c1:update(1)
assert.equal(counter, 0)
cron.update(1)
c2:update(1)
assert.equal(counter, 0)
-- 2
c1:update(1)
assert.equal(counter, 1)
cron.update(1)
c2:update(1)
assert.equal(counter, 1)
cron.update(1)
-- 3
c1:update(1)
assert.equal(counter, 1)
c2:update(1)
assert.equal(counter, 1)
-- 4
c1:update(1)
assert.equal(counter, 1)
c2:update(1)
assert.equal(counter, 2)
end)
it('Passes on parameters to the function, if specified', function()
cron.after(1, count, 2)
cron.update(1)
it('Passes on parameters to the callback', function()
local c1 = cron.after(1, count, 2)
c1:update(1)
assert.equal(counter, 2)
end)
end)
describe('.every', function()
it('Throws errors if time is not a positive number, or callback is not function', function()
it('checks parameters', function()
assert.error(function() cron.every('error', count) end)
assert.error(function() cron.every(2, 'error') end)
assert.error(function() cron.every(-2, count) end)
@ -84,49 +85,33 @@ describe( 'cron', function()
assert.not_error(function() cron.every(2, countable) end)
end)
it('Executes periodical actions periodically', function()
cron.every(3, count)
cron.update(1)
it('Invokes callback periodically', function()
local c = cron.every(3, count)
c:update(1)
assert.equal(counter, 0)
cron.update(2)
c:update(2)
assert.equal(counter, 1)
cron.update(2)
c:update(2)
assert.equal(counter, 1)
cron.update(1)
c:update(1)
assert.equal(counter, 2)
end)
it('Executes the same action multiple times on a single update if appropiate', function()
cron.every(1, count)
cron.update(2)
local c = cron.every(1, count)
c:update(2)
assert.equal(counter, 2)
end)
it('Respects parameters', function()
cron.every(1, count, 2)
cron.update(2)
local c = cron.every(1, count, 2)
c:update(2)
assert.equal(counter, 4)
end)
end)
describe('.cancel', function()
it('Cancels timed entries', function()
local id = cron.after(1, count)
cron.update(1)
assert.equal(counter, 1)
cron.cancel(id)
cron.update(1)
assert.equal(counter, 1)
end)
it('Cancels periodical entries', function()
local id = cron.every(1, count)
cron.update(1)
assert.equal(counter, 1)
cron.cancel(id)
cron.update(1)
assert.equal(counter, 1)
end)
end)
end)