diff --git a/20170613-mock/code/ggee/guessing/game.py b/20170613-mock/code/ggee/guessing/game.py index ddc610b..60d6e10 100755 --- a/20170613-mock/code/ggee/guessing/game.py +++ b/20170613-mock/code/ggee/guessing/game.py @@ -19,6 +19,35 @@ # TODO: implement a high-score # see https://github.com/chenl/talks/issues/4 +class PromptGGEE(object): + """This class was made to work around a problem, + where a string is translated before formatting. + + E.g. a part like `{level}` might translate too, + thus breaking the formatting. + + This class allows to replace `{level}` with `{0:0}`: + >>> prompt = PromptGGEE(3, 7, 5) + >>> 'using level {0:0}'.format(prompt) + + Using a fixed mapping between indices (0) and attrs (level), + we prevent the translation of any attr. + """ + + attr_by_index = {'0': 'level', '1': 'max_num', '2': 'num'} + + def __init__(self, level, max_num, num): + self.level = str(level) + self.max_num = str(max_num) + self.num = str(num) + + def __getitem__(self, item): + attr = self.attr_by_index[item] + return getattr(self, attr) + + def __format__(self, format_spec): + return self[format_spec] + def game(): # type: () -> None intro() @@ -47,14 +76,14 @@ def think_of_a_number(level): def play(level): # type: (int) -> None - print(T("Level {level}: 0 to {max_num}").format( - level=level, max_num=max_number(level))) num = think_of_a_number(level) + prompt = PromptGGEE(level=level, max_num=max_number(level), num=num) + print(T("Level {0:0}: 0 to {0:1}").format(prompt)) while True: print(T("Can you guess what number I am thinking about?")) guess = your_guess() if guess is None: - print(T("Just wanted you to know that I was thinking about {}").format(num)) + print(T("Just wanted you to know that I was thinking about {0:2}").format(prompt)) break if guess < num: print(T("No, my number is bigger than that")) diff --git a/20170613-mock/code/ggee/tests/test_game.py b/20170613-mock/code/ggee/tests/test_game.py index 4eafeaf..15c0b09 100644 --- a/20170613-mock/code/ggee/tests/test_game.py +++ b/20170613-mock/code/ggee/tests/test_game.py @@ -3,10 +3,9 @@ import pytest try: - from io import StringIO -except ImportError: - #from io import BytesIO as StringIO from StringIO import StringIO +except ImportError: + from io import StringIO try: from unittest import mock @@ -88,9 +87,16 @@ def test_your_guess_quit(mock_stdout, mock_readline, mock_lang): ) +def test_PromptGGEE(): + prompt = game.PromptGGEE(level=3, max_num=7, num=5) + assert '{0:0} {0:1} {0:2}'.format(prompt) == '3 7 5' + assert '{a} {b:1} {c}'.format(a='a', b=prompt, c='c') == 'a 7 c' + assert 'simple'.format(prompt) == 'simple' + + @pytest.mark.parametrize('guesses,expected_messages', [ ([4, 6, 5], [ # full scenario - "Level 3: 0 to 7", + "Level {0:0}: 0 to {0:1}", "Can you guess what number I am thinking about?", "No, my number is bigger than that", "Can you guess what number I am thinking about?", @@ -99,12 +105,12 @@ def test_your_guess_quit(mock_stdout, mock_readline, mock_lang): "Yes, this is the number I was thinking about! How did you know that?", ]), ([None], [ # empty scenario - "Level 3: 0 to 7", + "Level {0:0}: 0 to {0:1}", "Can you guess what number I am thinking about?", - "Just wanted you to know that I was thinking about 5", + "Just wanted you to know that I was thinking about {0:2}", ]), ([5], [ # lucky scenario - "Level 3: 0 to 7", + "Level {0:0}: 0 to {0:1}", "Can you guess what number I am thinking about?", "Yes, this is the number I was thinking about! How did you know that?", ]), @@ -120,5 +126,9 @@ def test_play(mock_stdout, mock_T, guesses, expected_messages): mock.patch('guessing.game.your_guess', side_effect=guesses): game.play(level) - mock_T.call_args_list = map(mock.call, expected_messages) - assert mock_stdout.getvalue() == '\n'.join(expected_messages) + '\n' + assert mock_T.call_args_list == map(mock.call, expected_messages) + + prompt = game.PromptGGEE(level=level, max_num=7, num=num) + printed_messages = [msg.format(prompt) + '\n' + for msg in expected_messages] + assert mock_stdout.getvalue() == ''.join(printed_messages)