[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 1122 - (view) (download) (as text)

1 : lr003k 1122 #!/usr/local/bin/webwork-perl
2 : sh002i 1050
3 :     # This file provided the fundamental macros for the pg language
4 :     # These macros define the interface between the problems written by
5 :     # the professor and the processing which occurs in the script
6 :     # processProblem.pl
7 :    
8 :    
9 :     BEGIN {
10 :     be_strict();
11 :     }
12 :    
13 :     sub _PG_init{
14 :    
15 :     }
16 :    
17 :     #package PG;
18 :    
19 :    
20 :     =head1 NAME
21 :    
22 :     PG.pl --- located in the courseScripts directory.
23 :     Defines the Program Generating language at the most basic level.
24 :    
25 :     =head1 SYNPOSIS
26 :    
27 :     The basic PG problem structure:
28 :    
29 :     DOCUMENT(); # should be the first statment in the problem
30 :     loadMacros(.....); # (optional) load other macro files if needed.
31 :     # (loadMacros is defined in F<dangerousMacros.pl>)
32 :    
33 :     HEADER_TEXT(...); # (optional) used only for inserting javaScript into problems.
34 :    
35 :     # # insert text of problems
36 :     TEXT("Problem text to be",
37 :     "displayed. Enter 1 in this blank:",
38 :     ANS_RULE(1,30) # ANS_RULE() defines an answer blank 30 characters long.
39 :     # It is defined in F<PGbasicmacros.pl>
40 :     );
41 :    
42 :    
43 :     ANS( answer_evalutors); # see F<PGanswermacros.pl> for examples of answer evaluatiors.
44 :    
45 :     ENDDOCUMENT() # must be the last statement in the problem
46 :    
47 :    
48 :    
49 :     =head1 DESCRIPTION
50 :    
51 :     As described in the synopsis, this file and the macros C<DOCUMENT()> and C<ENDDOCUMENT()> determine
52 :     the interface between problems written in the PG language and the rest of B<WeBWorK>, in particular
53 :     the subroutine C<createPGtext(()> in the file F<translate.pl>.
54 :    
55 :     C<DOCUMENT()> must be the first statement in each problem template.
56 :     It initializes variables,
57 :     in particular all of the contents of the
58 :     environment variable become defined in the problem enviroment.
59 :     (See
60 :     L</webwork_system_html/docs/techdescription/pglanguage/PGenvironment.html>)
61 :    
62 :     ENDDOCUMENT() must the last executable statement in any problem template. It returns
63 :     the rendered problem, answer evaluators and other flags to the rest of B<WeBWorK>, specificially
64 :     to the routine C<createPGtext()> defined in F<translate.pl>
65 :    
66 :    
67 :     The C<HEADER_TEXT()>, C<TEXT()>, and C<ANS()> functions load the
68 :     header text string, the problem text string.
69 :     and the answer evaulator queue respectively.
70 :    
71 :    
72 :     =cut
73 :    
74 :    
75 :     # Private variables for the PG.pl file.
76 :    
77 :     my ($STRINGforOUTPUT, $STRINGforHEADER_TEXT, @PG_ANSWERS, @PG_UNLABELED_ANSWERS);
78 :     my %PG_ANSWERS_HASH ;
79 :    
80 :     # DOCUMENT must come early in every .pg file, before any answers or text are
81 :     # defined. It initializes the variables.
82 :     # It can appear only once.
83 :    
84 :     =head2 DOCUMENT()
85 :    
86 :     C<DOCUMENT()> must be the first statement in each problem template. It can
87 :     only be used once in each problem.
88 :    
89 :     C<DOCUMENT()> initializes some empty variables and via C<INITIALIZE_PG()> unpacks the
90 :     variables in the C<%envir> variable which is implicitly passed to the problem. It must
91 :     be the first statement in any problem template. It
92 :     also unpacks any answers submitted and places them in the C<@submittedAnswer> list,
93 :     saves the problem seed in C<$PG_original_problemSeed> in case you need it later, and
94 :     initializes the pseudo random number generator object in C<$PG_random_generator>.
95 :    
96 :     You can reset the standard number generator using the command:
97 :    
98 :     $PG_random_generator->srand($new_seed_value);
99 :    
100 :     (See also C<SRAND> in the L<PGbasicmacros.pl> file.)
101 :    
102 :     The
103 :     environment variable contents is defined in
104 :     L</webwork_system_html/docs/techdescription/pglanguage/PGenvironment.html>
105 :    
106 :    
107 :     =cut
108 :    
109 :     sub DOCUMENT {
110 :     $STRINGforOUTPUT ="";
111 :     $STRINGforHEADER_TEXT ="";
112 :     @PG_ANSWERS=();
113 :     @main::PG_ANSWER_ENTRY_ORDER = ();
114 :     @PG_UNLABELED_ANSWERS = ();
115 :     %PG_ANSWERS_HASH = ();
116 :     $main::ANSWER_PREFIX = 'AnSwEr';
117 :     %main::PG_FLAGS=(); #global flags
118 :     $main::showPartialCorrectAnswers = 0 unless defined($main::showPartialCorrectAnswers );
119 :     $main::showHint = 1 unless defined($main::showHint);
120 :     $main::solutionExists =0;
121 :     $main::hintExists =0;
122 :     %main::gifs_created = ();
123 :    
124 :     die "The environment variable envir has not been defined" unless defined(%main::envir);
125 :    
126 :     foreach my $var ( keys %main::envir ) {
127 :     eval("\$main::$var =\$main::envir{'$var'}");
128 :     warn "Problem defining ", q{\$main::$var}, " while inititializing the PG problem: $@" if $@;
129 :     }
130 : lr003k 1122
131 : sh002i 1050 @main::submittedAnswers = @{$main::refSubmittedAnswers} if defined($main::refSubmittedAnswers);
132 :     $main::PG_original_problemSeed = $main::problemSeed;
133 :     $main::PG_random_generator = new PGrandom($main::problemSeed) || die "Can't create random number generator.";
134 :     $main::ans_rule_count = 0; # counts questions
135 :    
136 :     # end unpacking of environment variables.
137 :     }
138 :    
139 :     # HEADER_TEXT is for material which is destined to be placed in the header of the html problem -- such
140 :     # as javaScript code.
141 :    
142 :     =head2 HEADER_TEXT()
143 :    
144 :    
145 :     HEADER_TEXT("string1", "string2", "string3");
146 :    
147 :     The C<HEADER_TEXT()>
148 :     function concatenates its arguments and places them in the output
149 :     header text string. It is used for material which is destined to be placed in
150 :     the header of the html problem -- such as javaScript code.
151 :     It can be used more than once in a file.
152 :    
153 :    
154 :     =cut
155 :    
156 :     sub HEADER_TEXT {
157 :     my @in = @_;
158 :     $STRINGforHEADER_TEXT .= join(" ",@in);
159 :     }
160 :    
161 :     # TEXT is the function which defines text which will appear in the problem.
162 :     # All text must be an argument to this function. Any other statements
163 :     # are calculations (done in perl) which will not directly appear in the
164 :     # output. Think of this as the "print" function for the .pg language.
165 :     # It can be used more than once in a file.
166 :    
167 :     =head2 TEXT()
168 :    
169 :     TEXT("string1", "string2", "string3");
170 :    
171 :     The C<TEXT()> function concatenates its arguments and places them in the output
172 :     text string. C<TEXT()> is the function which defines text which will appear in the problem.
173 :     All text must be an argument to this function. Any other statements
174 :     are calculations (done in perl) which will not directly appear in the
175 :     output. Think of this as the "print" function for the .pg language.
176 :     It can be used more than once in a file.
177 :    
178 :     =cut
179 :    
180 :     sub TEXT {
181 :     my @in = @_;
182 :     $STRINGforOUTPUT .= join(" ",@in);
183 :     }
184 :    
185 :    
186 :    
187 :     =head2 ANS()
188 :    
189 :     ANS(answer_evaluator1, answer_evaluator2, answer_evaluator3,...)
190 :    
191 :     Places the answer evaluators in the unlabeled answer_evaluator queue. They will be paired
192 :     with unlabeled answer rules (answer entry blanks) in the order entered. This is the standard
193 :     method for entering answers.
194 :    
195 :     LABELED_ANS(answer_evaluater_name1, answer_evaluator1, answer_evaluater_name2,answer_evaluator2,...)
196 :    
197 :     Places the answer evaluators in the labeled answer_evaluator hash. This allows pairing of
198 :     labeled answer evaluators and labeled answer rules which may not have been entered in the same
199 :     order.
200 :    
201 :     =cut
202 :    
203 :     sub ANS{ # store answer evaluators which have not been explicitly labeled
204 :     my @in = @_;
205 :     while (@in ) {
206 :     warn("<BR><B>Error in ANS:$in[0]</B> -- inputs must be references to
207 :     subroutines<BR>")
208 :     unless ref($in[0]);
209 :     push(@PG_ANSWERS, shift @in );
210 :     }
211 :     }
212 :     sub LABELED_ANS { #a better alias for NAMED_ANS
213 :     &NAMED_ANS;
214 :     }
215 :    
216 :     sub NAMED_ANS{ # store answer evaluators which have been explicitly labeled (submitted in a hash)
217 :     my @in = @_;
218 :     while (@in ) {
219 :     my $label = shift @in;
220 :     my $ans_eval = shift @in;
221 :     TEXT("<BR><B>Error in NAMED_ANS:$in[0]</B>
222 :     -- inputs must be references to subroutines<BR>")
223 :     unless ref($ans_eval);
224 :     $PG_ANSWERS_HASH{$label}= $ans_eval;
225 :     }
226 :     }
227 :     sub RECORD_ANS_NAME { # this maintains the order in which the answer rules are printed.
228 :     my $label = shift;
229 :     push(@main::PG_ANSWER_ENTRY_ORDER, $label);
230 :     $label;
231 :     }
232 :    
233 :     sub NEW_ANS_NAME { # this keeps track of the answers which are entered implicitly,
234 :     # rather than with a specific label
235 :     my $number=shift;
236 :     my $label = "$main::ANSWER_PREFIX$number";
237 :     push(@PG_UNLABELED_ANSWERS,$label);
238 :     $label;
239 :     }
240 :     sub ANS_NUM_TO_NAME { # This converts a number to an answer label for use in
241 :     # radio button and check box answers. No new answer
242 :     # name is recorded.
243 :     my $number=shift;
244 :     my $label = "$main::ANSWER_PREFIX$number";
245 :     $label;
246 :     }
247 :    
248 : lr003k 1122 my $vecnum;
249 :    
250 :     sub NEW_ANS_ARRAY_NAME { # this keeps track of the answers which are entered implicitly,
251 :     # rather than with a specific label
252 :     my $number=shift;
253 :     $vecnum = 0;
254 :     my $row = shift;
255 :     my $col = shift;
256 :     my $label = "ArRaY"."$number"."["."$vecnum".","."$row".","."$col"."]";
257 :     push(@PG_UNLABELED_ANSWERS,$label);
258 :     $label;
259 :     }
260 :    
261 :     sub NEW_ANS_ARRAY_NAME_EXTENSION { # this keeps track of the answers which are entered implicitly,
262 :     # rather than with a specific label
263 :     my $number=shift;
264 :     my $row = shift;
265 :     my $col = shift;
266 :     if( $row == 0 && $col == 0 ){
267 :     $vecnum += 1;
268 :     }
269 :     my $label = "ArRaY"."$number"."["."$vecnum".","."$row".","."$col"."]";
270 :     $label;
271 :     }
272 :    
273 : sh002i 1050 # ENDDOCUMENT must come at the end of every .pg file.
274 :     # It exports the resulting text of the problem, the text to be used in HTML header material
275 :     # (for javaScript), the list of answer evaluators and any other flags. It can appear only once and
276 :     # it MUST be the last statement in the problem.
277 :    
278 :     =head2 ENDDOCUMENT()
279 :    
280 :     ENDDOCUMENT() must the last executable statement in any problem template. It can
281 :     only appear once. It returns
282 :     an array consisting of
283 :    
284 :     A reference to a string containing the rendered text of the problem.
285 :     A reference to a string containing text to be placed in the header
286 :     (for javaScript)
287 :     A reference to the array containing the answer evaluators.
288 :     (May be changed to a hash soon.)
289 :     A reference to an associative array (hash) containing various flags.
290 :    
291 :     The following flags are set by ENDDOCUMENT:
292 :     (1) showPartialCorrectAnswers -- determines whether students are told which
293 :     of their answers in a problem are wrong.
294 :     (2) recordSubmittedAnswers -- determines whether students submitted answers
295 :     are saved.
296 :     (3) refreshCachedImages -- determines whether the cached image of the problem
297 :     in typeset mode is always refreshed (i.e. setting this to 1 means cached
298 :     images are not used).
299 :     (4) solutionExits -- indicates the existence of a solution.
300 :     (5) hintExits -- indicates the existence of a hint.
301 :     (6) showHintLimit -- determines the number of attempts after which hint(s) will be shown
302 :    
303 :     (7) PROBLEM_GRADER_TO_USE -- chooses the problem grader to be used in this order
304 :     (a) A problem grader specified by the problem using:
305 :     install_problem_grader(\&grader);
306 :     (b) One of the standard problem graders defined in PGanswermacros.pl when set to
307 :     'std_problem_grader' or 'avg_problem_grader' by the environment variable
308 :     $PG_environment{PROBLEM_GRADER_TO_USE}
309 :     (c) A subroutine referenced by $PG_environment{PROBLEM_GRADER_TO_USE}
310 :     (d) The default &std_problem_grader defined in PGanswermacros.pl
311 :    
312 :    
313 :     =cut
314 :    
315 :     sub ENDDOCUMENT {
316 :    
317 :     my $index=0;
318 :     foreach my $label (@PG_UNLABELED_ANSWERS) {
319 :     if ( defined($PG_ANSWERS[$index]) ) {
320 :     $PG_ANSWERS_HASH{"$label"}= $PG_ANSWERS[$index];
321 :     } else {
322 :     warn "No answer provided by instructor for answer $label";
323 :     }
324 :     $index++;
325 :     }
326 :    
327 :     $STRINGforOUTPUT .="\n";
328 :     ##eval q{ #make sure that "main" points to the current safe compartment by evaluating these lines.
329 :     $main::PG_FLAGS{'showPartialCorrectAnswers'} = $main::showPartialCorrectAnswers;
330 :     $main::PG_FLAGS{'recordSubmittedAnswers'} = $main::recordSubmittedAnswers;
331 :     $main::PG_FLAGS{'refreshCachedImages'} = $main::refreshCachedImages;
332 :     $main::PG_FLAGS{'hintExists'} = $main::hintExists;
333 :     $main::PG_FLAGS{'showHintLimit'} = $main::showHint;
334 :     $main::PG_FLAGS{'solutionExists'} = $main::solutionExists;
335 :     $main::PG_FLAGS{ANSWER_ENTRY_ORDER} = \@main::PG_ANSWER_ENTRY_ORDER;
336 :     $main::PG_FLAGS{ANSWER_PREFIX} = $main::ANSWER_PREFIX;
337 :     # install problem grader
338 :     if (defined($main::PG_FLAGS{PROBLEM_GRADER_TO_USE}) ) {
339 :     # problem grader defined within problem -- no further action needed
340 :     } elsif ( defined( $main::envir{PROBLEM_GRADER_TO_USE} ) ) {
341 :     if (ref($main::envir{PROBLEM_GRADER_TO_USE}) eq 'CODE' ) { # user defined grader
342 :     $main::PG_FLAGS{PROBLEM_GRADER_TO_USE} = $main::envir{PROBLEM_GRADER_TO_USE};
343 :     } elsif ($main::envir{PROBLEM_GRADER_TO_USE} eq 'std_problem_grader' ) {
344 :     if (defined(&std_problem_grader) ){
345 :     $main::PG_FLAGS{PROBLEM_GRADER_TO_USE} = \&std_problem_grader; # defined in PGanswermacros.pl
346 :     } # std_problem_grader is the default in any case so don't give a warning.
347 :     } elsif ($main::envir{PROBLEM_GRADER_TO_USE} eq 'avg_problem_grader' ) {
348 :     if (defined(&avg_problem_grader) ){
349 :     $main::PG_FLAGS{PROBLEM_GRADER_TO_USE} = \&avg_problem_grader; # defined in PGanswermacros.pl
350 :     }
351 :     #else { # avg_problem_grader will be installed by PGtranslator so there is no need for a warning.
352 :     # warn "The problem grader 'avg_problem_grader' has not been defined. Has PGanswermacros.pl been loaded?";
353 :     #}
354 :     } else {
355 :     warn "Error: $main::PG_FLAGS{PROBLEM_GRADER_TO_USE} is not a known program grader.";
356 :     }
357 :     } elsif (defined(&std_problem_grader)) {
358 :     $main::PG_FLAGS{PROBLEM_GRADER_TO_USE} = \&std_problem_grader; # defined in PGanswermacros.pl
359 :     } else {
360 :     # PGtranslator will install its default problem grader
361 :     }
362 :     ##};
363 :     warn "ERROR: The problem grader is not a subroutine" unless ref( $main::PG_FLAGS{PROBLEM_GRADER_TO_USE}) eq 'CODE'
364 :     or $main::PG_FLAGS{PROBLEM_GRADER_TO_USE} = 'std_problem_grader'
365 :     or $main::PG_FLAGS{PROBLEM_GRADER_TO_USE} = 'avg_problem_grader';
366 :     # return results
367 :     (\$STRINGforOUTPUT, \$STRINGforHEADER_TEXT,\%PG_ANSWERS_HASH,\%main::PG_FLAGS);
368 :     }
369 :    
370 :    
371 :    
372 :     =head2 INITIALIZE_PG()
373 :    
374 :     This is executed each C<DOCUMENT()> is called. For backward compatibility
375 :     C<loadMacros> also checks whether the C<macroDirectory> has been defined
376 :     and if not, it runs C<INITIALIZE_PG()> and issues a warning.
377 :    
378 :     =cut
379 :    
380 :    
381 :     1;

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9