1.1 --- a/convert.py Thu Jul 26 16:34:42 2018 +0200
1.2 +++ b/convert.py Thu Jul 26 20:10:38 2018 +0200
1.3 @@ -1,6 +1,6 @@
1.4 #!/usr/bin/env python
1.5
1.6 -from moinformat import get_serialiser, make_parser, parse, serialise
1.7 +from moinformat import make_linker, make_parser, make_serialiser, parse, serialise
1.8 from os.path import split
1.9 import sys
1.10
1.11 @@ -65,8 +65,9 @@
1.12 if tree:
1.13 print d.prettyprint()
1.14 else:
1.15 - p.translate_links(format, pagename)
1.16 - print serialise(d, get_serialiser(format))
1.17 + l = make_linker(format, pagename)
1.18 + s = make_serialiser(format, l)
1.19 + print serialise(d, s)
1.20 finally:
1.21 f.close()
1.22
2.1 --- a/moinformat/__init__.py Thu Jul 26 16:34:42 2018 +0200
2.2 +++ b/moinformat/__init__.py Thu Jul 26 20:10:38 2018 +0200
2.3 @@ -19,6 +19,7 @@
2.4 this program. If not, see <http://www.gnu.org/licenses/>.
2.5 """
2.6
2.7 +from moinformat.links import make_linker
2.8 from moinformat.parsers import parse, parsers as all_parsers
2.9 from moinformat.serialisers import serialise, serialisers as all_serialisers
2.10
2.11 @@ -40,4 +41,16 @@
2.12
2.13 return all_serialisers["%s.moin" % name]
2.14
2.15 +def make_serialiser(name, linker=None):
2.16 +
2.17 + """
2.18 + Return a serialiser instance for the format having the given 'name'.
2.19 +
2.20 + The optional 'linker' is used to control which linking scheme is used with
2.21 + the serialiser, with the default having the same name as the serialiser.
2.22 + """
2.23 +
2.24 + linker = linker or make_linker(name, "")
2.25 + return get_serialiser(name)(formats=all_serialisers, linker=linker)
2.26 +
2.27 # vim: tabstop=4 expandtab shiftwidth=4
3.1 --- a/moinformat/links/__init__.py Thu Jul 26 16:34:42 2018 +0200
3.2 +++ b/moinformat/links/__init__.py Thu Jul 26 20:10:38 2018 +0200
3.3 @@ -26,10 +26,23 @@
3.4 def get_linker(name):
3.5
3.6 """
3.7 - Return the linking scheme handler with the given 'name' or None if no such
3.8 - handler is found.
3.9 + Return the linking scheme handler class with the given 'name' or None if no
3.10 + such handler is found.
3.11 """
3.12
3.13 return linkers.get(name)
3.14
3.15 +def make_linker(name, pagename):
3.16 +
3.17 + """
3.18 + Return a linking scheme handler with the given 'name' and using the given
3.19 + 'pagename'.
3.20 + """
3.21 +
3.22 + linker_cls = get_linker(name)
3.23 + if not linker_cls:
3.24 + return None
3.25 +
3.26 + return linker_cls(pagename)
3.27 +
3.28 # vim: tabstop=4 expandtab shiftwidth=4
4.1 --- a/moinformat/links/html.py Thu Jul 26 16:34:42 2018 +0200
4.2 +++ b/moinformat/links/html.py Thu Jul 26 20:10:38 2018 +0200
4.3 @@ -35,12 +35,12 @@
4.4 levels = self.pagename.count("/")
4.5 return "/".join([".."] * levels)
4.6
4.7 - def is_url(self, link):
4.8 + def is_url(self, target):
4.9
4.10 - "Return whether the 'link' references a URL."
4.11 + "Return whether the 'target' references a URL."
4.12
4.13 - scheme, host, path, params, query, fragment = urlparse(link.target)
4.14 - return scheme
4.15 + scheme, host, path, params, query, fragment = urlparse(target)
4.16 + return scheme and target or None
4.17
4.18 def normalise(self, path):
4.19
4.20 @@ -48,92 +48,91 @@
4.21
4.22 return not path.endswith("/") and "%s/" % path or path
4.23
4.24 - def translate(self, link):
4.25 + def translate(self, target):
4.26
4.27 - "Translate the 'link', rewriting the target."
4.28 + "Translate the 'target' and return the rewritten string."
4.29
4.30 - target = link.target.rstrip("/")
4.31 + target = target.rstrip("/")
4.32
4.33 # Sub-pages.
4.34
4.35 if target.startswith("/"):
4.36 - self.translate_subpage(link, target)
4.37 + return self.translate_subpage(target)
4.38
4.39 # Sibling (of ancestor) pages.
4.40
4.41 - elif target.startswith("../"):
4.42 - self.translate_relative(link, target)
4.43 + if target.startswith("../"):
4.44 + return self.translate_relative(target)
4.45
4.46 # Attachment or interwiki link.
4.47
4.48 - elif self.translate_qualified_link(link, target):
4.49 - pass
4.50 + rewritten = self.translate_qualified_link(target)
4.51 + if rewritten:
4.52 + return rewritten
4.53
4.54 # Plain URL.
4.55
4.56 - elif self.is_url(link):
4.57 - pass
4.58 + rewritten = self.is_url(target)
4.59 + if rewritten:
4.60 + return rewritten
4.61
4.62 # Top-level pages.
4.63
4.64 - else:
4.65 - top_level = self.get_top_level()
4.66 - link.target = "%s%s" % (top_level and "%s/" % top_level or "", target)
4.67 + top_level = self.get_top_level()
4.68 + return "%s%s" % (top_level and "%s/" % top_level or "", target)
4.69
4.70 - def translate_qualified_link(self, link, target):
4.71 + def translate_qualified_link(self, target):
4.72
4.73 """
4.74 - Translate a possible qualified 'link', returning whether translation
4.75 - occurred.
4.76 + Translate a possible qualified link 'target', returning a rewritten
4.77 + target or None if the link is not suitable.
4.78 """
4.79
4.80 t = target.split(":", 1)
4.81 if len(t) != 2:
4.82 - return False
4.83 + return None
4.84
4.85 prefix, target = t
4.86
4.87 # Attachment links.
4.88
4.89 if prefix == "attachment":
4.90 - self.translate_attachment(link, target)
4.91 - return True
4.92 + return self.translate_attachment(target)
4.93
4.94 # Interwiki links.
4.95
4.96 url = self.mapping.get(prefix)
4.97 if url:
4.98 - self.translate_interwiki(link, url, target)
4.99 - return True
4.100 + return self.translate_interwiki(url, target)
4.101
4.102 - return False
4.103 + return None
4.104
4.105 # Specific link translators.
4.106
4.107 - def translate_attachment(self, link, target):
4.108 + def translate_attachment(self, target):
4.109
4.110 - "Update 'link' for the given attachment 'target'."
4.111 + "Return a translation of the given attachment 'target'."
4.112
4.113 - link.target = "%sattachments/%s/%s" % (
4.114 + return "%sattachments/%s/%s" % (
4.115 self.get_top_level(), self.pagename, target)
4.116
4.117 - def translate_interwiki(self, link, url, target):
4.118 + def translate_interwiki(self, url, target):
4.119
4.120 - "Update 'link' for the given interwiki 'target'."
4.121 + "Return a translation of the given interwiki 'target'."
4.122
4.123 - link.target = "%s%s" % (self.normalise(url), target)
4.124 + return "%s%s" % (self.normalise(url), target)
4.125
4.126 - def translate_relative(self, link, target):
4.127 + def translate_relative(self, target):
4.128
4.129 - "Update 'link' for the given relative 'target'."
4.130 + "Return a translation of the given relative 'target'."
4.131
4.132 - link.target = target[len("../"):]
4.133 + return target[len("../"):]
4.134
4.135 - def translate_subpage(self, link, target):
4.136 + def translate_subpage(self, target):
4.137
4.138 - "Update 'link' for the given subpage 'target'."
4.139 + "Return a translation of the given subpage 'target'."
4.140
4.141 - link.target = ".%s" % target
4.142 + return ".%s" % target
4.143
4.144 linker = HTMLLinker
4.145
5.1 --- a/moinformat/parsers/moin.py Thu Jul 26 16:34:42 2018 +0200
5.2 +++ b/moinformat/parsers/moin.py Thu Jul 26 20:10:38 2018 +0200
5.3 @@ -21,7 +21,6 @@
5.4
5.5 # Document transformations.
5.6
5.7 -from moinformat.links import get_linker
5.8 from moinformat.macros import get_macro
5.9
5.10 # Parser functionality and pattern definition.
5.11 @@ -68,7 +67,6 @@
5.12 # Record certain node occurrences for later evaluation.
5.13
5.14 self.macros = []
5.15 - self.links = []
5.16
5.17 # Principal parser methods.
5.18
5.19 @@ -119,30 +117,6 @@
5.20 macro = macro_cls(node, self.region)
5.21 macro.evaluate()
5.22
5.23 - # Link translation.
5.24 -
5.25 - def translate_links(self, scheme, name, base=""):
5.26 -
5.27 - """
5.28 - Translate the link nodes in the document for the given 'scheme' and
5.29 - employing the given document 'name' and 'base'.
5.30 - """
5.31 -
5.32 - # Obtain a class for the named linker.
5.33 -
5.34 - linker_cls = get_linker(scheme)
5.35 - if not linker_cls:
5.36 - return
5.37 -
5.38 - # Instantiate the class with document metadata.
5.39 -
5.40 - linker = linker_cls(name, base)
5.41 -
5.42 - for node in self.links:
5.43 -
5.44 - # Translate the link.
5.45 -
5.46 - linker.translate(node)
5.47
5.48
5.49 # Parser methods supporting different page features.
5.50 @@ -517,10 +491,6 @@
5.51 link = Link(text and [Text(text)], target)
5.52 region.append_inline(link)
5.53
5.54 - # Record the link for later processing.
5.55 -
5.56 - self.root.links.append(link)
5.57 -
5.58 def parse_macro(self, region):
5.59 name = self.match_group("name")
5.60 args = self.match_group("args")
6.1 --- a/moinformat/serialisers/__init__.py Thu Jul 26 16:34:42 2018 +0200
6.2 +++ b/moinformat/serialisers/__init__.py Thu Jul 26 20:10:38 2018 +0200
6.3 @@ -24,12 +24,17 @@
6.4
6.5 # Top-level functions.
6.6
6.7 -def serialise(doc, serialiser=MoinSerialiser):
6.8 +def serialise(doc, serialiser=None):
6.9
6.10 - "Serialise 'doc' using 'serialiser' or the Moin serialiser if omitted."
6.11 + """
6.12 + Serialise 'doc' using the given 'serialiser' instance or the Moin serialiser
6.13 + if omitted.
6.14 + """
6.15
6.16 l = []
6.17 - doc.to_string(serialiser(l.append, serialisers))
6.18 + serialiser = serialiser or MoinSerialiser(formats=serialisers)
6.19 + serialiser.out = l.append
6.20 + doc.to_string(serialiser)
6.21 return "".join(l)
6.22
6.23 # vim: tabstop=4 expandtab shiftwidth=4
7.1 --- a/moinformat/serialisers/common.py Thu Jul 26 16:34:42 2018 +0200
7.2 +++ b/moinformat/serialisers/common.py Thu Jul 26 20:10:38 2018 +0200
7.3 @@ -25,15 +25,17 @@
7.4
7.5 format = None # defined by subclasses
7.6
7.7 - def __init__(self, out, formats=None):
7.8 + def __init__(self, out=None, formats=None, linker=None):
7.9
7.10 """
7.11 - Initialise the serialiser with an 'out' callable and an optional
7.12 - 'formats' mapping from names to serialiser classes.
7.13 + Initialise the serialiser with an 'out' callable, an optional 'formats'
7.14 + mapping from names to serialiser classes, and an optional 'linker'
7.15 + object for translating links.
7.16 """
7.17
7.18 self.out = out
7.19 self.formats = formats
7.20 + self.linker = linker
7.21 self.init()
7.22
7.23 def init(self):
7.24 @@ -43,7 +45,8 @@
7.25 pass
7.26
7.27 def __repr__(self):
7.28 - return "%s(%r, %r)" % (self.__class__.__name__, self.out, self.formats)
7.29 + return "%s(%r, %r, %r)" % (self.__class__.__name__, self.out,
7.30 + self.formats, self.linker)
7.31
7.32 def escape_attr(s):
7.33
8.1 --- a/moinformat/serialisers/html/moin.py Thu Jul 26 16:34:42 2018 +0200
8.2 +++ b/moinformat/serialisers/html/moin.py Thu Jul 26 20:10:38 2018 +0200
8.3 @@ -97,6 +97,8 @@
8.4 self.out("</big>")
8.5
8.6 def start_link(self, target):
8.7 + if self.linker:
8.8 + target = self.linker.translate(target)
8.9 self.out('<a href="%s">' % escape_attr(target))
8.10
8.11 def end_link(self):
9.1 --- a/moinformat/tree/moin.py Thu Jul 26 16:34:42 2018 +0200
9.2 +++ b/moinformat/tree/moin.py Thu Jul 26 20:10:38 2018 +0200
9.3 @@ -146,8 +146,9 @@
9.4 # Retain the same serialiser if no appropriate serialiser could be
9.5 # obtained.
9.6
9.7 - region_out = serialiser_cls and serialiser_cls(out.out, out.formats) \
9.8 - or out
9.9 + region_out = serialiser_cls and serialiser_cls is not out and \
9.10 + serialiser_cls(out.out, out.formats, out.linker) or \
9.11 + out
9.12
9.13 # Serialise the region.
9.14
10.1 --- a/tests/test_parser.py Thu Jul 26 16:34:42 2018 +0200
10.2 +++ b/tests/test_parser.py Thu Jul 26 20:10:38 2018 +0200
10.3 @@ -12,7 +12,7 @@
10.4 if split(parent)[1] == "MoinLight":
10.5 sys.path.append(parent)
10.6
10.7 -from moinformat import get_serialiser, parse, serialise
10.8 +from moinformat import make_serialiser, parse, serialise
10.9 from moinformat.tree.moin import Container
10.10 from glob import glob
10.11
10.12 @@ -36,7 +36,7 @@
10.13 print "-" * 60
10.14 print s
10.15 print "-" * 60
10.16 - print serialise(d, get_serialiser("html"))
10.17 + print serialise(d, make_serialiser("html"))
10.18 print "-" * 60
10.19 print
10.20