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

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

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

Revision 4997 Revision 5179
1################################################################################
2# WeBWorK Program Generation Language
3# Copyright � 2000-2007 The WeBWorK Project, http://openwebwork.sf.net/
4# $CVSHeader: webwork2/lib/WeBWorK.pm,v 1.97 2007/06/29 19:54:19 sh002i Exp $
5#
6# This program is free software; you can redistribute it and/or modify it under
7# the terms of either: (a) the GNU General Public License as published by the
8# Free Software Foundation; either version 2, or (at your option) any later
9# version, or (b) the "Artistic License" which comes with this package.
10#
11# This program is distributed in the hope that it will be useful, but WITHOUT
12# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13# FOR A PARTICULAR PURPOSE. See either the GNU General Public License or the
14# Artistic License for more details.
15################################################################################
1 16
17=head1 NAME
18
19PG.pl - Provides core Program Generation Language functionality.
20
21=head1 SYNPOSIS
22
23In a PG problem:
24
25 DOCUMENT(); # should be the first statment in the problem
26
27 loadMacros(.....); # (optional) load other macro files if needed.
28 # (loadMacros is defined in F<dangerousMacros.pl>)
29
30 HEADER_TEXT(...); # (optional) used only for inserting javaScript into problems.
31
32 TEXT( # insert text of problems
33 "Problem text to be",
34 "displayed. Enter 1 in this blank:",
35 ANS_RULE(1,30) # ANS_RULE() defines an answer blank 30 characters long.
36 # It is defined in F<PGbasicmacros.pl>
37 );
38
39 ANS(answer_evalutors); # see F<PGanswermacros.pl> for examples of answer evaluatiors.
40
41 ENDDOCUMENT() # must be the last statement in the problem
42
43=head1 DESCRIPTION
44
2# This file provided the fundamental macros for the pg language 45This file provides the fundamental macros that define the PG language. It
3# These macros define the interface between the problems written by 46maintains a problem's text, header text, and answers:
4# the professor and the processing which occurs in the script
5# processProblem.pl
6 47
48=over
49
50=item *
51
52Problem text: The text to appear in the body of the problem. See TEXT()
53below.
54
55=item *
56
57Header text: When a problem is processed in an HTML-based display mode,
58this variable can contain text that the caller should place in the HEAD of the
59resulting HTML page. See HEADER_TEXT() below.
60
61=item *
62
63Implicitly-labeled answers: Answers that have not been explicitly
64assigned names, and are associated with their answer blanks by the order in
65which they appear in the problem. These types of answers are designated using
66the ANS() macro.
67
68=item *
69
70Explicitly-labeled answers: Answers that have been explicitly assigned
71names with the LABELED_ANS() macro, or a macro that uses it. An explicitly-
72labeled answer is associated with its answer blank by name.
73
74=item *
75
76"Extra" answers: Names of answer blanks that do not have a 1-to-1
77correspondance to an answer evaluator. For example, in matrix problems, there
78will be several input fields that correspond to the same answer evaluator.
79
80=back
81
82=head1 USAGE
83
84This file is automatically loaded into the namespace of every PG problem. The
85macros within can then be called to define the structure of the problem.
86
87DOCUMENT() should be the first executable statement in any problem. It
88initializes vriables and defines the problem environment.
89
90ENDDOCUMENT() must be the last executable statement in any problem. It packs
91up the results of problem processing for delivery back to WeBWorK.
92
93The HEADER_TEXT(), TEXT(), and ANS() macros add to the header text string,
94body text string, and answer evaluator queue, respectively.
95
96=cut
7 97
8BEGIN { 98BEGIN {
9 be_strict(); 99 be_strict();
10} 100}
11 101
12sub _PG_init{ 102sub _PG_init{
13 103
14} 104}
15 105
16#package PG; 106#package PG;
17
18
19=head1 NAME
20
21 PG.pl --- located in the courseScripts directory.
22 Defines the Program Generating language at the most basic level.
23
24=head1 SYNPOSIS
25
26 The basic PG problem structure:
27
28 DOCUMENT(); # should be the first statment in the problem
29 loadMacros(.....); # (optional) load other macro files if needed.
30 # (loadMacros is defined in F<dangerousMacros.pl>)
31
32 HEADER_TEXT(...); # (optional) used only for inserting javaScript into problems.
33
34 # # insert text of problems
35 TEXT("Problem text to be",
36 "displayed. Enter 1 in this blank:",
37 ANS_RULE(1,30) # ANS_RULE() defines an answer blank 30 characters long.
38 # It is defined in F<PGbasicmacros.pl>
39 );
40
41
42 ANS( answer_evalutors); # see F<PGanswermacros.pl> for examples of answer evaluatiors.
43
44 ENDDOCUMENT() # must be the last statement in the problem
45
46
47
48=head1 DESCRIPTION
49
50As described in the synopsis, this file and the macros C<DOCUMENT()> and C<ENDDOCUMENT()> determine
51the interface between problems written in the PG language and the rest of B<WeBWorK>, in particular
52the subroutine C<createPGtext(()> in the file F<translate.pl>.
53
54C<DOCUMENT()> must be the first statement in each problem template.
55It initializes variables,
56in particular all of the contents of the
57environment variable become defined in the problem enviroment.
58(See
59L</webwork_system_html/docs/techdescription/pglanguage/PGenvironment.html>)
60
61ENDDOCUMENT() must the last executable statement in any problem template. It returns
62the rendered problem, answer evaluators and other flags to the rest of B<WeBWorK>, specificially
63to the routine C<createPGtext()> defined in F<translate.pl>
64
65
66The C<HEADER_TEXT()>, C<TEXT()>, and C<ANS()> functions load the
67header text string, the problem text string.
68and the answer evaulator queue respectively.
69
70
71=cut
72
73 107
74# Private variables for the PG.pl file. 108# Private variables for the PG.pl file.
75 109
76my ($STRINGforOUTPUT, $STRINGforHEADER_TEXT, @PG_ANSWERS, @PG_UNLABELED_ANSWERS); 110my ($STRINGforOUTPUT, $STRINGforHEADER_TEXT, @PG_ANSWERS, @PG_UNLABELED_ANSWERS);
77my %PG_ANSWERS_HASH ; 111my %PG_ANSWERS_HASH ;
79 113
80# my variables are unreliable if two DOCUMENTS were to be called before an ENDDOCUMENT 114# my variables are unreliable if two DOCUMENTS were to be called before an ENDDOCUMENT
81# there could be conflicts. As I understand the behavior of the Apache child 115# there could be conflicts. As I understand the behavior of the Apache child
82# this cannot occur -- a child finishes with one request before obtaining the next 116# this cannot occur -- a child finishes with one request before obtaining the next
83 117
84# DOCUMENT must come early in every .pg file, before any answers or text are 118################################################################################
85# defined. It initializes the variables.
86# It can appear only once.
87 119
120=head1 MACROS
121
122These macros may be used from PG problem files.
123
124=over
125
88=head2 DOCUMENT() 126=item DOCUMENT()
89 127
90C<DOCUMENT()> must be the first statement in each problem template. It can 128DOCUMENT() should be the first statement in each problem template. It can
91only be used once in each problem. 129only be used once in each problem.
92 130
93C<DOCUMENT()> initializes some empty variables and via C<INITIALIZE_PG()> unpacks the 131DOCUMENT() initializes some empty variables and unpacks the variables in the
94variables in the C<%envir> variable which is implicitly passed to the problem. It must 132%envir hash which is implicitly passed from WeBWorK to the problem. It must be
95be the first statement in any problem template. It 133the first statement in any problem. It also unpacks any answers submitted and
96also unpacks any answers submitted and places them in the C<@submittedAnswer> list, 134places them in the @submittedAnswer list, saves the problem seed in
97saves the problem seed in C<$PG_original_problemSeed> in case you need it later, and 135$PG_original_problemSeed in case you need it later, and initializes the pseudo
98initializes the pseudo random number generator object in C<$PG_random_generator>. 136random number generator object in $PG_random_generator.
99 137
100You can reset the standard number generator using the command: 138You can reset the standard number generator using the command:
101 139
102 $PG_random_generator->srand($new_seed_value); 140 $PG_random_generator->srand($new_seed_value);
103 141
104(See also C<SRAND> in the L<PGbasicmacros.pl> file.) 142See also SRAND() in the L<PGbasicmacros.pl> file.
105
106The
107environment variable contents is defined in
108L</webwork_system_html/docs/techdescription/pglanguage/PGenvironment.html>
109
110 143
111=cut 144=cut
112 145
113sub DOCUMENT { 146sub DOCUMENT {
114 147
207 $STRINGforOUTPUT = '<SCRIPT SRC="'.$main::envir{LaTeXMathMLURL}.'"></SCRIPT>'."\n" . $STRINGforOUTPUT 240 $STRINGforOUTPUT = '<SCRIPT SRC="'.$main::envir{LaTeXMathMLURL}.'"></SCRIPT>'."\n" . $STRINGforOUTPUT
208 if ($main::envir{displayMode} eq 'HTML_LaTeXMathML'); 241 if ($main::envir{displayMode} eq 'HTML_LaTeXMathML');
209 242
210} 243}
211 244
212sub inc_ans_rule_count {
213 eval(q!++$main::ans_rule_count!); # evalute at runtime to get correct main::
214}
215# HEADER_TEXT is for material which is destined to be placed in the header of the html problem -- such
216# as javaScript code.
217
218=head2 HEADER_TEXT() 245=item HEADER_TEXT()
219 246
220
221 HEADER_TEXT("string1", "string2", "string3"); 247 HEADER_TEXT("string1", "string2", "string3");
222 248
223The C<HEADER_TEXT()> 249HEADER_TEXT() concatenates its arguments and appends them to the stored header
224function concatenates its arguments and places them in the output
225header text string. It is used for material which is destined to be placed in
226the header of the html problem -- such as javaScript code.
227 It can be used more than once in a file. 250text string. It can be used more than once in a file.
228 251
252The macro is used for material which is destined to be placed in the HEAD of
253the page when in HTML mode, such as JavaScript code.
254
255Spaces are placed between the arguments during concatenation, but no spaces are
256introduced between the existing content of the header text string and the new
257content being appended.
229 258
230=cut 259=cut
231 260
232sub HEADER_TEXT { 261sub HEADER_TEXT {
233 my @in = @_; 262 my @in = @_;
234 $STRINGforHEADER_TEXT .= join(" ",@in); 263 $STRINGforHEADER_TEXT .= join(" ",@in);
235 } 264 }
236 265
237# TEXT is the function which defines text which will appear in the problem. 266=item TEXT()
238# All text must be an argument to this function. Any other statements
239# are calculations (done in perl) which will not directly appear in the
240# output. Think of this as the "print" function for the .pg language.
241# It can be used more than once in a file.
242 267
243=head2 TEXT()
244
245 TEXT("string1", "string2", "string3"); 268 TEXT("string1", "string2", "string3");
246 269
247The C<TEXT()> function concatenates its arguments and places them in the output 270TEXT() concatenates its arguments and appends them to the stored problem text
248text string. C<TEXT()> is the function which defines text which will appear in the problem. 271string. It is used to define the text which will appear in the body of the
249All text must be an argument to this function. Any other statements
250are calculations (done in perl) which will not directly appear in the
251output. Think of this as the "print" function for the .pg language.
252It can be used more than once in a file. 272problem. It can be used more than once in a file.
273
274This macro has no effect if rendering has been stopped with the STOP_RENDERING()
275macro.
276
277This macro defines text which will appear in the problem. All text must be
278passed to this macro, passed to another macro that calls this macro, or included
279in a BEGIN_TEXT/END_TEXT block, which uses this macro internally. No other
280statements in a PG file will directly appear in the output. Think of this as the
281"print" function for the PG language.
282
283Spaces are placed between the arguments during concatenation, but no spaces are
284introduced between the existing content of the header text string and the new
285content being appended.
253 286
254=cut 287=cut
255 288
256sub TEXT { 289sub TEXT {
257 return "" if $PG_STOP_FLAG; 290 return "" if $PG_STOP_FLAG;
258 my @in = @_; 291 my @in = @_;
259 $STRINGforOUTPUT .= join(" ",@in); 292 $STRINGforOUTPUT .= join(" ",@in);
260} 293}
261 294
262=head2 STOP_RENDERING() 295=item ANS()
263 296
264 STOP_RENDERING() unless all_answers_are_correct; 297 TEXT(ans_rule(), ans_rule(), ans_rule());
265
266No text is printed and no answer blanks or answer evaluators are stored or processed until
267RESUME_RENDERING() is executed.
268
269=cut
270
271sub STOP_RENDERING {
272 $PG_STOP_FLAG=1;
273 "";
274}
275
276=head2 RESUME_RENDERING()
277
278 RESUME_RENDERING();
279
280Resumes processing of text, answer blanks, and
281answer evaluators.
282
283=cut
284
285sub RESUME_RENDERING {
286 $PG_STOP_FLAG=0;
287 "";
288}
289
290=head2 ANS()
291
292 ANS(answer_evaluator1, answer_evaluator2, answer_evaluator3,...) 298 ANS($answer_evaluator1, $answer_evaluator2, $answer_evaluator3);
293 299
294Places the answer evaluators in the unlabeled answer_evaluator queue. They will be paired 300Adds the answer evaluators listed to the list of unlabeled answer evaluators.
295with unlabeled answer rules (answer entry blanks) in the order entered. This is the standard 301They will be paired with unlabeled answer rules (a.k.a. answer blanks) in the
296method for entering answers. 302order entered. This is the standard method for entering answers.
297 303
298 LABELED_ANS(answer_evaluater_name1, answer_evaluator1, answer_evaluater_name2,answer_evaluator2,...) 304In the above example, answer_evaluator1 will be associated with the first
305answer rule, answer_evaluator2 with the second, and answer_evaluator3 with the
306third. In practice, the arguments to ANS() will usually be calls to an answer
307evaluator generator such as the cmp() method of MathObjects or the num_cmp()
308macro in L<PGanswermacros.pl>.
299 309
300Places the answer evaluators in the labeled answer_evaluator hash. This allows pairing of
301labeled answer evaluators and labeled answer rules which may not have been entered in the same
302order.
303
304=cut 310=cut
305 311
306sub ANS{ # store answer evaluators which have not been explicitly labeled 312sub ANS{
307 return "" if $PG_STOP_FLAG; 313 return "" if $PG_STOP_FLAG;
308 my @in = @_; 314 my @in = @_;
309 while (@in ) { 315 while (@in ) {
310 warn("<BR><B>Error in ANS:$in[0]</B> -- inputs must be references to 316 warn("<BR><B>Error in ANS:$in[0]</B> -- inputs must be references to
311 subroutines<BR>") 317 subroutines<BR>")
312 unless ref($in[0]); 318 unless ref($in[0]);
313 push(@PG_ANSWERS, shift @in ); 319 push(@PG_ANSWERS, shift @in );
314 } 320 }
315} 321}
316sub LABELED_ANS { #a better alias for NAMED_ANS 322
323=item LABELED_ANS()
324
325 TEXT(labeled_ans_rule("name1"), labeled_ans_rule("name2"));
326 LABELED_ANS(name1 => answer_evaluator1, name2 => answer_evaluator2);
327
328Adds the answer evaluators listed to the list of labeled answer evaluators.
329They will be paired with labeled answer rules (a.k.a. answer blanks) in the
330order entered. This allows pairing of answer evaluators and answer rules that
331may not have been entered in the same order.
332
333=cut
334
335sub LABELED_ANS {
317 &NAMED_ANS; 336 &NAMED_ANS;
318} 337}
319 338
320sub NAMED_ANS{ # store answer evaluators which have been explicitly labeled (submitted in a hash) 339=item NAMED_ANS()
340
341Old name for LABELED_ANS(). DEPRECATED.
342
343=cut
344
345sub NAMED_ANS{
321 return "" if $PG_STOP_FLAG; 346 return "" if $PG_STOP_FLAG;
322 my @in = @_; 347 my @in = @_;
323 while (@in ) { 348 while (@in ) {
324 my $label = shift @in; 349 my $label = shift @in;
325 $label = eval(q!$main::QUIZ_PREFIX.$label!); 350 $label = eval(q!$main::QUIZ_PREFIX.$label!);
328 -- inputs must be references to subroutines<BR>") 353 -- inputs must be references to subroutines<BR>")
329 unless ref($ans_eval); 354 unless ref($ans_eval);
330 $PG_ANSWERS_HASH{$label}= $ans_eval; 355 $PG_ANSWERS_HASH{$label}= $ans_eval;
331 } 356 }
332} 357}
333sub RECORD_ANS_NAME { # this maintains the order in which the answer rules are printed.
334 return "" if $PG_STOP_FLAG;
335 my $label = shift;
336 eval(q!push(@main::PG_ANSWER_ENTRY_ORDER, $label)!);
337 $label;
338}
339 358
340sub NEW_ANS_NAME { # this keeps track of the answers which are entered implicitly, 359=item STOP_RENDERING()
341 # rather than with a specific label
342 return "" if $PG_STOP_FLAG;
343 my $number=shift;
344 my $prefix = eval(q!$main::QUIZ_PREFIX.$main::ANSWER_PREFIX!);
345 my $label = $prefix.$number;
346 push(@PG_UNLABELED_ANSWERS,$label);
347 $label;
348}
349sub ANS_NUM_TO_NAME { # This converts a number to an answer label for use in
350 # radio button and check box answers. No new answer
351 # name is recorded.
352 my $number=shift;
353 my $label = eval(q!$main::QUIZ_PREFIX.$main::ANSWER_PREFIX!).$number;
354 $label;
355}
356 360
357my $vecnum; 361 STOP_RENDERING() unless all_answers_are_correct();
358 362
359sub RECORD_FORM_LABEL { # this stores form data (such as sticky answers), but does nothing more 363Temporarily suspends accumulation of problem text and storing of answer blanks
360 # it's a bit of hack since we are storing these in the KEPT_EXTRA_ANSWERS queue even if they aren't answers per se. 364and answer evaluators until RESUME_RENDERING() is called.
361 return "" if $PG_STOP_FLAG;
362 my $label = shift; # the label of the input box or textarea
363 eval(q!push(@main::KEPT_EXTRA_ANSWERS, $label)!); #put the labels into the hash to be caught later for recording purposes
364 $label;
365}
366sub NEW_ANS_ARRAY_NAME { # this keeps track of the answers which are entered implicitly,
367 # rather than with a specific label
368 return "" if $PG_STOP_FLAG;
369 my $number=shift;
370 $vecnum = 0;
371 my $row = shift;
372 my $col = shift;
373# my $label = "ArRaY"."$number"."["."$vecnum".","."$row".","."$col"."]";
374 my $label = eval(q!$main::QUIZ_PREFIX."ArRaY"."$number"."__"."$vecnum".":"."$row".":"."$col"."__"!);
375 push(@PG_UNLABELED_ANSWERS,$label);
376 $label;
377}
378 365
379sub NEW_ANS_ARRAY_NAME_EXTENSION { # this keeps track of the answers which are entered implicitly, 366=cut
380 # rather than with a specific label
381 return "" if $PG_STOP_FLAG;
382 my $number=shift;
383 my $row = shift;
384 my $col = shift;
385 if( $row == 0 && $col == 0 ){
386 $vecnum += 1;
387 }
388 #FIXME change made to conform to HTML 4.01 standards. "Name" attributes can only contain
389 # alphanumeric characters, _ : and .
390 # Also need to make corresponding changes in PGmorematrixmacros. grep for ArRaY.
391 #my $label = "ArRaY"."$number"."["."$vecnum".","."$row".","."$col"."]";
392 my $label = eval(q!$main::QUIZ_PREFIX."ArRaY"."$number"."__"."$vecnum".":"."$row".":"."$col"."__"!);
393 eval(q!push(@main::KEPT_EXTRA_ANSWERS, $label)!);#put the labels into the hash to be caught later for recording purposes
394 $label;
395}
396 367
397 368sub STOP_RENDERING {
398sub get_PG_ANSWERS_HASH { 369 $PG_STOP_FLAG=1;
399 # update the PG_ANSWWERS_HASH, then report the result. 370 "";
400 # This is used in writing sequential problems
401 # if there is an input, use that as a key into the answer hash
402 my $key = shift;
403 my (%pg_answers_hash, @pg_unlabeled_answers);
404 %pg_answers_hash= %PG_ANSWERS_HASH;
405 #warn "order ", eval(q!@main::PG_ANSWER_ENTRY_ORDER!);
406 #warn "pg answers", %PG_ANSWERS_HASH;
407 #warn "unlabeled", @PG_UNLABELED_ANSWERS;
408 my $index=0;
409 foreach my $label (@PG_UNLABELED_ANSWERS) {
410 if ( defined($PG_ANSWERS[$index]) ) {
411 $pg_answers_hash{"$label"}= $PG_ANSWERS[$index];
412 #warn "recording answer label = $label";
413 } else {
414 warn "No answer provided by instructor for answer $label";
415 }
416 $index++;
417 }
418 if ($key) {
419 return $pg_answers_hash{$key};
420 } else {
421 return %pg_answers_hash;
422 }
423} 371}
424# ENDDOCUMENT must come at the end of every .pg file.
425# It exports the resulting text of the problem, the text to be used in HTML header material
426# (for javaScript), the list of answer evaluators and any other flags. It can appear only once and
427# it MUST be the last statement in the problem.
428 372
373=item RESUME_RENDERING()
374
375 RESUME_RENDERING();
376
377Resumes accumulating problem text and storing answer blanks and answer
378evaluators. Reverses the effect of STOP_RENDERING().
379
380=cut
381
382sub RESUME_RENDERING {
383 $PG_STOP_FLAG=0;
384 "";
385}
386
429=head2 ENDDOCUMENT() 387=item ENDDOCUMENT()
430 388
431ENDDOCUMENT() must the last executable statement in any problem template. It can 389 ENDDOCUMENT();
432only appear once. It returns
433an array consisting of
434 390
391When PG problems are evaluated, the result of evaluating the entire problem is
392interpreted as the return value of ENDDOCUMENT(). Therefore, ENDDOCUMENT() must
393the last executable statement of every problem. It can only appear once. It
394returns an list consisting of:
395
396=over
397
398=item *
399
435 A reference to a string containing the rendered text of the problem. 400A reference to a string containing the rendered text of the problem.
401
402=item *
403
436 A reference to a string containing text to be placed in the header 404A reference to a string containing text to be placed in the HEAD block
437 (for javaScript) 405when in and HTML-based mode (e.g. for JavaScript).
438 A reference to the array containing the answer evaluators. 406
439 (May be changed to a hash soon.) 407=item *
408
409A reference to the hash mapping answer labels to answer evaluators.
410
411=item *
412
440 A reference to an associative array (hash) containing various flags. 413A reference to a hash containing various flags:
441 414
442 The following flags are set by ENDDOCUMENT: 415=over
443 (1) showPartialCorrectAnswers -- determines whether students are told which 416
444 of their answers in a problem are wrong. 417=item *
418
419C<showPartialCorrectAnswers>: determines whether students are told which of their answers in a problem are wrong.
420
421=item *
422
445 (2) recordSubmittedAnswers -- determines whether students submitted answers 423C<recordSubmittedAnswers>: determines whether students submitted answers are saved.
446 are saved. 424
447 (3) refreshCachedImages -- determines whether the cached image of the problem 425=item *
448 in typeset mode is always refreshed (i.e. setting this to 1 means cached 426
449 images are not used). 427C<refreshCachedImages>: determines whether the cached image of the problem in typeset mode is always refreshed
428(i.e. setting this to 1 means cached images are not used).
429
430=item *
431
450 (4) solutionExits -- indicates the existence of a solution. 432C<solutionExits>: indicates the existence of a solution.
433
434=item *
435
451 (5) hintExits -- indicates the existence of a hint. 436C<hintExits>: indicates the existence of a hint.
437
438=item *
439
452 (6) comment -- contents of COMMENT commands if any. 440C<comment>: contents of COMMENT commands if any.
441
442=item *
443
453 (7) showHintLimit -- determines the number of attempts after which hint(s) will be shown 444C<showHintLimit>: determines the number of attempts after which hint(s) will be shown
454 445
455 (8) PROBLEM_GRADER_TO_USE -- chooses the problem grader to be used in this order 446=item *
456 (a) A problem grader specified by the problem using:
457 install_problem_grader(\&grader);
458 (b) One of the standard problem graders defined in PGanswermacros.pl when set to
459 'std_problem_grader' or 'avg_problem_grader' by the environment variable
460 $PG_environment{PROBLEM_GRADER_TO_USE}
461 (c) A subroutine referenced by $PG_environment{PROBLEM_GRADER_TO_USE}
462 (d) The default &std_problem_grader defined in PGanswermacros.pl
463 447
448C<PROBLEM_GRADER_TO_USE>: a reference to the chosen problem grader.
449ENDDOCUMENT chooses the problem grader as follows:
450
451=over
452
453=item *
454
455If a problem grader has been chosen in the problem by calling
456C<install_problem_grader(\&grader)>, it is used.
457
458=item *
459
460Otherwise, if the C<PROBLEM_GRADER_TO_USE> PG environment variable
461contains a reference to a subroutine, it is used.
462
463=item *
464
465Otherwise, if the C<PROBLEM_GRADER_TO_USE> PG environment variable
466contains the string C<std_problem_grader> or the string C<avg_problem_grader>,
467C<&std_problem_grader> or C<&avg_problem_grader> are used. These graders are defined
468in L<PGanswermacros.pl>.
469
470=item *
471
472Otherwise, the PROBLEM_GRADER_TO_USE flag will contain an empty value
473and the PG translator should select C<&std_problem_grader>.
474
475=back
476
477=back
478
479=back
464 480
465=cut 481=cut
466 482
467sub ENDDOCUMENT { 483sub ENDDOCUMENT {
468 484
534 $STRINGforOUTPUT .= MODES(%{PG_restricted_eval('$main::problemPostamble')}); 550 $STRINGforOUTPUT .= MODES(%{PG_restricted_eval('$main::problemPostamble')});
535 551
536 (\$STRINGforOUTPUT, \$STRINGforHEADER_TEXT,\%PG_ANSWERS_HASH,eval(q!\%main::PG_FLAGS!)); 552 (\$STRINGforOUTPUT, \$STRINGforHEADER_TEXT,\%PG_ANSWERS_HASH,eval(q!\%main::PG_FLAGS!));
537} 553}
538 554
555=back
539 556
540
541=head2 INITIALIZE_PG()
542
543This is executed each C<DOCUMENT()> is called. For backward compatibility
544C<loadMacros> also checks whether the C<macroDirectory> has been defined
545and if not, it runs C<INITIALIZE_PG()> and issues a warning.
546
547=cut 557=cut
548 558
559################################################################################
560
561=head1 PRIVATE MACROS
562
563These macros should only be used by other macro files. In practice, they are
564used exclusively by L<PGbasicmacros.pl>.
565
566=over
567
568=item inc_ans_rule_count()
569
570 NEW_ANS_NAME(inc_ans_rule_count());
571
572Increments the internal count of the number of answer blanks that have been
573defined ($ans_rule_count) and returns the new count. This should only be used
574when one is about to define a new answer blank, for example with NEW_ANS_NAME().
575
576=cut
577
578sub inc_ans_rule_count {
579 eval(q!++$main::ans_rule_count!); # evalute at runtime to get correct main::
580}
581
582=item RECORD_ANS_NAME()
583
584 RECORD_ANS_NAME("label");
585
586Records the label for an answer blank. Used internally by L<PGbasicmacros.pl>
587to record the order of explicitly-labelled answer blanks.
588
589=cut
590
591sub RECORD_ANS_NAME {
592 return "" if $PG_STOP_FLAG;
593 my $label = shift;
594 eval(q!push(@main::PG_ANSWER_ENTRY_ORDER, $label)!);
595 $label;
596}
597
598=item NEW_ANS_NAME()
599
600 NEW_ANS_NAME($num);
601
602Generates an answer label from the supplied answer number. The label is
603added to the list of implicity-labeled answers. Used internally by
604L<PGbasicmacros.pl> to generate labels for unlabeled answer blanks.
605
606=cut
607
608sub NEW_ANS_NAME {
609 return "" if $PG_STOP_FLAG;
610 my $number=shift;
611 my $prefix = eval(q!$main::QUIZ_PREFIX.$main::ANSWER_PREFIX!);
612 my $label = $prefix.$number;
613 push(@PG_UNLABELED_ANSWERS,$label);
614 $label;
615}
616
617=item ANS_NUM_TO_NAME()
618
619 ANS_NUM_TO_NAME($num);
620
621Generates an answer label from the supplied answer number, but does not add it
622to the list of inplicitly-labeled answers. Used internally by
623L<PGbasicmacros.pl> in generating answers blanks that use radio buttons or
624check boxes. (This type of answer blank uses multiple HTML INPUT elements with
625the same label, but the label should only be added to the list of implicitly-
626labeled answers once.)
627
628=cut
629
630sub ANS_NUM_TO_NAME {
631 my $number=shift;
632 my $label = eval(q!$main::QUIZ_PREFIX.$main::ANSWER_PREFIX!).$number;
633 $label;
634}
635
636my $vecnum;
637
638=item RECORD_FROM_LABEL()
639
640 RECORD_FORM_LABEL("label");
641
642Stores the label of a form field in the "extra" answers list. This is used to
643keep track of answer blanks that are not associated with an answer evaluator.
644
645=cut
646
647sub RECORD_FORM_LABEL { # this stores form data (such as sticky answers), but does nothing more
648 # it's a bit of hack since we are storing these in the KEPT_EXTRA_ANSWERS queue even if they aren't answers per se.
649 return "" if $PG_STOP_FLAG;
650 my $label = shift; # the label of the input box or textarea
651 eval(q!push(@main::KEPT_EXTRA_ANSWERS, $label)!); #put the labels into the hash to be caught later for recording purposes
652 $label;
653}
654
655=item NEW_ANS_ARRAY_NAME()
656
657 NEW_ANS_ARRAY_NAME($num, $row, $col);
658
659Generates a new answer label for an array (vector) element and adds it to the
660list of implicitly-labeled answers.
661
662=cut
663
664sub NEW_ANS_ARRAY_NAME { # this keeps track of the answers which are entered implicitly,
665 # rather than with a specific label
666 return "" if $PG_STOP_FLAG;
667 my $number=shift;
668 $vecnum = 0;
669 my $row = shift;
670 my $col = shift;
671# my $label = "ArRaY"."$number"."["."$vecnum".","."$row".","."$col"."]";
672 my $label = eval(q!$main::QUIZ_PREFIX."ArRaY"."$number"."__"."$vecnum".":"."$row".":"."$col"."__"!);
673 push(@PG_UNLABELED_ANSWERS,$label);
674 $label;
675}
676
677=item NEW_ANS_ARRAY_NAME_EXTENSION()
678
679 NEW_ANS_ARRAY_NAME_EXTENSION($num, $row, $col);
680
681Generate an additional answer label for an existing array (vector) element and
682add it to the list of "extra" answers.
683
684=cut
685
686sub NEW_ANS_ARRAY_NAME_EXTENSION { # this keeps track of the answers which are entered implicitly,
687 # rather than with a specific label
688 return "" if $PG_STOP_FLAG;
689 my $number=shift;
690 my $row = shift;
691 my $col = shift;
692 if( $row == 0 && $col == 0 ){
693 $vecnum += 1;
694 }
695 #FIXME change made to conform to HTML 4.01 standards. "Name" attributes can only contain
696 # alphanumeric characters, _ : and .
697 # Also need to make corresponding changes in PGmorematrixmacros. grep for ArRaY.
698 #my $label = "ArRaY"."$number"."["."$vecnum".","."$row".","."$col"."]";
699 my $label = eval(q!$main::QUIZ_PREFIX."ArRaY"."$number"."__"."$vecnum".":"."$row".":"."$col"."__"!);
700 eval(q!push(@main::KEPT_EXTRA_ANSWERS, $label)!);#put the labels into the hash to be caught later for recording purposes
701 $label;
702}
703
704=item get_PG_ANSWERS_HASH()
705
706 get_PG_ANSWERS_HASH();
707 get_PG_ANSWERS_HASH($key);
708
709
710
711=cut
712
713sub get_PG_ANSWERS_HASH {
714 # update the PG_ANSWWERS_HASH, then report the result.
715 # This is used in writing sequential problems
716 # if there is an input, use that as a key into the answer hash
717 my $key = shift;
718 my (%pg_answers_hash, @pg_unlabeled_answers);
719 %pg_answers_hash= %PG_ANSWERS_HASH;
720 #warn "order ", eval(q!@main::PG_ANSWER_ENTRY_ORDER!);
721 #warn "pg answers", %PG_ANSWERS_HASH;
722 #warn "unlabeled", @PG_UNLABELED_ANSWERS;
723 my $index=0;
724 foreach my $label (@PG_UNLABELED_ANSWERS) {
725 if ( defined($PG_ANSWERS[$index]) ) {
726 $pg_answers_hash{"$label"}= $PG_ANSWERS[$index];
727 #warn "recording answer label = $label";
728 } else {
729 warn "No answer provided by instructor for answer $label";
730 }
731 $index++;
732 }
733 if ($key) {
734 return $pg_answers_hash{$key};
735 } else {
736 return %pg_answers_hash;
737 }
738}
739
740=back
741
742=head1 SEE ALSO
743
744L<PGbasicmacros.pl>, L<PGanswermacros.pl>.
745
746=cut
549 747
5501; 7481;
749

Legend:
Removed from v.4997  
changed lines
  Added in v.5179

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9