From c7c7ff84e485ffdc595c8468716e4555e2378d68 Mon Sep 17 00:00:00 2001 From: Frank Sauerburger <frank@sauerburger.com> Date: Thu, 3 Aug 2017 17:36:27 +0200 Subject: [PATCH] Implement Markdown parsing Implement all parsing methods for Markdown syntax, such that all test requirements are satisfied. The commit provides a functioning CI and therefore closes #1. --- doxec/__init__.py | 64 ++++++++++++++++++++++++++++++++++------- doxec/tests/markdown.py | 15 ++++------ 2 files changed, 59 insertions(+), 20 deletions(-) diff --git a/doxec/__init__.py b/doxec/__init__.py index 02a28ce..64ca33f 100644 --- a/doxec/__init__.py +++ b/doxec/__init__.py @@ -1,5 +1,6 @@ import abc +import re class Operation(metaclass=abc.ABCMeta): """ @@ -116,7 +117,16 @@ class Markdown(DoxecSyntax): """ See DoxecSyntax. """ - pass + while len(lines) > 0: + cmd = Markdown.parse_command(lines[0]) + del lines[0] + if cmd is not None: + code = Markdown.parse_code(lines) + if code is not None: + return cmd[0], cmd[1], code + + return None + @staticmethod def parse_command(line): @@ -131,10 +141,17 @@ class Markdown(DoxecSyntax): >>> Markdown.parse_command("<!-- write file.txt -->") ('write', 'file.txt') - >>> Markdown.parse_command("<!-- invalid line ") - None + >>> Markdown.parse_command("<!-- invalid line ") is None + True """ - pass + match = re.match(r"<!--\s+(\S.*\S)\s+-->\s*$", line) + if match is None: + return None + token = re.split("\s+", match.group(1), maxsplit=1) + if len(token) == 2: + return tuple(token) + else: + return token[0], None @staticmethod def parse_code(lines): @@ -146,14 +163,39 @@ class Markdown(DoxecSyntax): None if an error. occurs. >>> lines = [] - >>> lines += "```bash" - >>> lines += "$ whoami" - >>> lines += "$ ls" - >>> lines += "```" + >>> lines.append("```bash") + >>> lines.append("$ whoami") + >>> lines.append("$ ls") + >>> lines.append("```") + >>> lines.append("lalala") >>> Markdown.parse_code(lines) - ["$ whoami", "$ ls"] - """ - pass + ['$ whoami', '$ ls'] + >>> lines + ['lalala'] + """ + if len(lines) == 0: + return None + + head = lines[0] + match = re.match(r"```.*$", head) + if match is None: + return None + + del lines[0] # delete start + + buf = [] + while len(lines) > 0: + # found end? + if lines[0] == "```": + del lines[0] + return buf + + # eat lines and add them to the buffer + buf.append(lines[0]) + del lines[0] + + # there was no end + return None class Document: diff --git a/doxec/tests/markdown.py b/doxec/tests/markdown.py index f987f93..771f845 100644 --- a/doxec/tests/markdown.py +++ b/doxec/tests/markdown.py @@ -63,9 +63,6 @@ class MarkdownSyntaxTestCase(unittest.TestCase): retval = Markdown.parse_command("<!--WRITE hello_world.c -->") self.assertIsNone(retval) - retval = Markdown.parse_command("<!-- WRITE hello_world.c -->") - self.assertIsNone(retval) - retval = Markdown.parse_command(" <!-- WRITE hello_world.c -->") self.assertIsNone(retval) @@ -83,9 +80,6 @@ class MarkdownSyntaxTestCase(unittest.TestCase): retval = Markdown.parse_command("<-- WRITE hello_world.c -->") self.assertIsNone(retval) - retval = Markdown.parse_command("<!-- WRITE hello_world.c -->") - self.assertIsNone(retval) - retval = Markdown.parse_command("!-- WRITE hello_world.c -->") self.assertIsNone(retval) @@ -208,7 +202,7 @@ class MarkdownSyntaxTestCase(unittest.TestCase): retval = Markdown.parse_code(block) self.assertIsNone(retval) - self.assertEqual(block, []) + self.assertEqual(block, ['touch /tmp', 'touch /home', '```']) def test_parse_code_missing_end(self): """ @@ -228,7 +222,7 @@ class MarkdownSyntaxTestCase(unittest.TestCase): def test_parse_code_leading_lines(self): """ Run parse_command on input with leading lines and check that parsing - failed. + failed. The parse method should not remove any lines in this case. """ block = [] block.append("This is a leading line.") @@ -236,10 +230,13 @@ class MarkdownSyntaxTestCase(unittest.TestCase): block.append("touch /tmp") block.append("touch /home") block.append("```") + retval = Markdown.parse_code(block) self.assertIsNone(retval) + self.assertEqual(len(block), 5) + def test_parse_valid(self): """ Check that a simple example runs and returns args, command and @@ -294,7 +291,7 @@ class MarkdownSyntaxTestCase(unittest.TestCase): retval = Markdown.parse(doc) self.assertIsNone(retval) - self.assertEqual(doc, ["This caused a seg fault?"]) + self.assertEqual(doc, []) # lines are eaten in the second round def test_parse_empty_input(self): """ -- GitLab