diff --git a/README.textile b/README.textile index 66dc6a0..7488300 100644 --- a/README.textile +++ b/README.textile @@ -9,6 +9,7 @@ h1. Examples of use * @cron.cancel(id)@ will stop a timed action from happening, and will interrupt the periodical execution of a periodic action. * @cron.reset()@ removes all timed and periodic actions, and resets the time passed back to 0. * @cron.update(dt)@ is needed to be executed on the main program loop. @dt@ is the amount of time that has passed since the last iteration. When @cron.update@ is executed, cron will check the list of pending actions and execute them if needed. +* @cron.tagged(tag1, tag2, tag3 ...)@ filters other cron methods (@cron.after@, @cron.every@, @cron.update@ & @cron.cancel@ but not @cron.reset@) so that they create clocks with specific tags/ act on clocks with specific tags.
local cron = require 'cron' @@ -35,6 +36,20 @@ cron.cancel(id) -- stops the execution the element defined by id. Works with per cron.reset() -- stops all the current actions, both timed ones and periodical ones.+Some tag examples: +
+ -- This has the same effect of cron.after(2, showMenu), except that the + -- time entry is tagged with the tags 'main-menu' and 'menu' + cron.tagged('main-menu', 'menu').after(2, showMenu) + + -- This updates the time entries tagged with the tag 'menu', but not the rest + cron.tagged('menu').update(2) + + -- cron.cancel does not admit filtering via tags, but it admits tags as params + -- the previous call is equivalent to this one: + cron.tagged('main-menu').cancel() ++ h1. Gotchas / Warnings diff --git a/cron.lua b/cron.lua index 290c1a5..af378f0 100644 --- a/cron.lua +++ b/cron.lua @@ -13,7 +13,8 @@ -- Private functions -local entries = {} +local entries, tagGroups -- initialized in cron.reset +local cron = {} local function isCallable(callback) local tc = type(callback) @@ -46,7 +47,7 @@ local function updateTimedEntry(self, dt) -- returns true if expired self.running = self.running + dt if self.running >= self.time then self.callback(unpack(self.args)) - entries[self] = nil + cron.cancel(self) end end @@ -59,16 +60,62 @@ local function updatePeriodicEntry(self, dt) end end --- Public functions - -local cron = {} - -function cron.reset() - entries = {} +local function addTags(...) + local tags = {...} + local len = #tags + for i=1, len do + local tag = tags[i] + taggedEntries[tag] = taggedEntries[tag] or setmetatable({}, {__mode = 'k'}) + end + return tags, len end +local function registerEntry(scope, entry) + for i=1, scope.len do + taggedEntries[scope.tags[i]][entry] = entry + end + entry.tags = scope.tags + return entry +end + +function tagged_update(scope, dt) + for i=1, scope.len do + for _,entry in pairs(taggedEntries[scope.tags[i]]) do + entry:update(dt) + end + end +end + +function tagged_cancel(scope) + for i=1, scope.len do + local tag = scope.tags[i] + for _,entry in pairs(taggedEntries[tag]) do + cron.cancel(entry) + end + taggedEntries[tag] = nil + end +end + +local function newTaggedScope(tags, len) + local scope = { tags = tags, len = len } + + scope.after = function(...) return registerEntry(scope, cron.after(...)) end + scope.every = function(...) return registerEntry(scope, cron.every(...)) end + scope.update = function(dt) tagged_update(scope, dt) end + scope.cancel = function(dt) tagged_cancel(scope) end + + return scope +end + +-- Public functions + function cron.cancel(id) entries[id] = nil + if id.tags then + for i=1, #id.tags do + taggedEntries[id.tags[i]][id] = nil + end + end end function cron.after(time, callback, ...) @@ -87,5 +134,19 @@ function cron.update(dt) for _, entry in pairs(entries) do entry:update(dt) end end +function cron.tagged(...) + return newTaggedScope(addTags(...)) +end + +function cron.reset() + entries = {} + taggedEntries = setmetatable({}, {__mode='k'}) +end + +-- tagged functions + + +cron.reset() + return cron diff --git a/spec/cron_spec.lua b/spec/cron_spec.lua index cebc078..f413457 100644 --- a/spec/cron_spec.lua +++ b/spec/cron_spec.lua @@ -128,4 +128,31 @@ describe( 'cron', function() assert_equal(counter, 1) end) end) + + describe('.tagged', function() + before(function() + cron.tagged('hello').every(5, count) -- A + cron.tagged('hello').after(2, count) -- B + cron.every(1, count) -- C + end) + + it('filters update', function() + cron.tagged('hello').update(5) + assert_equal(counter, 2) -- A + B, but not C + end) + + it('filters cancel', function() + cron.tagged('hello', 'girl').every(5, count) -- D + + cron.tagged('hello').update(5) -- A + B + D - C + assert_equal(counter, 3) + + cron.tagged('girl').cancel() + cron.tagged('hello').update(5) -- A + B - C + assert_equal(counter, 4) + + cron.tagged('girl').update(5) -- nothing (D is cancelled) + assert_equal(counter, 4) + end) + end) end)