Comments begin with #, following the Python convention.
Each template file can have as many as five sections. None of the sections are required to be in the file, but any definitions in the file must be placed inside a section header so that the code knows how to deal with the definition. The four possible section headers are: TEMPLATES, SPECIAL-TEMPLATES, OPTIONS, VARIABLES, DEFINITIONS. And note that a section header is always placed by itself on a line and has a colon appended to it, as in TEMPLATES:.
The TEMPLATES section of the file contains template definitions for formatting references. The SPECIAL-TEMPLATES section contains definitions for creating variables within each database entry. The OPTIONS section contains definitions for various keywords that can be used to modify program behavior. The VARIABLES section contains user definitions for new variables to be made available. The difference between these definitions and those in SPECIAL-TEMPLATES is that the ones provided in the VARIABLES section are in-line Python code, whereas the former use templates. Finally, the DEFINITIONS section of the file contains Python-executable code that can then make functionality available in the form of template variables. (An example is provided in the Python API section below.
All variable definitions within the TEMPLATES, SPECIAL-TEMPLATES, and OPTIONS sections use the variable name followed by whitespace, an equals sign, more whitespace, and then the definition itself. Thus the [whitespace+=+whitespace] expression is the delimiter between variable and definition, and is required syntax.
An ellipsis ... at the end of a line indicates a line continuation. All whitespace following the ellipsis, and all whitespace preceding text on the next line, is removed from the resulting connected text.
An ellipsis in the middle of a line indicates an “implicit loop”. For details, see the Examples for namelist formatting section below.
Inside the TEMPLATES section, all of the variable definitions are intended to map to a database entrytype name. For example:
article = <au>, ``<title>,'' <journal>, <volume>, <startpage>--<endpage> (<year>).
Here the article entrytype will be typeset so that the list of authors (<au>) is followed by the article title in double quotes, the journal name in standard font (i.e. not italics), the volume number, the page range, and the year.
A variable is indicated by angle brackets, as <var> and represents the contents of a field found within the bibliography database. Thus, when typesetting the bibliography, Bibulous will replace the variable <authorlist> with the string stored in the authorlist field of the current entry being formatted. An example list of typical variables one might use is:
<au>, <booktitle>, <chapter>, <edition>, <ed>, <eid>, <endpage>, <institution>, <journal>, <nationality>, <note>, <number>, <organization>, <publisher>, <school>, <series>, <startpage>, <title>, <version>, <volume>, <year>.
This list is actually freely extensible. A user can add any additional variables needed, so that if a video field is used in a .bib database file, then this can be used within a formatted reference simply by placing <video> into the template wherever the information needs to be inserted.
Any variable placed within square brackets [] indicate that it is an optional variable — it is not required that the database have that entry. While required entries that are not defined in the BibTeX database file (.bib file) are replaced with ‘???’, and undefined optional variables are simply skipped. If a | is present within the square brackets, it indicates an “elseif” clause. That is, if the template is [<var1>|<var2> and <var3>], then the code will look for var1 as a field within the current database entry being formatted. If it does not find the entry, then it will try the next block, where it finds the two variables var2 and var3. If both are defined, then the original template [<var1>|<var2> and <var3>] is replaced with <var2> and <var3> (i.e. removing the square brackets) and proceeds to replace the two variables with their corresponding fields. If either one of var2 or var3 is undefined in the entry, then the entire optional [...] portion of the template is skipped.
If the | symbol is used to create an empty last cell, as in [<var1>|<var2>|], this indicates that while the individual cells within the optional block are themselves optional, it is required to have at least _one_ among the cells to be defined. Thus, [<note>|] has the same meaning as simply <note> does.
Nesting of [] brackets is allowed, but the syntax becomes computationally expensive to parse, so that these structures should be used sparingly:
Users that need to use [, ], #, <, >, or | symbols as formatting elements within the reference list can implement them using some custom LaTeX-markup commands: {\makeopenbracket}, {\makehashsign}, {\makeclosebracket}, {\makegreaterthan}, {\makelessthan}, or {\makeverticalbar}. Note that the curly brackets used in each case are required.
In the TEMPLATES section of the file, if an entrytype format definition contains only another entrytype name on the right hand side of the =, i.e.:
inbook = incollection
then this means that the existing incollection template should be copied for use with inbook entrytypes. (Note that incollection should be defined above this line in order for this to work.)
Note that several fields are defined by default which are not directly from the bibliography database. These are au, authorlist, citekey, citenum, ed, editorlist, endpage, and startpage. These fields are derived from the original database file, but have been reformatted. See the Default Fields section below.
Although the entrytype template definitions listed below are in alphabetical order, that can be put in any desired order within the file. (The exception to this rule is that if a definition consists of, for example:
inbook = incollection
then the incollection template must already be defined. Also note that two entrytype names are special and so cannot be used on the left hand side of the equals sign here: comment and preamble.
A user wanting a localized form of quotation should use \enquote{<title>} rather than ``<title>'', and add \usepackage{csquotes} to the preamble of the LaTeX document.
In the OPTIONS section of the file are the formatting options. None of these definitions are required. The complete list is given in the Options keywords section below, together with explanations of each.
The SPECIAL-TEMPLATES section is where users can define their own fields that get generated for every database entry evaluated. For example, the variable definition:
group = [<organization>|<institution>|<corporation>|]
in the ``SPECIAL-TEMPLATES`` section will create a ``group`` field that can be used as the variable ``<group>`` within the regular ``TEMPLATES`` section of the file. This effectively allows users to create a shortcut. Where they could write out ``[<organization>|<institution>|<corporation>|]`` inside each template that needs this structure, the special template definition allows them to replace each instance with a simple ``<group>``.
Another example usage would be the following:::
author = [<著者名>|<author-en>|]
where the ``author`` field is actually redefined to include not only the *existing* author field, but also the fields ``著者名`` or ``author-en``. That is, if the ``author`` field is missing in the database entry, the code next searches for the ``著者名`` field. If it finds it, then it will create an ``author`` field that contains a copy of the ``著者名``'s field's contents. If the ``著者名`` is also missing, the code next searches for ``author-en`` and uses that fields contents to create the missing ``author`` field.
The order in which any definitions are placed within the special templates is important. For example, if a user has au = <authorlist.format_authorlist()> and then below that defines authorlist = <author.to_namelist()>, then the code will issue an error stating that authorlist is not defined when attempting to create the au variable. Since the definition for au assumes the presence of the authorlist variable, the latter definition must be placed above it.
A complete of the existing default fields is::
au
authorlist
citekey
citenum
ed
editorlist
Each of these default fields are defined as “special templates”. If a user defines a special template with the same name as one of the above, then the default is overwritten with the user’s version. The definitions of these six default special templates are::
authorlist = <author.to_namelist()>
editorlist = <editor.to_namelist()>
citelabel = <citenum.remove_leading_zeros()>
sortkey = <citenum>
au = <authorlist.format_authorlist()>
ed = <editorlist.format_editorlist()>
Note that the ordering of definitions is important. The following summarizes what these definitions are used for.
authorlist creates a list of dictionaries (one dictionary for each author name found within the database entry’s author field). Each name dictionary has keys “first”, “middle”, “prefix”, “last”, and “suffix”, where each of these keys is optional except for “last”. Thus, a user can access the first and last name of the first author in the database entry using <authorlist.0.first> <authorlist.0.last>. To access the middle name(s) of the second author, use <authorlist.1.middle>.
editorlist behaves exactly as authorlist but derives its list of names from the database entry’s editor field rather than author field.
citelabel is the thing that appears at the front of the formatted reference, and is identical to the citation label used in the manuscript to point to the item in the reference list. In technical journal articles, this is typically just a number, as in the default definition <citenum.remove_leading_zeros()>. The number used here for the label indicates the order in which the entry was cited. Since the variable citenum is a string that contains leading zeros, so that the entries are properly sorted in order of 001, 002, ..., 009, 010, 011, ... and not in the strict alphabetical order of 1, 10, 11, ..., 19, 2, 20, 21, .... But for a citation label, the leading zeros are unsightly, and so we use the .remove_leading_zeros() operator to remove them from the string before creating the label.
sortkey is the string used to sort the entry within the reference list. For technical journal articles, what is generally wanted is just the citation order, as indicated by the <citenum> variable.
au is the string representing the formatted list of author names. In the default definition shown above, the name list is a standard form, and so simply uses the .format_authorlist() operator. Generally, this operator creates name lists that have the form “firstauthor” for only one author, “firstauthor and secondauthor” if only two authors, “firstauthor, secondauthor, ..., and lastauthor” if more than two authors but less than the maximum, and “firstauthor, secondauthor, ..., minauthor, et al.” if more than the maximum allowed number of authors. Which author in the list is “minauthor” is defined using the minauthors option keyword. The maximum number of allowed authors is set by the maxauthors option keyword.
ed follows the same basic structure as au, but uses the maxeditors and mineditors keywords.
One can use the “dot” operator inside a variable name, as in <authorname.0.last.initial()>'' to perform any one of four functions: a explicit numerical index (the ``0 shown here), an implicit numerical index (using .n or .N, for which see section Examples for namelist formatting below for details), a dictionary lookup (the last used here), or the application of an operator (in this case, the .initial() operator which is used to reduce a name to its initial). A numerical index must apply to a list-type of variable, and a key index must apply to a dict-type of variable (i.e. a dictionary).
The complete list of operators available is::
.compress()
.format_authorlist()
.format_editorlist()
.frenchinitial()
.if_singular(var1,var2,var3)
.initial()
.monthabbrev()
.monthname()
.ordinal()
.remove_leading_zeros()
.sentence_case()
.tie()
.to_namelist()
The function of each operator is summarized below.
.compress() removes any whitespace found within the string. This is useful for generating namelists where the format requires “tight” spacing. An example would be “RMA Azzam”, where the three initials are grouped together without spacing. And example template for generating this type of name would be:
<authorlist.0.first><authorlist.0.middle.initial().compress()> <authorlist.0.last>
Without the .compress() operator, the name would come out as “RM A Azzam”, where the two middle name initials “M” amnd “A” are spaced apart from one another by default.
.format_authorlist() operates on a list of dictionaries type of variable (a namelist), and uses the keyword-based default formatting scheme to create a formatted string of names. The complete list keywords that it work with is: etal_message, maxauthors, minauthors, namelist_format, period_after_initial, terse_inits, use_firstname_initials, use_name_ties. The default formatter, while fast, is not very flexible, so that users looking for more customizability will want to make use of Bibulous’ implicit-index and implicit-loop based definitions. See the Example definitions for namelist formatting section below.
.format_editorlist() operates on a list of dictionaries type of variable (a namelist), and uses the keyword-based default formatting scheme to create a formatted string of names. The complete list keywords that it work with is: etal_message, maxeditors, mineditors, namelist_format, period_after_initial, terse_inits, use_firstname_initials, use_name_ties. (The difference with the .format_authorlist() operator is that it uses maxeditors and mineditors rather than maxauthors and minauthors) The default formatter, while fast, is not very flexible, so that users looking for more customizability will want to make use of Bibulous’ implicit-index and implicit-loop based definitions. See the Example definitions for namelist formatting section below.
.frenchinitial() is an alternative form of the .initial() operator that has slightly different behavior. If a name begins with one of the digraphs “Ch”, “Gn”, “Ll”, “Ph”, “Ss”, or “Th”, then the initial will truncate the name after the digraph instead of after the first letter.
.if_singular(var1,var2,var3) is an operator which inserts var2 if var1 has only one element, but var3 if var1 has more than one element. Here var1 is assumed to be a list-type of variable, and var2 and var3 are assumed to be either fields present within the database entry or variables defined in the SPECIAL-TEMPLATES section of the file.
.initial() will truncate the string to its first letter. Note that if a name begins with a LaTeX markup character, such as {\'E}, then the operator will convert the input string to its best attempt at a Unicode-equivalent (without character markup) prior to performing the truncation. Thus, applying the .initial() operator to the name {\v{Z}}ukauskas will produce the initialized form “Ž”.
.monthabbrev() assumes that the input field is a number from 1 to 12, and converts the numerical input into the abbreviated month according to the user’s current locale. If the system cannot determine the user’s locale, the operator will default to using the American English locale, which replaces the numerical field operated on with one of “Jan”, “Feb”, “Mar”, “Apr”, “May”, “Jun”, “Jul”, “Aug”, “Sep”, “Oct”, “Nov”, or “Dec” according to the field’s value. Thus, if the bibliography database entry has a field month = 11, and the template has the form <month.monthabbrev()>, then the template will be replaced with “Nov” for the default locale. For users with locale “Japan”, this same operator will return “11月”.
.monthname() behaves much like .monthabbrev() but rather than using an abbreviated form for the month’s name, it uses the full form. Thus if the bibliography database entry has a field month = 3, and the template has the form <month.monthname()>, then the template variable will be replaced with “March” for the default locale. For users with locale “Norway”, this same operator will return “Mars”.
.ordinal() creates an “ordinal” from a numerical field. Thus, if the field operated on is “1”, “2”, “3”, or “4”, then the operator will replace the template with “1st”, “2nd”, “3rd” or “4th”. Any number above 4 simply has “th” appended to the end of it. Currently Bibulous does not support non-English locales for this function. (Anyone having suggestions of how this may be implemented without too much fuss should contact us!)
.remove_leading_zeros() deletes any zeros from the front of the field operated on. Thus “003” will be returned as “3”.
.sentence_case() reduces the lower case any characters in the field, except for the initial letter and any letters protected within a pair of curly braces. For example, if the database entry has title = {Understanding Bohmian mechanics} and the template has the form <title.sentence_case()>, then the template variable will be replaced with “Understanding bohmian mechanics”. However, if the entry has title = {Understanding {B}ohmian mechanics}, the result will be “Understanding {B}ohmian mechanics”.
.tie() replaces any spaces with an unbreakable space. Thus, “R. M. A.” becomes “R.~M.~A.”. An example use of this operator would be the following template::
authorname = [<authorlist.n.first.initial()>.~][<authorlist.n.middle.initial().tie()>. ]...
[<authorlist.n.prefix>~]<authorlist.n.last>[, <authorlist.n.suffix>]
.to_namelist() parses the field (assumed to be a BibTeX-format “and”-delimited list of names) into a Bibulous-format namelist (i.e. a list of dictionaries).
A complete list of existing options keywords, together with their default definitions, is::
allow_scripts = False
backrefs = False
backrefstyle = none
bibitemsep = None
case_sensitive_field_names = False
edmsg1 = , ed.
edmsg2 = , eds
etal_message = , \\textit{et al.}
maxauthors = 9
maxeditors = 5
minauthors = 9
mineditors = 5
namelist_format = first_name_first
period_after_initial = True
procspie_as_journal = False
show_urls = False
sort_case = True
terse_inits = False
undefstr = ???
use_abbrevs = True
use_citeextract = True
use_firstname_initials = True
use_name_ties = False
Each of the keywords is summarized below.
allow_scripts [default value: False] tells Bibulous whether to allow the evaluation of Python code in the VARIABLES and DEFINITIONS sections of .bst files. It is important for users to realize that evaluating external code in this way is a security risk, and so they should not set allow_scripts = True when inserting code that they do not trust. However, as an additional security precaution, Bibulous prevents most security-sensitive operations from being used within its Python API.
backrefs [default value: False] THIS KEYWORD IS NOT YET IMPLEMENTED
backrefstyle [default value: none] THIS KEYWORD IS NOT YET IMPLEMENTED
bibitemsep [default value: None] provides users a means to change the amount of vertical separation that LaTeX sets between entries in the reference list. For example, users wanting a more compact list can define bibitemsep = 0pt.
case_sensitive_field_names [default value: False] tells Bibulous whether to consider, for example, a field named “Author” as being distinct from “author”.
edmsg1 [default value: , ed.] provides a string to use after a list of editor names, for the case when only one editor is present.
edmsg2 [default value: , eds] provides a string to use after a list of editor names, for the case when multiple editors are present.
etal_message [default value: , \textit{et al.}] provides a string to use after a truncated namelist (for example, when the number of authors exceeds the value given by the maxauthors keyword).
maxauthors [default value: 9] provides the maximum number of allowed names in the formatted list of authors. If the number of names is more than this, then the list of names is truncated to minauthors and the etal_message is appended to the result. (This keyword is only used within the .format_namelist() operator.)
maxeditors [default value: 5] provides the maximum number of allowed names in the formatted list of editors. If the number of names is more than this, then the list of names is truncated to mineditors and the etal_message is appended to the result. (This keyword is only used within the .format_namelist() operator.)
minauthors [default value: 9] provides the minimum number of author names to use when truncating an overlength author name list. (This keyword is only used within the .format_namelist() operator.)
mineditors [default value: 5] provides the minimum number of editor names to use when truncating an overlength author name list. (This keyword is only used within the .format_namelist() operator.)
namelist_format [default value: first_name_first, allowed values: {first_name_first, last_name_first}] defines how the formatted list of names should appear. If namelist_format = first_name_first then the individual names will appear in the order “firstname middle prefix last, suffix”. If namelist_format = last_name_first then the individual names will appear in the order “prefix last, firstname middle, suffix”. (This keyword is only used within the .format_namelist() operator.)
period_after_initial [default value: True] tells the .format_namelist() operator whether to place a period after each initial of an individual’s name. Thus, if period_after_initial = True, a name will appear as “R. M. A. Azzam”, but if False will appear as “R M A Azzam”. (This keyword is only used within the .format_namelist() operator.)
procspie_as_journal [default value: False] The “Proceedings of SPIE” are treated as special by the journals of the Optical Society of America. That is, they format these proceedings (and only these) in the same way that they do journal articles. Thus, a special keyword is required to allow this behavior.
show_urls [default value: False] informs Bibulous whether or not to use the hyperref package for placing hyperlinks into the formatted reference.
sort_case [default value: True] informs Bibulous whether or not to use case-sensitive sorting of reference keys.
terse_inits [default value: False] tells the .format_namelist() operator whether to compress together the initials of an individual’s name. Thus, if terse_inits = True, a name will appear as “RMA Azzam”, but if False will appear as “R. M. A. Azzam”. (This keyword is only used within the .format_namelist() operator.)
undefstr [default value: ???] informs Bibulous what kind of warning message to print when a required field is missing in the database entry.
use_abbrevs [default value: True] tells Bibulous whether or not to use the abbreviations defined in the bibliography database. (Used for debugging.)
use_citeextract [default value: True] tells Bibulous whether to perform “citation extraction”, which creates a small database of only the cited items from among the complete database provided in the .aux file.
use_firstname_initials [default value: True] Whether or not to initialize the first names of authors in the formatted authors list. (This keyword is only used within the .format_namelist() operator.)
use_name_ties [default value: False] Whether or not to replace spaces with unbreakable spaces (i.e. “R. M. A. Azzam” or “R.~M.~A. Azzam”) inside names in the name list. (This keyword is only used within the .format_namelist() operator.)
The following code provides an example usage of implicit indexing within an implicit loop structure::
authorlist = <author.to_namelist()>
editorlist = <editor.to_namelist()>
authorname.n = [<authorlist.n.first.initial()>. ][<authorlist.n.middle.initial()>. ]...
[<authorlist.n.prefix> ]<authorlist.n.last>[, <authorlist.n.suffix>]
au = <authorname.0>, ...,{ and }<authorname.9>
editorname.n = [<editorlist.n.first.initial()>. ][<editorlist.n.middle.initial()>. ]...
[<editorlist.n.prefix> ]<editorlist.n.last>[, <editorlist.n.suffix>]
ed = <editorname.0>, ...,{ and }<editorname.2>
Here the authorlist and editorlist definitions create namelist variables from the author and editor fields in the entry (if they exist). Next, the implicitly-indexed authorname.n cannot operate except within an implicit loop, and so we should describe that first. It is easier to describe the functionality of the ed template than the au one, as it has a smaller number of allowed names. The ed template has the definition:
<editorname.0>, ...,{ and }<editorname.2>
which simplifies to <editorname.0> when there is only one editor in the database entry, and:
<editorname.0> and <editorname.1>
when there are only two. Here the separator `` and `` comes from the { and } placed at the right hand side of the implicit loop. For three editors, the implicit loop expands the template to:
<editorname.0>, <editorname.1>, and <editorname.2>
where this time the comma alone is used as the first delimiter, as it is outside the enclosed braces. For the final element, both the comma and the { and } at the right hand side of the implicit loop are used as the final delimiter. Since the template does not specify the format for more than three editor names, the code builds an et al. construction when there more than this number of names, so that the result becomes:
<editorname.0>, <editorname.1>, <editorname.2>, \textit{et al.}
where the form of the string \textit{, et. al} is specified by the etal_message keyword option.
Thus, the implicit loop has filled out a unique template based on the number of editors it finds within the database entry. The next step is to use the implicitly-indexed editorname to complete building out the template. The latter template is defined as:
editorname.n = [<editorlist.n.first.initial()>. ][<editorlist.n.middle.initial()>. ]...
[<editorlist.n.prefix> ]<editorlist.n.last>[, <editorlist.n.suffix>]
so that a template variable of the form ``<editorname.0>’’ is replaced with:
[<editorlist.0.first.initial()>. ][<editorlist.0.middle.initial()>. ]...
[<editorlist.0.prefix> ]<editorlist.0.last>[, <editorlist.0.suffix>]
That is, the implicit index .n is everywhere replaced with the explicit index 0. For the case of a database entry containing two editor names, the final template will thus have the form:
[<editorlist.0.first.initial()>. ][<editorlist.0.middle.initial()>. ]...
[<editorlist.0.prefix> ]<editorlist.0.last>[, <editorlist.0.suffix>] and ...
[<editorlist.1.first.initial()>. ][<editorlist.1.middle.initial()>. ]...
[<editorlist.1.prefix> ]<editorlist.1.last>[, <editorlist.1.suffix>]
With this template now complete, the code begins to evaluate the entry and replace the individual variables with their corresponding database fields.
Bibulous also provides to users an extensible Python interface allowing users to directly manipulate Bibulous’ internal data structures. These use the VARIABLES and DEFINITIONS sections of the file, as shown below. For the `VARIABLES section, a variable name is defined (the first example below defines the variable year_bce, while the second example below defines pagerange). On the right hand side of the definition, however, is a Python function call. This is different from the other sections of the BST file, which use template syntax. Any variable defined in this way within the VARIABLES section can then be accessed as a template variable (i.e. <year_bce>) within the TEMPLATES section of the file. Two example uses are shown below.
To allow Bibulous to read the VARIABLES and DEFINITIONS sections of the file, users must set the option keyword allow_scripts to True.
First example: a custom yearstyle. For a bibliography containing works from authors dating from before year 0, a common approach is to append “BC” to the year number, and for positive-numbered years, appending “AD”. More recently, the convention has been to append “BCE” and “CE” rather than “BC” and “AD”. The example defines an option keyword yearstyle that allows users to switch between one style (BC/AD) and the other (BCE/CE). This keyword is accessed by placing options as an argument to the format_yearstyle() function defining the variable year_bce. Inside the function, it can then check the options dictionary for the yearstyle keyword and determine which convention to use.
The format_yearstyle() function itself is straightforward. It first checks whether the entry has a year field. If not, then it returns None, indicating that the function’s result is undefined. If it finds a year field, then it checks to see whether it corresponds to an integer. If not, then it returns the field as-is. (Perhaps a user defines his year fields as 45 BCE with the BCE already written out inside the field?) If it finds an integer value, then it determines which style to use (BC/AD or BCE/CE). If the year number is negative then it appends “BC” or “BCE to the end. If the year number is positive then it appends “AD” or “CE to the end, depending on the convention chosen.
Example:
OPTIONS:
allow_scripts = True
yearstyle = BCE/CE
VARIABLES:
year_bce = format_yearstyle(entry, options)
DEFINITIONS:
## NOTE! Only Unix-style line endings are allowed here.
def format_yearstyle(entry, options):
'''
Append "BC or "AD" to "year", depending on whether the year is positive or negative.
If the option "yearstyle" is set to "BCE/CE", then use "BCE" and "CE" instead of "BC"
and "AD".
'''
if ('year' not in entry):
return(options['undefstr'])
## First check that the year string is an integer. If not an integer, then just return
## the field itself.
if not str_is_integer(entry['year']):
return(entry['year'])
yearnum = int(entry['year'])
if (yearnum < 0):
if (options['yearstyle'] == 'BCE/CE'):
suffix = 'BCE'
else:
suffix = 'BC'
## The "[1:]" here removes the minus sign.
result = str(yearnum)[1:] + ' ' + suffix
elif (yearnum == 0):
result = str(yearnum)
else:
if (options['yearstyle'] == 'BCE/CE'):
suffix = 'CE'
else:
suffix = 'AD'
result = str(yearnum) + ' ' + suffix
return(result)
Second example: a custom pagestyle. For a bibliography containing works from magazines, it is not uncommon to find articles with large gaps in page numbers. Here is an example bibliography database entry:
@article{stewart,
title = {Interview with Walter Stewart},
author = {Doug Stewart},
journal = {Omni},
year = {1989},
volume = {11},
number = {5},
pages = {64--66, 87--92, 94}
}
where we can see that the article was broken into three sections in order to fit the editors’ formatting requirements. Many bibliography styles require a starting and ending page, but these are misleading when the article is broken across pages in this way. Thus, a user may want to have the option that if a comma is found within the pages field of an entry then it should be displayed as-is. If no comma is found, then it simply returns the standard startpage–endpage pair.
To make this work, first the option allow_scripts must be set to true. Next, a new pagerange variable is defined, so that it can be accessed in the TEMPLATES section of the file as <pagerange>. The variable is defined as the return value of the function format_pagerange() given in the DEFINITIONS section. The defined function first checks to see if there is a pages field defined in the entry. If not, then it returns None, so that the pagerange variable will also be undefined. If it finds the pages field, it looks to see if there is a comma present. If so, it returns the field as-is. If not, it looks for the endpage variable (generated by default by Bibulous from the pages field). If present, then the function returns a startpage–endpage pair. If endpage is not present, then it returns only the startpage variable.
Example:
OPTIONS:
allow_scripts = True
VARIABLES:
pagerange = format_pagerange(entry, options)
DEFINITIONS:
def format_pagerange(entry, options):
'''
If the "pages" field is comma-delimited, then return the pages field as-is. Otherwise
return the standard startpage--endpage range.
'''
if not ('pages' in entry):
return(None)
elif (',' in entry['pages']):
return(entry['pages'])
elif ('endpage' in entry):
return(entry['startpage']--entry['endpage'])
else:
return(entry['startpage'])