[system] / trunk / pg / macros / parserMultiPart.pl Repository:
ViewVC logotype

Diff of /trunk/pg/macros/parserMultiPart.pl

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

Revision 3632 Revision 3654
27# 27#
28# Finally, call $mp->cmp to produce the answer checker(s) used in the MultiPart. 28# Finally, call $mp->cmp to produce the answer checker(s) used in the MultiPart.
29# You need to provide a checker routine that will be called to determine if the 29# You need to provide a checker routine that will be called to determine if the
30# answers are correct or not. The checker will only be called if the student 30# answers are correct or not. The checker will only be called if the student
31# answers have no syntax errors and their types match the types of the professor's 31# answers have no syntax errors and their types match the types of the professor's
32# answers, so you don't ahve to worry about handling bad data from the student 32# answers, so you don't have to worry about handling bad data from the student
33# (at least as far as typechecking goes). 33# (at least as far as typechecking goes).
34# 34#
35# The checker routine should accept three parameters: a reference to the array 35# The checker routine should accept three parameters: a reference to the array
36# of correct answers, a reference to the array of student answers, and a reference 36# of correct answers, a reference to the array of student answers, and a reference
37# to the MultiPart itself. It should do whatever checking it needs to do and 37# to the MultiPart itself. It should do whatever checking it needs to do and
101# singleResult => 0 or 1 whether to show only one entry in the 101# singleResult => 0 or 1 whether to show only one entry in the
102# results area at the top of the page, 102# results area at the top of the page,
103# or one for each answer rule. 103# or one for each answer rule.
104# (Default: 0) 104# (Default: 0)
105# 105#
106# namedRules => 0 or 1 wether to use named rules or default 106# namedRules => 0 or 1 whether to use named rules or default
107# rule names. Use named rules if you need 107# rule names. Use named rules if you need
108# to intersperse other rules with the 108# to intersperse other rules with the
109# ones for the MultiPart, in which case 109# ones for the MultiPart, in which case
110# you must use NAMED_ANS not ANS. 110# you must use NAMED_ANS not ANS.
111# (Default: 0) 111# (Default: 0)
114# professor's answers must match exactly 114# professor's answers must match exactly
115# or just pass the usual type-match error 115# or just pass the usual type-match error
116# checking (in which case, you should check 116# checking (in which case, you should check
117# the types before you use the data). 117# the types before you use the data).
118# (Default: 1) 118# (Default: 1)
119#
120# allowBlankAnswers=>0 or 1 whether to remove the blank-check prefilter
121# from the answer checkers for the answer
122# checkers used for type checking the student's
123# answers.
124# (Default: 0)
119# 125#
120# separator => string the string to use between entries in the 126# separator => string the string to use between entries in the
121# results area when singleResult is set. 127# results area when singleResult is set.
122# 128#
123# tex_separator => string same, but for the preview area. 129# tex_separator => string same, but for the preview area.
137 $x = Value::makeValue($x) unless Value::isValue($x); 143 $x = Value::makeValue($x) unless Value::isValue($x);
138 push(@cmp,$x->cmp(@ans_defaults)); 144 push(@cmp,$x->cmp(@ans_defaults));
139 } 145 }
140 bless { 146 bless {
141 data => [@data], cmp => [@cmp], ans => [], 147 data => [@data], cmp => [@cmp], ans => [],
142 part => 0, singleResult => 0, namedRules => 0, checkTypes => 1, 148 part => 0, singleResult => 0, namedRules => 0,
149 checkTypes => 1, allowBlankAnswers => 0,
143 tex_separator => $separator.'\,', separator => $separator.' ', 150 tex_separator => $separator.'\,', separator => $separator.' ',
144 context => $$Value::context, id => $answerPrefix.($count++), 151 context => $$Value::context, id => $answerPrefix.($count++),
145 }, $class; 152 }, $class;
146} 153}
147 154
157 $self->{$id} = $options{$id}; 164 $self->{$id} = $options{$id};
158 delete $options{$id}; 165 delete $options{$id};
159 } 166 }
160 } 167 }
161 die "You must supply a checker subroutine" unless ref($self->{checker}) eq 'CODE'; 168 die "You must supply a checker subroutine" unless ref($self->{checker}) eq 'CODE';
169 if ($self->{allowBlankAnswers}) {
170 foreach my $cmp (@{$self->{cmp}}) {
171 $cmp->install_pre_filter('erase');
172 $cmp->install_pre_filter(sub {
173 my $ans = shift;
174 $ans->{student_ans} =~ s/^\s+//g;
175 $ans->{student_ans} =~ s/\s+$//g;
176 return $ans;
177 });
178 }
179 }
162 my @cmp = (); 180 my @cmp = ();
163 if ($self->{singleResult}) { 181 if ($self->{singleResult}) {
164 push(@cmp,$self->ANS_NAME(0)) if $self->{namedRules}; 182 push(@cmp,$self->ANS_NAME(0)) if $self->{namedRules};
165 push(@cmp,$self->single_cmp(%options)); 183 push(@cmp,$self->single_cmp(%options));
166 } else { 184 } else {
276sub entry_check { 294sub entry_check {
277 my $self = shift; my $ans = shift; 295 my $self = shift; my $ans = shift;
278 my $i = $ans->{part}; 296 my $i = $ans->{part};
279 $self->{ans}[$i] = $self->{cmp}[$i]->evaluate($ans->{student_ans}); 297 $self->{ans}[$i] = $self->{cmp}[$i]->evaluate($ans->{student_ans});
280 $self->{ans}[$i]->score(0); 298 $self->{ans}[$i]->score(0);
281 $self->perform_check if ($i == $self->length - 1); 299 $self->perform_check($ans) if ($i == $self->length - 1);
282 return $self->{ans}[$i]; 300 return $self->{ans}[$i];
283} 301}
284 302
285###################################################################### 303######################################################################
286 304
292# don't call the user's routine. 310# don't call the user's routine.
293# Otherwise, call it, and if there was an error, report that. 311# Otherwise, call it, and if there was an error, report that.
294# Set the individual scores based on the result from the user's routine. 312# Set the individual scores based on the result from the user's routine.
295# 313#
296sub perform_check { 314sub perform_check {
315 my $self = shift; my $rh_ans = shift;
297 my $self = shift; $self->{context}->clearError; 316 $self->{context}->clearError;
298 my @correct; my @student; 317 my @correct; my @student;
299 foreach my $ans (@{$self->{ans}}) { 318 foreach my $ans (@{$self->{ans}}) {
300 push(@correct,$ans->{correct_value}); 319 push(@correct,$ans->{correct_value});
301 push(@student,$ans->{student_value}); 320 push(@student,$ans->{student_value});
302 return if $ans->{ans_message} ne "" || !defined($ans->{student_value}); 321 return if $ans->{ans_message} ne "" || !defined($ans->{student_value});
303 return if $self->{checkTypes} && $ans->{student_value}->type ne $ans->{correct_value}->type; 322 return if $self->{checkTypes} && $ans->{student_value}->type ne $ans->{correct_value}->type;
304 } 323 }
305 my $result = Value::cmp_compare([@correct],[@student],$self); 324 my $result = Value::cmp_compare([@correct],[@student],$self,$rh_ans);
306 if (!defined($result) && $self->{context}{error}{flag}) {$self->cmp_error($self->{ans}[0]); return 1} 325 if (!defined($result) && $self->{context}{error}{flag}) {$self->cmp_error($self->{ans}[0]); return 1}
307 $result = 0 if (!defined($result) || $result eq ''); 326 $result = 0 if (!defined($result) || $result eq '');
308 if (ref($result) eq 'ARRAY') { 327 if (ref($result) eq 'ARRAY') {
309 die "Checker subroutine returned the wrong number of results" 328 die "Checker subroutine returned the wrong number of results"
310 if (scalar(@{$result}) != $self->length); 329 if (scalar(@{$result}) != $self->length);

Legend:
Removed from v.3632  
changed lines
  Added in v.3654

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9