Defining custom quoted-no-more classes

A quoted-no-more infectious string type is a subclass of Python's unicode string class and instances of such a type are known to not need any further quoting. It is infectious in the sense that when combined with strings of other types, those strings will be first quoted. This infectious behaviour may be summarized with (where qnm is a quoted-no-more instance and s is some other string instance):

qnm + s = qnm + QNM(s)
qnm_join([s, qnm, ...]) = QNM(s) + qnm + ...
QNM("x %(key)s") % dict(key=s) = QNM("x ") + QNM(s)

Thus, the quoted-no-more pattern is a convenient way to liberally combine strings without having to worry about whether they are quoted or not, or whether they will ever be double-quoted.

The origins of the quoted-no-more pattern is the QPY Quoted String Data Type, and it is central to Evoque -- for custom automatic once-and-only-once quoting, all templates need to do is specify a quoted-no-more class as the value of the quoting parameter.

Custom quoted-no-more classes should subbclass evoque.quoted.quoted_no_more and provide an implementation for the _quote(s) class method, whose sole responsibility is to quote a single unicode and return it as an instance of the custom quoted-no-more class itself.

To explicitly quote a string or any other object, the class method quote(obj) is what should be used. This class method is defined by the quoted_no_more base class and will internally call the _quote(s) method on the subclass -- where s is a unicode-ified representation of the obj parameter received by quote(obj).

The evoque.quoted package includes some sample quoted-no-more implementations, such as the ones for xml and url quoted strings.

example: xml

For demo purposes only, a Python implementation of the xml quoted-no-more class is included in evoque.quoted.xml:

__revision__ = "$Id$"

from evoque.quoted.quoted_no_more import quoted_no_more

class xml(quoted_no_more):
    """ xml instances are strings that require no further XML quoting
    
    NOTE: this python class is provided as a demo for how to define custom
    quoted-no-more classes in python. The QPY package provides an equivalent
    implementation of this class in C, at qpy.xml, that is much faster.
    """
    
    def _quote(cls, s):
        """ (s:unicode) -> xml """
        return cls(s.replace("&", "&"
                    ).replace("<", "&lt;"
                    ).replace(">", "&gt;"
                    ).replace('"', "&quot;"
                    ).replace("'", "&#39;")) # &apos; is not HTML.
    _quote = classmethod(_quote)
    
# generic join
xml_join = xml().join

__all__ = ["xml", "xml_join"]

To use this class, we just specify it as the value of the quoting parameter anywhere that it is supported i.e. on the domain, on collections or on any individual template. For example:

from evoque.quoted.xml import xml
domain.get_template("template.html", quoting=xml).evoque()