|
Regarding FDoc I've mentioned FDoc in the context of Zope and the CMF on here before. I've gotten a few questions around the topic of "what is it?", so I'm going to attempt a sum-up here of what, why, where, and so on.
What is it?FDoc is a compound document framework for Zope. It's been developed in house over the past year based on work from various consulting projects. At its largest level, it's a decent sized framework addition to Zope, due to its dependencies on an unfinished event notification and inter-object relationship model. At its core, it treats content as a rich hierarchy of data, not as a mere stream of text or a single image with a fragile hyperlink between them.
Why make it?Since the firm I now work for is rather small, some of our clients have been very small. Not only were they faced with not knowing how to maintain a web site, they also didn't have time for heavy maintenance. They needed a way to enter simple text, upload pictures, and manage links, without the overhead of a site design tool and with better looking output than what a word processor could produce. So we gave them administrative screens where they could enter text, upload pictures, and enter links. In some cases, the data was very specific, like a Play information object. Other times, it was more free-form. In both cases, we essentially gave them slotted-content. While they could upload as many pictures as they wanted, and enter as much text as they wanted, the page's structure was very fixed.The architecture behind it all got heavier and heavier with each job. The separation of image/file handling, link handling, and text handling were all done via mix-ins to a very heavy Document class. There was no flexibility, yet there were more and more expectations of re-use (the kind that requires adaptability). I knew that I needed to step away from the inheritance-heavy architecture that had grown out of each job and back to the aggregation/component-esque model that I really wanted. I had worked on and thought heavily about Zope based compound content models in the past, and decided it was time to write one of my own. There are some other implementations out there, such as CMF Article, but I had different design goals in mind that what other tools offered.
The ConceptsI was a big fan of OpenDoc, the compound document concept spearheaded by Apple, IBM, and CI Labs. OpenDoc was an attempt to move away from the application-centric view of data and place emphasis on the document itself. Apple killed it just when it was really starting to pick up steam on the Mac OS, which is too bad. But it had some great ideas. In OpenDoc's view, the Document was just the outer shell. ALL content was in what it called Parts. Parts had an editor associated with them, and the editor-to-part bindings could be changed via configuration. Thus, a simple text part could be handled by a basic built in text part editor (ala Mac OS X's TextEdit or Windows' NotePad), or one could install something like BBEdit Lite (which was made available as an OpenDoc part) and configure all standard text parts to be editable by BBEdit.
Primary InterfacesSo in my designs, I decided to follow suit in some ways. I made the IDocument contractual interface very small. All that an FDoc document is contractually obligated to do is provide a way to find the Part Registry which stamps out new parts, to provide a way for Parts of a document to find their way back to the document, and to provide access to the Root Part. By keeping this contract small, it's easy to implement new Document types for different situations, such as CMF deployment. The responsibility of actually dealing with the content is passed off to the Root Part. This keeps the internal structure of a compound document the same, regardless of the world it's going to get deployed in or responsibilities it will maintain.Another fundamental contractual interface is that of the IPartContainer. Like Zope's ObjectManager class/concept, the Part Container is responsible for querying, getting, adding, deleting parts. Its other responsibilities include reordering parts and enacting a policy of what Part Types are allowed. It has no content of its own, but there is nothing stopping a Part from implementing both the IPart and IPartContainer interfaces. Which leads to the last of the primary interfaces, IPart. Parts are signified my their major and minor modes, similar to MIME types. This allows for general editors to be registered, such as image/*, which will deal with all image types unless someone registers a specific editor for PNG's. A Part has limited responsibilities in order to fit into the major system, but is generally allowed to go about its business as it sees fit. All parts must supply basic render() and renderToStream() methods, but the general architecture of a system or Document may decide to render Parts differently.
Primary Parts and ServicesOne very key service is the Part Registry. It is responsible for finding and returning Factories to instantiate new Parts, and for registering new parts into its system. It also allows applications to register extra properties for a given Part Type. This is used in FDoc CMF to register view/preview/edit "skin methods":
registry.registerPropertiesFor(
partType = 'text/*',
properties = {
'fdoc_cmf': {'view': 'textpart_view.pt',
'preview': 'textpart_preview.pt',
'edit': 'textpart_edit_form.pt'},
},
)
Which can, of course, be queried later. Other applications can register their own properties with the registry and attach them to different types.A fundamental service that isn't required but has proven to be very useful is the Handler Registry. This registry allows for componentization of text handlers, and allows a single Text Part component (and any other component that wishes to use it) to handle and allow different types of text input. For example, if I wanted to be able to add some example Python code to a document and have it be colorized, I could just write a PythonTextHandler and register it with the handler registry. The registry has some queries built in to it to list the available text types, which can be used to populate HTML forms for authors to choose their text format for a specific block of text. Having the Handler Registry allows the default TextPart to be usable for any basic document text block task, while allowing different/new formats to be registered. The default TextPart actually marries its Minor mode to that of a Handler Registry key, which can help establish what the contents of a particular text block are. 'text/safe-html', 'text/python', 'text/plain', all map to the same fundamental component. However, due to the design of the system, a PythonCodePart component could be written (even subclassing from the default TextPart) which could present some extra properties and rendering settings, like "show line numbers?", and registered with the Part Registry as 'text/python'.
What state is it in?As of October 27, 2002, FDoc is still a private framework. All of the CMF level code is primarily wrapped up in code for a consulting project. Like the CMF, FDoc is actually separated out into different frameworks. The core framework is fairly solid, but still includes a lot of commented-out code that remains from some of the pre-compound engagements that was copied into the new project. As mentioned earlier, there are half-finished services for Event Notification and Object Relations. They're not fundamental to the project, but I'd like them to be. Work inches slowly along to make it all happen.For the consulting engagement, the CMF level code has worked great. It integrated easily with the CMF, since the requirements for an FDoc document are so low. By subclassing the default FDoc document (which does very little beyond realizing the IDocument interface), and mixing in the CMFDefault default Dublin Core meta-data class, I basically had a working system. I have started copying the code that is not specific for this customer to a new Python package, but even an early release is still a ways away. I still plan on making such a release, but there is part of me that is tempted to put a lot of the work that's been done towards a Zope 3 product since it's closest in ideology to Zope 3 (very service / registry / utility / interface based). Ultimately, I wanted to answer some questions and document some of the design thinking that went behind this.
There is an older version of this story that has some different thought processes that this one, as it dealt with core framework / default implementation design issues. You can read it here. |
Navigation
|