Beginning of automatic generation of template_ref.rst

This commit is contained in:
Charles Haley 2011-06-01 19:44:08 +01:00
parent efac88d69a
commit 9dac9bfbc3
2 changed files with 138 additions and 2 deletions

View file

@ -0,0 +1,93 @@
#!/usr/bin/env python
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
__license__ = 'GPL v3'
__copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
from collections import defaultdict
PREAMBLE = '''\
.. include:: global.rst
.. _templaterefcalibre:
Reference for all builtin template language functions
========================================================
Here, we document all the builtin functions available in the |app| template language. Every function is implemented as a class in python and you can click the source links to see the source code, in case the documentation is insufficient. The functions are arranged in logical groups by type.
.. contents::
:depth: 2
:local:
.. module:: calibre.utils.formatter_functions
'''
CATEGORY_TEMPLATE = '''\
{category}
{dashes}
'''
FUNCTION_TEMPLATE = '''\
{fs}
{hats}
.. autoclass:: {cn}
'''
POSTAMBLE = '''\
API of the Metadata objects
----------------------------
The python implementation of the template functions is passed in a Metadata object. Knowing it's API is useful if you want to define your own template functions.
.. module:: calibre.ebooks.metadata.book.base
.. autoclass:: Metadata
:members:
:member-order: bysource
.. data:: STANDARD_METADATA_FIELDS
The set of standard metadata fields.
.. literalinclude:: ../ebooks/metadata/book/__init__.py
:lines: 7-
'''
def generate_template_language_help():
from calibre.utils.formatter_functions import all_builtin_functions
funcs = defaultdict(dict)
for func in all_builtin_functions:
class_name = func.__class__.__name__
func_sig = getattr(func, 'doc')
x = func_sig.find(' -- ')
if x < 0:
print 'No sig for ', class_name
continue
func_sig = func_sig[:x]
func_cat = getattr(func, 'category')
funcs[func_cat][func_sig] = class_name
output = PREAMBLE
cats = sorted(funcs.keys())
for cat in cats:
output += CATEGORY_TEMPLATE.format(category=cat, dashes='-'*len(cat))
entries = [k for k in sorted(funcs[cat].keys())]
for entry in entries:
output += FUNCTION_TEMPLATE.format(fs = entry, cn=funcs[cat][entry],
hats='^'*len(entry))
output += POSTAMBLE
print output
return output # and hope that something good happens to it
if __name__ == '__main__':
generate_template_language_help()

View file

@ -57,6 +57,7 @@ class FormatterFunction(object):
doc = _('No documentation provided')
name = 'no name provided'
category = 'Unknown'
arg_count = 0
def evaluate(self, formatter, kwargs, mi, locals, *args):
@ -87,6 +88,7 @@ def __init__(self):
class BuiltinStrcmp(BuiltinFormatterFunction):
name = 'strcmp'
arg_count = 5
category = 'Relational'
__doc__ = doc = _('strcmp(x, y, lt, eq, gt) -- does a case-insensitive comparison of x '
'and y as strings. Returns lt if x < y. Returns eq if x == y. '
'Otherwise returns gt.')
@ -101,6 +103,7 @@ def evaluate(self, formatter, kwargs, mi, locals, x, y, lt, eq, gt):
class BuiltinCmp(BuiltinFormatterFunction):
name = 'cmp'
category = 'Relational'
arg_count = 5
__doc__ = doc = _('cmp(x, y, lt, eq, gt) -- compares x and y after converting both to '
'numbers. Returns lt if x < y. Returns eq if x == y. Otherwise returns gt.')
@ -117,6 +120,7 @@ def evaluate(self, formatter, kwargs, mi, locals, x, y, lt, eq, gt):
class BuiltinStrcat(BuiltinFormatterFunction):
name = 'strcat'
arg_count = -1
category = 'String Manipulation'
__doc__ = doc = _('strcat(a, b, ...) -- can take any number of arguments. Returns a '
'string formed by concatenating all the arguments')
@ -130,6 +134,7 @@ def evaluate(self, formatter, kwargs, mi, locals, *args):
class BuiltinAdd(BuiltinFormatterFunction):
name = 'add'
arg_count = 2
category = 'Arithmetic'
__doc__ = doc = _('add(x, y) -- returns x + y. Throws an exception if either x or y are not numbers.')
def evaluate(self, formatter, kwargs, mi, locals, x, y):
@ -140,6 +145,7 @@ def evaluate(self, formatter, kwargs, mi, locals, x, y):
class BuiltinSubtract(BuiltinFormatterFunction):
name = 'subtract'
arg_count = 2
category = 'Arithmetic'
__doc__ = doc = _('subtract(x, y) -- returns x - y. Throws an exception if either x or y are not numbers.')
def evaluate(self, formatter, kwargs, mi, locals, x, y):
@ -150,6 +156,7 @@ def evaluate(self, formatter, kwargs, mi, locals, x, y):
class BuiltinMultiply(BuiltinFormatterFunction):
name = 'multiply'
arg_count = 2
category = 'Arithmetic'
__doc__ = doc = _('multiply(x, y) -- returns x * y. Throws an exception if either x or y are not numbers.')
def evaluate(self, formatter, kwargs, mi, locals, x, y):
@ -160,6 +167,7 @@ def evaluate(self, formatter, kwargs, mi, locals, x, y):
class BuiltinDivide(BuiltinFormatterFunction):
name = 'divide'
arg_count = 2
category = 'Arithmetic'
__doc__ = doc = _('divide(x, y) -- returns x / y. Throws an exception if either x or y are not numbers.')
def evaluate(self, formatter, kwargs, mi, locals, x, y):
@ -170,6 +178,8 @@ def evaluate(self, formatter, kwargs, mi, locals, x, y):
class BuiltinTemplate(BuiltinFormatterFunction):
name = 'template'
arg_count = 1
category = 'Recursion'
__doc__ = doc = _('template(x) -- evaluates x as a template. The evaluation is done '
'in its own context, meaning that variables are not shared between '
'the caller and the template evaluation. Because the { and } '
@ -185,6 +195,7 @@ def evaluate(self, formatter, kwargs, mi, locals, template):
class BuiltinEval(BuiltinFormatterFunction):
name = 'eval'
arg_count = 1
category = 'Recursion'
__doc__ = doc = _('eval(template) -- evaluates the template, passing the local '
'variables (those \'assign\'ed to) instead of the book metadata. '
' This permits using the template processor to construct complex '
@ -198,6 +209,7 @@ def evaluate(self, formatter, kwargs, mi, locals, template):
class BuiltinAssign(BuiltinFormatterFunction):
name = 'assign'
arg_count = 2
category = 'Other'
__doc__ = doc = _('assign(id, val) -- assigns val to id, then returns val. '
'id must be an identifier, not an expression')
@ -208,6 +220,7 @@ def evaluate(self, formatter, kwargs, mi, locals, target, value):
class BuiltinPrint(BuiltinFormatterFunction):
name = 'print'
arg_count = -1
category = 'Other'
__doc__ = doc = _('print(a, b, ...) -- prints the arguments to standard output. '
'Unless you start calibre from the command line (calibre-debug -g), '
'the output will go to a black hole.')
@ -219,14 +232,16 @@ def evaluate(self, formatter, kwargs, mi, locals, *args):
class BuiltinField(BuiltinFormatterFunction):
name = 'field'
arg_count = 1
category = 'Get values from metadata'
__doc__ = doc = _('field(name) -- returns the metadata field named by name')
def evaluate(self, formatter, kwargs, mi, locals, name):
return formatter.get_value(name, [], kwargs)
class BuiltinRaw_field(BuiltinFormatterFunction):
class BuiltinRawField(BuiltinFormatterFunction):
name = 'raw_field'
arg_count = 1
category = 'Get values from metadata'
__doc__ = doc = _('raw_field(name) -- returns the metadata field named by name '
'without applying any formatting.')
@ -236,6 +251,7 @@ def evaluate(self, formatter, kwargs, mi, locals, name):
class BuiltinSubstr(BuiltinFormatterFunction):
name = 'substr'
arg_count = 3
category = 'String Manipulation'
__doc__ = doc = _('substr(str, start, end) -- returns the start\'th through the end\'th '
'characters of str. The first character in str is the zero\'th '
'character. If end is negative, then it indicates that many '
@ -249,6 +265,7 @@ def evaluate(self, formatter, kwargs, mi, locals, str_, start_, end_):
class BuiltinLookup(BuiltinFormatterFunction):
name = 'lookup'
arg_count = -1
category = 'Iterating over values'
__doc__ = doc = _('lookup(val, pattern, field, pattern, field, ..., else_field) -- '
'like switch, except the arguments are field (metadata) names, not '
'text. The value of the appropriate field will be fetched and used. '
@ -276,6 +293,7 @@ def evaluate(self, formatter, kwargs, mi, locals, val, *args):
class BuiltinTest(BuiltinFormatterFunction):
name = 'test'
arg_count = 3
category = 'If-then-else'
__doc__ = doc = _('test(val, text if not empty, text if empty) -- return `text if not '
'empty` if the field is not empty, otherwise return `text if empty`')
@ -288,6 +306,7 @@ def evaluate(self, formatter, kwargs, mi, locals, val, value_if_set, value_not_s
class BuiltinContains(BuiltinFormatterFunction):
name = 'contains'
arg_count = 4
category = 'If-then-else'
__doc__ = doc = _('contains(val, pattern, text if match, text if not match) -- checks '
'if field contains matches for the regular expression `pattern`. '
'Returns `text if match` if matches are found, otherwise it returns '
@ -303,6 +322,7 @@ def evaluate(self, formatter, kwargs, mi, locals,
class BuiltinSwitch(BuiltinFormatterFunction):
name = 'switch'
arg_count = -1
category = 'Iterating over values'
__doc__ = doc = _('switch(val, pattern, value, pattern, value, ..., else_value) -- '
'for each `pattern, value` pair, checks if the field matches '
'the regular expression `pattern` and if so, returns that '
@ -323,6 +343,7 @@ def evaluate(self, formatter, kwargs, mi, locals, val, *args):
class BuiltinInList(BuiltinFormatterFunction):
name = 'in_list'
arg_count = 5
category = 'List Lookup'
__doc__ = doc = _('in_list(val, separator, pattern, found_val, not_found_val) -- '
'treat val as a list of items separated by separator, '
'comparing the pattern against each value in the list. If the '
@ -340,6 +361,8 @@ def evaluate(self, formatter, kwargs, mi, locals, val, sep, pat, fv, nfv):
class BuiltinStrInList(BuiltinFormatterFunction):
name = 'str_in_list'
arg_count = 5
category = 'List Lookup'
category = 'Iterating over values'
__doc__ = doc = _('str_in_list(val, separator, string, found_val, not_found_val) -- '
'treat val as a list of items separated by separator, '
'comparing the string against each value in the list. If the '
@ -360,6 +383,7 @@ def evaluate(self, formatter, kwargs, mi, locals, val, sep, str, fv, nfv):
class BuiltinRe(BuiltinFormatterFunction):
name = 're'
arg_count = 3
category = 'String Manipulation'
__doc__ = doc = _('re(val, pattern, replacement) -- return the field after applying '
'the regular expression. All instances of `pattern` are replaced '
'with `replacement`. As in all of calibre, these are '
@ -371,6 +395,7 @@ def evaluate(self, formatter, kwargs, mi, locals, val, pattern, replacement):
class BuiltinIfempty(BuiltinFormatterFunction):
name = 'ifempty'
arg_count = 2
category = 'If-then-else'
__doc__ = doc = _('ifempty(val, text if empty) -- return val if val is not empty, '
'otherwise return `text if empty`')
@ -383,6 +408,7 @@ def evaluate(self, formatter, kwargs, mi, locals, val, value_if_empty):
class BuiltinShorten(BuiltinFormatterFunction):
name = 'shorten'
arg_count = 4
category = 'String Manipulation'
__doc__ = doc = _('shorten(val, left chars, middle text, right chars) -- Return a '
'shortened version of the field, consisting of `left chars` '
'characters from the beginning of the field, followed by '
@ -408,6 +434,7 @@ def evaluate(self, formatter, kwargs, mi, locals,
class BuiltinCount(BuiltinFormatterFunction):
name = 'count'
arg_count = 2
category = 'List Manipulation'
__doc__ = doc = _('count(val, separator) -- interprets the value as a list of items '
'separated by `separator`, returning the number of items in the '
'list. Most lists use a comma as the separator, but authors '
@ -419,6 +446,7 @@ def evaluate(self, formatter, kwargs, mi, locals, val, sep):
class BuiltinListitem(BuiltinFormatterFunction):
name = 'list_item'
arg_count = 3
category = 'List Lookup'
__doc__ = doc = _('list_item(val, index, separator) -- interpret the value as a list of '
'items separated by `separator`, returning the `index`th item. '
'The first item is number zero. The last item can be returned '
@ -439,6 +467,7 @@ def evaluate(self, formatter, kwargs, mi, locals, val, index, sep):
class BuiltinSelect(BuiltinFormatterFunction):
name = 'select'
arg_count = 2
category = 'List Lookup'
__doc__ = doc = _('select(val, key) -- interpret the value as a comma-separated list '
'of items, with the items being "id:value". Find the pair with the'
'id equal to key, and return the corresponding value.'
@ -456,6 +485,7 @@ def evaluate(self, formatter, kwargs, mi, locals, val, key):
class BuiltinSublist(BuiltinFormatterFunction):
name = 'sublist'
arg_count = 4
category = 'List Manipulation'
__doc__ = doc = _('sublist(val, start_index, end_index, separator) -- interpret the '
'value as a list of items separated by `separator`, returning a '
'new list made from the `start_index` to the `end_index` item. '
@ -486,6 +516,7 @@ def evaluate(self, formatter, kwargs, mi, locals, val, start_index, end_index, s
class BuiltinSubitems(BuiltinFormatterFunction):
name = 'subitems'
arg_count = 3
category = 'List Manipulation'
__doc__ = doc = _('subitems(val, start_index, end_index) -- This function is used to '
'break apart lists of items such as genres. It interprets the value '
'as a comma-separated list of items, where each item is a period-'
@ -523,6 +554,7 @@ def evaluate(self, formatter, kwargs, mi, locals, val, start_index, end_index):
class BuiltinFormatDate(BuiltinFormatterFunction):
name = 'format_date'
arg_count = 2
category = 'Get values from metadata'
__doc__ = doc = _('format_date(val, format_string) -- format the value, '
'which must be a date, using the format_string, returning a string. '
'The formatting codes are: '
@ -551,6 +583,7 @@ def evaluate(self, formatter, kwargs, mi, locals, val, format_string):
class BuiltinUppercase(BuiltinFormatterFunction):
name = 'uppercase'
arg_count = 1
category = 'String case changes'
__doc__ = doc = _('uppercase(val) -- return value of the field in upper case')
def evaluate(self, formatter, kwargs, mi, locals, val):
@ -559,6 +592,7 @@ def evaluate(self, formatter, kwargs, mi, locals, val):
class BuiltinLowercase(BuiltinFormatterFunction):
name = 'lowercase'
arg_count = 1
category = 'String case changes'
__doc__ = doc = _('lowercase(val) -- return value of the field in lower case')
def evaluate(self, formatter, kwargs, mi, locals, val):
@ -567,6 +601,7 @@ def evaluate(self, formatter, kwargs, mi, locals, val):
class BuiltinTitlecase(BuiltinFormatterFunction):
name = 'titlecase'
arg_count = 1
category = 'String case changes'
__doc__ = doc = _('titlecase(val) -- return value of the field in title case')
def evaluate(self, formatter, kwargs, mi, locals, val):
@ -575,6 +610,7 @@ def evaluate(self, formatter, kwargs, mi, locals, val):
class BuiltinCapitalize(BuiltinFormatterFunction):
name = 'capitalize'
arg_count = 1
category = 'String case changes'
__doc__ = doc = _('capitalize(val) -- return value of the field capitalized')
def evaluate(self, formatter, kwargs, mi, locals, val):
@ -583,6 +619,7 @@ def evaluate(self, formatter, kwargs, mi, locals, val):
class BuiltinBooksize(BuiltinFormatterFunction):
name = 'booksize'
arg_count = 0
category = 'Get values from metadata'
__doc__ = doc = _('booksize() -- return value of the size field')
def evaluate(self, formatter, kwargs, mi, locals):
@ -596,6 +633,7 @@ def evaluate(self, formatter, kwargs, mi, locals):
class BuiltinOndevice(BuiltinFormatterFunction):
name = 'ondevice'
arg_count = 0
category = 'Get values from metadata'
__doc__ = doc = _('ondevice() -- return Yes if ondevice is set, otherwise return '
'the empty string')
@ -607,6 +645,7 @@ def evaluate(self, formatter, kwargs, mi, locals):
class BuiltinFirstNonEmpty(BuiltinFormatterFunction):
name = 'first_non_empty'
arg_count = -1
category = 'Iterating over values'
__doc__ = doc = _('first_non_empty(value, value, ...) -- '
'returns the first value that is not empty. If all values are '
'empty, then the empty value is returned.'
@ -623,6 +662,7 @@ def evaluate(self, formatter, kwargs, mi, locals, *args):
class BuiltinAnd(BuiltinFormatterFunction):
name = 'and'
arg_count = -1
category = 'Boolean'
__doc__ = doc = _('and(value, value, ...) -- '
'returns the string "1" if all values are not empty, otherwise '
'returns the empty string. This function works well with test or '
@ -639,6 +679,7 @@ def evaluate(self, formatter, kwargs, mi, locals, *args):
class BuiltinOr(BuiltinFormatterFunction):
name = 'or'
arg_count = -1
category = 'Boolean'
__doc__ = doc = _('or(value, value, ...) -- '
'returns the string "1" if any value is not empty, otherwise '
'returns the empty string. This function works well with test or '
@ -655,6 +696,7 @@ def evaluate(self, formatter, kwargs, mi, locals, *args):
class BuiltinNot(BuiltinFormatterFunction):
name = 'not'
arg_count = 1
category = 'Boolean'
__doc__ = doc = _('not(value) -- '
'returns the string "1" if the value is empty, otherwise '
'returns the empty string. This function works well with test or '
@ -671,6 +713,7 @@ def evaluate(self, formatter, kwargs, mi, locals, *args):
class BuiltinMergeLists(BuiltinFormatterFunction):
name = 'merge_lists'
arg_count = 3
category = 'List Manipulation'
__doc__ = doc = _('merge_lists(list1, list2, separator) -- '
'return a list made by merging the items in list1 and list2, '
'removing duplicate items using a case-insensitive compare. If '
@ -716,7 +759,7 @@ def evaluate(self, formatter, kwargs, mi, locals, list1, list2, separator):
builtin_ondevice = BuiltinOndevice()
builtin_or = BuiltinOr()
builtin_print = BuiltinPrint()
builtin_raw_field = BuiltinRaw_field()
builtin_raw_field = BuiltinRawField()
builtin_re = BuiltinRe()
builtin_select = BuiltinSelect()
builtin_shorten = BuiltinShorten()