(**** * * Module Quiz defines the objects and operations related to * creating a Quiz * for use by the CSTutor application. * *) module Quiz; from Page import all except TagsWeCareAbout; from Data import ServerFilespace; export all; object Quiz inherits from Page components: qc:QuizContent and cq:CurrentQuestion and ShowQuizResults and tp:TotalPoints and author:Author; description: (* A Quiz contains all the elements to present information in a Quiz. *); end Quiz; object CurrentQuestion is QuestionNumber description: (* This is equal to the maximum number of points on the quiz. *); end CurrentQuestion; object TotalPoints is integer description: (* This is equal to the maximum number of points on the quiz. *); end TotalPoints; object Author is UserID description: (* The author of the quiz. *); end Author; object ShowQuizResults is boolean description: (* If true, students are allowed to view their scores right after they take the quiz. If false, then students do not see their scores, and consequently do not see any Helpful Links or Next-Lesson Links. *); end ShowQuizResults; operation Submit -- look at data.rsl to see where this is going inputs: q:Quiz, s:ServerFilespace; outputs: s':ServerFilespace; precondition: (* ServerFilespace is not nil. *) s != nil; postcondition: (* there's an author folder af, with its author = the quiz's author in s.authorFolders, such that q in af.quizFolder *) (exists (af in s'.authorFolders) af.userID = q.Author); description: (* This operation happens when an user taking the quiz presses the submit button. *); end Submit; object QuestionNumber is integer description: (* The question's number. *); end QuestionNumber; (***********************************************************) object QuizContent is Question* description: (* Each quiz is made up of HTMLContent (which was inherited from Page) and QuizContent. This is the content that is specific to a quiz. *); end QuizContent; object Question is components: qn:QuestionNumber and pv:PointValue and qt:QuestionText and qac:QuestionAnswerContent; description: (* Defines the beginning and end of each question and all of the components that belong to each question. *); end Question; object QuestionAnswerContent is QuestionNumber and Answer* description: (* Each QuestionAnswerContent belongs to one question, which QuestionNumber denotes. It is also made up of a collection of Answer objects. *); end QuestionAnswerContent; object Answer is check:Checkbox or radio:RadioButton or text:Textbox or code:CodeSegment description: (* Each question can have multiple Answer objects. A question needs an Answer objects for each checkbox, radio button, textbox, and code segment. *); end Answer; object Checkbox is boolean description: (* If true, then the checkbox is checked. If false, then it is unchecked. *); end Checkbox; object RadioButton is boolean description: (* If true, then the radio button is selected. If false, then it is unselected. *); end RadioButton; object Textbox is string description: (* The value of the textbox is stored in here. *); end Textbox; object CodeSegment is cs:CodeString and GradeThroughComparisonOfCode description: (* The CodeString is the answer for the CodeSegment, and GradeThroughComparisonOfCode has to do with how it is graded. *); end CodeSegment; object GradeThroughComparisonOfCode is boolean description: (* if it is true, then the code segment is graded through comparison of code. if it is false, then it is graded through comparison of standard output. *); end GradeThroughComparisonOfCode; object CodeString is string description: (* This is the answer to a CodeSegment. *); end CodeString; (***********************************************************) object PointValue is integer description: (* The number of points a question is worth. *); end PointValue; object QuestionText is string* description: (* This includes all text in a question (but does not include Textbox or CodeSegment text). *); end QuestionText; object TagsWeCareAbout description: (* These are tags that need to be modeled for a particular tool's use of HTML, i.e., tags that the tool uses explicitly. These include tags, tags, and tags. *); end TagsWeCareAbout; (***********************************************************) operation InsertCheckbox is inputs: qac:QuestionAnswerContent and ica:IsCorrectAnswer; outputs: qac':QuestionAnswerContent; precondition: (* QuestionAnswerContent cannot be nil. *) (qac != nil); postcondition: (* Nothing about the Question was altered except for the checkbox was inserted in the current question. The correct answer is added to QuestionAnswerContent. *) (exists (newans:Answer | newans?check) ( newans.check = ica; )) and (forall (a':Answer) -- only the appropriate answer is altered. (a' in qac') iff ((a' in qac) or (a' = newans))); description: (* Inserts a selected checkbox if IsCorrectAnswer is true. Otherwise, inserts an unselected checkbox. *); end InsertCheckbox; object IsCorrectAnswer is boolean description: (* If true, then this Answer is a correct answer. If false, then it is incorrect. *); end IsCorrectAnswer; operation InsertRadioButton is inputs: qac:QuestionAnswerContent and ica:IsCorrectAnswer; outputs: qac':QuestionAnswerContent; precondition: (* QuestionAnswerContent cannot be nil. *) (qac != nil); postcondition: (* Nothing about the Question was altered except for the radio button was inserted in the current question. The correct answer is added to QuestionAnswerContent. *) (exists (newans:Answer | newans?radio) ( newans.radio = ica; )) and (forall (a':Answer) -- only the appropriate answer is altered. (a' in qac') iff ((a' in qac) or (a' = newans))); description: (* Inserts a selected radio button if IsCorrectAnswer is true. Otherwise, inserts an unselected radio button. *); end InsertRadioButton; operation InsertTextbox is inputs: qac:QuestionAnswerContent and input:TextboxInput; outputs: qac':QuestionAnswerContent; precondition: (* QuestionAnswerContent cannot be nil. *) (qac != nil); postcondition: (* Nothing about the Question was altered except for the textbox was inserted in the current question. The correct answer is added to QuestionAnswerContent. *) (exists (newans:Answer | newans?text) ( newans.text = input; )) and (forall (a':Answer) -- only the appropriate answer is altered. (a' in qac') iff ((a' in qac) or (a' = newans))); description: (* Inserts a textbox with TextboxInput as the value. *); end InsertTextbox; object TextboxInput is string description: (* This is the string value of the Textbox. *); end TextboxInput; operation InsertCodeSegment is inputs: qac:QuestionAnswerContent and input:TextboxInput and gtcoc:GradeThroughComparisonOfCode; outputs: qac':QuestionAnswerContent; precondition: (* QuestionAnswerContent cannot be nil. *) (qac != nil); postcondition: (* Nothing about the Question was altered except for the code segment was inserted in the current question. The correct answer is added to QuestionAnswerContent. *) (exists (newans:Answer | newans?code) ( newans.code.cs = input; )) and (forall (a':Answer) -- only the appropriate answer is altered. (a' in qac') iff ((a' in qac) or (a' = newans))); description: (* Inserts a textbox with TextboxInput as the value. *); end InsertCodeSegment; operation InsertQuestion is inputs: q:Quiz, ques:Question; outputs: q':Quiz; precondition: (* A Quiz must be open. Only the question number and point value is defined, everything else is nil. *) (q != nil) and (ques.qt = nil) and (ques.qac = nil); postcondition: (* A new question is created, and no other question is altered. *) forall (ques':Question) (ques' in q'.qc) iff (ques' = ques) or (ques'in q.qc); description: (* A new question is started. *); end InsertQuestion; (***********************************************************) object HelpfulLinks is HelpfulLink* description: (* These are the HelpfulLinks that are displayed next to each answer. *); end HelpfulLinks; object HelpfulLink is QuestionNumber and InternalLink description: (* These are InternalLinks which correspond to each question, as denoted by QuestionNumber. *); end HelpfulLink; operation EditHelpfulLink is inputs: q:Quiz and hl:HelpfulLink and il:InternalLink; outputs: hl':HelpfulLink; precondition: (* Students must be shown their answers. *) q.ShowQuizResults = true; postcondition: (* the HelpfulLink's internal link is changed to the new one. *) hl'.InternalLink = il; description: (* Changes a HelpfulLink's internal link. *); end EditHelpfulLink; (***********************************************************) object NextLessonLinks is nln:NextLessonLink* description: (* These are the Next-Lesson Links that are displayed at the end of each quiz result. *); end NextLessonLinks; object NextLessonLink is pe:PointsEarned and InternalLink description: (* These are InternalLinks which correspond to each question, as denoted by QuestionNumber. *); end NextLessonLink; object PointsEarned is integer description: (* This number corresponds to how many points the student needs to get right in order to be shown the corresponding Next-Lesson Link. *); end PointsEarned; operation EditNextLessonLink is inputs: nln:NextLessonLink and il:InternalLink; outputs: nln':NextLessonLink; precondition: (* Students must be shown their answers. *) ShowQuizResults = true; postcondition: (* the NextLessonLink's internal link is changed to the new one. *) nln'.il = il; description: (* Changes a NextLessonLink's internal link. *); end EditNextLessonLink; operation PointsEarnedIsValid is inputs: q:Quiz and nlns:NextLessonLinks; outputs: nlns':NextLessonLinks; precondition: (* Students must be shown their answers. *) ShowQuizResults = true; postcondition: (* isValid is true if: all PointsEarned objects are greater than zero, but no greater than the maximum number of points on the quiz; PointsEarned objects are also be in descending order. otherwise, it is false. *) forall (i:integer | (i >= 1) and (i < #nln)) (nln[i].pe > nln[i+1].pe) -- descending order and (nln[i].pe > 0) -- greater than 0 and (nln[i].pe <= q.tp); -- less or equal to the total points on quiz description: (* Checks PointsEarned objects for validity. This happens when the user presses OK in the Next-Lesson Links dialog. If they are valid, then this is true. Otherwise, it is false. *); end PointsEarnedIsValid; end Quiz;