Sorrows mudlib: An event notification/subscription model, part 3
Previous post: Sorrows mudlib: An event notification/subscription model, part 2
I've settled on three methods of registering for events using my module. My events module will only directly support the first two, and while the third is my preferred approach, it requires the legwork to be done externally.
- Manual registration of object instances.
- Manual registration of direct callbacks.
- Automatic registration of object instances.
EventHandler
, named events
. Remember that what events an instance is registered for, is intended to be determined by the name of functions within the class of the instance. Specifically, functions named with the prefix of event_
.Manual registration of object instances
The most likely use of this approach, is an instance registering itself by a call within its
__init__
function.class SomeObject:This approach is problematic however if you are using a code reloading system, like I am. Adding a call to
def __init__(self):
events.Register(self)
Register
within __init__
in a change to a relevant class, will leave existing instances unregistered for any events you have added. Removing a call to Register
within __init__
in a change to a relevant class, will leave existing instances registered for any events they were previously registered for.Manual registration of direct callbacks
Often there is a need to dynamically register a callback for events, which is what this approach allows.
class SomeObject:It also suffers from the same problems related to code reloading systems, as the previous approach.
def Callback(self):
pass
instance = SomeObject()
events.SomeEvent.Register(instance.Callback)
Automatic registration of object instances
As mentioned at the top of this post, this approach has to be driven by external legwork. In my case, this will be my code reloading system. All a developer will have to do, is name a function intended to be notified of an event within a class, with the
event_
prefix.class SomeObject:The external legwork would look something like the following.
def event_SomeEvent(self):
pass
def OnClassChanged(class_, instances):The code reloading system would be required to provide a callback notifying that a class had been changed, and also a list of the instances of the class that are in existence. This is information that the code reloading system would most likely have.
oldEvents = getattr(class_, "__EVENTS__", set())
matches = eh.ProcessClass(class_)
if len(matches):
## Handle instances yet to be created.
old_init = class_.__init__
def new_init(self, *args, **kwargs):
eh.Register(self)
old_init(*args, **kwargs)
class_.__init__ = new_init
## Handle existing instances.
newEvents = set([ t[0] for t in matches ])
# Remove existing registrations.
removedEvents = oldEvents - newEvents
addedEvents = newEvents - oldEvents
matchesLookup = dict(matches)
for instance in instances:
for eventName in removedEvents:
eh._Unregister(eventName, instance)
functionName = matchesLookup[eventName]
for eventName in addedEvents:
eh._Register(eventName, instance, functionName)
class_.__EVENTS__ = newEvents
Conclusion
The event model is now ready for use in my MUD framework. I still need to decide how to make it available for use, whether through a built-in
EventHandler
instance or otherwise. And I still need to link it up to the code reloading system.Source code: events.py
No comments:
Post a Comment