I decided to start a “series” of articles which will cover small projects that can be completed in less than a day
and are fun enough for a nice Sunday morning.So yeah, hacking Sunday(that’s a cool name) starts now!
For the first one i’ll be rebuilding the node.js EventEmitter which is one of the core objects of node in plain ruby.
Before starting i already took a peak in the source for implementation ideas and read through the docs with which our ruby api will conform fully.
If you are already familiar with the node api it will be pretty straightforward since names and behaviors have been purposefully kept the same, if not, i guess that’s even more fun(or not?),
the docs are really clear and not long.
I have also posted the whole thing plus two usage examples on a gist here.
Usage and looks
Let’s support a block api as well
I will be showing the internal private methods first because we will be seeing them all over going forward.
They are three special kinds of events for new_listener, remove_listener and error which don’t follow the exact same logic as normal events do.
The check_listener_limit() will issue warnings if we have exceeded the max listener limit.
.on() and .emit() are our core methods.
For .on() first emit a new_listener event then add the listener proc to the event array
and afterwards check if the listener limit has been exceeded(to issue a warning, as node does).
For .emit(), execute all listeners for an event,if there is a reference in the @once array(an array of references of listeners registered with .once() instead of .on()) remove the listener and the reference after emitting.
If there are listeners for error events we will delegate the exception there, if not we just reraise it and crash.
The .once() method is same as .on() but it will also keep a reference of the proc name in the @once[event] array(so we can find it and remove it after emitting)
.remove_listener() does the actual work of removing the listeners(i guess we don’t want to remove new_listener, remove_listener and error). .remove_all_listeners() loops through a specific event type or through all the listeners in the instance and calls .remove_listener()