Fix this markdown extension nonsense.

Previously, every single spline-pokedex request tacked another markdown
extension onto a global list in spline, making markdown processing just
a little bit slower over time.  This is terrible.

Now we do something a little less crazy and a little more global.  Wait,
is that less crazy or more?
This commit is contained in:
Eevee 2011-09-06 21:50:00 -07:00
parent bb1a164a34
commit 25ab674c7c
3 changed files with 44 additions and 49 deletions

View file

@ -47,19 +47,17 @@ class MarkdownString(object):
def __html__(self): def __html__(self):
return self.as_html() return self.as_html()
def as_html(self, object_url=None, identifier_url=None, make_link=None): def as_html(self, extension_cls=None):
"""Returns the string as HTML. """Returns the string as HTML.
If given, the optional arguments will be used instead of those in the Pass a custom `extension_cls` to use your own class to generate links.
session's pokedex_link_maker. See MarkdownLinkMaker for documentation. The default (and recommended superclass) is `PokedexLinkExtension`,
described below.
""" """
extension = self.session.pokedex_link_maker.get_extension( if extension_cls is None:
self.language, extension_cls = self.session.markdown_extension_class
object_url=object_url, extension = extension_cls(self.session)
identifier_url=identifier_url,
make_link=make_link,
)
md = markdown.Markdown( md = markdown.Markdown(
extensions=['extra', extension], extensions=['extra', extension],
@ -78,8 +76,8 @@ class MarkdownString(object):
# the links by their text. # the links by their text.
# XXX: The tables get unaligned # XXX: The tables get unaligned
link_maker = MarkdownLinkMaker(self.session) link_maker = PokedexLinkExtension(self.session)
pattern = PokedexLinkPattern(link_maker, self.language) pattern = PokedexLinkPattern(link_maker, self.session, self.language)
regex = '()%s()' % pattern.regex regex = '()%s()' % pattern.regex
def handleMatch(m): def handleMatch(m):
return pattern.handleMatch(m).text return pattern.handleMatch(m).text
@ -130,6 +128,7 @@ class MoveEffectPropertyMap(MoveEffectProperty):
newdict[key] = _markdownify_effect_text(obj, newdict[key], key) newdict[key] = _markdownify_effect_text(obj, newdict[key], key)
return newdict return newdict
class PokedexLinkPattern(markdown.inlinepatterns.Pattern): class PokedexLinkPattern(markdown.inlinepatterns.Pattern):
"""Matches [label]{category:target}. """Matches [label]{category:target}.
@ -137,10 +136,10 @@ class PokedexLinkPattern(markdown.inlinepatterns.Pattern):
""" """
regex = ur'(?x) \[ ([^]]*) \] \{ ([-a-z0-9]+) : ([-a-z0-9]+) \}' regex = ur'(?x) \[ ([^]]*) \] \{ ([-a-z0-9]+) : ([-a-z0-9]+) \}'
def __init__(self, factory, string_language, game_language=None): def __init__(self, factory, session, string_language=None, game_language=None):
markdown.inlinepatterns.Pattern.__init__(self, self.regex) markdown.inlinepatterns.Pattern.__init__(self, self.regex)
self.factory = factory self.factory = factory
self.session = factory.session self.session = session
self.string_language = string_language self.string_language = string_language
self.game_language = game_language self.game_language = game_language
@ -167,7 +166,7 @@ class PokedexLinkPattern(markdown.inlinepatterns.Pattern):
name = None name = None
# Translations can be incomplete; in which case we want to use a # Translations can be incomplete; in which case we want to use a
# fallback. # fallback.
if table in [tables.Type]: if table in [tables.Type] and self.string_language:
# Type wants to be localized to the same language as the text # Type wants to be localized to the same language as the text
name = obj.name_map.get(self.string_language) name = obj.name_map.get(self.string_language)
if not name and self.game_language: if not name and self.game_language:
@ -181,32 +180,20 @@ class PokedexLinkPattern(markdown.inlinepatterns.Pattern):
el.text = markdown.AtomicString(label or name) el.text = markdown.AtomicString(label or name)
return el return el
class MarkdownLinkMaker(object): class PokedexLinkExtension(markdown.Extension):
"""Creates Markdown extensions for handling links for the given session. u"""Markdown extension that translates the syntax used in effect text:
There are two ways to customize the link handling: either override the `[label]{category:identifier}` is treated as a link to a Pokédex object,
*_url methods in a subclass, or give them as arguments to get_extension where `category` is the table's singular name, and `label` is an optional
(or MarkdownString.as_html). link title that defaults to the object's name in the current language.
""" """
def __init__(self, session=None): def __init__(self, session):
self.session = session self.session = session
def get_extension(self, language=None, object_url=None, identifier_url=None,
make_link=None):
"""Get a Markdown extension that handles links using the given language.
"""
link_maker = self
class LinkExtension(markdown.Extension):
def extendMarkdown(self, md, md_globals): def extendMarkdown(self, md, md_globals):
self.identifier_url = identifier_url or link_maker.identifier_url pattern = PokedexLinkPattern(self, self.session)
self.object_url = object_url or link_maker.object_url
self.make_link = make_link or link_maker.make_link
self.session = link_maker.session
pattern = PokedexLinkPattern(self, language)
md.inlinePatterns['pokedex-link'] = pattern md.inlinePatterns['pokedex-link'] = pattern
return LinkExtension()
def make_link(self, category, obj, url, text): def make_link(self, category, obj, url, text):
"""Make an <a> element """Make an <a> element
@ -218,17 +205,17 @@ class MarkdownLinkMaker(object):
return el return el
def identifier_url(self, category, identifier): def identifier_url(self, category, identifier):
"""Return the URL for the given {category:identifier} link """Return the URL for the given {category:identifier} link. For ORM
objects, object_url is tried first.
For ORM objects, object_url is tried first Returns None by default, which causes <span> to be used in place of
<a>.
Returns None by default, which causes <span> to be used in place of <a>
""" """
return None return None
def object_url(self, category, obj): def object_url(self, category, obj):
"""Return the URL for the ORM object obj """Return the URL for the ORM object `obj`.
Returns None by default, which causes identifier_url to be used Returns None by default, which causes identifier_url to be tried.
""" """
return None return None

View file

@ -193,12 +193,14 @@ class MultilangSession(Session):
Needs to be used with `MultilangScopedSession`, below. Needs to be used with `MultilangScopedSession`, below.
""" """
default_language_id = None default_language_id = None
markdown_extension_class = markdown.PokedexLinkExtension
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
if 'default_language_id' in kwargs: if 'default_language_id' in kwargs:
self.default_language_id = kwargs.pop('default_language_id') self.default_language_id = kwargs.pop('default_language_id')
self.pokedex_link_maker = markdown.MarkdownLinkMaker(self) if 'markdown_extension_class' in kwargs:
self.markdown_extension_class = kwargs.pop('markdown_extension_class')
kwargs.setdefault('query_cls', MultilangQuery) kwargs.setdefault('query_cls', MultilangQuery)
@ -218,7 +220,5 @@ class MultilangScopedSession(ScopedSession):
self.registry().default_language_id = new self.registry().default_language_id = new
@property @property
def pokedex_link_maker(self): def markdown_extension_class(self):
"""Passes the new link maker through to the current session. return self.registry().markdown_extension_class
"""
return self.registry().pokedex_link_maker

View file

@ -95,10 +95,18 @@ def test_markdown_string():
md = markdown.MarkdownString('[]{move:thunderbolt} [paralyzes]{mechanic:paralysis}', connection, en) md = markdown.MarkdownString('[]{move:thunderbolt} [paralyzes]{mechanic:paralysis}', connection, en)
assert unicode(md) == 'Thunderbolt paralyzes' assert unicode(md) == 'Thunderbolt paralyzes'
assert md.as_html() == '<p><span>Thunderbolt</span> <span>paralyzes</span></p>' assert md.as_html() == '<p><span>Thunderbolt</span> <span>paralyzes</span></p>'
assert md.as_html(object_url=lambda category, obj: "%s/%s" % (category, obj.identifier)) == (
class ObjectTestExtension(markdown.PokedexLinkExtension):
def object_url(self, category, obj):
return "%s/%s" % (category, obj.identifier)
class IdentifierTestExtension(markdown.PokedexLinkExtension):
def identifier_url(self, category, ident):
return "%s/%s" % (category, ident)
assert md.as_html(extension_cls=ObjectTestExtension) == (
'<p><a href="move/thunderbolt">Thunderbolt</a> <span>paralyzes</span></p>') '<p><a href="move/thunderbolt">Thunderbolt</a> <span>paralyzes</span></p>')
print md.as_html(identifier_url=lambda category, ident: "%s/%s" % (category, ident)) assert md.as_html(extension_cls=IdentifierTestExtension) == (
assert md.as_html(identifier_url=lambda category, ident: "%s/%s" % (category, ident)) == (
'<p><a href="move/thunderbolt">Thunderbolt</a> <a href="mechanic/paralysis">paralyzes</a></p>') '<p><a href="move/thunderbolt">Thunderbolt</a> <a href="mechanic/paralysis">paralyzes</a></p>')
def markdown_column_params(): def markdown_column_params():