Scrap docutils for markdown. #275
[zzz-pokedex.git] / pokedex / db / markdown.py
1 # encoding: utf8
2 u"""Implements the markup used for description and effect text in the database.
3
4 The language used is a variation of Markdown and Markdown Extra. There are
5 docs for each at http://daringfireball.net/projects/markdown/ and
6 http://michelf.com/projects/php-markdown/extra/ respectively.
7
8 Pokédex links are represented with the extended syntax `[name]{type}`, e.g.,
9 `[Eevee]{pokemon}`. The actual code that parses these is in spline-pokedex.
10 """
11
12 import markdown
13 import sqlalchemy.types
14
15 class MarkdownString(object):
16 """Wraps a Markdown string. Stringifies to the original text, but .as_html
17 will return an HTML rendering.
18
19 To add extensions to the rendering (which is necessary for rendering links
20 correctly, and which spline-pokedex does), you must append to this class's
21 `markdown_extensions` list. Yep, that's gross.
22 """
23
24 markdown_extensions = ['extra']
25
26 def __init__(self, source_text):
27 self.source_text = source_text
28 self._as_html = None
29
30 def __unicode__(self):
31 return self.source_text
32
33 @property
34 def as_html(self):
35 """Returns the string as HTML4."""
36
37 if self._as_html:
38 return self._as_html
39
40 md = markdown.Markdown(
41 extensions=self.markdown_extensions,
42 safe_mode='escape',
43 output_format='xhtml1',
44 )
45
46 self._as_html = md.convert(self.source_text)
47
48 return self._as_html
49
50 @property
51 def as_text(self):
52 """Returns the string in a plaintext-friendly form.
53
54 At the moment, this is just the original source text.
55 """
56 return self.source_text
57
58
59 class MoveEffectProperty(object):
60 """Property that wraps a move effect. Used like this:
61
62 MoveClass.effect = MoveEffectProperty('effect')
63
64 some_move.effect # returns a MarkdownString
65 some_move.effect.as_html # returns a chunk of HTML
66
67 This class also performs simple substitution on the effect, replacing
68 `$effect_chance` with the move's actual effect chance.
69 """
70
71 def __init__(self, effect_column):
72 self.effect_column = effect_column
73
74 def __get__(self, move, move_class):
75 effect_text = getattr(move.move_effect, self.effect_column)
76 effect_text = effect_text.replace(
77 u'$effect_chance',
78 unicode(move.effect_chance),
79 )
80
81 return MarkdownString(effect_text)
82
83 class MarkdownColumn(sqlalchemy.types.TypeDecorator):
84 """Generic SQLAlchemy column type for Markdown text.
85
86 Do NOT use this for move effects! They need to know what move they belong
87 to so they can fill in, e.g., effect chances. Use the MoveEffectProperty
88 property class above.
89 """
90 impl = sqlalchemy.types.Unicode
91
92 def process_bind_param(self, value, dialect):
93 if not isinstance(value, basestring):
94 # Can't assign, e.g., MarkdownString objects yet
95 raise NotImplementedError
96
97 return unicode(value)
98
99 def process_result_value(self, value, dialect):
100 return MarkdownString(value)