Language: en

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>