# vim:ai:ff=unix:fileencoding=utf-8:sw=4:ts=4: # pretext.py # Copyright © 2008 Matthew W. Samsonoff. # # This program is free software: you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software # Foundation, either version 3 of the License, or (at your option) any later # version. # # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along with # this program. If not, see . import cStringIO import sys import unittest _TRACE = False def _sequence(trace, args): return _Command(trace, _State.sequence, _to_iterable(args)) def _text(trace, value): if None == value: raise TypeError, value if not isinstance(value, basestring): raise TypeError, value return _Command(trace, _State.text, value) def _to_command(value): if None == value: raise TypeError if isinstance(value, _Command): return value else: return text(value) def _to_iterable(args): if len(args) == 1: args = args[0] if None == args: raise TypeError else: return map(_to_command, args) def _trace(depth=1): #pragma: no cover frame = sys._getframe(depth) return (frame.f_code.co_filename, frame.f_lineno) if not _TRACE: _trace = lambda: None class _State(object): def __init__(self, stream, newline, tab): self._stream = stream self._newline = newline self._tab = tab self._indent = True self._stack = [] def empty(self): return self def newline(self): self._stream.write(self._newline) self._indent = True return self def indent(self): self._stack.append(self._tab) return self def indent_ex(self, tab): self._stack.append(tab) return self def dedent(self): self._stack.pop() return self def text(self, characters): if self._indent: for tab in self._stack: self._stream.write(tab) self._indent = False self._stream.write(characters) return self def wrap(self, prefix, middle, suffix, characters): return self def sequence(self, iterable): state = self for command in iterable: state = command._execute(state) return state def add_prefix(self, prefix, iterable): state = self for command in iterable: state = prefix._execute(state) state = command._execute(state) return state def add_suffix(self, suffix, iterable): state = self for command in iterable: state = command._execute(state) state = suffix._execute(state) return state def join(self, separator, iterable): state = self iterator = iter(iterable) try: command = iterator.next() state = command._execute(state) except StopIteration: pass else: for command in iterator: state = separator._execute(state) state = command._execute(state) return state class _Command(object): __slots__ = ('_trace', '_method', '_args', '_kwargs') def __init__(self, trace, method, *args, **kwargs): self._trace = trace self._method = method self._args = args self._kwargs = kwargs def _execute(self, state): try: return self._method(state, *self._args, **self._kwargs) except: #pragma: no cover if _TRACE: print >> sys.stderr, self._trace raise empty = _Command(None, _State.empty) newline = _Command(None, _State.newline) indent = _Command(None, _State.indent) dedent = _Command(None, _State.dedent) def indent_ex(tab): trace = _trace() return _Command(trace, _State.indent_ex, tab) def text(value): trace = _trace() return _text(trace, value) def textln(value): trace = _trace() return _sequence(trace, (_text(trace, value), newline)) def wrap(prefix, middle, suffix, characters): trace = _trace() return _Command(trace, _State.wrap, prefix, middle, suffix, characters) def sequence(*args): if 0 == len(args): return empty else: trace = _trace() return _sequence(trace, args) def add_prefix(prefix, *args): if 0 == len(args): return empty else: trace = _trace() return _Command( trace, _State.add_prefix, _to_command(prefix), _to_iterable(args)) def add_suffix(suffix, *args): if 0 == len(args): return empty else: trace = _trace() return _Command( trace, _State.add_suffix, _to_command(suffix), _to_iterable(args)) def join(separator, *args): if 0 == len(args): return empty else: trace = _trace() return _Command( trace, _State.join, _to_command(separator), _to_iterable(args)) def to_stream(text, stream, newline='\n', tab='\t'): state = _State(stream, newline, tab) text._execute(state) def to_string(text, newline='\n', tab='\t'): stream = cStringIO.StringIO() to_stream(text, stream, newline, tab) return stream.getvalue() class _Test(unittest.TestCase): # # to_string # def test_to_string(self): t = sequence( textln('a'), indent, textln('b')) s = to_string(t) self.assertEqual('a\n\tb\n', s) def test_to_string_newline(self): t = sequence( textln('a'), indent, textln('b')) s = to_string(t, newline='\r\n') self.assertEqual('a\r\n\tb\r\n', s) def test_to_string_tab(self): t = sequence( textln('a'), indent, textln('b')) s = to_string(t, tab=' ') self.assertEqual('a\n b\n', s) # # empty # def test_empty(self): t = empty s = to_string(t) self.assertEqual('', s) # # newline # def test_newline(self): t = newline s = to_string(t) self.assertEqual('\n', s) # # indent/dedent # def test_indent_1(self): t = sequence( textln('a'), indent, textln('b'), dedent, textln('c')) s = to_string(t) self.assertEqual('a\n\tb\nc\n', s) def test_indent_2(self): t = sequence( textln('a'), indent, textln('b'), indent, textln('c'), dedent, textln('d'), dedent, textln('e')) s = to_string(t) self.assertEqual('a\n\tb\n\t\tc\n\td\ne\n', s) def test_indent_empty(self): t = sequence( textln('a'), indent, textln('b'), empty) s = to_string(t) self.assertEqual('a\n\tb\n', s) # # text # def test_text(self): t = text('ab') s = to_string(t) self.assertEqual('ab', s) def test_text_TypeError_1(self): self.assertRaises(TypeError, text, 1) def test_text_TypeError_None(self): self.assertRaises(TypeError, text, None) # # textln # def test_textln(self): t = textln('ab') s = to_string(t) self.assertEqual('ab\n', s) def test_textln_TypeError_1(self): self.assertRaises(TypeError, textln, 1) def test_textln_TypeError_None(self): self.assertRaises(TypeError, textln, None) # # sequence # def test_sequence_0(self): t = sequence() s = to_string(t) self.assertEqual('', s) def test_sequence_empty_1(self): t = sequence(text('a'), empty, text('b')) s = to_string(t) self.assertEqual('ab', s) def test_sequence_empty_1_str(self): t = sequence('a', empty, 'b') s = to_string(t) self.assertEqual('ab', s) def test_sequence_empty_2(self): t = sequence(empty, empty) s = to_string(t) self.assertEqual('', s) # args def test_sequence_args_2(self): t = sequence(text('a'), text('b')) s = to_string(t) self.assertEqual('ab', s) def test_sequence_args_2_str(self): t = sequence('a', 'b') s = to_string(t) self.assertEqual('ab', s) def test_sequence_args_3(self): t = sequence(text('a'), text('b'), text('c')) s = to_string(t) self.assertEqual('abc', s) def test_sequence_args_3_str(self): t = sequence('a', 'b', 'c') s = to_string(t) self.assertEqual('abc', s) def test_sequence_args_TypeError(self): self.assertRaises(TypeError, sequence, None, None) # list def test_sequence_list_0(self): l = [] t = sequence(l) s = to_string(t) self.assertEqual('', s) def test_sequence_list_1(self): l = [text('a')] t = sequence(l) s = to_string(t) self.assertEqual('a', s) def test_sequence_list_1_str(self): l = ['a'] t = sequence(l) s = to_string(t) self.assertEqual('a', s) def test_sequence_list_2(self): l = [text('a'), text('b')] t = sequence(l) s = to_string(t) self.assertEqual('ab', s) def test_sequence_list_2_str(self): l = ['a', 'b'] t = sequence(l) s = to_string(t) self.assertEqual('ab', s) def test_sequence_list_3(self): l = [text('a'), text('b'), text('c')] t = sequence(l) s = to_string(t) self.assertEqual('abc', s) def test_sequence_list_3_str(self): l = ['a', 'b', 'c'] t = sequence(l) s = to_string(t) self.assertEqual('abc', s) def test_sequence_list_TypeError_iterable(self): self.assertRaises(TypeError, sequence, None) def test_sequence_list_TypeError_iterable_1(self): self.assertRaises(TypeError, sequence, [None]) # # add_prefix # def test_add_prefix(self): t = add_prefix(text('1')) s = to_string(t) self.assertEqual('', s) def test_add_prefix_str(self): t = add_prefix('1') s = to_string(t) self.assertEqual('', s) def test_add_prefix_empty_1(self): t = add_prefix(text('1'), text('a'), empty, text('b')) s = to_string(t) self.assertEqual('1a11b', s) def test_add_prefix_empty_1_str(self): t = add_prefix('1', 'a', empty, 'b') s = to_string(t) self.assertEqual('1a11b', s) def test_add_prefix_empty_2(self): t = add_prefix(text('1'), empty, empty) s = to_string(t) self.assertEqual('11', s) def test_add_prefix_empty_2_str(self): t = add_prefix('1', empty, empty) s = to_string(t) self.assertEqual('11', s) # args def test_add_prefix_args_2(self): t = add_prefix(text('1'), text('a'), text('b')) s = to_string(t) self.assertEqual('1a1b', s) def test_add_prefix_args_2_str(self): t = add_prefix('1', 'a', 'b') s = to_string(t) self.assertEqual('1a1b', s) def test_add_prefix_args_3(self): t = add_prefix(text('1'), text('a'), text('b'), text('c')) s = to_string(t) self.assertEqual('1a1b1c', s) def test_add_prefix_args_3_str(self): t = add_prefix('1', 'a', 'b', 'c') s = to_string(t) self.assertEqual('1a1b1c', s) def test_add_prefix_args_TypeError_prefix(self): self.assertRaises(TypeError, add_prefix, None, text('a'), text('b')) def test_add_prefix_args_TypeError_iterable(self): self.assertRaises(TypeError, add_prefix, text('1'), None, None) # list def test_add_prefix_list_0(self): l = [] t = add_prefix(text('1'), l) s = to_string(t) self.assertEqual('', s) def test_add_prefix_list_0_Str(self): l = [] t = add_prefix('1', l) s = to_string(t) self.assertEqual('', s) def test_add_prefix_list_1(self): l = [text('a')] t = add_prefix(text('1'), l) s = to_string(t) self.assertEqual('1a', s) def test_add_prefix_list_1_str(self): l = [text('a')] t = add_prefix('1', l) s = to_string(t) self.assertEqual('1a', s) def test_add_prefix_list_2(self): l = [text('a'), text('b')] t = add_prefix(text('1'), l) s = to_string(t) self.assertEqual('1a1b', s) def test_add_prefix_list_2_str(self): l = ['a', 'b'] t = add_prefix('1', l) s = to_string(t) self.assertEqual('1a1b', s) def test_add_prefix_list_TypeError_prefix(self): self.assertRaises(TypeError, add_prefix, None, [text('a')]) def test_add_prefix_list_TypeError_iterable(self): self.assertRaises(TypeError, add_prefix, text('1'), None) def test_add_prefix_list_TypeError_iterable_1(self): self.assertRaises(TypeError, add_prefix, text('1'), [None]) # # add_suffix # def test_add_suffix(self): t = add_suffix(text('1')) s = to_string(t) self.assertEqual('', s) def test_add_suffix_str(self): t = add_suffix('1') s = to_string(t) self.assertEqual('', s) def test_add_suffix_empty_1(self): t = add_suffix(text('1'), text('a'), empty, text('b')) s = to_string(t) self.assertEqual('a11b1', s) def test_add_suffix_empty_1_str(self): t = add_suffix('1', 'a', empty, 'b') s = to_string(t) self.assertEqual('a11b1', s) def test_add_suffix_empty_2(self): t = add_suffix(text('1'), empty, empty) s = to_string(t) self.assertEqual('11', s) def test_add_suffix_empty_2_str(self): t = add_suffix('1', empty, empty) s = to_string(t) self.assertEqual('11', s) # args def test_add_suffix_args_2(self): t = add_suffix(text('1'), text('a'), text('b')) s = to_string(t) self.assertEqual('a1b1', s) def test_add_suffix_args_2_str(self): t = add_suffix('1', 'a', 'b') s = to_string(t) self.assertEqual('a1b1', s) def test_add_suffix_args_3(self): t = add_suffix(text('1'), text('a'), text('b'), text('c')) s = to_string(t) self.assertEqual('a1b1c1', s) def test_add_suffix_args_3_str(self): t = add_suffix('1', 'a', 'b', 'c') s = to_string(t) self.assertEqual('a1b1c1', s) def test_add_suffix_args_TypeError_suffix(self): self.assertRaises(TypeError, add_suffix, None, text('a'), text('b')) def test_add_suffix_args_TypeError_iterable(self): self.assertRaises(TypeError, add_suffix, text('1'), None, None) # list def test_add_suffix_list_0(self): l = [] t = add_suffix(text('1'), l) s = to_string(t) self.assertEqual('', s) def test_add_suffix_list_0_str(self): l = [] t = add_suffix('1', l) s = to_string(t) self.assertEqual('', s) def test_add_suffix_list_1(self): l = [text('a')] t = add_suffix(text('1'), l) s = to_string(t) self.assertEqual('a1', s) def test_add_suffix_list_1_str(self): l = ['a'] t = add_suffix('1', l) s = to_string(t) self.assertEqual('a1', s) def test_add_suffix_list_2(self): l = [text('a'), text('b')] t = add_suffix(text('1'), l) s = to_string(t) self.assertEqual('a1b1', s) def test_add_suffix_list_2_str(self): l = ['a', 'b'] t = add_suffix('1', l) s = to_string(t) self.assertEqual('a1b1', s) def test_add_suffix_list_TypeError_suffix(self): self.assertRaises(TypeError, add_suffix, None, [text('a')]) def test_add_suffix_list_TypeError_iterable(self): self.assertRaises(TypeError, add_suffix, text('1'), None) def test_add_suffix_list_TypeError_iterable_1(self): self.assertRaises(TypeError, add_suffix, text('1'), [None]) # # join # def test_join(self): t = join(text('1')) s = to_string(t) self.assertEqual('', s) def test_join_str(self): t = join('1') s = to_string(t) self.assertEqual('', s) def test_join_empty(self): t = join(text('1'), empty, empty) s = to_string(t) self.assertEqual('1', s) # args def test_join_args_2(self): t = join(text('1'), text('a'), text('b')) s = to_string(t) self.assertEqual('a1b', s) def test_join_args_2_str(self): t = join('1', 'a', 'b') s = to_string(t) self.assertEqual('a1b', s) def test_join_args_3(self): t = join(text('1'), text('a'), text('b'), text('c')) s = to_string(t) self.assertEqual('a1b1c', s) def test_join_args_3_str(self): t = join('1', 'a', 'b', 'c') s = to_string(t) self.assertEqual('a1b1c', s) def test_join_args_TypeError_separator(self): self.assertRaises(TypeError, join, None, text('a'), text('b')) def test_join_args_TypeError_iterable(self): self.assertRaises(TypeError, join, text('1'), None, None) # list def test_join_list_0(self): l = [] t = join(text('1'), l) s = to_string(t) self.assertEqual('', s) def test_join_list_0_str(self): l = [] t = join('1', l) s = to_string(t) self.assertEqual('', s) def test_join_list_1(self): l = [text('a')] t = join(text('1'), l) s = to_string(t) self.assertEqual('a', s) def test_join_list_1_str(self): l = ['a'] t = join('1', l) s = to_string(t) self.assertEqual('a', s) def test_join_list_2(self): l = [text('a'), text('b')] t = join(text('1'), l) s = to_string(t) self.assertEqual('a1b', s) def test_join_list_2_str(self): l = ['a', 'b'] t = join('1', l) s = to_string(t) self.assertEqual('a1b', s) def test_join_list_TypeError_separator(self): self.assertRaises(TypeError, join, None, [text('a')]) def test_join_list_TypeError_iterable(self): self.assertRaises(TypeError, join, text('1'), None) def test_join_list_TypeError_iterable_1(self): self.assertRaises(TypeError, join, text('1'), [None]) if __name__ == '__main__': #pragma: no cover unittest.main()