2 r
"""Functionality for handling reStructuredText fields in the database.
4 This module defines the following extra text roles. By default, they merely
5 bold the contents of the tag. Calling code may redefine them with
6 `docutils.parsers.rst.roles.register_local_role`. Docutils role extensions
7 are, apparently, global.
13 These all wrap objects of the corresponding type. They're intended to be
14 used to link to these items.
17 This is a general-purpose reference role. The Web Pokédex uses these to
18 link to pages on mechanics. Amongst the things tagged with this are:
19 * Stats, e.g., Attack, Speed
20 * Major status effects, e.g., paralysis, freezing
21 * Minor status effects not unique to a single move, e.g., confusion
22 * Battle mechanics, e.g., "regular damage", "lowers/raises" a stat
25 Depends on context. Created for move effect chances; some effects contain
26 text like "Has a \:data\:\`move.effect_chance\` chance to...". Here, the
27 enclosed text is taken as a reference to a column on the associated move.
28 Other contexts may someday invent their own constructs.
30 This is actually implemented by adding a `_pokedex_handle_data` attribute
31 to the reST document itself, which the `data` role handler attempts to
32 call. This function takes `rawtext` and `text` as arguments and should
36 from docutils
.frontend
import OptionParser
37 from docutils
.io
import Output
39 from docutils
.parsers
.rst
import Parser
, roles
41 from docutils
.writers
.html4css1
import Writer
as HTMLWriter
43 ### Subclasses of bits of docutils, to munge it into doing what I want
44 class HTMLFragmentWriter(HTMLWriter
):
45 """Translates reST to HTML, but only as a fragment. Enclosing <body>,
46 <head>, and <html> tags are omitted.
49 def apply_template(self
):
50 subs
= self
.interpolation_dict()
53 class UnicodeOutput(Output
):
54 """reST Unicode output. The distribution only has a StringOutput, and I
58 def write(self
, data
):
59 """Returns data (a Unicode string) unaltered."""
65 def generic_role(name
, rawtext
, text
, lineno
, inliner
, options
={}, content
=[]):
66 node
= docutils
.nodes
.strong(text
, rawtext
, **options
)
69 roles
.register_local_role('ability', generic_role
)
70 roles
.register_local_role('item', generic_role
)
71 roles
.register_local_role('move', generic_role
)
72 roles
.register_local_role('pokemon', generic_role
)
73 roles
.register_local_role('mechanic', generic_role
)
75 def data_role(name
, rawtext
, text
, lineno
, inliner
, options
={}, content
=[]):
76 document
= inliner
.document
77 node
= document
._pokedex_handle_data(rawtext
, text
)
80 roles
.register_local_role('data', data_role
)
85 class RstString(object):
86 """Wraps a reStructuredText string. Stringifies to the original text, but
87 may be translated to HTML with .to_html().
90 def __init__(self
, source_text
, document_properties
={}):
93 List of extra properties to attach to the reST document object.
95 self
.source_text
= source_text
96 self
.document_properties
= document_properties
97 self
._rest_document
= None
99 def __unicode__(self
):
100 return self
.source_text
103 def rest_document(self
):
104 """reST parse tree of the source text.
106 This property is lazy-loaded.
109 # Return it if we have it
110 if self
._rest_document
:
111 return self
._rest_document
114 settings
= OptionParser(components
=(Parser
,HTMLWriter
)).get_default_values()
115 document
= docutils
.utils
.new_document('pokedex', settings
)
117 # Add properties (in this case, probably just the data role handler)
118 document
.__dict__
.update(self
.document_properties
)
121 parser
.parse(self
.source_text
, document
)
123 self
._rest_document
= document
128 """Returns the string as HTML4."""
130 document
= self
.rest_document
131 destination
= UnicodeOutput()
133 writer
= HTMLFragmentWriter()
134 return writer
.write(document
, destination
)
137 class MoveEffectProperty(object):
138 """Property that wraps a move effect. Used like this:
140 MoveClass.effect = MoveEffectProperty()
142 some_move.effect # returns an RstString
143 some_move.effect.as_html # returns a chunk of HTML
145 This class also performs `%` substitution on the effect, replacing
146 `%(effect_chance)d` with the move's actual effect chance. Also this is a
147 lie and it doesn't yet.
150 def __get__(self
, move
, move_class
):
151 # Attach a function for handling the `data` role
152 # XXX make this a little more fault-tolerant.. maybe..
153 def data_role_func(rawtext
, text
):
154 assert text
[0:5] == 'move.'
155 newtext
= getattr(move
, text
[5:])
156 return docutils
.nodes
.Text(newtext
, rawtext
)
158 return RstString(move
.move_effect
.effect
,
159 document_properties
=dict(
160 _pokedex_handle_data
=data_role_func
))