+from ..grid import symbols
+
+class GridRenderer(object):
+ """Class that renders a grid in some human-consumable form.
+
+ This base class's methods result in a flat string of symbols, but it's easy
+ to create a more useful rendering by just overriding a few methods.
+ """
+
+ def render_grid(self, grid):
+ """Renders the entire grid. Code on the outside probably only needs to
+ call this.
+
+ Returns a string.
+ """
+ parts = []
+
+ parts.append(self.before_grid(grid))
+ for idx, row in enumerate(grid._rows):
+ if idx and idx % grid._box_height == 0:
+ parts.append(self.inside_grid(grid))
+ parts.append(self.render_row(row))
+ parts.append(self.after_grid(grid))
+
+ return ''.join(parts)
+
+ def render_row(self, row):
+ """Renders a single row."""
+ parts = []
+
+ parts.append(self.before_row(row))
+ for idx, cell in enumerate(row.cells):
+ if idx and idx % row._grid._box_width == 0:
+ parts.append(self.inside_row(row))
+ parts.extend(self.render_cell(cell))
+ parts.append(self.after_row(row))
+
+ return ''.join(parts)
+
+ def render_cell(self, cell):
+ """Renders a single cell."""
+ return ''.join([
+ self.before_cell(cell),
+ self.inside_cell(cell),
+ self.after_cell(cell),
+ ])
+
+
+ def before_grid(self, grid):
+ """Content prepended before the entire grid."""
+ return self.inside_grid(grid)
+
+ def inside_grid(self, grid):
+ """Content inserted within the grid, between boxes."""
+ return ''
+
+ def after_grid(self, grid):
+ """Content appended after the entire grid."""
+ return self.inside_grid(grid)
+
+
+ def before_row(self, row):
+ """Content prepended before each row."""
+ return self.inside_row(row)
+
+ def inside_row(self, row):
+ """Content inserted within each row, between boxes."""
+ return ''
+
+ def after_row(self, row):
+ """Content appended after each row.
+
+ Note that newlines are not assumed; you must provide one if you want
+ one included in the rendering.
+ """
+
+ return self.inside_row(row)
+
+
+ def before_cell(self, cell):
+ """Content prepended before each cell in a row."""
+ return ''
+
+ def inside_cell(self, cell):
+ """Content used to represent the actual cell value."""
+ if cell.value:
+ return symbols[cell.value]
+ else:
+ return '.'
+
+ def after_cell(self, cell):
+ """Content appended after each row in a cell."""
+ return ''
+