Add question class storage (lookups in QUESTION_CLASS)
authorW. Trevor King <wking@tremily.us>
Tue, 5 Feb 2013 15:58:40 +0000 (10:58 -0500)
committerW. Trevor King <wking@tremily.us>
Tue, 5 Feb 2013 15:58:40 +0000 (10:58 -0500)
This allows us to specify questions with alternate processing classes.
As a simple example, I've added NormalizedStringQuestion, which
softens the string comparison used in the basic Question.  The next
step is to add a command-line question ;).

quiz.json
quizzer/question.py
quizzer/quiz.py

index 1789fd67d0be893eb82c9d691ec7dbe96ae4b1d4..9677dba3574d40271b28ad43a52a2a9dea90b116 100644 (file)
--- a/quiz.json
+++ b/quiz.json
@@ -15,8 +15,9 @@
                                ]
                },
                {
+                       "class": "NormalizedStringQuestion",
                        "prompt": "What is your favourite color?",
-                       "answer": "Blue",
+                       "answer": "blue",
                        "hint": "Channel Sir Lancelot",
                        "dependencies": [
                                "What is your quest?"
index e423adf0da629d40b9e8feaef49931f54c5c1808..10ae4fd2003e6c503907fc0a649b31615564a3ad 100644 (file)
@@ -1,3 +1,10 @@
+QUESTION_CLASS = {}
+
+
+def register_question(question_class):
+    QUESTION_CLASS[question_class.__name__] = question_class
+
+
 class Question (object):
     def __init__(self, id=None, prompt=None, answer=None, help=None,
                  dependencies=None):
@@ -36,3 +43,23 @@ class Question (object):
 
     def check(self, answer):
         return answer == self.answer
+
+
+class NormalizedStringQuestion (Question):
+    def normalize(self, string):
+        return string.strip().lower()
+
+    def check(self, answer):
+        return self.normalize(answer) == self.normalize(self.answer)
+
+
+for name,obj in list(locals().items()):
+    if name.startswith('_'):
+        continue
+    try:
+        subclass = issubclass(obj, Question)
+    except TypeError:  # obj is not a class
+        continue
+    if subclass:
+        register_question(obj)
+del name, obj
index c3fa5a5df5a0ff6f4e19fc4913fa72bccd415df9..7c49e941f1a9e3b559a250efaccba9afa43c67d8 100644 (file)
@@ -28,14 +28,20 @@ class Quiz (list):
             raise NotImplementedError('upgrade from {} to {}'.format(
                     version, __version__))
         for state in data['questions']:
-            q = _question.Question()
+            question_class_name = state.pop('class', 'Question')
+            question_class = _question.QUESTION_CLASS[question_class_name]
+            q = question_class()
             q.__setstate__(state)
             self.append(q)
 
     def save(self, **kwargs):
+        questions = []
+        for question in self:
+            state = question.__getstate__()
+            state['class'] = type(question).__name__
         data = {
             'version': __version__,
-            'questions': [question.__getstate__() for question in self],
+            'questions': questions,
             }
         with self._open(mode='w', **kwargs) as f:
             _json.dump(