quizzer: Add ChoiceQuestion.open_ended
authorW. Trevor King <wking@tremily.us>
Thu, 14 Mar 2013 11:54:50 +0000 (07:54 -0400)
committerW. Trevor King <wking@tremily.us>
Thu, 14 Mar 2013 11:54:50 +0000 (07:54 -0400)
This allows us to ask open-ended multiple-choice questions, like:

  Pick one:
  1) Answer-1
  2) Answer-2
  or fill in something else
  quizzer? Answer-3

quizzer/question.py
quizzer/ui/cli.py
quizzer/ui/wsgi.py

index a4da65534bd2a31db57fbc71c116646d14dfdf68..cc4cfff34a43c3be2fb840a7d2047db77f477e99 100644 (file)
@@ -108,15 +108,17 @@ class NormalizedStringQuestion (Question):
 class ChoiceQuestion (Question):
     _state_attributes = Question._state_attributes + [
         'display_choices',
+        'open_ended',
         ]
 
     def __setstate__(self, state):
-        if 'display_choices' not in state:
-            state['display_choices'] = False
+        for key in ['display_choices', 'open_ended']:
+            if key not in state:
+                state[key] = False
         super(ChoiceQuestion, self).__setstate__(state)
 
     def check(self, answer):
-        correct = answer in self.answer
+        correct = answer in self.answer or self.open_ended
         details = None
         if not correct:
             details = 'answer ({}) is not in list of expected values'.format(
index 7b857b0a06dfe96cecd89afdeda15d4c07199d71..e91a0dd25060e475d015c76677d63c50bd4ee332 100644 (file)
@@ -90,6 +90,8 @@ class QuestionCommandLine (_cmd.Cmd):
                 self.question.display_choices):
             for i,choice in enumerate(self.question.answer):
                 yield '{}) {}'.format(i, choice)
+            if self.question.open_ended:
+                yield 'or fill in something else'
         return []
 
     def _process_answer(self, answer):
index c29323c09bd99b24b4eab116ba8bf60120372776..de2c595372cc2b344e68134cf15b47eda2d19463 100644 (file)
@@ -244,10 +244,15 @@ class QuestionApp (WSGI_DataObject):
                 307, 'Temporary Redirect', headers=[('Location', '/results/')])
         if (isinstance(question, _question.ChoiceQuestion) and
                 question.display_choices):
-            answer_element = '\n'.join(
+            choices = [
                 ('<input type="radio" name="answer" value="{0}"/>{0}<br/>'
                  ).format(answer)
-                for answer in question.answer)
+                for answer in question.answer]
+            if question.open_ended:
+                choices.extend([
+                    '<input type="radio" name="answer" value="open_ended"/>',
+                    '<input type="text" size="60" name="answer-other"/>'])
+            answer_element = '\n'.join(choices)
         elif question.multiline:
             answer_element = (
                 '<textarea rows="5" cols="60" name="answer"></textarea>')
@@ -293,10 +298,16 @@ class QuestionApp (WSGI_DataObject):
             question = self.ui.quiz.get(id=question_id)
         except KeyError as e:
             raise HandlerError(404, 'Not Found') from e
-        if question.multiline:
+        if (isinstance(question, _question.ChoiceQuestion) and
+                question.display_choices and
+                question.open_ended and
+                raw_answer == 'open_ended'):
+            answer = print_answer = data.get('answer-other', None)
+        elif question.multiline:
             answer = raw_answer.splitlines()
+            print_answer = raw_answer
         else:
-            answer = raw_answer
+            answer = print_answer = raw_answer
         correct,details = self.ui.process_answer(
             question=question, answer=answer, user=user)
         link_target = '../question/'
@@ -323,7 +334,7 @@ class QuestionApp (WSGI_DataObject):
             '    <h1>Answer</h1>',
             '    <p>{}</p>'.format(
                 question.format_prompt(newline='<br/>')),
-            '    <pre>{}</pre>'.format(raw_answer),
+            '    <pre>{}</pre>'.format(print_answer),
             '    <p>{}</p>'.format(correct_msg),
             details or '',
             '    <form name="question" action="{}" method="post">'.format(