Assemblage is an object assembler for Python programs. It can produce instances of arbitrary classes, along which the required dependencies, effortlessly.
Assemblage can be installed by easy_install:
# easy_install assemblage
An assembler object, capable of instantiate registered types and and their dependencies, is easily produced:
import assemblage assembler = assemblage.assembler()
Let lightbulb be a type defined as below:
class lightbulb(object): pass
The following line registers this type in the assembler object:
assembler.register(lightbulb)
And a instance of lightbulb is built by the following call:
assembler.provide(lightbulb)
Types might have dependencies. Assemblage is capable of providing these dependencies by passing them to the type constructor.
Let bedroom be a type defined as below:
class car(object): def __init__(self, bed, wardrobe, lightbulb): self.bed = bed self.wardrobe = wardrobe self.lightbulb = lightbulb
Instances of bedroom require instances of the types bed, wardrobe and lightbulb. These requirements, therefore, must be expressed when the bedroom type is registered in the assembler:
assembler.register(bedroom, requires=[bed, wardrobe, lightbulb])
Instances of the required classes will be automatically provided when an instance of bedroom is requested:
assembler.provide(bedroom)
Often, an usable object cannot be built by a simple constructor call. In cases like these, a factory method can be provided to instruct the assembler on how to build the desired type.
Let trash_can be a type as defined below:
class trash_can(object): def __init__(self): self.bag = None def set_plastic_bag(self, bag): self.bag = bag
The assembler can produce instances of the trash_can class, and automatically feed them instances of plastic_bag, through the usage of a factory method:
def make_trash_can(plastic_bag): trash = trash_can() bag = plastic_bag() trash.set_plastic_bag(bag) return trash assembler.register(trash_can, depends=[plastic_bag], factory=make_trash_can)
By default, the assembler will cache every object it produces. Then, when an instance of a type is requested, the assembler will return the previously cached instance of that type, if it exists.
It's possible to have a new instance produced at every provide call by registering the type as uncacheable:
assembler.register(plastic_bag, cacheable=False)
It's possible to implement different scopes for the objects in an application by using different assembler objects. Still, it's convenient to have different assemblers sharing cached instances and construction rules.
Given an assembler, an child assembler can be produced:
child_assembler = parent_assembler.spawn_child()
The child assembler have access to all construction rules and cached instances present in the parent assembler.