Hi folks. First, let me thank you all for these great tools, Elixir and
soaplib. They're both immeasurably helpful to our product.
Unfortunately, though, they're two great tastes that don't taste great
together. Specifically, a class that attempts to inherit from both Elixir's
Entity class and soaplib's ClassSerializer class fails because both Entity
and ClassSerializer rely on helpful metaclasses, and as we all learned from
"Highlander," there can be only one.
What makes this inability to compose metaclasses particularly painful in
this case, though, is that they have extremely similar goals: mutatis
mutandis, both are concerned with allowing the user to specify attributes of
the class that the metaclass is of, as well as some metadata about their
types. This metadata is sufficient to support a transformation on the graph
of instances of the class that the metaclass is of. In the case of Elixir,
the transformation is between the object graph and the kinda-sorta set
theory of a SQL database schema; in the case of soaplib, the transformation
is between the object graph and the textual serialization of the XML infoset
representing a SOAP envelope. The Elixir Entity ends up with a "table"
attribute containing this metadata, constructed using the "has_one,"
"has_many," "belongs_to," and "has_and_belongs_to_many" statements; the
soaplib ClassSerializer ends up with a "soap_members" attribute containing
this metadata, constructed using the "types" nested class.
It would seem potentially beneficial to attempt to derive a uniform API for:
* Describing some subset of the attributes of a class and their types.
* Given an object graph with such descriptions, perform transformations on
the graph:
incrementally or
atomically
* Process nodes based on both their value and type metadata
* Support lifecycle customization (before transformation, before node,
after node, after transformation)
This really just sounds like a combination of visitor and observer patterns,
and possibly the strategy pattern for processing the nodes. Elixir would
provide a SQLization strategy; soaplib would provide an XMLization strategy.
Of course, this glosses over a great many details, such as how each system
would attach system-specific metadata, e.g. "required" for Elixir or
"min/max" for soaplib. One approach might be to leverage decorators, since
decorators compose over the thing they decorate.
Any thoughts?
In the meantime, does anyone have any concrete advice on how to use Elixir
and soaplib together? Ben Bangert suggested having my class only inherit
from Entity, and then adding ClassSerializer manually:
class Foo(Entity):
...
Foo.__bases__ = Foo.__bases__ + (ClassSerializer,)
Naturally, actually attempting to use Foo in normal soaplib practice fails
because no initialization on the metaclass has been done--the metadata that
ClassSerializerMeta.__init__ creates obviously hasn't been created--so I
tried:
class Foo(Entity):
...
Foo.__bases__ = Foo.__bases__ + (ClassSerializer,)
ClassSerializerMeta.__init__(Foo, "Foo", [], {})
This complains that __init__ wants an instance of ClassSerializerMeta and
instead is getting an instance of EntityMeta. So I tried:
class Foo(Entity):
...
Foo.__bases__ = Foo.__bases__ + (ClassSerializer,)
_old = Foo.__metaclass__
Foo.__metaclass__ = ClassSerializerMeta
ClassSerializerMeta.__init__(Foo, "Foo", [], {})
Foo.__metaclass__ = _old
Python isn't fooled one bit: __init__ still complains that it's getting an
instance of EnityMeta, not ClassSerializerMeta. At this point I decided that
this was getting too ugly, talked to Ben Bangert about it some more, and he
encouraged me to discuss it here. So here it is.
Many thanks and best regards,
Paul Snively
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"SQLElixir" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at
http://groups.google.com/group/sqlelixir?hl=en
-~----------~----~----~----~------~----~------~--~---