Annotated XML DTD
<!--
Seep Configuration File DTD
A Seep configuration file is a collection of 'object'
elements, each defining an object factory.
-->
<!ELEMENT objects (
object*
)>
<!--
Seep must be able to load and instantiate user-specified classes.
That means being able to determine both the string to require and
the full class name. Seep could force specification of both, but
that is awkward at best, and downright annoying when a predictable
convention is being used.
No fixed mapping from full class name to the require string
is enforced by Ruby: the language requires that the
require string and class name be provided separately by the
programmer. It is generally impossible to map from the require
string to the class name, as Ruby mandates 'CamelCase' for its
class names and lower-case for file and directory names.
Seep supports two different conventions that allow the user to
specify the full class name only. Seep also allows use of the
'general' mapping where both the full class name and require string
are specified.
The most common Ruby convention for mapping from the full class
name to a require string appears to be: set the class name
components to lower case, and convert the '::' separators to '/'.
For example, 'CamelCase::ObjectName' is associated with
'camelcase/objectname'. We call this the 'ruby' mapping.
Another mapping we have encountered employes an underscore to
separate the words delimited by upper-case letters, so that
'CamelCase::ObjectName' is associated with
'camel_case/object_name'. This one can get complicated:
'XxxxYYYYaZ' is mapped to 'xxxx_yyyya_z'.
We call this the 'underscore' mapping.
A variation on 'underscore' is 'prefixed-underscore', where a
path prefix to the full class name may be given. Using the
'prefixed-underscore mapping, the string '/a/b/C::D' implies the
require string '/a/b/c/d' and full class name 'C::D'.
The Seep configuration file allows a default mapping to be
specified; if not set explicitly, the 'ruby' mapping is the
default.
-->
<!ATTLIST objects default-class-mapping (
general|prefixed-underscore|ruby|underscore
) "ruby" #IMPLIED>
<!--
An object is really an object *factory* for a Ruby object.
All object factories are currently singleton factories: one
object is created when the first request for the object is
received, and all further requests receive the same object.
-->
<!ELEMENT object (
initializer?
attribute*
)>
<!--
Every top-level object factory must have an id, a textual tag
used to reference the object factory elsewhere in the
configuration file. An anonymous object factory, defined
as an object factory nested within another object factory,
does not have a user-specified id. If an id is specified for an
anonymous object factory it will be ignored.
An object factory has two conceptual parts, the 'object broker'
and the 'object source'. The broker determines the strategy for
object creation: singleton (lazy or eager instantiation),
prototype, per-thread. The source determines how the object is
created: using a class name and 'new', using a Seep-referenced
object as a factory, using a Ruby class method as a factory.
-->
<!ATTLIST object id CDATA>
<!--
An 'object source' specifier.
There are three 'object source' possibilities:
1) new
2) object factory
3) class factory
The 'class' attribute implies use of the object source
that uses the 'new' operator. The given class's 'new' method is
called to instantiate an object. Elements nested in an
'initialize' element are passed passed as parameters to 'new'.
The format for specifying the class is determined by the default
class mapping (see default-class-mapping above) or the class
mapping specified in this object specification (see class-mapping
below).
-->
<!ATTLIST object class CDATA>
<!--
The 'factory_id' attribute implies use of the 'object factory'
object source.
The 'factory_id' value identifies a Seep-served object
which is used as a factory. The method called defaults to
'get_instance' unless overridden by the 'factory_method'
attribute.
-->
<!ATTLIST object factory_id CDATA>
<!--
The 'factory_class' attribute implies use of the 'class factory'
object source.
The 'factory class' attribute gives the name of a class object
which is used as a factory. The method called defaults to
'get_instance' unless overridden by the 'factory_method'
attribute.
-->
<!ATTLIST object factory_class CDATA>
<!--
Additional information for the 'factory object' and 'factory
class' object sources.
-->
<!ATTLIST object factory_method CDATA>
<!--
Additional information for the 'new' and 'factory
class' object sources.
Allow each object to override the default class -> require string
mapping.
-->
<!ATTLIST object class-mapping (
general|prefixed-underscore|ruby|underscore
)>
<!--
Additional 'object source' information.
There are three types of Dependency Injection: constructor,
accessor, and interface. The 'initializer' element is how Seep
provides dependency injection of objects that must be initialized
with arguments, e.g., constructor injection.
The elements nested within the 'initialize' element specify the
arguments handed to the object initializer.
Use of an initialize element is only compatible with the 'new'
object source, identified by use of the 'class' attribute.
-->
<!ELEMENT initialize
(array|boolean|false|hash|integer|object|ref|symbol|true|value)*
>
<!--
The 'object broker' specifier.
Not Implemented
Currently the only object broker is 'singleton', hence the limited
set of options available to this (optional) element.
<!ATTLIST object broker (singleton) "singleton" #IMPLIED>
-->
<!--
Additional 'object broker' information.
Not Implemented
The singleton object broker may be either lazy or eager.
Eager implies creation of the singleton immediately upon assembly
of the Seep services; lazy implies that the singleton is not
instantiated until explicitly requested (directly or indirectly)
by user code.
<!ATTLIST object singleton_ethic (lazy|eager) "lazy" #IMPLIED>
-->
<!--
The 'attribute' element is a way that Seep provides dependency
injection for objects that can be intialized via accessor methods.
An attribute may hold one element; the contents of that element
are used to construct an object which is presented to the
assignment method for the given attribute name.
-->
<!ELEMENT attribute
(array|boolean|false|hash|integer|object|ref|symbol|true|value)
>
<!--
The attribute name is mandatory. Any named attribute (say, 'x')
must have a corresponding assignment accessor 'def x=(value)...'.
-->
<!ATTLIST attribute name CDATA #REQUIRED>
<!--
A string. May contain property values, e.g., '${blah}', which
will be substituted if a YAML file is specified for the
Seep::ContextFactory.properties_filename attribute.
-->
<!ELEMENT value (#PCDATA)>
<!--
Reference to a Seep object factory specified in this file.
-->
<!ELEMENT ref (
id
)>
<!--
A Ruby Integer object will be constructed from the text value.
-->
<!ELEMENT integer (#PCDATA)>
<!--
A Ruby true or false object will be constructed from the text
value, which must be one of 'true' or 'false'.
-->
<!ELEMENT boolean (#PCDATA)>
<!--
A Ruby true object.
-->
<!ELEMENT true EMPTY>
<!--
A Ruby false object.
-->
<!ELEMENT false EMPTY>
<!--
A Ruby Symbol object will be constructed from the text value.
The colon syntax is not required, and if used will yield a Symbol
containing a colon!
-->
<!ELEMENT symbol (#PCDATA)>
<!--
A Ruby Array object will be constructed from elements
nested within the 'array' element.
-->
<!ELEMENT array
(array|boolean|false|hash|integer|object|ref|symbol|true|value)*
>
<!--
A native Ruby Hash object will be constructed from the 'entry'
elements nested within the 'hash' element.
An 'entry' element represents one (key, value) pair in the
enclosing hash table.
There are two ways to specify a pair. The first form is:
<entry key="blah">
<a_value_element/>
</entry>
In this form, the key value is automatically converted to a
Symbol.
The second form is:
<entry>
<a_key_element/>
<a_value_element/>
</entry>
This form allows the key to be any object which can be described in
Seep.
The grammar for hash entries is admittedly awkward. The idea is
to support a compact most-common-case specification (symbol key,
object value), but also allow the most general case (object
key, object value).
The main thing I don't like about this grammar is that it
cannot be validated by DTD.
-->
<!ELEMENT hash (entry*)>
<!ELEMENT entry (
(array|boolean|false|hash|integer|object|ref|symbol|true|value)?,
(array|boolean|false|hash|integer|object|ref|symbol|true|value)
)>
<!ATTLIST entry key CDATA>