# quoter /

Filename Size Date modified Message
test
106 B
10.3 KB
446 B
35 B
8.9 KB
2.0 KB
123 B

In dealing with text, one quotes values all the time. Single quotes. Double quotes. Curly quotes. Backticks. Funny Unicode quotes. HTML or XML markup code. Et cetera.

For simple cases, this isn't hard, and there a lot of ways to do it:

value = 'something'
print '{x}'.replace('x', value)             # {something}
print "'{}'".format(value)                  # 'value'
print "'" + value + "'"                     # 'value'
print "{}{}{}".format('"', value, '"')      # "value"
print ''.join(['"', value, '"'])            # "value"


But for such a simple, common task as wrapping values in surrounding text, it looks pretty ugly, it's very low-level, and it's easy to type the wrong character here or there. The ad hoc nature makes quoting tiresome and error-prone. It's never more so than when you're constructing multi-level quoted strings, such as Unix command line arguments, SQL commands, or HTML attributes.

So this module provides an clean, consistent, higher-level alternative.

## Usage

from quoter import single, double, backticks, braces

print single('this')       # 'this'
print double('that')       # "that"
print backticks('ls -l')   # ls -l
print braces('curlycue')   # {curlycue}


It pre-defines callable Quoters for a handful of the most common quoting styles:

• braces {example}
• brackets [example]
• angles <example>
• parens (example)
• double "example"
• single 'example'
• backticks example
• anglequote «example»
• curlysingle ‘example’
• curlysdouble “example”

But there are a huge number of ways you might want to wrap or quote text. Even considering just "quotation marks," there are well over a dozen. There are also numerous bracketing symbols in common use. That's to say nothing of the constucts seen in markup, programming, and templating languages. So quoter couldn't possibly provide an option for every possible quoting style. Instead, it provides a general-purpose mechanism for defining your own:

from quoter import Quoter

bars = Quoter('|')
print bars('x')                    # |x|

plus = Quoter('+','')
print plus('x')                    # +x

para = Quoter('<p>', '</p>')
print para('this is a paragraph')  # <p>this is a paragraph</p>

variable = Quoter('${', '}') print variable('x') #${x}


Note that bars is specified with just one symbol. If only one is given, the prefix and suffix are considered to be identical. If you really only want a prefix or a suffix, and not both, then instantiate the Quoter with two, one of which is an empty string, as in plus above. For symmetrical quotes, where the length of the prefix and the suffix are the same, you can specify the prefix and suffix all in one go. The prefix will be the first half, the second, the second half

In most cases, it's cleaner and more efficient to define a style, but there's nothing preventing you from an on-the-fly usage:

print Quoter('+[ ', ' ]+')('castle')   # +[ castle ]+


## Formatting and Encoding

The Devil, as they say, is in the details. We often don't just want quote marks wrapped around values. We also want those values set apart from the rest of the text. quoter supports this with padding and margin settings patterned on the CSS box model. In CSS, moving out from content one finds padding, a border, and then a margin. Padding can be thought of as an internal margin, and the prefix and suffix strings like the border. With that in mind:

print braces('this')                      # '{this}'
print braces('this', padding=1)           # '{ this }'
print braces('this', margin=1)            # ' {this} '
print braces('this', padding=1, margin=1) # ' { this } '


If desired, the padding and margin can be given as strings, though usually they will be integers specifying the number of spaces surrounding the text.

One can also define the encoding used for each call, per instance, or globally. If some of your quote symbox use Unicode characters, yet your output medium doesn't support them directly, this is an easy fix. E.g.:

Quoter.encoding = 'utf-8'
print curlydouble('something something')


Will output UTF-8 bytes. But in general, this is just a convenience funciton. If you're using Unicode glyphs, you should manage encoding at the time of input and output, not as each piece of output is constructed.

## Shortcuts

One often sees very long function calls and expressions as text parts are being assembled. In order to reduce this problem, quoter defines aliases for single, double, and triple quoting, as well as backticks:

from quoter import qs, qd, qt, qb

print qs('one'), qd('two'), qb('and'), qt('three')
# 'one' "two" and """three"""


You can, of course, define your own aliases as well, and/or redefine existing styles. If, for example, you like braces but wish it added a padding space by default, it's simple to redefine:

braces = Quoter('{', '}', padding=1, name='braces')
print braces('braces plus spaces!')  # '{ braces plus spaces! }'


You could still get the no-padding variation with:

print braces('no space braces', padding=0) # '{no space braces}'


## Dynamic Quoters

It is possible to define Quoters that don't just concatenate text, but that examine it and provide dynamic rewriting on the fly. For example, in finance, one often wants to present numbers with a special formatting:

from quoter import LambdaQuoter

f = lambda v: ('(', abs(v), ')') if v < 0 else ('', v, '')
financial = LambdaQuoter(f)
print financial(-3)            # (3)
print financial(45)            # 45

password = LambdaQuoter(lambda v: ('', 'x' * len(v), ''))

wf = lambda v:  ('**', v, '**') if v < 0 else ('', v, '')
warning = LambdaQuoter(wf)
print warning(12)              # 12
print warning(-99)             # **-99**


The trick is instantiating LambdaQuoter with a callable (e.g. lambda expression or function) that accepts one value and returns a tuple of three values: the quote prefix, the value (possibly rewritten), and the suffix.

LambdaQuoter is an edge case, arcing over towards being a general formatting function. That has the virtue of providing a consistent mechanism for tactical output tranformation with built-in margin and padding support. But, one could argue that such full transformations are "a bridge too far" for a quoting module. So use the dynamic component ofquoter, or not, as you see fit.

## Alternate API

It may be that you don't want a separate quote function for every style possible. In that case, registered styles can all be accessed through a single function:

from quoter import quote

print quote('tag', 'anglebrackets')


yields:

<tag>


A style is 'registered' when it's created if it's given a name. For example, to register the template variable style above, we'd use:

variable = Quoter('\${', '}', name='variable')
print quote('myvar', style='variable')


## Extended X/HTML Usage

There is an extended quoting mode designed for HTML construction. Instead of prefix and suffix strings, it takes tag names. Or more accurately, tag specifications. Like jQuery it supports id and class attributes in a style similar to that of CSS selectors. It also understands that some elements are 'void', meaning they do not want or need closing tags.:

from quoter import HTMLQuoter

para = HTMLQuoter('p')
print para('this is great!', {'class':'emphatic'})
print para('this is great!', '.emphatic')

print para('First para!', '#first')

para_e = HTMLQuoter('p.emphatic')
print para_e('this is great!')
print para_e('this is great?', '.question')

br = HTMLQuoter('br', void=True)
print br()


yields:

<p class='emphatic'>this is great!</p>
<p class='emphatic'>this is great!</p>
<p id='first'>First para!</p>
<p class='emphatic'>this is great!</p>
<p class='question'>this is great?</p>
<br>


HTMLQuoter quotes attributes by default with single quotes. If you prefer double quotes, you may set them when the element is defined:

div = HTMLQuoter('div', attquote=double)


HTMLQuoter basically works, but buyer beware: It's not as well tested as the rest of the module.

## Notes

• quoter provides simple transformations that could be alternatively implemented as a series of small functions. The problem is that such "little functions" tend to be constantly re-implemented, in different ways, and spread through many programs. That need to constantly re-implement such common and straightforward text formatting has led me to re-think how software should format text. quoter is one facet of a project to systematize higher-level formatting operations.
• quoter is also a test case for options, a module that supports flexible option handling.
• Commenced automated multi-version testing with pytest and tox. Now successfully packaged for, and tested against, Python 2.6, 2.7, 3.2, and 3.3.
• Successfully tested against PyPy 1.9 (based on Python 2.7.2).
pip install quoter

python3.3 -m easy_install quoter