Module mediator

Mediator pattern implementation for Lua.

mediator2 allows you to subscribe and publish to a central object so you can decouple function calls in your application. It's as simple as:

mediator:addSubscriber({"channel"}, function)

Supports namespacing, predicates, wildcards, and more.

Some basics:

Priorities

Subscribers can have priorities. The lower the number, the higher the priority. The default priority is after all existing handlers. The priorities are implemented as array-indices, so they are 1-based (highest). This also means that changing priority of a subscriber might impact the absolute value of the priority of other subscribers.

Channels

Channels have a tree structure, where each channel can have multiple sub-channels. When publishing to a channel, the parent channel will be published to as well. Channels are automatically created when subscribing or publishing to them. Technically the channel is implemented as an array of namespaces, for example: {"car", "engine", "rpm"}

Context

Subscribers can have a context. The context is a value that will be passed to the subscriber on each call. The context will be omitted from the callback if not provided (nil). It can be any valid Lua value, and usually is a table. The context doubles as a self parameter for object-based handlers.

Predicates

Subscribers can have predicates. A predicate is a function that returns a boolean. If the predicate returns true, the subscriber will be called. The predicate function will be passed the ctx (if present) + the arguments that were passed to the publish function.

Callback results

Subscriber callback functions can return 2 values:

  1. A signal to the mediator to stop or continue calling the next subscriber. Should be mediator.CONTINUE (default) or mediator.STOP.
  2. Any value to be stored in the result table and passed back to the publisher.

Info:

  • Copyright: Copyright (c) 2012-2020 Olivine Labs, 2024-2025 Thijs Schreijer
  • Release: 2.0.0
  • License: MIT

Class Subscriber

Subscriber:remove () Removes the subscriber.
Subscriber:setPriority (priority) Changes the priority of the subscriber.
Subscriber:update (updates) Updates the subscriber with new options.

Class Channel

Channel:addChannel (namespace) Adds a single namespace/sub-channel to the current channel.
Channel:addSubscriber (fn, options) Creates a subscriber and adds it to the channel.
Channel:getChannel (namespace) Gets a single namespace/sub-channel from the current channel, or creates it if it doesn't exist.
Channel:getNamespaces () Gets the full namespace array for the current channel.
Channel:hasChannel (namespace) Checks if a single namespace/sub-channel exists within the current channel.

Class Mediator

Mediator.CONTINUE Lets the mediator continue calling the next subscriber.
Mediator.STOP Stops the mediator from calling the next subscriber.
Mediator.WILDCARD A wildcard value to be used in channel namespaces to match any namespace.
Mediator:addSubscriber (channelNamespaces, fn, options) Subscribes to a channel.
Mediator:getChannel (channelNamespaces) Gets a channel by its namespaces, or creates them if they don't exist.
Mediator:publish (channelNamespaces, ...) Publishes to a channel (and its parents).


Class Subscriber

Subscriber class. This class is instantiated by the mediator:addSubscriber and Channel:addSubscriber methods.

Usage:

local m = require("mediator")()
local sub1 = m:addSubscriber({"car", "engine", "rpm"}, function(value, unit)
    print("Sub1 ", value, unit)
  end)
local sub2 = m:addSubscriber({"car", "engine", "rpm"}, function(value, unit)
    print("Sub2 ", value, unit)
  end)

m:publish({"car", "engine", "rpm"}, 1000, "rpm")
-- Output:
-- Sub1 1000 rpm
-- Sub2 1000 rpm

sub2:setPriority(1)

m:publish({"car", "engine", "rpm"}, 2000, "rpm")
-- Output:
-- Sub2 2000 rpm
-- Sub1 2000 rpm

sub1:remove()

m:publish({"car", "engine", "rpm"}, 3000, "rpm")
-- Output:
-- Sub2 3000 rpm

local options = {
  ctx = { count = 0 },       -- if provided, will be passed on each call
  predicate = nil,
  priority = 1,              -- make this one the top-priority
}
local sub3 = m:addSubscriber({"car", "engine", "rpm"}, function(ctx, value, unit)
    ctx.count = ctx.count + 1
    print("Sub3 ", ctx.count, value, unit)
    return m.STOP, count     -- stop the mediator from calling the next subscriber
  end)

local results = m:publish({"car", "engine", "rpm"}, 1000, "rpm")
-- Output:
-- Sub3 1 1000 rpm

print(results[1]) -- 1      -- the result, count, returned from subscriber sub3
Subscriber:remove ()
Removes the subscriber.

Returns:

    the removed Subscriber
Subscriber:setPriority (priority)
Changes the priority of the subscriber.

Parameters:

  • priority number The new priority of the subscriber.

Returns:

    the priority as set
Subscriber:update (updates)
Updates the subscriber with new options.

Parameters:

  • updates A table of updates options for the subscriber, with fields:
    • fn function The new callback function to be called when the channel is published to. (optional)
    • options table The new options for the subscriber, see mediator:addSubscriber for fields. (optional)

Returns:

    nothing

Class Channel

Channel class. This class is instantiated automatically by accessing channels (passing the namespace-array) to the mediator methods. To create or access one use mediator:getChannel.
Channel:addChannel (namespace)
Adds a single namespace/sub-channel to the current channel. If the channel already exists, the existing one will be returned.

Parameters:

  • namespace string The namespace of the channel to add.

Returns:

    Channel the newly created channel
Channel:addSubscriber (fn, options)
Creates a subscriber and adds it to the channel.

Parameters:

  • fn function The callback function to be called when the channel is published to.
  • options table A table of options for the subscriber. See mediator:subscribe for fields.

Returns:

    Subscriber the newly created subscriber
Channel:getChannel (namespace)
Gets a single namespace/sub-channel from the current channel, or creates it if it doesn't exist.

Parameters:

  • namespace string The namespace of the channel to get.

Returns:

    Channel the existing, or newly created channel
Channel:getNamespaces ()
Gets the full namespace array for the current channel.

Returns:

    Array the full namespace array
Channel:hasChannel (namespace)
Checks if a single namespace/sub-channel exists within the current channel.

Parameters:

  • namespace string The namespace of the channel to check.

Returns:

    boolean true if the channel exists, false otherwise

Class Mediator

Mediator class. This class is instantiated by calling on the module table.
Mediator.CONTINUE
Lets the mediator continue calling the next subscriber. This is the default value if nothing is returned from a subscriber callback.
  • CONTINUE

Usage:

    local sub = mediator:addSubscriber({"channel"}, function()
      result_data = {}
      return mediator.CONTINUE, result_data
    end)
Mediator.STOP
Stops the mediator from calling the next subscriber.
  • STOP

Usage:

    local sub = mediator:addSubscriber({"channel"}, function()
      result_data = {}
      return mediator.STOP, result_data
    end)
Mediator.WILDCARD
A wildcard value to be used in channel namespaces to match any namespace. Note: when using wildcards, the priority will be to always call the named channel first, and then the wildcard channel. So changing the priority of a subscriber has an effect within the named or wildcard channel, but not between them.
  • WILDCARD

Usage:

    local sub = mediator:addSubscriber({"part1", mediator.WILDCARD, "part2"}, function()
      print('This will be called for {"part1", "anything", "part2"}')
      print('but also for: {"part1", "otherthing", "part2"}')
    end)
Mediator:addSubscriber (channelNamespaces, fn, options)
Subscribes to a channel.

Parameters:

  • channelNamespaces array The namespace-array of the channel to subscribe to (created if it doesn't exist).
  • fn function The callback function to be called when the channel is published to. signature:
    continueSignal, result = fn([ctx,] ...)
    where result is any value to be stored in the result table and passed back to the publisher. continueSignal is a signal to the mediator to stop or continue calling the next subscriber, should be mediator.STOP or mediator.CONTINUE (default).
  • options A table of options for the subscriber, with fields:
    • ctx any The context to call the subscriber with, will be omitted from the callback if nil. (optional)
    • predicate function A function that returns a boolean. If true, the subscriber will be called. The predicate function will be passed the ctx + the arguments that were passed to the publish function. (optional)
    • priority integer The priority of the subscriber. The lower the number, the higher the priority. Defaults to after all existing handlers. (optional)
    • skipChildren boolean If true, the subscriber will only be invoked on direct publishes to this channel, but not for any child channels. (optional)

Returns:

    Subscriber the newly created subscriber
Mediator:getChannel (channelNamespaces)
Gets a channel by its namespaces, or creates them if they don't exist.

Parameters:

  • channelNamespaces array The namespace-array of the channel to get.

Returns:

    Channel the existing, or newly created channel

Usage:

    local m = require("mediator")()
    local channel = m:getChannel({"car", "engine", "rpm"})
Mediator:publish (channelNamespaces, ...)
Publishes to a channel (and its parents).

Parameters:

  • channelNamespaces array The namespace-array of the channel to publish to (created if it doesn't exist).
  • ... The arguments to pass to the subscribers.

Returns:

    table The result table after all subscribers have been called.

Usage:

    local m = require("mediator")()
    m:publish({"car", "engine", "rpm"}, 1000, "rpm")
generated by LDoc 1.5.0