[system] / trunk / webwork2 / lib / WeBWorK / PG.pm Repository:
ViewVC logotype

Diff of /trunk/webwork2/lib/WeBWorK/PG.pm

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

Revision 425 Revision 1196
1################################################################################
2# WeBWorK mod_perl (c) 2000-2002 WeBWorK Project
3# $Id$
4################################################################################
5
1package WeBWorK::PG; 6package WeBWorK::PG;
2 7
3# hide PG::* from the not-yet-insane. 8=head1 NAME
9
10WeBWorK::PG - Wrap the action of the PG Translator in an easy-to-use API.
11
12=cut
4 13
5use strict; 14use strict;
6use warnings; 15use warnings;
7use WeBWorK::Utils qw(readFile formatDateTime); 16use File::Path qw(rmtree);
8use WeBWorK::DB::Classlist; 17use WeBWorK::PG::ImageGenerator;
9use WeBWorK::DB::WW;
10use WeBWorK::PG::Translator; 18use WeBWorK::PG::Translator;
19use WeBWorK::Utils qw(readFile formatDateTime writeTimingLogEntry makeTempDirectory);
11 20
12sub new($$$$$$$$) { 21sub new {
13 my $invocant = shift; 22 my $invocant = shift;
14 my $class = ref($invocant) || $invocant; 23 my $class = ref($invocant) || $invocant;
15 my ( 24 my (
16 $courseEnv, 25 $courseEnv,
17 $userName, 26 $user,
18 $key, 27 $key,
19 $setName, 28 $set,
20 $problemNumber, 29 $problem,
30 $psvn,
31 $formFields, # in CGI::Vars format
21 $translationOptions, # hashref containing options for the 32 $translationOptions, # hashref containing options for the
22 # translator, such as whether to show 33 # translator, such as whether to show
23 # hints and the display mode to use 34 # hints and the display mode to use
24 $formFields, # in CGI::Vars format
25 ) = @_; 35 ) = @_;
26 36
27 # get database information 37 # write timing log entry
28 my $classlist = WeBWorK::DB::Classlist->new($courseEnv); 38 writeTimingLogEntry($courseEnv, "WeBWorK::PG::new",
29 my $wwdb = WeBWorK::DB::WW->new($courseEnv); 39 "user=".$user->user_id.",problem=".$courseEnv->{courseName}."/".$set->set_id."/".$problem->problem_id.",mode=".$translationOptions->{displayMode},
30 my $user = $classlist->getUser($userName); 40 "begin");
31 my $set = $wwdb->getSet($userName, $setName); 41
32 my $problem = $wwdb->getProblem($userName, $setName, $problemNumber); 42 # install a local warn handler to collect warnings
33 my $psvn = $wwdb->getPSVN($userName, $setName); 43 my $warnings = "";
44 local $SIG{__WARN__} = sub { $warnings .= shift }
45 if $courseEnv->{pg}->{options}->{catchWarnings};
34 46
35 # create a Translator 47 # create a Translator
36 warn "PG: creating a Translator\n"; 48 #warn "PG: creating a Translator\n";
37 my $translator = WeBWorK::PG::Translator->new; 49 my $translator = WeBWorK::PG::Translator->new;
38 50
39 # set the directory hash 51 # set the directory hash
40 warn "PG: setting the directory hash\n"; 52 #warn "PG: setting the directory hash\n";
41 $translator->rh_directories({ 53 $translator->rh_directories({
42 courseScriptsDirectory => $courseEnv->{webworkDirs}->{macros}, 54 courseScriptsDirectory => $courseEnv->{webworkDirs}->{macros},
43 macroDirectory => $courseEnv->{courseDirs}->{macros}, 55 macroDirectory => $courseEnv->{courseDirs}->{macros},
44 templateDirectory => $courseEnv->{courseDirs}->{templates}, 56 templateDirectory => $courseEnv->{courseDirs}->{templates},
45 tempDirectory => $courseEnv->{courseDirs}->{html_temp}, 57 tempDirectory => $courseEnv->{courseDirs}->{html_temp},
46 }); 58 });
47 59
48 # evaluate modules and "extra packages" 60 # evaluate modules and "extra packages"
49 warn "PG: evaluating modules and \"extra packages\"\n"; 61 #warn "PG: evaluating modules and \"extra packages\"\n";
50 my @modules = @{ $courseEnv->{pg}->{modules} }; 62 my @modules = @{ $courseEnv->{pg}->{modules} };
51 foreach my $module_packages (@modules) { 63 foreach my $module_packages_ref (@modules) {
52 # the first item in $module_packages is the main package 64 my ($module, @extra_packages) = @$module_packages_ref;
65 # the first item is the main package
53 $translator->evaluate_modules(shift @$module_packages); 66 $translator->evaluate_modules($module);
54 # the remaining items are "extra" packages 67 # the remaining items are "extra" packages
55 $translator->load_extra_packages(@$module_packages); 68 $translator->load_extra_packages(@extra_packages);
56 } 69 }
57 70
58 # set the environment (from defineProblemEnvir) 71 # set the environment (from defineProblemEnvir)
59 warn "PG: setting the environment (from defineProblemEnvir)\n"; 72 #warn "PG: setting the environment (from defineProblemEnvir)\n";
73 my $envir = defineProblemEnvir(
74 $courseEnv,
75 $user,
76 $key,
77 $set,
78 $problem,
79 $psvn,
80 $formFields,
81 $translationOptions,
82 );
60 $translator->environment(defineProblemEnvir( 83 $translator->environment($envir);
61 $courseEnv, $user, $key, $set, $problem, $psvn, $formFields, $translationOptions));
62 84
63 # initialize the Translator 85 # initialize the Translator
64 warn "PG: initializing the Translator\n"; 86 #warn "PG: initializing the Translator\n";
65 $translator->initialize(); 87 $translator->initialize();
66 88
67 # load PG.pl and dangerousMacros.pl using unrestricted_load 89 # load IO.pl, PG.pl, and dangerousMacros.pl using unrestricted_load
68 # i'd like to change this at some point to have the same sort of interface to global.conf 90 # i'd like to change this at some point to have the same sort of interface to global.conf
69 # that the module loading does -- have a list of macros to load unrestrictedly. 91 # that the module loading does -- have a list of macros to load unrestrictedly.
70 warn "PG: loading PG.pl and dangerousMacros.pl using unrestricted_load\n"; 92 #warn "PG: loading IO.pl, PG.pl, and dangerousMacros.pl using unrestricted_load\n";
93 foreach (qw(IO.pl PG.pl dangerousMacros.pl)) {
71 my $pg_pl = $courseEnv->{webworkDirs}->{macros} . "/PG.pl"; 94 my $macroPath = $courseEnv->{webworkDirs}->{macros} . "/$_";
72 my $dangerousMacros_pl = $courseEnv->{webworkDirs}->{macros} . "/dangerousMacros.pl";
73 my $err = $translator->unrestricted_load($pg_pl); 95 my $err = $translator->unrestricted_load($macroPath);
74 warn "Error while loading $pg_pl: $err" if $err; 96 warn "Error while loading $macroPath: $err" if $err;
75 $err = $translator->unrestricted_load($dangerousMacros_pl); 97 }
76 warn "Error while loading $dangerousMacros_pl: $err" if $err;
77 98
78 # set the opcode mask (using default values) 99 # set the opcode mask (using default values)
79 warn "PG: setting the opcode mask (using default values)\n"; 100 #warn "PG: setting the opcode mask (using default values)\n";
80 $translator->set_mask(); 101 $translator->set_mask();
81 102
82 # store the problem source 103 # store the problem source
83 warn "PG: storing the problem source\n"; 104 #warn "PG: storing the problem source\n";
105 my $sourceFile = $problem->source_file;
84 my $sourceFile = $courseEnv->{courseDirs}->{templates}."/".$problem->source_file; 106 $sourceFile = $courseEnv->{courseDirs}->{templates}."/".$sourceFile
107 unless ($sourceFile =~ /^\//);
85 $translator->source_string(readFile($sourceFile)); 108 eval { $translator->source_string(readFile($sourceFile)) };
109 if ($@) {
110 # well, we couldn't get the problem source, for some reason.
111 return bless {
112 translator => $translator,
113 head_text => "",
114 body_text => <<EOF,
115WeBWorK::Utils::readFile($sourceFile) says:
116$@
117EOF
118 answers => {},
119 result => {},
120 state => {},
121 errors => "Failed to read the problem source file.",
122 warnings => $warnings,
123 flags => {error_flag => 1},
124 }, $class;
125 }
86 126
87 # install a safety filter (&safetyFilter) 127 # install a safety filter (&safetyFilter)
88 warn "PG: installing a safety filter\n"; 128 #warn "PG: installing a safety filter\n";
89 $translator->rf_safety_filter(\&safetyFilter); 129 $translator->rf_safety_filter(\&safetyFilter);
90 130
131 # write timing log entry -- the translator is now all set up
132 writeTimingLogEntry($courseEnv, "WeBWorK::PG::new",
133 "initialized",
134 "intermediate");
135
91 # translate the PG source into text 136 # translate the PG source into text
92 warn "PG: translating the PG source into text\n"; 137 #warn "PG: translating the PG source into text\n";
93 $translator->translate(); 138 $translator->translate();
94 139
95 # [in Problem.pm and processProblem8.pl, "install a grader" is here] 140 # after we're done translating, we may have to clean up after the
141 # translator:
96 142
143 # for example, HTML_img mode uses a tempdir for dvipng's temp files.\
144 # We have to remove it.
145 if ($envir->{dvipngTempDir}) {
146 rmtree($envir->{dvipngTempDir}, 0, 0);
147 }
148
149 # HTML_dpng, on the other hand, uses an ImageGenerator. We have to
150 # render the queued equations.
151 if ($envir->{imagegen}) {
152 my $sourceFile = $courseEnv->{courseDirs}->{templates} . "/" . $problem->source_file;
153 my %mtimeOption = -e $sourceFile
154 ? (mtime => (stat $sourceFile)[9])
155 : ();
156
157 $envir->{imagegen}->render(
158 refresh => $translationOptions->{refreshMath2img},
159 %mtimeOption,
160 );
161 }
162
163 my ($result, $state); # we'll need these on the other side of the if block!
164 if ($translationOptions->{processAnswers}) {
165
97 # process student answers 166 # process student answers
98 warn "PG: processing student answers\n"; 167 #warn "PG: processing student answers\n";
99 $translator->process_answers($formFields); 168 $translator->process_answers($formFields);
100 169
101 # retrieve the problem state and give it to the translator 170 # retrieve the problem state and give it to the translator
102 warn "PG: retrieving the problem state and giving it to the translator\n"; 171 #warn "PG: retrieving the problem state and giving it to the translator\n";
103 $translator->rh_problem_state({ 172 $translator->rh_problem_state({
104 recorded_score => $problem->status, 173 recorded_score => $problem->status,
105 num_of_correct_ans => $problem->num_correct, 174 num_of_correct_ans => $problem->num_correct,
106 num_of_incorrect_ans => $problem->num_incorrect, 175 num_of_incorrect_ans => $problem->num_incorrect,
107 }); 176 });
108 177
109 # determine an entry order -- the ANSWER_ENTRY_ORDER flag is built by 178 # determine an entry order -- the ANSWER_ENTRY_ORDER flag is built by
110 # the PG macro package (PG.pl) 179 # the PG macro package (PG.pl)
111 warn "PG: determining an entry order\n"; 180 #warn "PG: determining an entry order\n";
112 my @answerOrder = 181 my @answerOrder =
113 $translator->rh_flags->{ANSWER_ENTRY_ORDER} 182 $translator->rh_flags->{ANSWER_ENTRY_ORDER}
114 ? @{ $translator->rh_flags->{ANSWER_ENTRY_ORDER} } 183 ? @{ $translator->rh_flags->{ANSWER_ENTRY_ORDER} }
115 : keys %{ $translator->rh_evaluated_answers }; 184 : keys %{ $translator->rh_evaluated_answers };
116 185
117 # install a grader -- use the one specified in the problem, 186 # install a grader -- use the one specified in the problem,
118 # or fall back on the default from the course environment. 187 # or fall back on the default from the course environment.
119 # (two magic strings are accepted, to avoid having to 188 # (two magic strings are accepted, to avoid having to
120 # reference code when it would be difficult.) 189 # reference code when it would be difficult.)
121 warn "PG: installing a grader\n"; 190 #warn "PG: installing a grader\n";
122 my $grader = $translator->rh_flags->{PROBLEM_GRADER_TO_USE} 191 my $grader = $translator->rh_flags->{PROBLEM_GRADER_TO_USE}
123 || $courseEnv->{pg}->{options}->{grader}; 192 || $courseEnv->{pg}->{options}->{grader};
124 $grader = $translator->rf_std_problem_grader 193 $grader = $translator->rf_std_problem_grader
125 if $grader eq "std_problem_grader"; 194 if $grader eq "std_problem_grader";
126 $grader = $translator->rf_avg_problem_grader 195 $grader = $translator->rf_avg_problem_grader
127 if $grader eq "avg_problem_grader"; 196 if $grader eq "avg_problem_grader";
128 die "Problem grader $grader is not a CODE reference." 197 die "Problem grader $grader is not a CODE reference."
129 unless ref $grader eq "CODE"; 198 unless ref $grader eq "CODE";
130 $translator->rf_problem_grader($grader); 199 $translator->rf_problem_grader($grader);
131 200
132 # grading the problem 201 # grade the problem
133 warn "PG: grade the problem\n"; 202 #warn "PG: grading the problem\n";
134 my ($result, $state) = $translator->grade_problem( 203 ($result, $state) = $translator->grade_problem(
135 answers_submitted => $translationOptions->{processAnswers}, 204 answers_submitted => $translationOptions->{processAnswers},
136 ANSWER_ENTRY_ORDER => \@answerOrder, 205 ANSWER_ENTRY_ORDER => \@answerOrder,
137 ); 206 );
207
208 }
209
210 # write timing log entry
211 writeTimingLogEntry($courseEnv, "WeBWorK::PG::new", "", "end");
138 212
139 # return an object which contains the translator and the results of 213 # return an object which contains the translator and the results of
140 # the translation process. this is DIFFERENT from the "format expected 214 # the translation process. this is DIFFERENT from the "format expected
141 # by Webwork.pm (and I believe processProblem8, but check.)" 215 # by Webwork.pm (and I believe processProblem8, but check.)"
142 return bless { 216 return bless {
144 head_text => ${ $translator->r_header }, 218 head_text => ${ $translator->r_header },
145 body_text => ${ $translator->r_text }, 219 body_text => ${ $translator->r_text },
146 answers => $translator->rh_evaluated_answers, 220 answers => $translator->rh_evaluated_answers,
147 result => $result, 221 result => $result,
148 state => $state, 222 state => $state,
149 errors => $translator->errors, # *** what is this doing? 223 errors => $translator->errors,
150 warnings => undef, # *** gotta catch warnings eventually... 224 warnings => $warnings,
151 flags => $translator->rh_flags, 225 flags => $translator->rh_flags,
152 }, $class; 226 }, $class;
153} 227}
154 228
155# ----- 229# -----
156 230
157sub defineProblemEnvir($$$$$$$) { 231sub defineProblemEnvir {
158 my ( 232 my (
159 $courseEnv, 233 $courseEnv,
160 $user, 234 $user,
161 $key, 235 $key,
162 $set, 236 $set,
166 $options, 240 $options,
167 ) = @_; 241 ) = @_;
168 242
169 my %envir; 243 my %envir;
170 244
245 # ----------------------------------------------------------------------
246
171 # PG environment variables 247 # PG environment variables
172 # from docs/pglanguage/pgreference/environmentvariables as of 06/25/2002 248 # from docs/pglanguage/pgreference/environmentvariables as of 06/25/2002
173 # any changes are noted by "ADDED:" or "REMOVED:" 249 # any changes are noted by "ADDED:" or "REMOVED:"
174 250
175 # Vital state information 251 # Vital state information
176 # ADDED: displayHintsQ, displaySolutionsQ, externalTTHPath 252 # ADDED: displayHintsQ, displaySolutionsQ, refreshMath2img,
253 # texDisposition
177 254
178 $envir{psvn} = $psvn; 255 $envir{psvn} = $set->psvn;
179 $envir{psvnNumber} = $envir{psvn}; 256 $envir{psvnNumber} = $envir{psvn};
180 $envir{probNum} = $problem->id; 257 $envir{probNum} = $problem->problem_id;
181 $envir{questionNumber} = $envir{probNum}; 258 $envir{questionNumber} = $envir{probNum};
182 $envir{fileName} = $problem->source_file; 259 $envir{fileName} = $problem->source_file;
183 $envir{probFileName} = $envir{fileName}; 260 $envir{probFileName} = $envir{fileName};
184 $envir{problemSeed} = $problem->problem_seed; 261 $envir{problemSeed} = $problem->problem_seed;
185 $envir{displayMode} = translateDisplayModeNames($options->{displayMode}); 262 $envir{displayMode} = translateDisplayModeNames($options->{displayMode});
186 $envir{languageMode} = $envir{displayMode}; 263 $envir{languageMode} = $envir{displayMode};
187 $envir{outputMode} = $envir{displayMode}; 264 $envir{outputMode} = $envir{displayMode};
188 $envir{displayHintsQ} = $options->{hints}; 265 $envir{displayHintsQ} = $options->{showHints};
189 $envir{displaySolutionsQ} = $options->{solutions}; 266 $envir{displaySolutionsQ} = $options->{showSolutions};
190 $envir{externalTTHPath} = $courseEnv->{externalPrograms}->{tth}; 267 # FIXME: this is HTML_img specific
268 #$envir{refreshMath2img} = $options->{refreshMath2img};
269 $envir{texDisposition} = "pdf"; # in webwork-modperl, we use pdflatex
191 270
192 # Problem Information 271 # Problem Information
193 # ADDED: courseName 272 # ADDED: courseName, formatedDueDate
194 273
195 $envir{openDate} = $set->open_date; 274 $envir{openDate} = $set->open_date;
196 $envir{formattedOpenDate} = formatDateTime($envir{openDate}); 275 $envir{formattedOpenDate} = formatDateTime($envir{openDate});
197 $envir{dueDate} = $set->due_date; 276 $envir{dueDate} = $set->due_date;
198 $envir{formattedDueDate} = formatDateTime($envir{dueDate}); 277 $envir{formattedDueDate} = formatDateTime($envir{dueDate});
278 $envir{formatedDueDate} = $envir{formattedDueDate}; # typo in many header files
199 $envir{answerDate} = $set->answer_date; 279 $envir{answerDate} = $set->answer_date;
200 $envir{formattedAnswerDate} = formatDateTime($envir{answerDate}); 280 $envir{formattedAnswerDate} = formatDateTime($envir{answerDate});
201 $envir{numOfAttempts} = $problem->num_correct + $problem->num_incorrect; 281 $envir{numOfAttempts} = ($problem->num_correct || 0) + ($problem->num_incorrect || 0);
202 $envir{problemValue} = $problem->value; 282 $envir{problemValue} = $problem->value;
203 $envir{sessionKey} = $key; 283 $envir{sessionKey} = $key;
204 $envir{courseName} = $courseEnv->{courseName}; 284 $envir{courseName} = $courseEnv->{courseName};
205 285
206 # Student Information 286 # Student Information
208 288
209 $envir{sectionName} = $user->section; 289 $envir{sectionName} = $user->section;
210 $envir{sectionNumber} = $envir{sectionName}; 290 $envir{sectionNumber} = $envir{sectionName};
211 $envir{recitationName} = $user->recitation; 291 $envir{recitationName} = $user->recitation;
212 $envir{recitationNumber} = $envir{recitationName}; 292 $envir{recitationNumber} = $envir{recitationName};
213 $envir{setNumber} = $set->id; 293 $envir{setNumber} = $set->set_id;
214 $envir{studentLogin} = $user->id; 294 $envir{studentLogin} = $user->user_id;
215 $envir{studentName} = $user->first_name . " " . $user->last_name; 295 $envir{studentName} = $user->first_name . " " . $user->last_name;
216 $envir{studentID} = $user->student_id; 296 $envir{studentID} = $user->student_id;
217 297
218 # Answer Information 298 # Answer Information
219 # REMOVED: refSubmittedAnswers (alledgedly unused, causes errors) 299 # REMOVED: refSubmittedAnswers
220 300
221 $envir{inputs_ref} = $formFields; 301 $envir{inputs_ref} = $formFields;
222 302
223 # Default values for evaluating answers 303 # External Programs
304 # ADDED: externalLaTeXPath, externalDvipngPath,
305 # externalGif2EpsPath, externalPng2EpsPath
224 306
225 my $ansEvalDefaults = $courseEnv->{pg}->{ansEvalDefaults}; 307 $envir{externalTTHPath} = $courseEnv->{externalPrograms}->{tth};
226 $envir{$_} = $ansEvalDefaults->{$_} foreach (keys %$ansEvalDefaults); 308 $envir{externalLaTeXPath} = $courseEnv->{externalPrograms}->{latex};
309 $envir{externalDvipngPath} = $courseEnv->{externalPrograms}->{dvipng};
310 $envir{externalGif2EpsPath} = $courseEnv->{externalPrograms}->{gif2eps};
311 $envir{externalPng2EpsPath} = $courseEnv->{externalPrograms}->{png2eps};
312 $envir{externalGif2PngPath} = $courseEnv->{externalPrograms}->{gif2png};
227 313
228 # Directories and URLs 314 # Directories and URLs
229 # REMOVED: courseName 315 # REMOVED: courseName
316 # ADDED: dvipngTempDir
230 317
231 $envir{cgiDirectory} = undef; 318 $envir{cgiDirectory} = undef;
232 $envir{cgiURL} = undef; 319 $envir{cgiURL} = undef;
233 $envir{classDirectory} = undef; 320 $envir{classDirectory} = undef;
234 $envir{courseScriptsDirectory} = $courseEnv->{webworkDirs}->{macros}."/"; 321 $envir{courseScriptsDirectory} = $courseEnv->{webworkDirs}->{macros}."/";
235 $envir{htmlDirectory} = $courseEnv->{courseDirs}->{html}."/"; 322 $envir{htmlDirectory} = $courseEnv->{courseDirs}->{html}."/";
236 $envir{htmlURL} = $courseEnv->{courseURLs}->{html}; 323 $envir{htmlURL} = $courseEnv->{courseURLs}->{html}."/";
237 $envir{macroDirectory} = $courseEnv->{courseDirs}->{macros}."/"; 324 $envir{macroDirectory} = $courseEnv->{courseDirs}->{macros}."/";
238 $envir{templateDirectory} = $courseEnv->{courseDirs}->{templates}."/"; 325 $envir{templateDirectory} = $courseEnv->{courseDirs}->{templates}."/";
239 $envir{tempDirectory} = $courseEnv->{courseDirs}->{html_temp}."/"; 326 $envir{tempDirectory} = $courseEnv->{courseDirs}->{html_temp}."/";
240 $envir{tempURL} = $courseEnv->{courseURLs}->{html_temp}; 327 $envir{tempURL} = $courseEnv->{courseURLs}->{html_temp}."/";
241 $envir{scriptDirectory} = undef; 328 $envir{scriptDirectory} = undef;
242 $envir{webworkDocsURL} = $courseEnv->{webworkURLs}->{docs}; 329 $envir{webworkDocsURL} = $courseEnv->{webworkURLs}->{docs}."/";
330 # FIXME: this is HTML_img mode-specific
331 #$envir{dvipngTempDir} = $options->{displayMode} eq 'images'
332 # ? makeTempDirectory($envir{tempDirectory}, "webwork-dvipng")
333 # : undef;
243 334
244 # Other things... (where's your brain?!?!) 335 # Information for sending mail
245 336
337 $envir{mailSmtpServer} = $courseEnv->{mail}->{smtpServer};
338 $envir{mailSmtpSender} = $courseEnv->{mail}->{smtpSender};
339 $envir{ALLOW_MAIL_TO} = $courseEnv->{mail}->{allowedRecipients};
340
341 # Default values for evaluating answers
342
343 my $ansEvalDefaults = $courseEnv->{pg}->{ansEvalDefaults};
344 $envir{$_} = $ansEvalDefaults->{$_} foreach (keys %$ansEvalDefaults);
345
346 # ----------------------------------------------------------------------
347
348 my $basename = "equation-$envir{psvn}.$envir{probNum}";
349 $basename .= ".$envir{problemSeed}" if $envir{problemSeed};
350
351 # Object for generating equation images
352 $envir{imagegen} = WeBWorK::PG::ImageGenerator->new(
353 tempDir => $courseEnv->{webworkDirs}->{tmp}, # global temp dir
354 dir => $envir{tempDirectory},
355 url => $envir{tempURL},
356 basename => $basename,
357 latex => $envir{externalLaTeXPath},
358 dvipng => $envir{externalDvipngPath},
359 );
360
361 # Other things...
362 $envir{QUIZ_PREFIX} = $options->{QUIZ_PREFIX}; # used by quizzes
246 $envir{PROBLEM_GRADER_TO_USE} = $courseEnv->{pg}->{options}->{grader}; 363 $envir{PROBLEM_GRADER_TO_USE} = $courseEnv->{pg}->{options}->{grader};
364 $envir{PRINT_FILE_NAMES_FOR} = $courseEnv->{pg}->{specialPGEnvironmentVars}->{PRINT_FILE_NAMES_FOR};
365
366 # variables for interpreting capa problems.
367 $envir{CAPA_Tools} = $courseEnv->{pg}->{specialPGEnvironmentVars}->{CAPA_Tools};
368 $envir{CAPA_MCTools} = $courseEnv->{pg}->{specialPGEnvironmentVars}->{CAPA_MCTools};
369 $envir{CAPA_Graphics_URL} = $courseEnv->{pg}->{specialPGEnvironmentVars}->{CAPA_Graphics_URL};
370 $envir{CAPA_GraphicsDirectory} = $courseEnv->{pg}->{specialPGEnvironmentVars}->{CAPA_GraphicsDirectory};
247 371
248 return \%envir; 372 return \%envir;
249} 373}
250 374
251sub translateDisplayModeNames($) { 375sub translateDisplayModeNames($) {
252 my $name = shift; 376 my $name = shift;
253 return { 377 return {
378 tex => "TeX",
254 plainText => "HTML", 379 plainText => "HTML",
255 formattedText => "HTML_tth", 380 formattedText => "HTML_tth",
256 images => "Latex2HTML" 381 images => "HTML_dpng", # "HTML_img",
257 }->{$name}; 382 }->{$name};
258} 383}
259 384
260sub safetyFilter { 385sub safetyFilter {
261 my $answer = shift; # accepts one answer and checks it 386 my $answer = shift; # accepts one answer and checks it
269 $errorno = 0; ## don't report blank answer as error 394 $errorno = 0; ## don't report blank answer as error
270 return ($answer,$errorno); 395 return ($answer,$errorno);
271 } 396 }
272 # replace ^ with ** (for exponentiation) 397 # replace ^ with ** (for exponentiation)
273 # $answer =~ s/\^/**/g; 398 # $answer =~ s/\^/**/g;
274 # Return if forbidden characters are found 399 # Return if forbidden characters are found
275 unless ($answer =~ /^[a-zA-Z0-9_\-\+ \t\/@%\*\.\n^\(\)]+$/ ) { 400 unless ($answer =~ /^[a-zA-Z0-9_\-\+ \t\/@%\*\.\n^\[\]\(\)\,\|]+$/ ) {
276 $answer =~ tr/a-zA-Z0-9_\-\+ \t\/@%\*\.\n^\(\)/#/c; 401 $answer =~ tr/a-zA-Z0-9_\-\+ \t\/@%\*\.\n^\(\)/#/c;
277 $errorno = "<BR>There are forbidden characters in your answer: $submittedAnswer<BR>"; 402 $errorno = "<BR>There are forbidden characters in your answer: $submittedAnswer<BR>";
278 return ($answer,$errorno); 403 return ($answer,$errorno);
279 } 404 }
280 $errorno = 0; 405 $errorno = 0;
281 return($answer, $errorno); 406 return($answer, $errorno);
282} 407}
283 408
2841; 4091;
410
411__END__
412
413=head1 SYNOPSIS
414
415 $pg = WeBWorK::PG->new(
416 $courseEnv, # a WeBWorK::CourseEnvironment object
417 $user, # a WeBWorK::DB::Record::User object
418 $sessionKey,
419 $set, # a WeBWorK::DB::Record::UserSet object
420 $problem, # a WeBWorK::DB::Record::UserProblem object
421 $psvn,
422 $formFields # in &WeBWorK::Form::Vars format
423 { # translation options
424 displayMode => "images", # (plainText|formattedText|images)
425 showHints => 1, # (0|1)
426 showSolutions => 0, # (0|1)
427 refreshMath2img => 0, # (0|1)
428 processAnswers => 1, # (0|1)
429 },
430 );
431
432 $translator = $pg->{translator}; # WeBWorK::PG::Translator
433 $body = $pg->{body_text}; # text string
434 $header = $pg->{head_text}; # text string
435 $answerHash = $pg->{answers}; # WeBWorK::PG::AnswerHash
436 $result = $pg->{result}; # hash reference
437 $state = $pg->{state}; # hash reference
438 $errors = $pg->{errors}; # text string
439 $warnings = $pg->{warnings}; # text string
440 $flags = $pg->{flags}; # hash reference
441
442=head1 DESCRIPTION
443
444WeBWorK::PG encapsulates the PG translation process, making multiple calls to
445WeBWorK::PG::Translator. Much of the flexibility of the Translator is hidden,
446instead making choices that are appropriate for the webwork-modperl system.
447
448=head1 CONSTRUCTION
449
450=over
451
452=item new (ENVIRONMENT, USER, KEY, SET, PROBLEM, PSVN, FIELDS, OPTIONS)
453
454The C<new> method creates a translator, initializes it using the parameters
455specified, translates a PG file, and processes answers. It returns a reference
456to a blessed hash containing the results of the translation process.
457
458=back
459
460=head2 Parameters
461
462=over
463
464=item ENVIRONMENT
465
466a WeBWorK::CourseEnvironment object
467
468=item USER
469
470a WeBWorK::User object
471
472=item KEY
473
474the session key of the current session
475
476=item SET
477
478a WeBWorK::Set object
479
480=item PROBLEM
481
482a WeBWorK::DB::Record::UserProblem object. The contents of the source_file
483field can specify a PG file either by absolute path or path relative to the
484"templates" directory. I<The caller should remove taint from this value before
485passing!>
486
487=item PSVN
488
489the problem set version number
490
491=item FIELDS
492
493a reference to a hash (as returned by &WeBWorK::Form::Vars) containing form
494fields submitted by a problem processor. The translator will look for fields
495like "AnSwEr[0-9]" containing submitted student answers.
496
497=item OPTIONS
498
499a reference to a hash containing the following data:
500
501=over
502
503=item displayMode
504
505one of "plainText", "formattedText", or "images"
506
507=item showHints
508
509boolean, render hints
510
511=item showSolutions
512
513boolean, render solutions
514
515=item refreshMath2img
516
517boolean, force images created by math2img (in "images" mode) to be recreated,
518even if the PG source has not been updated. FIXME: change the name of this
519option to "refreshEquations" and update the docs accordingly.
520
521=item processAnswers
522
523boolean, call answer evaluators and graders
524
525=back
526
527=back
528
529=head2 RETURN VALUE
530
531The C<new> method returns a blessed hash reference containing the following
532fields. More information can be found in the documentation for
533WeBWorK::PG::Translator.
534
535=over
536
537=item translator
538
539The WeBWorK::PG::Translator object used to render the problem.
540
541=item head_text
542
543HTML code for the E<lt>headE<gt> block of an resulting web page. Used for
544JavaScript features.
545
546=item body_text
547
548HTML code for the E<lt>bodyE<gt> block of an resulting web page.
549
550=item answers
551
552An C<AnswerHash> object containing submitted answers, and results of answer
553evaluation.
554
555=item result
556
557A hash containing the results of grading the problem.
558
559=item state
560
561A hash containing the new problem state.
562
563=item errors
564
565A string containing any errors encountered while rendering the problem.
566
567=item warnings
568
569A string containing any warnings encountered while rendering the problem.
570
571=item flags
572
573A hash containing PG_flags (see the Translator docs).
574
575=back
576
577=head1 OPERATION
578
579WeBWorK::PG goes through the following operations when constructed:
580
581=over
582
583=item Get database information
584
585Retrieve information about the current user, set, and problem from the
586database.
587
588=item Create a translator
589
590Instantiate a WeBWorK::PG::Translator object.
591
592=item Set the directory hash
593
594Set the translator's directory hash (courseScripts, macros, templates, and temp
595directories) from the course environment.
596
597=item Evaluate PG modules
598
599Using the module list from the course environment (pg->modules), perform a
600"use"-like operation to evaluate modules at runtime.
601
602=item Set the problem environment
603
604Use data from the user, set, and problem, as well as the course environemnt and
605translation options, to set the problem environment.
606
607=item Initialize the translator
608
609Call &WeBWorK::PG::Translator::initialize. What more do you want?
610
611=item Load PG.pl and dangerousMacros.pl
612
613These macros must be loaded without opcode masking, so they are loaded here.
614
615=item Set the opcode mask
616
617Set the opcode mask to the default specified by WeBWorK::PG::Translator.
618
619=item Load the problem source
620
621Give the problem source to the translator.
622
623=item Install a safety filter
624
625The safety filter is used to preprocess student input before evaluation. The
626default safety filter, &WeBWorK::PG::safetyFilter, is used.
627
628=item Translate the problem source
629
630Call &WeBWorK::PG::Translator::translate to render the problem source into the
631format given by the display mode.
632
633=item Process student answers
634
635Use form field inputs to evaluate student answers.
636
637=item Load the problem state
638
639Use values from the database to initialize the problem state, so that the
640grader will have a point of reference.
641
642=item Determine an entry order
643
644Use the ANSWER_ENTRY_ORDER flag to determine the order of answers in the
645problem. This is important for problems with dependancies among parts.
646
647=item Install a grader
648
649Use the PROBLEM_GRADER_TO_USE flag, or a default from the course environment,
650to install a grader.
651
652=item Grade the problem
653
654Use the selected grader to grade the problem.
655
656=back
657
658=head1 AUTHOR
659
660Written by Sam Hathaway, sh002i (at) math.rochester.edu.
661
662=cut

Legend:
Removed from v.425  
changed lines
  Added in v.1196

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9