Event venue built as a mixin.
npm install mediador --save
Mediador is also available for the browser and
RequireJS. You can install it with bower
.
bower install mediador --save
emit
maps each element in the second argument array as an argument to
send to the listener function.
var Mediador = require("mediador")
var mediador = new Mediador
mediador.on("event", function (text) {
console.log("event emitted with arg: " + text)
})
mediador.emit("event", ["hello"])
var Mediador = require("mediador")
var YourClass = function () {}
YourClass.prototype.on = Mediador.prototype.on
YourClass.prototype.emit = Mediador.prototype.emit
var yourInstance = new YourClass()
yourInstance.on("event", function (you) {
console.log(you + " already firing events!")
})
yourInstance.emit("event", ["Me"])
The simplest way to use Mediador is to make instances, but it is not the recommended way.
Mediador is a mixin. The idea is that you can add its methods to the prototypes or objects that you want to amplify with events, without having to make them inherit directly from Mediador.
The events are stored in the listeners
property within the emitter
object, in this case yourInstance
.
Bear this in mind so to not accidentally override the property.
You can find these examples in the examples
folder in this
repo. You can run them without installing mediador
by running npm link
on the repo folder (may require sudo
).
var Mediador = require("mediador")
var YourClass = function () {}
YourClass.prototype.on = Mediador.prototype.on
YourClass.prototype.off = Mediador.prototype.off
YourClass.prototype.emit = Mediador.prototype.emit
var yourInstance = new YourClass()
var listener = function (you) {
console.log(you + " already firing events!")
}
yourInstance.on("event", listener)
yourInstance.emit("event", ["Me"])
yourInstance.off("event", listener)
// Will do nothing
yourInstance.emit("event", ["Nothing"])
var Mediador = require("mediador")
var emitter = {}
emitter.on = Mediator.prototype.on
emitter.emit = Mediator.prototype.emit
emitter.on("event", function (text) {
console.log(text)
})
emitter.emit("event", ["Hello World"])
The event emitter is always sent to the listener functions as the last argument.
This is crucial, because otherwise in the contexts of many listeners there would be no available references to the emitter–the emitter would be unreachable. The emitter is needed for listeners to be able to emit further events in it–in fact, that might be the only way for a listener to pass information forward.
Another strategy to make the emitter available for the listeners would be to bind the listener to
this
,this
being the emitter object. I really don't like when libraries do that.
var Mediador = require("mediador")
var YourClass = function () {}
YourClass.prototype.on = Mediador.prototype.on
YourClass.prototype.off = Mediador.prototype.off
YourClass.prototype.emit = Mediador.prototype.emit
var yourInstance = new YourClass()
yourInstance.on("event", function (irrelevant, emitter) {
emitter.emit("completed")
})
yourInstance.on("completed", function () {
console.log("The 'event' was successfully emited and 'completed' too")
})
yourInstance.emit("event", ["something irrelevant"])
var Mediador = require("mediador")
var YourClass = function () {}
YourClass.prototype.on = Mediador.prototype.on
YourClass.prototype.off = Mediador.prototype.off
YourClass.prototype.emit = Mediador.prototype.emit
var yourInstance = new YourClass()
var subscriptionSet = {
event: function () {
console.log("Called the event")
}
}
yourInstance.on(subscriptionSet)
yourInstance.emit("event")
yourInstance.off(subscriptionSet)
subscriptionSet
?Mediador introduces the concept of an subscriptionSet
, that is just an
object where every property method will be added as a listener in the
emitter. For example, if the set has a read
method, its function will
be added as a listener for the read
event in the emitter.
This is very useful both for adding events in bulk and for removing them.
Mediador provides support for both operations in the on
and off
methods.
subscriptions
property?This is a question about namespace pollution.
When you add a subscription using the on
method, Mediador adds the
subscription to the subscriptions
property of the object, which will be
created if not present and used as it is if present. Mediador uses the
subscription
property without checking for the property's type. The
property may well have been written by another function not related to
Mediador. Is this OK?
The thing is, there are several strategies to avoid name collision within an
object, and most of them involve encapsulating the library specific data
in a private data object or using some kind of namespace (such a as
naming the property mediator_subscriptions
or _subscriptions
).
I don't favor this approach because:
subscriptions
set.In other words, I consider that using lightly a library that extends your objects is a poor design choice. Mediador and other libraries of its kind should be considered part of your design and taken for what they are: tested, encapsulated and standardized methods to achieve certain behaviors that are useful only because they save you time.
once
method?Remember:
// You can name an anonymous function to call it from within
// You can totally do this:
mediador.on("fire", function notAnonymousAnymore() {
mediador.off("fire", notAnonymousAnymore)
console.log("The 'fire' event was called")
})
Corollary: EventEmitter's
once
method is not required. Keep your APIs simple.
Creates an stores a subscription object, passing the endpoint
, callback
,
context
and the current venue (this
) to the subscription's constructor.
By default Mediador uses it's own Subscription type, which takes any kind
of endpoint
as argument and makes an equality comparison with the event
to decide whether to emit itself or not. The most common use case of this
Subscription type is to use String
s as endpoints
and events
: used in
that way, Mediador has close compatibility with Node's EventEmitter
.
The Subscription type can be overriden however, by calling
registerSubscription
in the Mediador instance or in the prototype
of a
Mediador descendant. Once overriden, the behaviour depends on the
implementation of the registered type.
If provided, the subscriptionClass
function will be used to create the
instances instead of searching for one for the current object or the parent.
Chainable.
String
endpointFunction
callbackObject
contextFunction
subscriptionClassMediador
thisIf on
is called with only one argument that is an object, the argument
will be assumed to be a subscriptionSet
. A subscriptionSet
is a way to
create subscriptions in bulk: each property of the set that has a Function
as value will be used to create a subscription:
endpoint
Function
will be used as the callback
context
The subscription type in usage should be capable of dealing with String
endpoints, so this feature is not useful if the Subscription
requires
endpoints of a different type.
Chainable.
Object
subscriptionSetMediador
thisNotifies all the subscriptions about the emission. Each subscription may decide to fire the callback or not.
To notify the subscriptions, is fires the notify
method of the
subscription passing all the arguments
plus this
, the venue, as the
last argument.
Chainable.
Object
default arguments object
Mediador
thisRemoves the subscription that matches the provided endpoint
, callback
and, if provided, context
and subscriptionClass
. By default (using the
default Mediador.Subscription
) it removes the subscription which
endpoint
is equal to the provided one and has the same context
and
callback
. The endpoint
is typically a String
, such as "event"
, and
consequently the behavior will be the same as Node EventEmitter
's. If
the subscription class has been overrided, the behavior may vary.
The off
method relies on the subscription object's match
method to
decide whether or not there is a match between the subscription and the
provided arguments.
If subscriptionClass
is provided, it checks the type of the subscription
and only if it matches, it passes all the other arguments to the match
function. If no subscriptionClass
is provided, it passes all arguments
to match
. The venue itself (this
) will also be passed to the match
method, as the last argument.
If match
returns true, the subscription will be removed from the
subcriptions
Array
. Any amount of subscriptions may be removed.
Chainable.
Object
endpointFunction
callbackObject
contextFunction
subscriptionClassMediador
thisIf off
is called with only one argument that is an object, the argument
will be assumed to be a subscriptionSet
. A subscriptionSet
is a way to
manage subscriptions in bulk: each property of the set that has a Function
as value will be used by off
to remove a subscription:
endpoint
Function
will be used as the callback
context
The subscription type in usage should be capable of dealing with String
endpoints, so this feature is not useful if the Subscription
requires
endpoints of a different type.
Chainable.
Object
subscriptionSetMediador
thisRegisters the given subscription class as the one to be used with this object. Chainable
Function
subscriptionClassMediador
thisReturns the subscription class (Function
) to be instantiated for the
provided target
.
Object
targetFunction
functionRegisters the passed subscriptionClass
as to be used for the target
.
If the target
is null
, it overrides the default.
Object
targetFunction
subscriptionClassCreates and returns a subscription from the class corresponding to the
target
, forwarding the endpoint
, callback
and context
to the
constructor.
Object
targetObject
endpointFunction
callbackObject
objectObject
subscriptionMediador.Subscription is the default subscription object for Mediador. Mediador con be configured to use different subcription objects as long as they expose the same interface:
new <subscription>(endpoint, callback, context)
:
endpoint
is the object that represents the type of events toendpoint
is always of type String
, but it can be anything in othercallback
is a Function
that will be executed then thecontext
is an object that will be used as this
when running thecallback
..notify(event, arguments [, venue]) : Boolean
:
notify
thatevent
of the appropiate type as the first argumentString
in the default Subscription) and an Array
of argumentstrue
if the callback was fired,false
if not.venue
is an optional argument that in the default Subscription.match(event, callback) : Boolean
:
match
thatevent
/callback
Then clone the repo and run:
> npm install
> make test
Copyright 2014 Xavier Via
ISC license.
See LICENSE attached.