From 19de315e839fb2f99166300881314d79ab8beff2 Mon Sep 17 00:00:00 2001 From: Tim Hunt Date: Thu, 12 Jul 2012 19:11:06 +0100 Subject: [PATCH] MDL-34306 gift question format: allow import of general feedback This change introduces #### as a separator for general feedback. You need to add ####General feedback goes here as the last thing inside the {...}. For example // question: 123 name: Shortanswer ::Shortanswer::Which is the best animal?{ =Frog#Good! =%50%Cat#What is it with Moodlers and cats? =%0%*#Completely wrong ####Here is some general feedback! } Note that this change is not entirely backwards compatible. It will break any existing GIFT file where the character sequence #### us used between the {} as part of the question. This seems highly unlikely. --- question/format/gift/format.php | 68 ++++++++-- .../gift/tests/fixtures/questions.gift.txt | 5 +- .../format/gift/tests/giftformat_test.php | 117 ++++++++++++++++++ 3 files changed, 175 insertions(+), 15 deletions(-) diff --git a/question/format/gift/format.php b/question/format/gift/format.php index 06bcebc564a..9373b066bfb 100644 --- a/question/format/gift/format.php +++ b/question/format/gift/format.php @@ -213,42 +213,56 @@ class qformat_gift extends qformat_default { $question->name = false; } - - // FIND ANSWER section - // no answer means its a description + // Find the answer section. $answerstart = strpos($text, '{'); $answerfinish = strpos($text, '}'); $description = false; - if (($answerstart === false) and ($answerfinish === false)) { + if ($answerstart === false && $answerfinish === false) { + // No answer means it's a description. $description = true; $answertext = ''; $answerlength = 0; - } else if (!(($answerstart !== false) and ($answerfinish !== false))) { + + } else if ($answerstart === false || $answerfinish === false) { $this->error(get_string('braceerror', 'qformat_gift'), $text); return false; + } else { $answerlength = $answerfinish - $answerstart; $answertext = trim(substr($text, $answerstart + 1, $answerlength - 1)); } - // Format QUESTION TEXT without answer, inserting "_____" as necessary + // Format the question text, without answer, inserting "_____" as necessary. if ($description) { $questiontext = $text; } else if (substr($text, -1) == "}") { - // no blank line if answers follow question, outside of closing punctuation - $questiontext = substr_replace($text, "", $answerstart, $answerlength+1); + // No blank line if answers follow question, outside of closing punctuation. + $questiontext = substr_replace($text, "", $answerstart, $answerlength + 1); } else { - // inserts blank line for missing word format - $questiontext = substr_replace($text, "_____", $answerstart, $answerlength+1); + // Inserts blank line for missing word format. + $questiontext = substr_replace($text, "_____", $answerstart, $answerlength + 1); } - // Get questiontext format from questiontext + // Look to see if there is any general feedback. + $gfseparator = strrpos($answertext, '####'); + if ($gfseparator === false) { + $generalfeedback = ''; + } else { + $generalfeedback = substr($answertext, $gfseparator + 4); + $answertext = trim(substr($answertext, 0, $gfseparator)); + } + + // Get questiontext format from questiontext. $text = $this->parse_text_with_format($questiontext); $question->questiontextformat = $text['format']; - $question->generalfeedbackformat = $text['format']; $question->questiontext = $text['text']; + // Get generalfeedback format from questiontext. + $text = $this->parse_text_with_format($generalfeedback, $question->questiontextformat); + $question->generalfeedback = $text['text']; + $question->generalfeedbackformat = $text['format']; + // set question name if not already set if ($question->name === false) { $question->name = $question->questiontext; @@ -609,6 +623,27 @@ class qformat_gift extends qformat_default { return $output; } + /** + * Outputs the general feedback for the question, if any. This needs to be the + * last thing before the }. + * @param object $question the question data. + * @param string $indent to put before the general feedback. Defaults to a tab. + * If this is not blank, a newline is added after the line. + */ + public function write_general_feedback($question, $indent = "\t") { + $generalfeedback = $this->write_questiontext($question->generalfeedback, + $question->generalfeedbackformat, $question->questiontextformat); + + if ($generalfeedback) { + $generalfeedback = '####' . $generalfeedback; + if ($indent) { + $generalfeedback = $indent . $generalfeedback . "\n"; + } + } + + return $generalfeedback; + } + public function writequestion($question) { global $OUTPUT; @@ -631,7 +666,9 @@ class qformat_gift extends qformat_default { case ESSAY: $expout .= $this->write_name($question->name); $expout .= $this->write_questiontext($question->questiontext, $question->questiontextformat); - $expout .= "{}\n"; + $expout .= "{"; + $expout .= $this->write_general_feedback($question, ''); + $expout .= "}\n"; break; case TRUEFALSE: @@ -662,6 +699,7 @@ class qformat_gift extends qformat_default { if ($rightfeedback) { $expout .= '#' . $rightfeedback; } + $expout .= $this->write_general_feedback($question, ''); $expout .= "}\n"; break; @@ -686,6 +724,7 @@ class qformat_gift extends qformat_default { } $expout .= "\n"; } + $expout .= $this->write_general_feedback($question); $expout .= "}\n"; break; @@ -699,6 +738,7 @@ class qformat_gift extends qformat_default { '#' . $this->write_questiontext($answer->feedback, $answer->feedbackformat, $question->questiontextformat) . "\n"; } + $expout .= $this->write_general_feedback($question); $expout .= "}\n"; break; @@ -717,6 +757,7 @@ class qformat_gift extends qformat_default { $answer->feedbackformat, $question->questiontextformat) . "\n"; } } + $expout .= $this->write_general_feedback($question); $expout .= "}\n"; break; @@ -729,6 +770,7 @@ class qformat_gift extends qformat_default { $subquestion->questiontextformat, $question->questiontextformat) . ' -> ' . $this->repchar($subquestion->answertext) . "\n"; } + $expout .= $this->write_general_feedback($question); $expout .= "}\n"; break; diff --git a/question/format/gift/tests/fixtures/questions.gift.txt b/question/format/gift/tests/fixtures/questions.gift.txt index e7ad9a611a6..c434dcdc096 100644 --- a/question/format/gift/tests/fixtures/questions.gift.txt +++ b/question/format/gift/tests/fixtures/questions.gift.txt @@ -37,9 +37,10 @@ =%0%*#Completely wrong } -// true/false +// true/false, with general feedback ::Q1:: 42 is the Absolute Answer to everything.{ -FALSE#42 is the Ultimate Answer.#You gave the right answer.}"; +FALSE#42 is the Ultimate Answer.#You gave the right answer. +####This is, of course, a Hitchiker's Guide to the Galaxy reference.}"; // name 0-11 ::2-08 TSL::TSL is blablabla.{T} diff --git a/question/format/gift/tests/giftformat_test.php b/question/format/gift/tests/giftformat_test.php index e06a12344af..54fcdb308c9 100644 --- a/question/format/gift/tests/giftformat_test.php +++ b/question/format/gift/tests/giftformat_test.php @@ -673,6 +673,62 @@ class qformat_gift_test extends question_testcase { $this->assert(new question_check_specified_fields_expectation($expectedq), $q); } + public function test_import_shortanswer_with_general_feedback() { + $gift = " +// question: 666 name: Shortanswer +::Shortanswer::Which is the best animal?{ + =Frog#Good! + =%50%Cat#What is it with Moodlers and cats? + =%0%*#Completely wrong + ####[html]Here is some general feedback! +}"; + $lines = preg_split('/[\\n\\r]/', str_replace("\r\n", "\n", $gift)); + + $importer = new qformat_gift(); + $q = $importer->readquestion($lines); + + $expectedq = (object) array( + 'name' => 'Shortanswer', + 'questiontext' => "Which is the best animal?", + 'questiontextformat' => FORMAT_MOODLE, + 'generalfeedback' => 'Here is some general feedback!', + 'generalfeedbackformat' => FORMAT_HTML, + 'qtype' => 'shortanswer', + 'defaultmark' => 1, + 'penalty' => 0.3333333, + 'length' => 1, + 'answer' => array( + 'Frog', + 'Cat', + '*', + ), + 'fraction' => array(1, 0.5, 0), + 'feedback' => array( + 0 => array( + 'text' => 'Good!', + 'format' => FORMAT_MOODLE, + 'files' => array(), + ), + 1 => array( + 'text' => "What is it with Moodlers and cats?", + 'format' => FORMAT_MOODLE, + 'files' => array(), + ), + 2 => array( + 'text' => "Completely wrong", + 'format' => FORMAT_MOODLE, + 'files' => array(), + ), + ), + ); + + // Repeated test for better failure messages. + $this->assertEquals($expectedq->answer, $q->answer); + $this->assertEquals($expectedq->fraction, $q->fraction); + $this->assertEquals($expectedq->feedback, $q->feedback); + $this->assert(new question_check_specified_fields_expectation($expectedq), $q); + } + public function test_export_shortanswer() { $qdata = (object) array( 'id' => 666 , @@ -728,6 +784,67 @@ class qformat_gift_test extends question_testcase { \t=%0%*#Completely wrong } +"; + + $this->assert_same_gift($expectedgift, $gift); + } + + public function test_export_shortanswer_with_general_feedback() { + $qdata = (object) array( + 'id' => 666 , + 'name' => 'Shortanswer', + 'questiontext' => "Which is the best animal?", + 'questiontextformat' => FORMAT_MOODLE, + 'generalfeedback' => 'Here is some general feedback!', + 'generalfeedbackformat' => FORMAT_HTML, + 'defaultmark' => 1, + 'penalty' => 1, + 'length' => 1, + 'qtype' => 'shortanswer', + 'options' => (object) array( + 'id' => 123, + 'question' => 666, + 'usecase' => 1, + 'answers' => array( + 1 => (object) array( + 'id' => 1, + 'answer' => 'Frog', + 'answerformat' => 0, + 'fraction' => 1, + 'feedback' => 'Good!', + 'feedbackformat' => FORMAT_MOODLE, + ), + 2 => (object) array( + 'id' => 2, + 'answer' => 'Cat', + 'answerformat' => 0, + 'fraction' => 0.5, + 'feedback' => "What is it with Moodlers and cats?", + 'feedbackformat' => FORMAT_MOODLE, + ), + 3 => (object) array( + 'id' => 3, + 'answer' => '*', + 'answerformat' => 0, + 'fraction' => 0, + 'feedback' => "Completely wrong", + 'feedbackformat' => FORMAT_MOODLE, + ), + ), + ), + ); + + $exporter = new qformat_gift(); + $gift = $exporter->writequestion($qdata); + + $expectedgift = "// question: 666 name: Shortanswer +::Shortanswer::Which is the best animal?{ +\t=%100%Frog#Good! +\t=%50%Cat#What is it with Moodlers and cats? +\t=%0%*#Completely wrong +\t####[html]Here is some general feedback! +} + "; $this->assert_same_gift($expectedgift, $gift);