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
.emphasis(rawtext
, text
, **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('type', generic_role
)
73 roles
.register_local_role('pokemon', generic_role
)
74 roles
.register_local_role('mechanic', generic_role
)
76 def data_role(name
, rawtext
, text
, lineno
, inliner
, options
={}, content
=[]):
77 document
= inliner
.document
78 node
= document
._pokedex_handle_data(rawtext
, text
)
81 roles
.register_local_role('data', data_role
)
86 class RstString(object):
87 """Wraps a reStructuredText string. Stringifies to the original text, but
88 may be translated to HTML with .to_html().
91 def __init__(self
, source_text
, document_properties
={}):
94 List of extra properties to attach to the reST document object.
96 self
.source_text
= source_text
97 self
.document_properties
= document_properties
98 self
._rest_document
= None
100 def __unicode__(self
):
101 return self
.source_text
104 def rest_document(self
):
105 """reST parse tree of the source text.
107 This property is lazy-loaded.
110 # Return it if we have it
111 if self
._rest_document
:
112 return self
._rest_document
115 settings
= OptionParser(components
=(Parser
,HTMLWriter
)).get_default_values()
116 document
= docutils
.utils
.new_document('pokedex', settings
)
118 # Add properties (in this case, probably just the data role handler)
119 document
.__dict__
.update(self
.document_properties
)
122 parser
.parse(self
.source_text
, document
)
124 self
._rest_document
= document
129 """Returns the string as HTML4."""
131 document
= self
.rest_document
132 destination
= UnicodeOutput()
134 writer
= HTMLFragmentWriter()
135 return writer
.write(document
, destination
)
138 class MoveEffectProperty(object):
139 """Property that wraps a move effect. Used like this:
141 MoveClass.effect = MoveEffectProperty()
143 some_move.effect # returns an RstString
144 some_move.effect.as_html # returns a chunk of HTML
146 This class also performs `%` substitution on the effect, replacing
147 `%(effect_chance)d` with the move's actual effect chance. Also this is a
148 lie and it doesn't yet.
151 def __init__(self
, effect_column
):
152 self
.effect_column
= effect_column
154 def __get__(self
, move
, move_class
):
155 # Attach a function for handling the `data` role
156 # XXX make this a little more fault-tolerant.. maybe..
157 def data_role_func(rawtext
, text
):
158 assert text
[0:5] == 'move.'
159 newtext
= getattr(move
, text
[5:])
160 return docutils
.nodes
.Text(newtext
, rawtext
)
162 return RstString(getattr(move
.move_effect
, self
.effect_column
),
163 document_properties
=dict(
164 _pokedex_handle_data
=data_role_func
))