mediador
v1.0.0
Published
EventEmitter look alike built as a mixin, with bulk listener setup support
Maintainers
Readme
Mediador
Event venue built as a mixin.
Installation
npm install mediador --saveBrowser and RequireJS
Mediador is also available for the browser and
RequireJS. You can install it with bower.
bower install mediador --saveUsage
Instance
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"])Mixin: Inheriting on/emit
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).
Off with the listener
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"])You can add the methods directly in an object
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 emitter is sent as argument
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,thisbeing 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"])It also works in bulk
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)What is the 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.
Why does Mediador inserts the 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:
- Are you really planning on using several event libraries on the same object?
- Will you gladly use a library that extends your object blindfolded and risk name collision anyways?
- Why closing the door to interacting with the properties set by the
library? You may very well wish to modify or query the
subscriptionsset.
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.
Why is there no 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
oncemethod is not required. Keep your APIs simple.
Mediador.prototype.on
on( endpoint, callback [, context [, subscriptionClass ] ] )
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 Strings 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.
Arguments
StringendpointFunctioncallback- optional
Objectcontext - optional
FunctionsubscriptionClass
Returns
Mediadorthis
on( subscriptionSet )
If 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:
- The property name will be used as the
endpoint - The
Functionwill be used as thecallback - The object itself will be used as
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.
Arguments
ObjectsubscriptionSet
Returns
Mediadorthis
Mediador.prototype.emit
emit( args )
Notifies 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.
Arguments
Objectdefault arguments object
Returns
Mediadorthis
Mediador.prototype.off
off( endpoint, callback [, context [, subscriptionClass ] ] )
Removes 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.
Arguments
ObjectendpointFunctioncallback- optional
Objectcontext - optional
FunctionsubscriptionClass
Returns
Mediadorthis
off( subscriptionSet )
If 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:
- The property name will be used as the
endpoint - The
Functionwill be used as thecallback - The object itself will be used as
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.
Arguments
ObjectsubscriptionSet
Returns
Mediadorthis
Mediador.prototype.registerSubscription
registerSubscription( subscriptionClass )
Registers the given subscription class as the one to be used with this object. Chainable
Arguments
FunctionsubscriptionClass
Returns
Mediadorthis
Mediador.getSubscriptionClassFor
getSubscriptionClassFor( target )
Returns the subscription class (Function) to be instantiated for the
provided target.
Arguments
Objecttarget
Returns
Functionfunction
Mediador.registerSubscriptionClassFor
registerSubscriptionClassFor( target, subscriptionClass )
Registers the passed subscriptionClass as to be used for the target.
If the target is null, it overrides the default.
Arguments
ObjecttargetFunctionsubscriptionClass
Mediador.createSubscriptionFor
createSubscriptionFor( target, endpoint, callback, context )
Creates and returns a subscription from the class corresponding to the
target, forwarding the endpoint, callback and context to the
constructor.
Arguments
ObjecttargetObjectendpointFunctioncallbackObjectobject
Returns
Objectsubscription
Mediador.Subscription
Mediador.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):- the
endpointis the object that represents the type of events to which this subscription is bound. In the default subscription theendpointis always of typeString, but it can be anything in other implementations. - the
callbackis aFunctionthat will be executed then the subscription is invoked. - the
contextis an object that will be used asthiswhen running thecallback.
- the
.notify(event, arguments [, venue]) : Boolean:- the subscription object should contain a method called
notifythat receives aneventof the appropiate type as the first argument (typeStringin the default Subscription) and anArrayof arguments as the second argument. The Subscription object is responsible of matching the event to it's own endpoint to find out whether it should invoke the callback or not. The notify event should return a Boolean with the result of the matching:trueif the callback was fired,falseif not. Thevenueis an optional argument that in the default Subscription object is forwarded as the last argument to the callback.
- the subscription object should contain a method called
.match(event, callback) : Boolean:- the subscription object should also contain a method called
matchthat returns whether or not the subscription matches theevent/callbackpair sent. It returns a Boolean. This method is used by the venue to be able to detach subscriptions while delegating the matching procedure to the subscription object. Testing
- the subscription object should also contain a method called
Then clone the repo and run:
> npm install
> make testLicense
Copyright 2014 Xavier Via
ISC license.
See LICENSE attached.
