Saturday, March 22, 2014

Reg for ZCA addicts - Part 1: Adapter

Recently I have been exploring Reg, a library inspired by zope.component written by Faassen, and I found its simplification of ZCA to be pretty interesting. Being really loving ZCA for a while now, I end up trying to figure out how the ZCA patterns fits if I were to use Reg in my future projects. So here are the list of items I discovered so far:

Adapters
This is the most common pattern I use with ZCA, primarily to simplify writing logic by standardizing the interface of objects I work with into a common set of behavior/functions:

In ZCA , adapters are done this way:

from zope import interface
from zope import component

class IDog(interface.Interface):
    def bark():
        pass

class Dog(object):
    interface.implements(IDog)

    def bark(self):
        return 'Woof'

class IDuck(interface.Interface):
    def quack():
        pass

class Duck(object):
    interface.implements(IDuck)

    def quack(self):
        return 'Quack'

class IAnimalSoundAdapter(interface.Interface):
    def make_sound():
        pass

class DogSoundAdapter(grok.Adapter):
    interface.implements(IAnimalAdapter)
    interface.adapts(IDog) 

    def __init__(self, dog):
        self._dog = dog

    def make_sound(self):
        return self._dog.bark()

class DuckSoundAdapter(grok.Adapter):
    interface.implements(IAnimalSoundAdapter)
    interface.adapts(IDuck)

    def __init__(self, duck):
        self._duck = duck

    def make_sound(self):
        return self._duck.quack()

gsm = component.getGlobalSiteManager()
gsm.registerAdapter(DogSoundAdapter, (IDog,), IAnimalSoundAdapter)
gsm.registerAdapter(DuckSoundAdapter, (IDuck,), IAnimalSoundAdapter)

dog = Dog()
duck = Duck()

dog.bark() # Woof
duck.quack() # Quack

IAnimalSoundAdapter(dog).make_sound() # Woof
IAnimalSoundAdapter(duck).make_sound() # Quack

And that is quite a code, which utilizes classes, and large external interfaces libraries and component libraries which might can make many pythonistas cringe. 

In Reg, things are simplified. Similar functionality is done not through interfaces and complex object/class markers, but through simple functions. Reg adapter interfaces are simply functions:

import reg
import reg.implicit


class Dog(object):
    def bark(self):
        return 'Woof'

class Duck(object):
    def quack(self):
        return 'Quack'

@reg.generic
def make_sound(obj):
    raise NotImplementedError

def dog_sound(dog):
    return dog.bark()

def duck_sound(duck):
    return duck.quack()

registry = reg.Registry()
reg.implicit.initialize(registry)

registry.register(make_sound, [Dog], dog_sound)
registry.register(make_sound, [Duck], duck_sound)

dog = Dog()
duck = Duck()

make_sound(dog) # Woof
make_sound(duck) # Quack

Now, ZCA users might shout by now, "I want class based adapters!" (I know I did). This is how it can be implemented in Reg:

import reg
import reg.implicit

class Dog(object):
    def bark(self):
        return 'Woof'

class Duck(object):
    def quack(self):
        return 'Quack'

@reg.generic
def animal_sound_adapter(obj):
    raise NotImplementedError

class DogSoundAdapter(object):

    def __init__(self, dog):
        self._dog = dog

    def make_sound(self):
        return self._dog.bark()

class DuckSoundAdapter(object):

    def __init__(self, duck):
        self._duck = duck

    def make_sound(self):
        return self._duck.quack() 

registry = reg.Registry()
reg.implicit.initialize(registry)

registry.register(animal_sound_adapter, [Dog], DogSoundAdapter)
registry.register(animal_sound_adapter, [Duck], DuckSoundAdapter)

dog = Dog()
duck = Duck()

animal_sound_adapter(dog).make_sound() # Woof
animal_sound_adapter(duck).make_sound() # Quack

Thats it for now, next one I will probably share about multiadapters on Reg.
Post a Comment
Locations of visitors to this page