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

Annotation of /trunk/pg/macros/PG.pl

Parent Directory Parent Directory | Revision Log Revision Log


Revision 6252 - (view) (download) (as text)

1 : gage 6248
2 :     #use AnswerEvaluator;
3 :    
4 :    
5 :     # provided by the translator
6 :     # initialize PGcore and PGrandom
7 :    
8 :    
9 :     $main::VERSION ="WW2";
10 :    
11 :     sub _PG_init{
12 :     $main::VERSION ="WW2.9+";
13 :     }
14 :     sub not_null {PGcore::not_null(@_)};
15 :    
16 :    
17 :     our $PG;
18 :    
19 :     sub DEBUG_MESSAGE {
20 :     $PG->append_debug_message(@_);
21 :     }
22 :    
23 :    
24 :     sub DOCUMENT {
25 :    
26 :     # get environment
27 :     $rh_envir = \%envir; #KLUDGE FIXME
28 :     # warn "rh_envir is ",ref($rh_envir);
29 :     $PG = new PGcore($rh_envir, # can add key/value options to modify
30 :     );
31 :     $PG->clear_internal_debug_messages;
32 :    
33 :     # initialize main:: variables
34 :    
35 :     $ANSWER_PREFIX = $PG->{ANSWER_PREFIX};
36 :     $QUIZ_PREFIX = $PG->{QUIZ_PREFIX};
37 :     $showPartialCorrectAnswers = $PG->{PG_FLAGS}->{showPartialCorrectAnswers};
38 :     $showHint = $PG->{PG_FLAGS}->{showHint};
39 :     $solutionExists = $PG->{PG_FLAGS}->{solutionExists};
40 :     $hintExists = $PG->{PG_FLAGS}->{hintExists};
41 :     $pgComment = '';
42 :     %gifs_created = %{ $PG->{gifs_created}};
43 :     %external_refs = %{ $PG->{external_refs}};
44 :    
45 :     @KEPT_EXTRA_ANSWERS =(); #temporary hack
46 :    
47 :     my %envir = %$rh_envir;
48 :     $displayMode = $PG->{displayMode};
49 :     $PG_random_generator = $PG->{PG_random_generator};
50 :     # Save the file name for use in error messages
51 :     # Doesn't appear to be used FIXME
52 :     # my ($callpkg,$callfile) = caller(0);
53 :     # $envir{__files__}{$callfile} = $envir{templateDirectory}.$envir{fileName};
54 :    
55 :     #no strict;
56 :     foreach my $var (keys %envir) {
57 :     PG_restricted_eval(qq!\$main::$var = \$envir{$var}!); #whew!! makes sure $var is interpolated but $main:: is evaluated at run time.
58 :     warn "Problem defining $var while initializing the PG problem: $@" if $@;
59 :     }
60 :     #use strict;
61 :     #FIXME
62 :     # load java script needed for displayModes
63 :     if ($envir{displayMode} eq 'HTML_jsMath') {
64 :     my $prefix = "";
65 :     if (!$envir{jsMath}{reportMissingFonts}) {
66 :     $prefix .= '<SCRIPT>noFontMessage = 1</SCRIPT>'."\n";
67 :     } elsif ($main::envir{jsMath}{missingFontMessage}) {
68 :     $prefix .= '<SCRIPT>missingFontMessage = "'.$main::envir{jsMath}{missingFontMessage}.'"</SCRIPT>'."\n";
69 :     }
70 :     $prefix .= '<SCRIPT>processDoubleClicks = '.($main::envir{jsMath}{processDoubleClicks}?'1':'0')."</SCRIPT>\n";
71 :     TEXT(
72 :     $prefix,
73 :     '<SCRIPT SRC="'.$envir{jsMathURL}. '"></SCRIPT>' . "\n" ,
74 :     '<NOSCRIPT><CENTER><FONT COLOR="#CC0000">' ,
75 :     "$BBOLD", 'Warning: the mathematics on this page requires JavaScript.', ,$BR,
76 :     'If your browser supports it, be sure it is enabled.',
77 :     "$EBOLD",
78 :     '</FONT></CENTER><p>
79 :     </NOSCRIPT>'
80 :     );
81 :     TEXT('<SCRIPT>jsMath.Setup.Script("plugins/noImageFonts.js")</SCRIPT>')
82 :     if ($envir{jsMath}{noImageFonts});
83 :     } elsif ($envir{displayMode} eq 'HTML_asciimath') {
84 :     TEXT('<SCRIPT SRC="'.$main::envir{asciimathURL}.'"></SCRIPT>' . "\n" ,
85 :     '<SCRIPT>mathcolor = "black"</SCRIPT>' );
86 :     } elsif ($envir{displayMode} eq 'HTML_LaTeXMathML') {
87 :     TEXT('<SCRIPT SRC="'.$envir{LaTeXMathMLURL}.'"></SCRIPT>'."\n");
88 :    
89 :     }
90 :    
91 :     }
92 :     $main::displayMode = $PG->{displayMode};
93 :     $main::PG = $PG;
94 :     sub TEXT {
95 :     $PG->TEXT(@_) ;
96 :     }
97 :    
98 :     sub HEADER_TEXT {
99 :     $PG->HEADER_TEXT(@_);
100 :     }
101 :    
102 :     sub LABELED_ANS {
103 :     $PG->LABELED_ANS(@_); # returns pointer to the labeled answer group
104 :     }
105 :    
106 :     sub NAMED_ANS {
107 :     $PG->LABELED_ANS(@_); # returns pointer to the labeled answer group
108 :     }
109 :    
110 :     sub ANS {
111 :     #warn "using PGnew for ANS";
112 :     $PG->ANS(@_); # returns pointer to the labeled answer group
113 :     }
114 :    
115 :     sub RECORD_ANS_NAME {
116 :     $PG->record_ans_name(@_);
117 :     }
118 :    
119 :     sub inc_ans_rule_count {
120 :     #$PG->{unlabeled_answer_blank_count}++;
121 :     #my $num = $PG->{unlabeled_answer_blank_count};
122 :     DEBUG_MESSAGE( " using PG to inc_ans_rule_count = $num ", caller(2));
123 :     warn " using PG to inc_ans_rule_count = $num ", caller(2);
124 :     $PG->{unlabeled_answer_blank_count};
125 :     }
126 :     sub ans_rule_count {
127 :     $PG->{unlabeled_answer_blank_count};
128 :     }
129 :     sub NEW_ANS_NAME {
130 :     return "" if $PG_STOP_FLAG;
131 :     #my $number=shift;
132 :     # we have an internal count so the number not actually used.
133 :     my $name =$PG->record_unlabeled_ans_name();
134 :     $name;
135 :     }
136 :     sub NEW_ARRAY_NAME {
137 :     return "" if $PG_STOP_FLAG;
138 :     my $name =$PG->record_unlabeled_array_name();
139 :     $name;
140 :     }
141 :    
142 :     # new subroutine
143 :     sub NEW_ANS_BLANK {
144 :     return "" if $PG_STOP_FLAG;
145 :     $PG->record_unlabeled_ans_name(@_);
146 :     }
147 :    
148 :     sub ANS_NUM_TO_NAME {
149 :     $PG->new_label(@_); # behaves as in PG.pl
150 :     }
151 :    
152 :     sub store_persistent_data {
153 :     $PG->store_persistent_data(@_); #needs testing
154 :     }
155 :     sub RECORD_FORM_LABEL { # this stores form data (such as sticky answers), but does nothing more
156 :     # it's a bit of hack since we are storing these in the
157 :     # KEPT_EXTRA_ANSWERS queue even if they aren't answers per se.
158 :     warn "Using RECORD_FORM_LABEL -- deprecated?";
159 :     RECORD_EXTRA_ANSWERS(@_);
160 :     }
161 :    
162 :     sub RECORD_EXTRA_ANSWERS {
163 :     return "" if $PG_STOP_FLAG;
164 :     my $label = shift; # the label of the input box or textarea
165 :     eval(q!push(@main::KEPT_EXTRA_ANSWERS, $label)!); #put the labels into the hash to be caught later for recording purposes
166 :     $label;
167 :    
168 :     }
169 :    
170 :    
171 :     sub NEW_ANS_ARRAY_NAME { # this keeps track of the answers within an array which are entered implicitly,
172 :     # rather than with a specific label
173 :     return "" if $PG_STOP_FLAG;
174 :     my $number=shift;
175 :     $main::vecnum = -1;
176 :     my $row = shift;
177 :     my $col = shift;
178 :     # my $array_ans_eval_label = "ArRaY"."$number"."__"."$vecnum".":";
179 :     my $label = $PG->{QUIZ_PREFIX}.$PG->{ARRAY_PREFIX}."$number"."__"."$vecnum".":"."$row".":"."$col"."__";
180 :     # my $response_group = new PGresponsegroup($label,undef);
181 :     # $PG->record_ans_name($array_ans_eval_label, $response_group);
182 :     # What does vecnum do?
183 :     # The name is simply so that it won't conflict when placed on the HTML page
184 :     # my $array_label = shift;
185 :     $PG->record_array_name($label); # returns $array_label, $ans_label
186 :     }
187 :    
188 :     sub NEW_ANS_ARRAY_NAME_EXTENSION {
189 :     NEW_ANS_ARRAY_ELEMENT_NAME(@_);
190 :     }
191 :    
192 :     sub NEW_ANS_ARRAY_ELEMENT_NAME { # creates a new array element answer name and records it
193 :    
194 :     return "" if $PG_STOP_FLAG;
195 :     my $number=shift;
196 :     my $row_num = shift;
197 :     my $col_num = shift;
198 :     if( $row_num == 0 && $col_num == 0 ){
199 :     $main::vecnum += 1;
200 :     }
201 :     # my $ans_label = "ArRaY".sprintf("%04u", $number);
202 :     my $ans_label = $PG->new_array_label($number);
203 :     my $element_ans_label = $PG->new_array_element_label($ans_label,$row_num, $col_num,vec_num=>$vecnum);
204 :     my $response = new PGresponsegroup($ans_label,$element_ans_label, undef);
205 :     $PG->extend_ans_group($ans_label,$response);
206 :     $element_ans_label;
207 :     }
208 :     sub NEW_LABELED_ANS_ARRAY { #not in PG_original
209 :     my $ans_label = shift;
210 :     my @response_list = @_;
211 :     #$PG->extend_ans_group($ans_label,@response_list);
212 :     $PG->{PG_ANSWERS_HASH}->{$ans_label}->insert_responses(@response_list);
213 :     # should this return an array of labeled answer blanks???
214 :     }
215 :     sub EXTEND_ANS_ARRAY { #not in PG_original
216 :     my $ans_label = shift;
217 :     my @response_list = @_;
218 :     #$PG->extend_ans_group($ans_label,@response_list);
219 :     $PG->{PG_ANSWERS_HASH}->{$ans_label}->append_responses(@response_list);
220 :     }
221 :     sub CLEAR_RESPONSES {
222 :     my $ans_label = shift;
223 :     # my $response_label = shift;
224 :     # my $ans_value = shift;
225 :     if (defined ($PG->{PG_ANSWERS_HASH}->{$ans_label}) ) {
226 :     my $responsegroup = $PG->{PG_ANSWERS_HASH}->{$ans_label}->{response};
227 :     if ( ref($responsegroup) ) {
228 :     $responsegroup->clear;
229 :     } else {
230 :     $responsegroup = $PG->{PG_ANSWERS_HASH}->{$ans_label}->{response} = new PGresponsegroup($label);
231 :     }
232 :     }
233 :     '';
234 :     }
235 :     sub INSERT_RESPONSE {
236 :     my $ans_label = shift;
237 :     my $response_label = shift;
238 :     my $ans_value = shift;
239 :     my $selected = shift;
240 :     # warn "\n\nanslabel $ans_label responselabel $response_label value $ans_value";
241 :     if (defined ($PG->{PG_ANSWERS_HASH}->{$ans_label}) ) {
242 :     my $responsegroup = $PG->{PG_ANSWERS_HASH}->{$ans_label}->{response};
243 :     $responsegroup->append_response($response_label, $ans_value, $selected);
244 :     #warn "\n$responsegroup responses are now ", $responsegroup->responses;
245 :     }
246 :     '';
247 :     }
248 :    
249 :     sub EXTEND_RESPONSE { # for radio buttons and checkboxes
250 :     my $ans_label = shift;
251 :     my $response_label = shift;
252 :     my $ans_value = shift;
253 :     my $selected = shift;
254 :     # warn "\n\nanslabel $ans_label responselabel $response_label value $ans_value";
255 :     if (defined ($PG->{PG_ANSWERS_HASH}->{$ans_label}) ) {
256 :     my $responsegroup = $PG->{PG_ANSWERS_HASH}->{$ans_label}->{response};
257 :     $responsegroup->extend_response($response_label, $ans_value,$selected);
258 : gage 6252 #warn "\n$responsegroup responses are now ", pretty_print($response_group);
259 : gage 6248 }
260 :     '';
261 :     }
262 :     sub ENDDOCUMENT {
263 :     # check that answers match
264 :     # gather up PG_FLAGS elements
265 :    
266 :    
267 :     my @elements = qw(showPartialCorrectAnswers
268 :     recordSubmittedAnswers refreshCachedImages
269 :     hintExists solutionExists
270 :     );
271 :     while (@elements) {
272 :     my $var= shift @elements;
273 :     $PG->{PG_FLAGS}->{$var} = ${$var};
274 :     }
275 :     $PG->{PG_FLAGS}->{comment} = $pgComment; #KLUDGE #FIXME
276 :     $PG->{PG_FLAGS}->{showHintLimit} = $showHint; #KLUDGE #FIXME
277 :    
278 :    
279 :     # install problem grader
280 :     if (defined($PG->{PG_FLAGS}->{PROBLEM_GRADER_TO_USE}) ) {
281 :     # problem grader defined within problem -- no further action needed
282 :     } elsif ( defined( $rh_envir->{PROBLEM_GRADER_TO_USE} ) ) {
283 :     if (ref($rh_envir->{PROBLEM_GRADER_TO_USE}) eq 'CODE' ) { # user defined grader
284 :     $PG->{PG_FLAGS}->{PROBLEM_GRADER_TO_USE} = $rh_envir->{PROBLEM_GRADER_TO_USE};
285 :     } elsif ($rh_envir->{PROBLEM_GRADER_TO_USE} eq 'std_problem_grader' ) {
286 :     if (defined(&std_problem_grader) ){
287 :     $PG->{PG_FLAGS}->{PROBLEM_GRADER_TO_USE} = \&std_problem_grader; # defined in PGanswermacros.pl
288 :     } # std_problem_grader is the default in any case so don't give a warning.
289 :     } elsif ($rh_envir->{PROBLEM_GRADER_TO_USE} eq 'avg_problem_grader' ) {
290 :     if (defined(&avg_problem_grader) ){
291 :     $PG->{PG_FLAGS}->{PROBLEM_GRADER_TO_USE} = \&avg_problem_grader; # defined in PGanswermacros.pl
292 :     }
293 :     } else {
294 :     warn "Error: ". $PG->{PG_FLAGS}->{PROBLEM_GRADER_TO_USE} . "is not a known program grader.";
295 :     }
296 :     } elsif (defined(&std_problem_grader)) {
297 :     $PG->{PG_FLAGS}->{PROBLEM_GRADER_TO_USE} = \&std_problem_grader; # defined in PGanswermacros.pl
298 :     } else {
299 :     # PGtranslator will install its default problem grader
300 :     }
301 :    
302 :     # add javaScripts
303 :     if ($rh_envir->{displayMode} eq 'HTML_jsMath') {
304 :     TEXT('<SCRIPT> jsMath.wwProcess() </SCRIPT>');
305 :     } elsif ($rh_envir->{displayMode} eq 'HTML_asciimath') {
306 :     TEXT('<SCRIPT> translate() </SCRIPT>');
307 :     my $STRING = join("", @{$PG->{HEADER_ARRAY} });
308 :     unless ($STRING =~ m/mathplayer/) {
309 :     HEADER_TEXT('<object id="mathplayer" classid="clsid:32F66A20-7614-11D4-BD11-00104BD3F987">' . "\n" .
310 :     '</object><?import namespace="mml" implementation="#mathplayer"?>'
311 :     );
312 :     }
313 :    
314 :     }
315 :     TEXT( MODES(%{$rh_envir->{problemPostamble}}) );
316 :    
317 :    
318 :    
319 :    
320 :    
321 :     @PG_ANSWERS=();
322 :    
323 :     #warn keys %{ $PG->{PG_ANSWERS_HASH} };
324 :     @PG_ANSWER_ENTRY_ORDER = ();
325 :     my $ans_debug = 0;
326 :     foreach my $key (keys %{ $PG->{PG_ANSWERS_HASH} }) {
327 :     $answergroup = $PG->{PG_ANSWERS_HASH}->{$key};
328 :     #warn "$key is defined =", defined($answergroup), "PG object is $PG";
329 :     #################
330 :     # EXTRA ANSWERS KLUDGE
331 :     #################
332 :     # The first response in each answer group is placed in @PG_ANSER_ENTRY_ORDER and %PG_ANSWERS_HASH
333 :     # The remainder of the response keys are placed in the EXTRA ANSWERS ARRAY
334 :     if (defined($answergroup)) {
335 :     my @response_keys = $answergroup->{response}->response_labels;
336 :     warn pretty_print($answergroup->{response}) if $ans_debug==1;
337 :     my $response_key = shift @response_keys;
338 :     #unshift @response_keys, $response_key unless ($response_key eq $answer_group->{ans_label});
339 :     # don't save the first response key if it is the same as the ans_label
340 :     # maybe we should insure that the first response key is always the same as the answer label?
341 :     # even if no answer blank is printed for it? or a hidden answer blank?
342 :     # this is still a KLUDGE
343 :     # for compatibility the first response key is closer to the old method than the $ans_label
344 :     # this is because a response key might indicate an array but an answer label won't
345 :     push @PG_ANSWERS, $response_key,$answergroup->{ans_eval};
346 :     push @PG_ANSWER_ENTRY_ORDER, $response_key;
347 :     push @KEPT_EXTRA_ANSWERS, @response_keys;
348 :     } else {
349 :     #warn "$key is ", join("|",%{$PG->{PG_ANSWERS_HASH}->{$key}});
350 :     }
351 :     }
352 :     push @KEPT_EXTRA_ANSWERS, keys %{$PG->{PERSISTENCE_HASH}};
353 :     my %PG_ANSWERS_HASH = @PG_ANSWERS;
354 :     $PG->{PG_FLAGS}->{KEPT_EXTRA_ANSWERS} = \@KEPT_EXTRA_ANSWERS;
355 :     $PG->{PG_FLAGS}->{ANSWER_ENTRY_ORDER} = \@PG_ANSWER_ENTRY_ORDER;
356 :     warn "KEPT_EXTRA_ANSWERS", join(" ", @KEPT_EXTRA_ANSWERS), $BR if $ans_debug==1;
357 :     warn "PG_ANSWER_ENTRY_ORDER",join(" ",@PG_ANSWER_ENTRY_ORDER), $BR if $ans_debug==1;
358 :     warn "DEBUG messages", join( "$BR",@{$PG->get_debug_messages} ) if $ans_debug==1;
359 :     warn "INTERNAL_DEBUG messages", join( "$BR",@{$PG->get_internal_debug_messages} ) if $ans_debug==1;
360 :     $STRINGforOUTPUT = join("", @{$PG->{OUTPUT_ARRAY} });
361 :    
362 :    
363 :     $STRINGforHEADER_TEXT = join("", @{$PG->{HEADER_ARRAY} });
364 :    
365 :     # warn pretty_print($PG->{PG_ANSWERS_HASH});
366 :     #warn "printing another warning";
367 :    
368 :     (\$STRINGforOUTPUT, \$STRINGforHEADER_TEXT,\%PG_ANSWERS_HASH, $PG->{PG_FLAGS} , $PG );
369 :     }
370 : sh002i 5179 ################################################################################
371 : gage 6248 #
372 :     # macros from dangerousMacros
373 :     #
374 :     ################################################################################
375 :     sub alias {
376 :     #warn "alias called ",@_;
377 :     $PG->{PG_alias}->make_alias(@_) ;
378 :     }
379 :     sub insertGraph {
380 :     $PG->insertGraph(@_);
381 :     }
382 :    
383 :     sub findMacroFile {
384 :     $PG->{PG_alias}->findMacroFile(@_);
385 :     }
386 :     sub check_url {
387 :     $PG->{PG_alias}->check_url(@_);
388 :     }
389 :     sub findAppletCodebase {
390 :     $PG->{PG_alias}->findAppletCodebase(@_);
391 :     }
392 :    
393 :     sub loadMacros {
394 :     $PG->{PG_loadMacros}->loadMacros(@_);
395 :     }
396 :     # FIXME? these were taken from the former dangerousMacros.pl file and might have issues when placed here.
397 :     #
398 :     # Some constants that can be used in perl experssions
399 :     #
400 :    
401 :     # ^function i
402 :     # ^uses $_parser_loaded
403 :     # ^uses &Complex::i
404 :     # ^uses &Value::Package
405 :     sub i () {
406 :     # check if Parser.pl is loaded, otherwise use Complex package
407 :     if (!eval(q!$main::_parser_loaded!)) {return Complex::i}
408 :     return Value->Package("Formula")->new('i')->eval;
409 :     }
410 :    
411 :     # ^function j
412 :     # ^uses $_parser_loaded
413 :     # ^uses &Value::Package
414 :     sub j () {
415 :     if (!eval(q!$main::_parser_loaded!)) {return 'j'}
416 :     Value->Package("Formula")->new('j')->eval;
417 :     }
418 :    
419 :     # ^function k
420 :     # ^uses $_parser_loaded
421 :     # ^uses &Value::Package
422 :     sub k () {
423 :     if (!eval(q!$main::_parser_loaded!)) {return 'k'}
424 :     Value->Package("Formula")->new('k')->eval;
425 :     }
426 :    
427 :     # ^function pi
428 :     # ^uses &Value::Package
429 :     sub pi () {Value->Package("Formula")->new('pi')->eval}
430 :    
431 :     # ^function Infinity
432 :     # ^uses &Value::Package
433 :     sub Infinity () {Value->Package("Infinity")->new()}
434 :    
435 :    
436 :     # ^function abs
437 :     # ^function sqrt
438 :     # ^function exp
439 :     # ^function log
440 :     # ^function sin
441 :     # ^function cos
442 :     # ^function atan2
443 :     #
444 :     # Allow these functions to be overridden
445 :     # (needed for log() to implement $useBaseTenLog)
446 :     #
447 :     use subs 'abs', 'sqrt', 'exp', 'log', 'sin', 'cos', 'atan2';
448 :     sub abs($) {return CORE::abs($_[0])};
449 :     sub sqrt($) {return CORE::sqrt($_[0])};
450 :     sub exp($) {return CORE::exp($_[0])};
451 :     sub log($) {return CORE::log($_[0])};
452 :     sub sin($) {return CORE::sin($_[0])};
453 :     sub cos($) {return CORE::cos($_[0])};
454 :     sub atan2($$) {return CORE::atan2($_[0],$_[1])};
455 :    
456 :     sub Parser::defineLog {eval {sub log($) {CommonFunction->Call("log",@_)}}};
457 :     =head2 Filter utilities
458 :    
459 :     These two subroutines can be used in filters to set default options. They
460 :     help make filters perform in uniform, predictable ways, and also make it
461 :     easy to recognize from the code which options a given filter expects.
462 :    
463 :    
464 :     =head4 assign_option_aliases
465 :    
466 :     Use this to assign aliases for the standard options. It must come before set_default_options
467 :     within the subroutine.
468 :    
469 :     assign_option_aliases(\%options,
470 :     'alias1' => 'option5'
471 :     'alias2' => 'option7'
472 :     );
473 :    
474 :    
475 :     If the subroutine is called with an option " alias1 => 23 " it will behave as if it had been
476 :     called with the option " option5 => 23 "
477 :    
478 :     =cut
479 :    
480 :    
481 :     # ^function assign_option_aliases
482 :     sub assign_option_aliases {
483 :     my $rh_options = shift;
484 :     warn "The first entry to set_default_options must be a reference to the option hash" unless ref($rh_options) eq 'HASH';
485 :     my @option_aliases = @_;
486 :     while (@option_aliases) {
487 :     my $alias = shift @option_aliases;
488 :     my $option_key = shift @option_aliases;
489 :    
490 :     if (defined($rh_options->{$alias} )) { # if the alias appears in the option list
491 :     if (not defined($rh_options->{$option_key}) ) { # and the option itself is not defined,
492 :     $rh_options->{$option_key} = $rh_options->{$alias}; # insert the value defined by the alias into the option value
493 :     # the FIRST alias for a given option takes precedence
494 :     # (after the option itself)
495 :     } else {
496 :     warn "option $option_key is already defined as", $rh_options->{$option_key}, "<br>\n",
497 :     "The attempt to override this option with the alias $alias with value ", $rh_options->{$alias},
498 :     " was ignored.";
499 :     }
500 :     }
501 :     delete($rh_options->{$alias}); # remove the alias from the initial list
502 :     }
503 :    
504 :     }
505 :    
506 :     =head4 set_default_options
507 :    
508 :     set_default_options(\%options,
509 :     '_filter_name' => 'filter',
510 :     'option5' => .0001,
511 :     'option7' => 'ascii',
512 :     'allow_unknown_options => 0,
513 :     }
514 :    
515 :     Note that the first entry is a reference to the options with which the filter was called.
516 :    
517 :     The option5 is set to .0001 unless the option is explicitly set when the subroutine is called.
518 :    
519 :     The B<'_filter_name'> option should always be set, although there is no error if it is missing.
520 :     It is used mainly for debugging answer evaluators and allows
521 :     you to keep track of which filter is currently processing the answer.
522 :    
523 :     If B<'allow_unknown_options'> is set to 0 then if the filter is called with options which do NOT appear in the
524 :     set_default_options list an error will be signaled and a warning message will be printed out. This provides
525 :     error checking against misspelling an option and is generally what is desired for most filters.
526 :    
527 :     Occasionally one wants to write a filter which accepts a long list of options, not all of which are known in advance,
528 :     but only uses a subset of the options
529 :     provided. In this case, setting 'allow_unkown_options' to 1 prevents the error from being signaled.
530 :    
531 :     =cut
532 :    
533 :     # ^function set_default_options
534 :     # ^uses pretty_print
535 :     sub set_default_options {
536 :     my $rh_options = shift;
537 :     warn "The first entry to set_default_options must be a reference to the option hash" unless ref($rh_options) eq 'HASH';
538 :     my %default_options = @_;
539 :     unless ( defined($default_options{allow_unknown_options}) and $default_options{allow_unknown_options} == 1 ) {
540 :     foreach my $key1 (keys %$rh_options) {
541 :     warn "This option |$key1| is not recognized in this subroutine<br> ", pretty_print($rh_options) unless exists($default_options{$key1});
542 :     }
543 :     }
544 :     foreach my $key (keys %default_options) {
545 :     if ( not defined($rh_options->{$key} ) and defined( $default_options{$key} ) ) {
546 :     $rh_options->{$key} = $default_options{$key}; #this allows tol => undef to allow the tol option, but doesn't define
547 :     # this key unless tol is explicitly defined.
548 :     }
549 :     }
550 :     }
551 :     1;
552 :     __END__
553 :    
554 :     ################################################################################
555 : sh002i 5568 # WeBWorK Online Homework Delivery System
556 : gage 6248 # Copyright © 2000-2007 The WeBWorK Project, http://openwebwork.sf.net/
557 : gage 6252 # $CVSHeader: pg/macros/PG.pl,v 1.41 2010/05/14 01:13:12 gage Exp $
558 : sh002i 5568 #
559 : sh002i 5179 # This program is free software; you can redistribute it and/or modify it under
560 :     # the terms of either: (a) the GNU General Public License as published by the
561 :     # Free Software Foundation; either version 2, or (at your option) any later
562 :     # version, or (b) the "Artistic License" which comes with this package.
563 : sh002i 5568 #
564 : sh002i 5179 # This program is distributed in the hope that it will be useful, but WITHOUT
565 :     # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
566 :     # FOR A PARTICULAR PURPOSE. See either the GNU General Public License or the
567 :     # Artistic License for more details.
568 :     ################################################################################
569 : gage 4997
570 : sh002i 5179 =head1 NAME
571 : sh002i 1050
572 : sh002i 5179 PG.pl - Provides core Program Generation Language functionality.
573 : sh002i 1050
574 : sh002i 5179 =head1 SYNPOSIS
575 : sh002i 1050
576 : sh002i 5179 In a PG problem:
577 : sh002i 1050
578 : sh002i 5568 DOCUMENT(); # should be the first statment in the problem
579 :    
580 :     loadMacros(.....); # (optional) load other macro files if needed.
581 :     # (loadMacros is defined in F<dangerousMacros.pl>)
582 :    
583 :     HEADER_TEXT(...); # (optional) used only for inserting javaScript into problems.
584 :    
585 :     TEXT( # insert text of problems
586 :     "Problem text to be displayed. ",
587 :     "Enter 1 in this blank:",
588 :     ANS_RULE(1,30) # ANS_RULE() defines an answer blank 30 characters long.
589 :     # It is defined in F<PGbasicmacros.pl>
590 :     );
591 :    
592 :     ANS(answer_evalutors); # see F<PGanswermacros.pl> for examples of answer evaluatiors.
593 :    
594 :     ENDDOCUMENT() # must be the last statement in the problem
595 : sh002i 1050
596 : sh002i 5179 =head1 DESCRIPTION
597 : sh002i 1050
598 : sh002i 5179 This file provides the fundamental macros that define the PG language. It
599 :     maintains a problem's text, header text, and answers:
600 : sh002i 1050
601 : sh002i 5179 =over
602 : sh002i 1050
603 : sh002i 5179 =item *
604 : sh002i 1050
605 : sh002i 5179 Problem text: The text to appear in the body of the problem. See TEXT()
606 :     below.
607 : sh002i 1050
608 : sh002i 5179 =item *
609 : sh002i 1050
610 : sh002i 5179 Header text: When a problem is processed in an HTML-based display mode,
611 :     this variable can contain text that the caller should place in the HEAD of the
612 :     resulting HTML page. See HEADER_TEXT() below.
613 : sh002i 1050
614 : sh002i 5179 =item *
615 : sh002i 1050
616 : sh002i 5179 Implicitly-labeled answers: Answers that have not been explicitly
617 :     assigned names, and are associated with their answer blanks by the order in
618 :     which they appear in the problem. These types of answers are designated using
619 :     the ANS() macro.
620 : sh002i 1050
621 : sh002i 5179 =item *
622 : sh002i 1050
623 : sh002i 5179 Explicitly-labeled answers: Answers that have been explicitly assigned
624 :     names with the LABELED_ANS() macro, or a macro that uses it. An explicitly-
625 :     labeled answer is associated with its answer blank by name.
626 : sh002i 1050
627 : sh002i 5179 =item *
628 : sh002i 1050
629 : sh002i 5179 "Extra" answers: Names of answer blanks that do not have a 1-to-1
630 :     correspondance to an answer evaluator. For example, in matrix problems, there
631 :     will be several input fields that correspond to the same answer evaluator.
632 : sh002i 1050
633 : sh002i 5179 =back
634 : sh002i 1050
635 : sh002i 5179 =head1 USAGE
636 : sh002i 1050
637 : sh002i 5179 This file is automatically loaded into the namespace of every PG problem. The
638 :     macros within can then be called to define the structure of the problem.
639 : sh002i 1050
640 : sh002i 5179 DOCUMENT() should be the first executable statement in any problem. It
641 :     initializes vriables and defines the problem environment.
642 : sh002i 1050
643 : sh002i 5179 ENDDOCUMENT() must be the last executable statement in any problem. It packs
644 :     up the results of problem processing for delivery back to WeBWorK.
645 : sh002i 1050
646 : sh002i 5179 The HEADER_TEXT(), TEXT(), and ANS() macros add to the header text string,
647 :     body text string, and answer evaluator queue, respectively.
648 : sh002i 1050
649 : sh002i 5179 =over
650 :    
651 :     =item HEADER_TEXT()
652 : sh002i 1050
653 : sh002i 5179 HEADER_TEXT("string1", "string2", "string3");
654 : sh002i 1050
655 : sh002i 5179 HEADER_TEXT() concatenates its arguments and appends them to the stored header
656 :     text string. It can be used more than once in a file.
657 : sh002i 1050
658 : sh002i 5179 The macro is used for material which is destined to be placed in the HEAD of
659 :     the page when in HTML mode, such as JavaScript code.
660 : sh002i 1050
661 : sh002i 5179 Spaces are placed between the arguments during concatenation, but no spaces are
662 :     introduced between the existing content of the header text string and the new
663 :     content being appended.
664 : sh002i 1050
665 :    
666 :    
667 : sh002i 5179 =item TEXT()
668 : sh002i 1050
669 : sh002i 5179 TEXT("string1", "string2", "string3");
670 : sh002i 1050
671 : sh002i 5179 TEXT() concatenates its arguments and appends them to the stored problem text
672 :     string. It is used to define the text which will appear in the body of the
673 :     problem. It can be used more than once in a file.
674 : sh002i 1050
675 : sh002i 5179 This macro has no effect if rendering has been stopped with the STOP_RENDERING()
676 :     macro.
677 : sh002i 1050
678 : sh002i 5179 This macro defines text which will appear in the problem. All text must be
679 :     passed to this macro, passed to another macro that calls this macro, or included
680 :     in a BEGIN_TEXT/END_TEXT block, which uses this macro internally. No other
681 :     statements in a PG file will directly appear in the output. Think of this as the
682 :     "print" function for the PG language.
683 :    
684 :     Spaces are placed between the arguments during concatenation, but no spaces are
685 :     introduced between the existing content of the header text string and the new
686 :     content being appended.
687 :    
688 : sh002i 1050
689 : gage 3387
690 : sh002i 5179 =item ANS()
691 : gage 3387
692 : sh002i 5179 TEXT(ans_rule(), ans_rule(), ans_rule());
693 :     ANS($answer_evaluator1, $answer_evaluator2, $answer_evaluator3);
694 : gage 3387
695 : sh002i 5179 Adds the answer evaluators listed to the list of unlabeled answer evaluators.
696 :     They will be paired with unlabeled answer rules (a.k.a. answer blanks) in the
697 :     order entered. This is the standard method for entering answers.
698 : gage 3387
699 : sh002i 5179 In the above example, answer_evaluator1 will be associated with the first
700 :     answer rule, answer_evaluator2 with the second, and answer_evaluator3 with the
701 :     third. In practice, the arguments to ANS() will usually be calls to an answer
702 :     evaluator generator such as the cmp() method of MathObjects or the num_cmp()
703 :     macro in L<PGanswermacros.pl>.
704 :    
705 : gage 3387
706 :    
707 : sh002i 5179 =item LABELED_ANS()
708 : gage 3387
709 : sh002i 5179 TEXT(labeled_ans_rule("name1"), labeled_ans_rule("name2"));
710 :     LABELED_ANS(name1 => answer_evaluator1, name2 => answer_evaluator2);
711 : gage 3387
712 : sh002i 5179 Adds the answer evaluators listed to the list of labeled answer evaluators.
713 :     They will be paired with labeled answer rules (a.k.a. answer blanks) in the
714 :     order entered. This allows pairing of answer evaluators and answer rules that
715 :     may not have been entered in the same order.
716 : gage 3387
717 :    
718 : sh002i 1050
719 :    
720 : sh002i 5179 =item STOP_RENDERING()
721 : sh002i 1050
722 : sh002i 5179 STOP_RENDERING() unless all_answers_are_correct();
723 : lr003k 1122
724 : sh002i 5179 Temporarily suspends accumulation of problem text and storing of answer blanks
725 :     and answer evaluators until RESUME_RENDERING() is called.
726 : lr003k 1122
727 : sh002i 5179
728 : lr003k 1122
729 : sh002i 5179 =item RESUME_RENDERING()
730 : gage 3385
731 : sh002i 5179 RESUME_RENDERING();
732 :    
733 :     Resumes accumulating problem text and storing answer blanks and answer
734 :     evaluators. Reverses the effect of STOP_RENDERING().
735 :    
736 :    
737 : sh002i 1050
738 : sh002i 5179 =item ENDDOCUMENT()
739 : sh002i 1050
740 : sh002i 5179 ENDDOCUMENT();
741 : sh002i 1050
742 : sh002i 5179 When PG problems are evaluated, the result of evaluating the entire problem is
743 :     interpreted as the return value of ENDDOCUMENT(). Therefore, ENDDOCUMENT() must
744 : gage 5442 be the last executable statement of every problem. It can only appear once. It
745 :     returns a list consisting of:
746 : sh002i 1050
747 :    
748 : gage 6248
749 :    
750 : sh002i 5179 =item *
751 : sh002i 1050
752 : sh002i 5179 A reference to a string containing the rendered text of the problem.
753 : sh002i 1050
754 : sh002i 5179 =item *
755 :    
756 :     A reference to a string containing text to be placed in the HEAD block
757 :     when in and HTML-based mode (e.g. for JavaScript).
758 :    
759 :     =item *
760 :    
761 :     A reference to the hash mapping answer labels to answer evaluators.
762 :    
763 :     =item *
764 :    
765 :     A reference to a hash containing various flags:
766 :    
767 :    
768 : gage 6248
769 : sh002i 5179 =item *
770 :    
771 :     C<showPartialCorrectAnswers>: determines whether students are told which of their answers in a problem are wrong.
772 :    
773 :     =item *
774 :    
775 :     C<recordSubmittedAnswers>: determines whether students submitted answers are saved.
776 :    
777 :     =item *
778 :    
779 :     C<refreshCachedImages>: determines whether the cached image of the problem in typeset mode is always refreshed
780 :     (i.e. setting this to 1 means cached images are not used).
781 :    
782 :     =item *
783 :    
784 :     C<solutionExits>: indicates the existence of a solution.
785 :    
786 :     =item *
787 :    
788 :     C<hintExits>: indicates the existence of a hint.
789 :    
790 :     =item *
791 :    
792 :     C<comment>: contents of COMMENT commands if any.
793 :    
794 :     =item *
795 :    
796 :     C<showHintLimit>: determines the number of attempts after which hint(s) will be shown
797 :    
798 :     =item *
799 :    
800 :     C<PROBLEM_GRADER_TO_USE>: a reference to the chosen problem grader.
801 :     ENDDOCUMENT chooses the problem grader as follows:
802 :    
803 :     =over
804 :    
805 :     =item *
806 :    
807 :     If a problem grader has been chosen in the problem by calling
808 :     C<install_problem_grader(\&grader)>, it is used.
809 :    
810 :     =item *
811 :    
812 :     Otherwise, if the C<PROBLEM_GRADER_TO_USE> PG environment variable
813 :     contains a reference to a subroutine, it is used.
814 :    
815 :     =item *
816 :    
817 :     Otherwise, if the C<PROBLEM_GRADER_TO_USE> PG environment variable
818 :     contains the string C<std_problem_grader> or the string C<avg_problem_grader>,
819 :     C<&std_problem_grader> or C<&avg_problem_grader> are used. These graders are defined
820 :     in L<PGanswermacros.pl>.
821 :    
822 :     =item *
823 :    
824 :     Otherwise, the PROBLEM_GRADER_TO_USE flag will contain an empty value
825 :     and the PG translator should select C<&std_problem_grader>.
826 :    
827 :     =back
828 :    
829 :     =back
830 :    
831 :    
832 : gage 6248
833 : sh002i 1050 =cut
834 :    
835 :    
836 : sh002i 5179 ################################################################################
837 : sh002i 1050
838 : sh002i 5179 =head1 PRIVATE MACROS
839 : sh002i 1050
840 : sh002i 5179 These macros should only be used by other macro files. In practice, they are
841 :     used exclusively by L<PGbasicmacros.pl>.
842 :    
843 :     =over
844 :    
845 :     =item inc_ans_rule_count()
846 :    
847 : gage 6248 NEW_ANS_NAME();
848 : sh002i 5179
849 :     Increments the internal count of the number of answer blanks that have been
850 :     defined ($ans_rule_count) and returns the new count. This should only be used
851 :     when one is about to define a new answer blank, for example with NEW_ANS_NAME().
852 :    
853 : sh002i 1050 =cut
854 :    
855 : sh002i 5179 =item RECORD_ANS_NAME()
856 :    
857 : gage 6248 RECORD_ANS_NAME("label", "VALUE");
858 : sh002i 5179
859 :     Records the label for an answer blank. Used internally by L<PGbasicmacros.pl>
860 :     to record the order of explicitly-labelled answer blanks.
861 :    
862 :     =cut
863 :    
864 :     =item NEW_ANS_NAME()
865 :    
866 : gage 6248 NEW_ANS_NAME();
867 : sh002i 5179
868 : gage 6248 Generates an anonymous answer label from the internal count The label is
869 : sh002i 5179 added to the list of implicity-labeled answers. Used internally by
870 :     L<PGbasicmacros.pl> to generate labels for unlabeled answer blanks.
871 :    
872 :     =cut
873 :    
874 :     =item ANS_NUM_TO_NAME()
875 :    
876 :     ANS_NUM_TO_NAME($num);
877 :    
878 :     Generates an answer label from the supplied answer number, but does not add it
879 :     to the list of inplicitly-labeled answers. Used internally by
880 :     L<PGbasicmacros.pl> in generating answers blanks that use radio buttons or
881 :     check boxes. (This type of answer blank uses multiple HTML INPUT elements with
882 :     the same label, but the label should only be added to the list of implicitly-
883 :     labeled answers once.)
884 :    
885 :     =cut
886 :    
887 :     =item RECORD_FROM_LABEL()
888 :    
889 :     RECORD_FORM_LABEL("label");
890 :    
891 :     Stores the label of a form field in the "extra" answers list. This is used to
892 :     keep track of answer blanks that are not associated with an answer evaluator.
893 :    
894 :     =cut
895 :    
896 :     =item NEW_ANS_ARRAY_NAME()
897 :    
898 :     NEW_ANS_ARRAY_NAME($num, $row, $col);
899 :    
900 :     Generates a new answer label for an array (vector) element and adds it to the
901 :     list of implicitly-labeled answers.
902 :    
903 :     =cut
904 :    
905 :     =item NEW_ANS_ARRAY_NAME_EXTENSION()
906 :    
907 :     NEW_ANS_ARRAY_NAME_EXTENSION($num, $row, $col);
908 :    
909 :     Generate an additional answer label for an existing array (vector) element and
910 :     add it to the list of "extra" answers.
911 :    
912 :     =cut
913 :    
914 :     =item get_PG_ANSWERS_HASH()
915 :    
916 :     get_PG_ANSWERS_HASH();
917 :     get_PG_ANSWERS_HASH($key);
918 :    
919 :    
920 :    
921 :     =cut
922 :    
923 : jj 5269 =item includePGproblem($filePath)
924 :    
925 :     includePGproblem($filePath);
926 :    
927 :     Essentially runs the pg problem specified by $filePath, which is
928 :     a path relative to the top of the templates directory. The output
929 :     of that problem appears in the given problem.
930 :    
931 :     =cut
932 :    
933 : sh002i 5179 =back
934 :    
935 :     =head1 SEE ALSO
936 :    
937 :     L<PGbasicmacros.pl>, L<PGanswermacros.pl>.
938 :    
939 :     =cut
940 :    
941 : gage 6248
942 :    
943 :    
944 :     1;

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9