Revision: 2eac96b5fe0d
Author:   Robot Framework Developers <[email protected]>
Date:     Fri Jan 20 03:06:10 2012
Log:      writer: grand refactoring
http://code.google.com/p/robotframework/source/detail?r=2eac96b5fe0d

Added:
 /src/robot/writer/aligners.py
 /src/robot/writer/dataextractor.py
 /src/robot/writer/htmlformatter.py
 /src/robot/writer/rowsplitter.py
 /utest/writer/test_extractor.py
Deleted:
 /src/robot/writer/tableformatters.py
Modified:
 /src/robot/writer/datafilewriter.py
 /src/robot/writer/filewriters.py
 /src/robot/writer/formatters.py
 /utest/writer/test_formatters.py

=======================================
--- /dev/null
+++ /src/robot/writer/aligners.py       Fri Jan 20 03:06:10 2012
@@ -0,0 +1,58 @@
+#  Copyright 2008-2011 Nokia Siemens Networks Oyj
+#
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+
+class _Aligner(object):
+
+    def __init__(self, widths, align_last_column=False):
+        self._widths = widths
+        self._align_last_column = align_last_column
+
+    def align_rows(self, rows):
+        return [self.align_row(r) for r in rows]
+
+    def align_row(self, row):
+        for index, col in enumerate(row[:self._last_aligned_column(row)]):
+            if len(self._widths) <= index:
+                continue
+            row[index] = row[index].ljust(self._widths[index])
+        return row
+
+    def _last_aligned_column(self, row):
+        return len(row) if self._align_last_column else -1
+
+
+class FirstColumnAligner(_Aligner):
+
+    def __init__(self, cols, first_column_width):
+        _Aligner.__init__(self, [first_column_width])
+
+
+class ColumnAligner(_Aligner):
+
+    def __init__(self, first_column_width, table, align_last_column):
+        self._first_column_width = first_column_width
+        _Aligner.__init__(self, self._count_justifications(table),
+            align_last_column)
+
+    def _count_justifications(self, table):
+ result = [self._first_column_width] + [len(h) for h in table.header[1:]]
+        for element in [list(kw) for kw in list(table)]:
+            for step in element:
+                for index, col in enumerate(step.as_list()):
+                    index += 1
+                    if len(result) <= index:
+                        result.append(0)
+                    result[index] = max(len(col), result[index])
+        return result
=======================================
--- /dev/null
+++ /src/robot/writer/dataextractor.py  Fri Jan 20 03:06:10 2012
@@ -0,0 +1,56 @@
+#  Copyright 2008-2011 Nokia Siemens Networks Oyj
+#
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+
+class DataExtractor(object):
+ """The DataExtractor object. Transforms table of a parsed Robot Framework
+    test data file into list of rows."""
+
+    def __init__(self, want_name_on_first_content_row=False):
+ self._want_names_on_first_content_row = want_name_on_first_content_row
+
+    def rows_from_simple_table(self, table):
+        """Return list of rows from a setting or variable table"""
+        return self._rows_from_item(table)
+
+    def rows_from_indented_table(self, table):
+        """Return list of rows from a test case or user keyword table"""
+        items = list(table)
+        for index, item in enumerate(items):
+            for row in self._rows_from_test_or_keyword(item):
+                yield row
+            if not self._last(items, index):
+                yield []
+
+    def _rows_from_test_or_keyword(self, test_or_keyword):
+        rows = list(self._rows_from_item(test_or_keyword, 1)) or ['']
+        first_row, rest = self._first_row(test_or_keyword.name, rows)
+        yield first_row
+        for r in rest:
+            yield r
+
+    def _first_row(self, name, rows):
+        if self._want_names_on_first_content_row:
+            return [name] + rows[0][1:], rows[1:]
+        return [name], rows
+
+    def _rows_from_item(self, item, indent=0):
+        for child in (c for c in item if c.is_set()):
+            yield [''] * indent + child.as_list()
+            if child.is_for_loop():
+                for row in self._rows_from_item(child, indent+1):
+                    yield row
+
+    def _last(self, items, index):
+        return index >= len(items) -1
=======================================
--- /dev/null
+++ /src/robot/writer/htmlformatter.py  Fri Jan 20 03:06:10 2012
@@ -0,0 +1,134 @@
+#  Copyright 2008-2011 Nokia Siemens Networks Oyj
+#
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+import re
+
+from robot import utils
+
+from .formatters import _DataFileFormatter
+
+
+class HtmlFormatter(_DataFileFormatter):
+    _want_names_on_first_content_row = True
+
+    def __init__(self):
+        _DataFileFormatter.__init__(self, 5)
+
+    def empty_row(self):
+        return [NameCell('')] + [HtmlCell('') for _ in range(self._cols-1)]
+
+    def _format_row(self, row):
+        row = self._pad(row)
+        if self._is_documentation_row(row):
+            return self._create_documentation_row(row)
+        first_cell = self._create_first_cell(row[0])
+        if self._is_indented_documentation_row(row[1:]):
+ return self._create_indented_documentation_row(first_cell, row[1:])
+        return [first_cell] + [HtmlCell(c) for c in row[1:]]
+
+    def _is_documentation_row(self, row):
+        return row[0] == 'Documentation'
+
+    def _create_documentation_row(self, row):
+ return [NameCell(row[0]), DocumentationCell(row[1], span=self._cols-1)]
+
+    def _is_indented_documentation_row(self, cells):
+        return self._is_indented_table(self._current_table) and cells and \
+                    cells[0] == '[Documentation]'
+
+    def _create_indented_documentation_row(self, first_cell, cells):
+        start = [first_cell, HtmlCell(cells[0])]
+        if any(c.startswith('#') for c in cells):
+            return start + [HtmlCell(c) for c in cells[1:]]
+        return start + [DocumentationCell(cells[1], self._cols-2)]
+
+    def _create_first_cell(self, cell):
+        if self._is_indented_table(self._current_table) and cell:
+ return AnchorNameCell(cell, 'keyword' if self._current_table.type == 'keyword' else 'test')
+        return NameCell(cell)
+
+    def header_row(self, table):
+        if not self._should_align_columns(table) or len(table.header) == 1:
+            return [HeaderCell(table.header[0], self._cols)]
+        headers = self._pad_header(table)
+        return [HeaderCell(hdr) for hdr in headers]
+
+    def _pad_header(self, table):
+ return table.header + [''] * (self._max_column_count(table) - len(table.header))
+
+    def _max_column_count(self, table):
+        count = 0
+        for item in table:
+            for child in item:
+                count = max(count, len(child.as_list()) + 1)
+        return count
+
+    def _pad(self, row):
+ if len(self._current_table.header) == 1 or not self._is_indented_table(self._current_table):
+            cols = self._cols
+        else:
+            cols = max(self._max_column_count(self._current_table),
+                       len(self._current_table.header))
+        return row + [''] * (cols - len(row))
+class HtmlCell(object):
+    _backslash_matcher = re.compile(r'(\\+)n ')
+
+    def __init__(self, content='', attributes=None, tag='td', escape=True):
+        if escape:
+            content = utils.html_escape(content)
+        self.content = self._replace_newlines(content)
+        self.attributes = attributes or {}
+        self.tag = tag
+
+    def _replace_newlines(self, content):
+        def replacer(match):
+            backslash_count = len(match.group(1))
+            if backslash_count % 2 == 1:
+                return '%sn<br>\n' % match.group(1)
+            return match.group()
+        return self._backslash_matcher.sub(replacer, content)
+
+
+class NameCell(HtmlCell):
+
+    def __init__(self, name='', attributes=None):
+        HtmlCell.__init__(self, name, attributes)
+        self.attributes.update({'class': 'name'})
+
+
+class AnchorNameCell(HtmlCell):
+
+    def __init__(self, name, type_):
+        HtmlCell.__init__(self, self._link_from_name(name, type_),
+                {'class': 'name'}, escape=False)
+
+    def _link_from_name(self, name, type_):
+ return '<a name="%s_%s">%s</a>' % (type_, utils.html_attr_escape(name),
+                                           utils.html_escape(name))
+
+
+class DocumentationCell(HtmlCell):
+
+    def __init__(self, content, span):
+        HtmlCell.__init__(self, content)
+ self.attributes = {'class': 'colspan%d' % span, 'colspan': '%d' % span}
+
+
+class HeaderCell(HtmlCell):
+
+    def __init__(self, name, span=1):
+ HtmlCell.__init__(self, name, {'class': 'name', 'colspan': '%d' % span},
+            tag='th')
+
+
=======================================
--- /dev/null
+++ /src/robot/writer/rowsplitter.py    Fri Jan 20 03:06:10 2012
@@ -0,0 +1,62 @@
+#  Copyright 2008-2011 Nokia Siemens Networks Oyj
+#
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+
+import itertools
+
+class RowSplitter(object):
+    _comment_mark = '#'
+    _empty_cell_escape = '${EMPTY}'
+    _line_continuation = '...'
+
+    def __init__(self, cols=8):
+        self._cols = cols
+
+    def split(self, row, indented_table=False):
+        if not row:
+            return [[]]
+        return self._split_to_rows(row, indented_table)
+
+    def _split_to_rows(self, data, indented_table):
+        indent = len(list(itertools.takewhile(lambda x: x == '', data)))
+        if indented_table:
+            indent = max(indent, 1)
+        rows = []
+        while data:
+            current, data = self._split(data)
+            rows.append(self._escape_last_empty_cell(current))
+            if data:
+                data = self._indent(data, indent)
+        return rows
+
+    def _split(self, data):
+        row, rest = data[:self._cols], data[self._cols:]
+ self._in_comment = any(c for c in row if c.startswith( self._comment_mark))
+        rest = self._add_line_continuation(rest)
+        return row, rest
+
+    def _escape_last_empty_cell(self, row):
+        if not row[-1].strip():
+            row[-1] = self._empty_cell_escape
+        return row
+
+    def _add_line_continuation(self, data):
+        if data:
+            if self._in_comment:
+                data[0] = self._comment_mark + data[0]
+            data = [self._line_continuation] + data
+        return data
+
+    def _indent(self, row, indent):
+        return [''] * indent + row
=======================================
--- /dev/null
+++ /utest/writer/test_extractor.py     Fri Jan 20 03:06:10 2012
@@ -0,0 +1,49 @@
+import unittest
+
+from robot.parsing.model import VariableTable, TestCaseTable
+from robot.utils.asserts import assert_equals
+from robot.writer.dataextractor import DataExtractor
+
+var_table = VariableTable(None)
+var_table.add('${A scalar}', 'value', 'var comment')
+var_table.add('@{A list}', ['v', 'a', 'lue'])
+
+var_table_rows = [['${A scalar}', 'value', '# var comment'],
+                  ['@{A list}', 'v', 'a', 'lue']]
+
+test_table = TestCaseTable(None)
+test = test_table.add('A test case')
+test.add_step(['No Operation'])
+test.add_step(['Log Many', 'bar', 'quux', '#comment'])
+loop = test.add_for_loop(['${i}', 'IN RANGE', '10'])
+loop.add_step(['Log', '${i}'])
+test2 = test_table.add('Second test')
+test2.add_step(['FAIL'])
+
+test_table_rows = [['A test case'],
+                   ['', 'No Operation'],
+                   ['', 'Log Many', 'bar', 'quux', '#comment'],
+                   ['',': FOR', '${i}', 'IN RANGE', '10'],
+                   ['', '', 'Log', '${i}'],
+                   [],
+                   ['Second test'],
+                   ['', 'FAIL'],
+                   []]
+
+class DataExtractorTest(unittest.TestCase):
+
+    def test_extracting_from_simple_table(self):
+ assert_equals(list(DataExtractor().rows_from_simple_table(var_table)),
+                      var_table_rows)
+
+    def test_extracting_from_indented_table(self):
+ for idx, row in enumerate(DataExtractor().rows_from_indented_table(test_table)):
+            assert_equals(row, test_table_rows[idx])
+
+    def test_names_on_first_content_row(self):
+        table = TestCaseTable(None)
+        t = table.add('Test')
+        t.add_step(['No op'])
+        extractor = DataExtractor(want_name_on_first_content_row=True)
+        assert_equals(list(extractor.rows_from_indented_table(table)),
+                      [['Test', 'No op'], []])
=======================================
--- /src/robot/writer/tableformatters.py        Thu Jan  5 07:23:09 2012
+++ /dev/null
@@ -1,325 +0,0 @@
-#  Copyright 2008-2011 Nokia Siemens Networks Oyj
-#
-#  Licensed under the Apache License, Version 2.0 (the "License");
-#  you may not use this file except in compliance with the License.
-#  You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-#  Unless required by applicable law or agreed to in writing, software
-#  distributed under the License is distributed on an "AS IS" BASIS,
-#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-#  See the License for the specific language governing permissions and
-#  limitations under the License.
-
-import re
-
-from robot.parsing.settings import Documentation
-from robot import utils
-
-
-class _Formatter(object):
-
-    def _rows_from_simple_table(self, item, indent=0):
-        return self._rows_from_item(item, indent)
-
-    def _rows_from_indented_table(self, table):
-        items = list(table)
-        for index, item in enumerate(items):
-            yield self._format_name(item)
-            for row in self._rows_from_item(item, 1):
-                yield row
-            if index < len(items) -1:
-                yield []
-
-    def _rows_from_item(self, item, indent=0):
-        for child in (c for c in item if c.is_set()):
-            for row in self._format_model_item(child, indent):
-                yield row
-            if child.is_for_loop():
-                for row in self._rows_from_simple_table(child, indent+1):
-                    yield row
-
-    def _format_name(self, item):
-        return  [item.name]
-
-    def _format_model_item(self, item, indent):
-        return item.as_list()
-
-
-class RowSplittingFormatter(_Formatter):
-
-    def __init__(self, cols):
-        self._cols = cols
-        self._row_splitter = RowSplitter(cols)
-
-    def format_simple_table(self, table):
-        for row in self._rows_from_simple_table(table):
-            yield row
-
-    def format_indented_table(self, table):
-        for row in self._rows_from_indented_table(table):
-            yield row
-
-    def _format_model_item(self, item, indent):
-        return self._row_splitter.split(item.as_list(), indent)
-
-
-class _Aligner(_Formatter):
-
-    def __init__(self, widths, align_last_column=False):
-        self._widths = widths
-        self._align_last_column = align_last_column
-
-    def align_rows(self, rows):
-        return [self.align_row(r) for r in rows]
-
-    def align_row(self, row):
-        for index, col in enumerate(row[:self._last_aligned_column(row)]):
-            if len(self._widths) <= index:
-                continue
-            row[index] = row[index].ljust(self._widths[index])
-        return row
-
-
-    def _last_aligned_column(self, row):
-        return len(row) if self._align_last_column else -1
-
-
-class SettingTableAligner(_Aligner):
-
-    def __init__(self, cols, first_column_width):
-        self._row_splitter = RowSplitter(cols)
-        _Aligner.__init__(self, [first_column_width])
-
-    def format_simple_table(self, table):
-        return self.align_rows(self._rows_from_simple_table(table))
-
-    def _format_model_item(self, item, indent):
-        return self._row_splitter.split(item.as_list(), indent)
-
-
-class ColumnAligner(_Aligner):
-
-    def __init__(self, first_column_width, table, align_last_column):
-        self._first_column_width = first_column_width
-        _Aligner.__init__(self, self._count_justifications(table),
-                          align_last_column)
-
-    def _count_justifications(self, table):
- result = [self._first_column_width] + [len(h) for h in table.header[1:]]
-        for element in [list(kw) for kw in list(table)]:
-            for step in element:
-                for index, col in enumerate(step.as_list()):
-                    index += 1
-                    if len(result) <= index:
-                        result.append(0)
-                    result[index] = max(len(col), result[index])
-        return result
-
-    def format_indented_table(self, table):
-        items = list(table)
-        for i, item in enumerate(items):
-            rows = list(self._rows_from_item(item, 1))
-            if len(item.name) > self._first_column_width:
-                yield [item.name]
-            else:
-                first_row = [item.name] + rows[0][1:]
-                yield self.align_row(first_row)
-                rows = rows[1:]
-            for r in rows:
-                yield self.align_row(r)
-            if i < len(items) - 1:
-                yield []
-
-    def _format_model_item(self, item, indent):
-        return [self._escape(['']*indent + item.as_list())]
-
-    def _escape(self, row):
-        if len(row) >= 2 and row[0] == '' and row[1] == '':
-            row[1] = '\\'
- return [re.sub('\s\s+(?=[^\s])', lambda match: '\\'.join(match.group(0)), item) for item in row]
-
-
-class SplittingHtmlFormatter(RowSplittingFormatter):
-
-    def format_indented_table(self, table):
-        items = list(table)
-        for i, item in enumerate(items):
-            rows = list(self._rows_from_item(item, 1))
-            yield self._first_row(item, rows[0])
-            for row in rows[1:]:
-                yield row
-            if i < len(items) - 1:
-                yield self._pad([NameCell()])
-
-    def _first_row(self, item, row):
-        return [self._format_name(item)] + row[1:]
-
-    def _format_name(self, item):
-        from robot.parsing.model import UserKeyword
-        type_ = 'keyword' if isinstance(item, UserKeyword) else 'test'
-        return AnchorNameCell(item.name, type_)
-
-    def _format_model_item(self, item, indent):
-        if isinstance(item, Documentation):
-            return self._format_documentation(item, indent)
-        rows = self._row_splitter.split(item.as_list(), indent)
- return [self._pad([NameCell(row[0])] + [HtmlCell(c) for c in row[1:]]) for row in rows]
-
-    def _format_documentation(self, doc, indent):
-        if indent:
-            start = [NameCell(), HtmlCell(doc.setting_name)]
-            value = doc.as_list()[1:]
-            if len(value) == 1:
- return [start + [DocumentationCell(doc.value, self._cols-1-indent)]]
-            return [self._pad(start + [HtmlCell(v) for v in value])]
-        return [[NameCell(doc.setting_name),
-                DocumentationCell(doc.value, self._cols-1)]]
-
-    def _format_row(self, row):
-        if row and not isinstance(row[0], basestring):
-            return row
- return self._pad([NameCell(row[0])] + [HtmlCell(c) for c in row[1:]])
-
-    def _pad(self, row, colspan=False, indent=0):
-        if colspan:
-            return row
-        return row + [HtmlCell()] * (self._cols - len(row) - indent)
-
-
-class SingleLineHtmlFormatter(_Formatter):
-
-    def __init__(self, cols):
-        self._cols = cols
-
-    def format_indented_table(self, table):
-        items = list(table)
-        for i, item in enumerate(items):
-            rows = list(self._rows_from_item(item, 1))
-            yield self._pad(self._first_row(item, rows[0]))
-            for row in rows[1:]:
-                yield self._pad(row)
-            if i < len(items) - 1:
-                yield self._pad([NameCell()])
-
-    def _pad(self, row):
-        return row + [HtmlCell()] * (self._cols - len(row))
-
-    def _first_row(self, item, row):
-        return [self._format_name(item)] + row[1:]
-
-    def _format_name(self, item):
-        from robot.parsing.model import UserKeyword
-        type_ = 'keyword' if isinstance(item, UserKeyword) else 'test'
-        return AnchorNameCell(item.name, type_)
-
-    def _format_model_item(self, item, indent):
-        if isinstance(item, Documentation):
-            return self._format_documentation(item, indent)
-        data = [''] * indent + item.as_list()
-        return [[NameCell(data[0])] + [HtmlCell(c) for c in data[1:]]]
-
-    def _format_documentation(self, doc, indent):
-        if indent:
-            start = [NameCell(), HtmlCell(doc.setting_name)]
-            value = doc.as_list()[1:]
-            if len(value) == 1:
-                return [start + [DocumentationCell(doc.value, 1)]]
-            return [start + [HtmlCell(v) for v in value]]
- return [[NameCell(doc.setting_name), DocumentationCell(doc.value, 1)]]
-
-
-class HtmlCell(object):
-    _backslash_matcher = re.compile(r'(\\+)n ')
-
-    def __init__(self, content='', attributes=None, tag='td', escape=True):
-        if escape:
-            content = utils.html_escape(content)
-        self.content = self._replace_newlines(content)
-        self.attributes = attributes or {}
-        self.tag = tag
-
-    def _replace_newlines(self, content):
-        def replacer(match):
-            backslash_count = len(match.group(1))
-            if backslash_count % 2 == 1:
-                return '%sn<br>\n' % match.group(1)
-            return match.group()
-        return self._backslash_matcher.sub(replacer, content)
-
-
-class NameCell(HtmlCell):
-
-    def __init__(self, name='', attributes=None):
-        HtmlCell.__init__(self, name, attributes)
-        self.attributes.update({'class': 'name'})
-
-
-class AnchorNameCell(HtmlCell):
-
-    def __init__(self, name, type_):
-        HtmlCell.__init__(self, self._link_from_name(name, type_),
-                          {'class': 'name'}, escape=False)
-
-    def _link_from_name(self, name, type_):
- return '<a name="%s_%s">%s</a>' % (type_, utils.html_attr_escape(name),
-                                           utils.html_escape(name))
-
-
-class DocumentationCell(HtmlCell):
-
-    def __init__(self, content, span):
-        HtmlCell.__init__(self, content)
- self.attributes = {'class': 'colspan%d' % span, 'colspan': '%d' % span}
-
-
-class HeaderCell(HtmlCell):
-
-    def __init__(self, name, span=1):
- HtmlCell.__init__(self, name, {'class': 'name', 'colspan': '%d' % span},
-                          tag='th')
-
-
-class RowSplitter(object):
-    _comment_mark = '#'
-    _empty_cell_escape = '${EMPTY}'
-    _line_continuation = '...'
-
-    def __init__(self, cols=8):
-        self._cols = cols
-
-    def split(self, row, indent):
-        self._in_comment = False
-        return self._split_to_rows(row, indent)
-
-    def _split_to_rows(self, data, indent=0):
-        if not data:
-            return [[]]
-        rows = []
-        while data:
-            current, data = self._split(self._indent(data, indent))
-            rows.append(self._escape_last_empty_cell(current))
-        return rows
-
-    def _split(self, data):
-        row, rest = data[:self._cols], data[self._cols:]
-        self._in_comment = any(c for c in row if
-                               c.startswith(self._comment_mark))
-        rest = self._add_line_continuation(rest)
-        return row, rest
-
-    def _escape_last_empty_cell(self, row):
-        if not row[-1].strip():
-            row[-1] = self._empty_cell_escape
-        return row
-
-    def _add_line_continuation(self, data):
-        if data:
-            if self._in_comment:
-                data[0] = self._comment_mark + data[0]
-            data = [self._line_continuation] + data
-        return data
-
-    def _indent(self, row, indent):
-        return [''] * indent + row
=======================================
--- /src/robot/writer/datafilewriter.py Wed Jan 18 22:55:12 2012
+++ /src/robot/writer/datafilewriter.py Fri Jan 20 03:06:10 2012
@@ -28,9 +28,9 @@
:param datafile: A robot.parsing.model.DataFile object to be written :param options: A :py:class:`.WriteConfiguration` is created with these
         """
-        context = WriteConfiguration(datafile, **options)
-        FileWriter(context).write(datafile)
-        context.finish()
+        configuration = WriteConfiguration(datafile, **options)
+        FileWriter(configuration).write(datafile)
+        configuration.finish()


 class WriteConfiguration(object):
=======================================
--- /src/robot/writer/filewriters.py    Wed Jan 18 22:55:12 2012
+++ /src/robot/writer/filewriters.py    Fri Jan 20 03:06:10 2012
@@ -11,6 +11,7 @@
 #  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 #  See the License for the specific language governing permissions and
 #  limitations under the License.
+from robot.writer.htmlformatter import HtmlFormatter

 try:
     import csv
@@ -20,7 +21,7 @@

 from robot import utils

-from .formatters import TsvFormatter, TxtFormatter, PipeFormatter, HtmlFormatter
+from .formatters import TsvFormatter, TxtFormatter, PipeFormatter
 from .htmltemplate import TEMPLATE_START, TEMPLATE_END


@@ -65,10 +66,10 @@
         self._write_row(self._formatter.header_row(table))

     def _formatted_table(self, table):
-        formatter = {'setting': self._formatter.setting_rows,
-                     'variable': self._formatter.variable_rows,
-                     'test case': self._formatter.test_rows,
-                     'keyword': self._formatter.keyword_rows}[table.type]
+        formatter = {'setting': self._formatter.setting_table,
+                     'variable': self._formatter.variable_table,
+                     'test case': self._formatter.test_table,
+                     'keyword': self._formatter.keyword_table}[table.type]
         return formatter(table)

     def _write_empty_row(self):
=======================================
--- /src/robot/writer/formatters.py     Tue Jan 10 05:00:23 2012
+++ /src/robot/writer/formatters.py     Fri Jan 20 03:06:10 2012
@@ -13,57 +13,74 @@
 #  limitations under the License.

 import re
-from robot.writer.tableformatters import SingleLineHtmlFormatter
-
-from .tableformatters import (RowSplittingFormatter, SplittingHtmlFormatter,
-    ColumnAligner, SettingTableAligner, NameCell, HeaderCell, HtmlCell)
+
+from .aligners import FirstColumnAligner, ColumnAligner
+from .dataextractor import DataExtractor
+from .rowsplitter import RowSplitter


-class _TestDataFileFormatter(object):
-
-    def variable_rows(self, variables):
- for row in self._variable_table_formatter().format_simple_table(variables):
-            yield self._format_row(row)
-
-    def setting_rows(self, settings):
- for row in self._setting_table_formatter().format_simple_table(settings):
-            yield self._format_row(row)
-
-    def test_rows(self, tests):
- for row in self._test_table_formatter(tests).format_indented_table(tests):
-            yield self._format_row(row)
-
-    def keyword_rows(self, keywords):
- for row in self._keyword_table_formatter(keywords).format_indented_table(keywords):
-            yield self._format_row(row)
-
-    def empty_row(self):
-        return self._format_row([])
-
-    def _format_row(self, row):
-        return row
-
-    def _should_align_columns(self, table):
- return table.type in ['test case', 'keyword'] and bool(table.header[1:])
-
-
-class TsvFormatter(_TestDataFileFormatter):
-
-    def __init__(self, cols=8):
-        self._cols = cols
-        self._formatter = RowSplittingFormatter(self._cols)
-
-    def _variable_table_formatter(self):
-        return self._formatter
-
-    def _setting_table_formatter(self):
-        return self._formatter
-
-    def _test_table_formatter(self, tests):
-        return self._formatter
-
-    def _keyword_table_formatter(self, keywords):
-        return self._formatter
+class _DataFileFormatter(object):
+    _want_names_on_first_content_row = False
+
+    def __init__(self, cols):
+        self._splitter = RowSplitter(cols)
+        self._cols = cols
+        self._current_table = None
+ self._extractor = DataExtractor(self._want_names_on_first_content_row)
+
+    def empty_row(self):
+        return self._format_row([])
+
+    def setting_table(self, settings):
+        self._current_table = settings
+        return self._simple_table()
+
+    def variable_table(self, variables):
+        self._current_table = variables
+        return self._simple_table()
+
+    def _simple_table(self):
+ return self._format_rows(self._extractor.rows_from_simple_table(self._current_table))
+
+    def test_table(self, tests):
+        self._current_table = tests
+        return self._indented_table()
+
+    def keyword_table(self, keywords):
+        self._current_table = keywords
+        return self._indented_table()
+
+    def _indented_table(self):
+ return self._format_rows(self._extractor.rows_from_indented_table(self._current_table))
+
+    def _format_rows(self, rows):
+        if self._should_split_rows():
+            return self._split_rows(rows)
+        return [self._format_row(r) for r in rows]
+
+    def _should_split_rows(self):
+        return True
+
+    def _split_rows(self, rows):
+        for row in rows:
+ for r in self._splitter.split(row, self._is_indented_table(self._current_table)):
+                yield self._format_row(r)
+
+    def _should_align_columns(self, table):
+        return self._is_indented_table(table) and bool(table.header[1:])
+
+    def _is_indented_table(self, table):
+        return table.type in ['test case', 'keyword']
+
+    def _format_row(self, row):
+        return row
+
+
+class TsvFormatter(_DataFileFormatter):
+
+    def __init__(self, cols=8):
+        _DataFileFormatter.__init__(self, cols)
+        self._cols = cols

     def header_row(self, table):
         return self._format_row(['*%s*' % cell for cell in table.header])
@@ -76,41 +93,41 @@
         return row + [''] * (self._cols - len(row))


-class TxtFormatter(_TestDataFileFormatter):
-    _FIRST_COL_WIDTH = 18
-    _SETTING_NAME_WIDTH = 14
+class TxtFormatter(_DataFileFormatter):
+    _test_or_keyword_name_width = 18
+    _setting_and_variable_name_width = 14
     _align_last_column = False

     def __init__(self, cols=8):
-        self._cols = cols
-
-    def _variable_table_formatter(self):
-        return SettingTableAligner(self._cols, self._SETTING_NAME_WIDTH)
-
-    def _setting_table_formatter(self):
-        return SettingTableAligner(self._cols, self._SETTING_NAME_WIDTH)
-
-    def _test_table_formatter(self, tests):
-        return self._indented_table_formatter(tests)
-
-    def _keyword_table_formatter(self, keywords):
-        return self._indented_table_formatter(keywords)
+        _DataFileFormatter.__init__(self, cols)
+        self._simple_aligner = FirstColumnAligner(cols,
+            self._setting_and_variable_name_width)
+        self._aligner = None
+
+    def _format_row(self, row):
+        row = self._escape(row)
+        if self._aligner:
+            return self._aligner.align_row(row)
+        return row

     def header_row(self, table):
         header = ['*** %s ***' % table.header[0]] + table.header[1:]
         if self._should_align_columns(table):
-            return ColumnAligner(self._FIRST_COL_WIDTH, table,
-                                 self._align_last_column).align_row(header)
+ aligner = ColumnAligner(self._test_or_keyword_name_width, table,
+                self._align_last_column)
+            return aligner.align_row(header)
         return header

-    def _indented_table_formatter(self, table):
-        if self._should_align_columns(table):
-            return ColumnAligner(self._FIRST_COL_WIDTH, table,
-                                 self._align_last_column)
-        return RowSplittingFormatter(self._cols)
-
-    def _format_row(self, row):
-        return self._escape(row)
+    def _should_split_rows(self):
+        if self._should_align_columns(self._current_table):
+            self._aligner = ColumnAligner(self._test_or_keyword_name_width,
+ self._current_table, self._align_last_column)
+            return False
+        elif self._is_indented_table(self._current_table):
+            self._aligner = None
+            return True
+        self._aligner = self._simple_aligner
+        return True

     def _escape(self, row):
         return self._escape_consecutive_whitespace(
@@ -147,50 +164,3 @@
             cell = cell[:-1] + '\\|'
         return cell

-
-class HtmlFormatter(_TestDataFileFormatter):
-
-    def __init__(self):
-        self._default_cols = 5
-        self._cols = self._default_cols
-        self._formatter = SplittingHtmlFormatter(self._default_cols)
-
-    def empty_row(self):
-        return [NameCell('')] + [HtmlCell('') for _ in range(self._cols-1)]
-
-    def _setting_table_formatter(self):
-        self._cols = self._default_cols
-        return self._formatter
-
-    def _variable_table_formatter(self):
-        self._cols = self._default_cols
-        return self._formatter
-
-    def _test_table_formatter(self, tests):
-        return self._dynamic_width_formatter(tests)
-
-    def _keyword_table_formatter(self, keywords):
-        return self._dynamic_width_formatter(keywords)
-
-    def _dynamic_width_formatter(self, table):
-        if len(table.header) == 1:
-            self._cols = self._default_cols
-            return SplittingHtmlFormatter(self._cols)
-        self._cols = max(self._max_column_count(table), len(table.header))
-        return SingleLineHtmlFormatter(self._cols)
-
-    def header_row(self, table):
-        if not self._should_align_columns(table) or len(table.header) == 1:
-            return [HeaderCell(table.header[0], self._default_cols)]
-        headers = self._pad_header(table)
-        return [HeaderCell(hdr) for hdr in headers]
-
-    def _pad_header(self, table):
- return table.header + [''] * (self._max_column_count(table) - len(table.header))
-
-    def _max_column_count(self, table):
-        count = 0
-        for item in table:
-            for child in item:
-                count = max(count, len(child.as_list()) + 1)
-        return count
=======================================
--- /utest/writer/test_formatters.py    Tue Jan  3 04:46:29 2012
+++ /utest/writer/test_formatters.py    Fri Jan 20 03:06:10 2012
@@ -1,8 +1,8 @@
 import unittest
 from robot.parsing.model import TestCaseTable, TestCaseFileSettingTable

-from robot.writer.formatters import TxtFormatter, HtmlFormatter, TsvFormatter, PipeFormatter
-from robot.writer.tableformatters import RowSplitter, HtmlCell
+from robot.writer.formatters import TxtFormatter, TsvFormatter, PipeFormatter, RowSplitter
+from robot.writer.htmlformatter import HtmlFormatter, HtmlCell
 from robot.utils.asserts import assert_equals, assert_true


@@ -40,7 +40,7 @@
     def test_empty_cell(self):
         settings = TestCaseFileSettingTable(None)
         settings.force_tags.value = ['f1', '', 'f3']
-        assert_equals(list(PipeFormatter().setting_rows(settings))[0],
+        assert_equals(list(PipeFormatter().setting_table(settings))[0],
                       ['Force Tags    ', 'f1', '  ', 'f3'])


@@ -59,7 +59,7 @@
         table = TestCaseFileSettingTable(None)
         table.set_header('Settings')
         table.doc.value = 'Some documentation'
-        formatted = list(self._formatter.setting_rows(table))
+        formatted = list(self._formatter.setting_table(table))
         assert_equals(self._rows_to_text(formatted),
                       [['Documentation', 'Some documentation']])
         assert_equals(formatted[0][1].attributes,
@@ -70,7 +70,7 @@
         test = table.add('A Test')
         test.tags.value = ['t1', 't2', 't3', 't4']
         formatted = self._rows(table)
-        assert_equals(len(formatted), 2)
+        assert_equals(len(formatted), 2, formatted)
assert_equals(formatted[0], ['<a name="test_A Test">A Test</a>', '[Tags]', 't1', 't2', 't3'])
         assert_equals(formatted[1], ['', '...', 't4', '', ''])

@@ -80,7 +80,7 @@
         test.doc.value = 'Some doc'
         assert_equals(self._rows(table)[0],
['<a name="test_Test">Test</a>', '[Documentation]', 'Some doc']) - assert_equals(list(self._formatter.test_rows(table))[0][2].attributes, + assert_equals(list(self._formatter.test_table(table))[0][2].attributes,
                       {'colspan': '3', 'class': 'colspan3'})

     def test_test_documentation_with_comment(self):
@@ -90,7 +90,7 @@
         test.doc._set_comment('a comment')
         assert_equals(self._rows(table)[0],
['<a name="test_Test">Test</a>', '[Documentation]', 'Some doc', '# a comment', '']) - assert_equals(list(self._formatter.test_rows(table))[0][2].attributes, {}) + assert_equals(list(self._formatter.test_table(table))[0][2].attributes, {})

     def test_testcase_table_custom_headers(self):
         self._check_header_length([], 1)
@@ -128,13 +128,13 @@
         self._check_row_lengths(table, 4)

     def _check_row_lengths(self, table, expected_length):
-        rows = list(self._formatter.test_rows(table))
+        rows = list(self._formatter.test_table(table))
         assert_true(len(rows) > 0)
         for row in rows:
             assert_equals(len(row), expected_length)

     def _rows(self, table):
-        return self._rows_to_text(self._formatter.test_rows(table))
+        return self._rows_to_text(self._formatter.test_table(table))

     def _rows_to_text(self, rows):
         return [[cell.content for cell in row] for row in rows]

Reply via email to