summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthew Peveler <matt.peveler@gmail.com>2022-02-17 10:04:25 -0500
committerMatthew Peveler <matt.peveler@gmail.com>2022-02-17 10:04:25 -0500
commiteb304c9113364f9642e140ed9fd814097f645d0b (patch)
tree525aadb69a72a749d39e9c3b1da54175a2b12765
parent43d1abfa0f7588ab88377155b0e1b41e67c52502 (diff)
downloadasciidoc-py3-eb304c9113364f9642e140ed9fd814097f645d0b.tar.gz
Migrate standalone Table code to own module
Signed-off-by: Matthew Peveler <matt.peveler@gmail.com>
-rw-r--r--asciidoc/asciidoc.py74
-rw-r--r--asciidoc/blocks/__init__.py0
-rw-r--r--asciidoc/blocks/table.py75
-rw-r--r--tests/blocks/__init__.py0
-rw-r--r--tests/blocks/test_table.py45
5 files changed, 124 insertions, 70 deletions
diff --git a/asciidoc/asciidoc.py b/asciidoc/asciidoc.py
index 8b196d9..795b22f 100644
--- a/asciidoc/asciidoc.py
+++ b/asciidoc/asciidoc.py
@@ -16,7 +16,6 @@ Public License version 2 (GPLv2).
# issue stating as much so as to help prevent breaking changes to your toolchain.
import ast
-import copy
import csv
from functools import lru_cache
import getopt
@@ -35,6 +34,7 @@ import zipfile
from collections import OrderedDict
+from .blocks.table import parse_table_span_spec, Cell, Column
from .collections import AttrDict, InsensitiveDict
from .exceptions import EAsciiDoc
from . import utils
@@ -2981,43 +2981,7 @@ class DelimitedBlocks(AbstractBlocks):
AbstractBlocks.validate(self)
-class Column:
- """Table column."""
- def __init__(self, width=None, align_spec=None, style=None):
- self.width = width or '1'
- self.halign, self.valign = Table.parse_align_spec(align_spec)
- self.style = style # Style name or None.
- # Calculated attribute values.
- self.abswidth = None # 1.. (page units).
- self.pcwidth = None # 1..99 (percentage).
-
-
-class Cell:
- def __init__(self, data, span_spec=None, align_spec=None, style=None):
- self.data = data
- self.span, self.vspan = Table.parse_span_spec(span_spec)
- self.halign, self.valign = Table.parse_align_spec(align_spec)
- self.style = style
- self.reserved = False
-
- def __repr__(self):
- return '<Cell: %d.%d %s.%s %s "%s">' % (
- self.span, self.vspan,
- self.halign, self.valign,
- self.style or '',
- self.data)
-
- def clone_reserve(self):
- """Return a clone of self to reserve vertically spanned cell."""
- result = copy.copy(self)
- result.vspan = 1
- result.reserved = True
- return result
-
-
class Table(AbstractBlock):
- ALIGN = {'<': 'left', '>': 'right', '^': 'center'}
- VALIGN = {'<': 'top', '>': 'bottom', '^': 'middle'}
FORMATS = ('psv', 'csv', 'dsv')
SEPARATORS = dict(
csv=',',
@@ -3039,36 +3003,6 @@ class Table(AbstractBlock):
self.rows = [] # Parsed rows, each row is a list of Cells.
self.columns = [] # List of Columns.
- @staticmethod
- def parse_align_spec(align_spec):
- """
- Parse AsciiDoc cell alignment specifier and return 2-tuple with
- horizontal and vertical alignment names. Unspecified alignments
- set to None.
- """
- result = (None, None)
- if align_spec:
- mo = re.match(r'^([<\^>])?(\.([<\^>]))?$', align_spec)
- if mo:
- result = (Table.ALIGN.get(mo.group(1)),
- Table.VALIGN.get(mo.group(3)))
- return result
-
- @staticmethod
- def parse_span_spec(span_spec):
- """
- Parse AsciiDoc cell span specifier and return 2-tuple with horizontal
- and vertical span counts. Set default values (1,1) if not
- specified.
- """
- result = (None, None)
- if span_spec:
- mo = re.match(r'^(\d+)?(\.(\d+))?$', span_spec)
- if mo:
- result = (mo.group(1) and int(mo.group(1)),
- mo.group(3) and int(mo.group(3)))
- return (result[0] or 1, result[1] or 1)
-
def load(self, name, entries):
AbstractBlock.load(self, name, entries)
@@ -3426,15 +3360,16 @@ class Table(AbstractBlock):
self.error('csv parse error: %s' % row)
return rows
- def parse_psv_dsv(self, text):
+ def parse_psv_dsv(self, text: str) -> typing.List[Cell]:
"""
Parse list of PSV or DSV table source text lines and return a list of
Cells.
"""
+ cells = []
def append_cell(data, span_spec, op, align_spec, style):
op = op or '+'
if op == '*': # Cell multiplier.
- span = Table.parse_span_spec(span_spec)[0]
+ span = parse_table_span_spec(span_spec)[0]
for i in range(span):
cells.append(Cell(data, '1', align_spec, style))
elif op == '+': # Column spanner.
@@ -3449,7 +3384,6 @@ class Table(AbstractBlock):
op = None
align = None
style = None
- cells = []
data = ''
for mo in re.finditer(separator, text):
data += text[start:mo.start()]
diff --git a/asciidoc/blocks/__init__.py b/asciidoc/blocks/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/asciidoc/blocks/__init__.py
diff --git a/asciidoc/blocks/table.py b/asciidoc/blocks/table.py
new file mode 100644
index 0000000..489260b
--- /dev/null
+++ b/asciidoc/blocks/table.py
@@ -0,0 +1,75 @@
+import copy
+import re
+from typing import Optional, Tuple
+
+ALIGN = {'<': 'left', '>': 'right', '^': 'center'}
+VALIGN = {'<': 'top', '>': 'bottom', '^': 'middle'}
+
+
+def parse_align_spec(align_spec: Optional[str]) -> Tuple[Optional[str], Optional[str]]:
+ """
+ Parse AsciiDoc cell alignment specifier and return 2-tuple with
+ horizontal and vertical alignment names. Unspecified alignments
+ set to None.
+ """
+ result = (None, None)
+ if align_spec:
+ mo = re.match(r'^([<\^>])?(\.([<\^>]))?$', align_spec)
+ if mo:
+ result = (
+ ALIGN.get(mo.group(1)),
+ VALIGN.get(mo.group(3)),
+ )
+ return result
+
+
+# TODO: remove _table_ from name once Table class has been moved into this file
+def parse_table_span_spec(span_spec: Optional[str]) -> Tuple[int, int]:
+ """
+ Parse AsciiDoc cell span specifier and return 2-tuple with horizontal
+ and vertical span counts. Set default values (1,1) if not
+ specified.
+ """
+ result = (None, None)
+ if span_spec:
+ mo = re.match(r'^(\d+)?(\.(\d+))?$', span_spec)
+ if mo:
+ result = (
+ mo.group(1) and int(mo.group(1)),
+ mo.group(3) and int(mo.group(3)),
+ )
+ return (result[0] or 1, result[1] or 1)
+
+
+class Column:
+ """Table column."""
+ def __init__(self, width=None, align_spec=None, style=None):
+ self.width = width or '1'
+ self.halign, self.valign = parse_align_spec(align_spec)
+ self.style = style # Style name or None.
+ # Calculated attribute values.
+ self.abswidth = None # 1.. (page units).
+ self.pcwidth = None # 1..99 (percentage).
+
+
+class Cell:
+ def __init__(self, data, span_spec=None, align_spec=None, style=None):
+ self.data = data
+ self.span, self.vspan = parse_table_span_spec(span_spec)
+ self.halign, self.valign = parse_align_spec(align_spec)
+ self.style = style
+ self.reserved = False
+
+ def __repr__(self):
+ return '<Cell: %d.%d %s.%s %s "%s">' % (
+ self.span, self.vspan,
+ self.halign, self.valign,
+ self.style or '',
+ self.data)
+
+ def clone_reserve(self):
+ """Return a clone of self to reserve vertically spanned cell."""
+ result = copy.copy(self)
+ result.vspan = 1
+ result.reserved = True
+ return result
diff --git a/tests/blocks/__init__.py b/tests/blocks/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/blocks/__init__.py
diff --git a/tests/blocks/test_table.py b/tests/blocks/test_table.py
new file mode 100644
index 0000000..f33ea97
--- /dev/null
+++ b/tests/blocks/test_table.py
@@ -0,0 +1,45 @@
+from asciidoc.blocks import table
+import pytest
+
+
+@pytest.mark.parametrize(
+ "input,expected",
+ (
+ (None, (None, None)),
+ ('', (None, None)),
+ ('<', ('left', None)),
+ ('^', ('center', None)),
+ ('>', ('right', None)),
+ ('.<', (None, 'top')),
+ ('.^', (None, 'middle')),
+ ('.>', (None, 'bottom')),
+ ('<.<', ('left', 'top')),
+ ('^.<', ('center', 'top')),
+ ('>.<', ('right', 'top')),
+ ('<.^', ('left', 'middle')),
+ ('^.^', ('center', 'middle')),
+ ('>.^', ('right', 'middle')),
+ ('<.>', ('left', 'bottom')),
+ ('^.>', ('center', 'bottom')),
+ ('>.>', ('right', 'bottom')),
+ )
+)
+def test_parse_align_spec(input, expected):
+ assert table.parse_align_spec(input) == expected
+
+
+@pytest.mark.parametrize(
+ "input,expected",
+ (
+ (None, (1, 1)),
+ ('', (1, 1)),
+ ('0', (1, 1)),
+ ('.0', (1, 1)),
+ ('0.0', (1, 1)),
+ ('2', (2, 1)),
+ ('.2', (1, 2)),
+ ('3.2', (3, 2)),
+ )
+)
+def test_parse_table_span_spec(input, expected):
+ assert table.parse_table_span_spec(input) == expected