[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 434 Revision 494
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
4# "PG Render" or something 9
10WeBWorK::PG - Wrap the action of the PG Translator in an easy-to-use API.
11
12=cut
5 13
6use strict; 14use strict;
7use warnings; 15use warnings;
8use WeBWorK::Utils qw(readFile formatDateTime);
9use WeBWorK::DB::Classlist; 16use WeBWorK::DB::Classlist;
10use WeBWorK::DB::WW; 17use WeBWorK::DB::WW;
11use WeBWorK::PG::Translator; 18use WeBWorK::PG::Translator;
19use WeBWorK::Problem;
20use WeBWorK::Utils qw(readFile formatDateTime);
12 21
13sub new($$$$$$$$) { 22sub new($$$$$$$$) {
14 my $invocant = shift; 23 my $invocant = shift;
15 my $class = ref($invocant) || $invocant; 24 my $class = ref($invocant) || $invocant;
16 my ( 25 my (
28 # get database information 37 # get database information
29 my $classlist = WeBWorK::DB::Classlist->new($courseEnv); 38 my $classlist = WeBWorK::DB::Classlist->new($courseEnv);
30 my $wwdb = WeBWorK::DB::WW->new($courseEnv); 39 my $wwdb = WeBWorK::DB::WW->new($courseEnv);
31 my $user = $classlist->getUser($userName); 40 my $user = $classlist->getUser($userName);
32 my $set = $wwdb->getSet($userName, $setName); 41 my $set = $wwdb->getSet($userName, $setName);
33 my $problem = $wwdb->getProblem($userName, $setName, $problemNumber);
34 my $psvn = $wwdb->getPSVN($userName, $setName); 42 my $psvn = $wwdb->getPSVN($userName, $setName);
43
44 my $problem;
45 if ($problemNumber =~ /^\d+$/) {
46 $problem = $wwdb->getProblem($userName, $setName, $problemNumber);
47 } else {
48 # This is the fun part: if $problemNumber is NON-NUMERIC, the
49 # user wants to specify a PG file directly. We manufacture a
50 # Problem object using fake data and the specified source file.
51 # This is potentially dangerous since an untrusted user is
52 # allowed to specifiy an arbitrary file to be evaluated as PG.
53 # A user of PG.pm MUST MAKE SURE that if $problemNumber is
54 # supplied by an untrusted source (i.e. the Apache request),
55 # it is numberic. A simple
56 #
57 # die unless $problemNumber =~ /^\d+$/;
58 #
59 # should suffice.
60 $problem = WeBWorK::Problem->new(
61 id => 0,
62 set_id => $set->id,
63 login_id => $user->id,
64 source_file => $problemNumber,
65 # the rest of Problem's fields are not needed
66 );
67 }
35 68
36 # create a Translator 69 # create a Translator
37 warn "PG: creating a Translator\n"; 70 warn "PG: creating a Translator\n";
38 my $translator = WeBWorK::PG::Translator->new; 71 my $translator = WeBWorK::PG::Translator->new;
39 72
47 }); 80 });
48 81
49 # evaluate modules and "extra packages" 82 # evaluate modules and "extra packages"
50 warn "PG: evaluating modules and \"extra packages\"\n"; 83 warn "PG: evaluating modules and \"extra packages\"\n";
51 my @modules = @{ $courseEnv->{pg}->{modules} }; 84 my @modules = @{ $courseEnv->{pg}->{modules} };
52 foreach my $module_packages (@modules) { 85 foreach my $module_packages_ref (@modules) {
53 # the first item in $module_packages is the main package 86 my ($module, @extra_packages) = @$module_packages_ref;
87 # the first item is the main package
54 $translator->evaluate_modules(shift @$module_packages); 88 $translator->evaluate_modules($module);
55 # the remaining items are "extra" packages 89 # the remaining items are "extra" packages
56 $translator->load_extra_packages(@$module_packages); 90 $translator->load_extra_packages(@extra_packages);
57 } 91 }
58 92
59 # set the environment (from defineProblemEnvir) 93 # set the environment (from defineProblemEnvir)
60 warn "PG: setting the environment (from defineProblemEnvir)\n"; 94 warn "PG: setting the environment (from defineProblemEnvir)\n";
61 $translator->environment(defineProblemEnvir( 95 $translator->environment(defineProblemEnvir(
80 warn "PG: setting the opcode mask (using default values)\n"; 114 warn "PG: setting the opcode mask (using default values)\n";
81 $translator->set_mask(); 115 $translator->set_mask();
82 116
83 # store the problem source 117 # store the problem source
84 warn "PG: storing the problem source\n"; 118 warn "PG: storing the problem source\n";
119 my $sourceFile = $problem->source_file;
85 my $sourceFile = $courseEnv->{courseDirs}->{templates}."/".$problem->source_file; 120 $sourceFile = $courseEnv->{courseDirs}->{templates}."/".$sourceFile
121 unless ($sourceFile =~ /^\//);
86 $translator->source_string(readFile($sourceFile)); 122 $translator->source_string(readFile($sourceFile));
87 123
88 # install a safety filter (&safetyFilter) 124 # install a safety filter (&safetyFilter)
89 warn "PG: installing a safety filter\n"; 125 warn "PG: installing a safety filter\n";
90 $translator->rf_safety_filter(\&safetyFilter); 126 $translator->rf_safety_filter(\&safetyFilter);
91 127
92 # translate the PG source into text 128 # translate the PG source into text
93 warn "PG: translating the PG source into text\n"; 129 warn "PG: translating the PG source into text\n";
94 $translator->translate(); 130 $translator->translate();
95 131
96 # [in Problem.pm and processProblem8.pl, "install a grader" is here] 132 my ($result, $state); # we'll need these on the other side of the if block!
97 133 if ($translationOptions->{processAnswers}) {
134
98 # process student answers 135 # process student answers
99 warn "PG: processing student answers\n"; 136 warn "PG: processing student answers\n";
100 $translator->process_answers($formFields); 137 $translator->process_answers($formFields);
101 138
102 # retrieve the problem state and give it to the translator 139 # retrieve the problem state and give it to the translator
103 warn "PG: retrieving the problem state and giving it to the translator\n"; 140 warn "PG: retrieving the problem state and giving it to the translator\n";
104 $translator->rh_problem_state({ 141 $translator->rh_problem_state({
105 recorded_score => $problem->status, 142 recorded_score => $problem->status,
106 num_of_correct_ans => $problem->num_correct, 143 num_of_correct_ans => $problem->num_correct,
107 num_of_incorrect_ans => $problem->num_incorrect, 144 num_of_incorrect_ans => $problem->num_incorrect,
108 }); 145 });
109 146
110 # determine an entry order -- the ANSWER_ENTRY_ORDER flag is built by 147 # determine an entry order -- the ANSWER_ENTRY_ORDER flag is built by
111 # the PG macro package (PG.pl) 148 # the PG macro package (PG.pl)
112 warn "PG: determining an entry order\n"; 149 warn "PG: determining an entry order\n";
113 my @answerOrder = 150 my @answerOrder =
114 $translator->rh_flags->{ANSWER_ENTRY_ORDER} 151 $translator->rh_flags->{ANSWER_ENTRY_ORDER}
115 ? @{ $translator->rh_flags->{ANSWER_ENTRY_ORDER} } 152 ? @{ $translator->rh_flags->{ANSWER_ENTRY_ORDER} }
116 : keys %{ $translator->rh_evaluated_answers }; 153 : keys %{ $translator->rh_evaluated_answers };
117 154
118 # install a grader -- use the one specified in the problem, 155 # install a grader -- use the one specified in the problem,
119 # or fall back on the default from the course environment. 156 # or fall back on the default from the course environment.
120 # (two magic strings are accepted, to avoid having to 157 # (two magic strings are accepted, to avoid having to
121 # reference code when it would be difficult.) 158 # reference code when it would be difficult.)
122 warn "PG: installing a grader\n"; 159 warn "PG: installing a grader\n";
123 my $grader = $translator->rh_flags->{PROBLEM_GRADER_TO_USE} 160 my $grader = $translator->rh_flags->{PROBLEM_GRADER_TO_USE}
124 || $courseEnv->{pg}->{options}->{grader}; 161 || $courseEnv->{pg}->{options}->{grader};
125 $grader = $translator->rf_std_problem_grader 162 $grader = $translator->rf_std_problem_grader
126 if $grader eq "std_problem_grader"; 163 if $grader eq "std_problem_grader";
127 $grader = $translator->rf_avg_problem_grader 164 $grader = $translator->rf_avg_problem_grader
128 if $grader eq "avg_problem_grader"; 165 if $grader eq "avg_problem_grader";
129 die "Problem grader $grader is not a CODE reference." 166 die "Problem grader $grader is not a CODE reference."
130 unless ref $grader eq "CODE"; 167 unless ref $grader eq "CODE";
131 $translator->rf_problem_grader($grader); 168 $translator->rf_problem_grader($grader);
132 169
133 # grading the problem 170 # grade the problem
134 warn "PG: grade the problem\n"; 171 warn "PG: grading the problem\n";
135 my ($result, $state) = $translator->grade_problem( 172 ($result, $state) = $translator->grade_problem(
136 answers_submitted => $translationOptions->{processAnswers}, 173 answers_submitted => $translationOptions->{processAnswers},
137 ANSWER_ENTRY_ORDER => \@answerOrder, 174 ANSWER_ENTRY_ORDER => \@answerOrder,
138 ); 175 );
176
177 }
139 178
140 # return an object which contains the translator and the results of 179 # return an object which contains the translator and the results of
141 # the translation process. this is DIFFERENT from the "format expected 180 # the translation process. this is DIFFERENT from the "format expected
142 # by Webwork.pm (and I believe processProblem8, but check.)" 181 # by Webwork.pm (and I believe processProblem8, but check.)"
143 return bless { 182 return bless {
172 # PG environment variables 211 # PG environment variables
173 # from docs/pglanguage/pgreference/environmentvariables as of 06/25/2002 212 # from docs/pglanguage/pgreference/environmentvariables as of 06/25/2002
174 # any changes are noted by "ADDED:" or "REMOVED:" 213 # any changes are noted by "ADDED:" or "REMOVED:"
175 214
176 # Vital state information 215 # Vital state information
177 # ADDED: displayHintsQ, displaySolutionsQ 216 # ADDED: displayHintsQ, displaySolutionsQ, refreshMath2img
178 217
179 $envir{psvn} = $psvn; 218 $envir{psvn} = $psvn;
180 $envir{psvnNumber} = $envir{psvn}; 219 $envir{psvnNumber} = $envir{psvn};
181 $envir{probNum} = $problem->id; 220 $envir{probNum} = $problem->id;
182 $envir{questionNumber} = $envir{probNum}; 221 $envir{questionNumber} = $envir{probNum};
255} 294}
256 295
257sub translateDisplayModeNames($) { 296sub translateDisplayModeNames($) {
258 my $name = shift; 297 my $name = shift;
259 return { 298 return {
299 tex => "TeX",
260 plainText => "HTML", 300 plainText => "HTML",
261 formattedText => "HTML_tth", 301 formattedText => "HTML_tth",
262 images => "HTML_img" 302 images => "HTML_img"
263 }->{$name}; 303 }->{$name};
264} 304}
286 $errorno = 0; 326 $errorno = 0;
287 return($answer, $errorno); 327 return($answer, $errorno);
288} 328}
289 329
2901; 3301;
331
332__END__
333
334=head1 SYNOPSIS
335
336 $pg = WeBWorK::PG->new(
337 $courseEnv, # a WeBWorK::CourseEnvironment object
338 $userName,
339 $sessionKey,
340 $setName,
341 $problemNumber,
342 { # translation options
343 displayMode => "images", # (plainText|formattedText|images)
344 showHints => 1, # (0|1)
345 showSolutions => 0, # (0|1)
346 refreshMath2img => 0, # (0|1)
347 processAnswers => 1, # (0|1)
348 },
349 $formFields # in WeBWorK::Form::Vars format
350 );
351
352 $translator = $pg->{translator}; # WeBWorK::PG::Translator
353 $body = $pg->{body_text}; # text string
354 $header = $pg->{head_text}; # text string
355 $answerHash = $pg->{answers}; # WeBWorK::PG::AnswerHash
356 $result = $pg->{result}; # hash reference
357 $state = $pg->{state}; # hash reference
358 $errors = $pg->{errors}; # text string
359 $warnings = $pg->{warnings}; # text string
360 $flags = $pg->{flags}; # hash reference
361
362=head1 DESCRIPTION
363
364WeBWorK::PG encapsulates the PG translation process, making multiple calls to
365WeBWorK::PG::Translator. Much of the flexibility of the Translator is hidden,
366instead making choices that are appropriate for the webwork-modperl system.
367
368=head1 CONSTRUCTION
369
370=over
371
372=item new (ENVIRONMENT, USER, KEY, SET, PROBLEM, OPTIONS, FIELDS)
373
374The C<new> method creates a translator, initializes it using the parameters
375specified, translates a PG file, and processes answers. It returns a reference
376to a blessed hash containing the results of the translation process.
377
378=back
379
380=head2 Parameters
381
382=over
383
384=item ENVIRONMENT
385
386a WeBWorK::CourseEnvironment object
387
388=item USER
389
390the name of the user for whom to render
391
392=item KEY
393
394the session key of the current session
395
396=item SET
397
398the name of the problem set from which to get the problem
399
400=item PROBLEM
401
402the number of the problem to render
403
404=item OPTIONS
405
406a reference to a hash containing the following data:
407
408=over
409
410=item displayMode
411
412one of "plainText", "formattedText", or "images"
413
414=item showHints
415
416boolean, render hints
417
418=item showSolutions
419
420boolean, render solutions
421
422=item refreshMath2img
423
424boolean, force images created by math2img (in "images" mode) to be recreated,
425even if the PG source has not been updated.
426
427=item processAnswers
428
429boolean, call answer evaluators and graders
430
431=back
432
433=item FIELDS
434
435a reference to a hash (as returned by &WeBWorK::Form::Vars) containing form
436fields submitted by a problem processor. The translator will look for fields
437like "AnSwEr[0-9]" containing submitted student answers.
438
439=back
440
441=head2 RETURN VALUE
442
443The C<new> method returns a blessed hash reference containing the following
444fields. More information can be found in the documentation for
445WeBWorK::PG::Translator.
446
447=over
448
449=item translator
450
451The WeBWorK::PG::Translator object used to render the problem.
452
453=item head_text
454
455HTML code for the E<lt>headE<gt> block of an resulting web page. Used for
456JavaScript features.
457
458=item body_text
459
460HTML code for the E<lt>bodyE<gt> block of an resulting web page.
461
462=item answers
463
464An C<AnswerHash> object containing submitted answers, and results of answer
465evaluation.
466
467=item result
468
469A hash containing the results of grading the problem.
470
471=item state
472
473A hash containing the new problem state.
474
475=item errors
476
477A string containing any errors encountered while rendering the problem.
478
479=item warnings
480
481A string containing any warnings encountered while rendering the problem.
482
483=item flags
484
485A hash containing PG_flags (see the Translator docs).
486
487=back
488
489=head1 OPERATION
490
491WeBWorK::PG goes through the following operations when constructed:
492
493=over
494
495=item Get database information
496
497Retrieve information about the current user, set, and problem from the
498database.
499
500=item Create a translator
501
502Instantiate a WeBWorK::PG::Translator object.
503
504=item Set the directory hash
505
506Set the translator's directory hash (courseScripts, macros, templates, and temp
507directories) from the course environment.
508
509=item Evaluate PG modules
510
511Using the module list from the course environment (pg->modules), perform a
512"use"-like operation to evaluate modules at runtime.
513
514=item Set the problem environment
515
516Use data from the user, set, and problem, as well as the course environemnt and
517translation options, to set the problem environment.
518
519=item Initialize the translator
520
521Call &WeBWorK::PG::Translator::initialize. What more do you want?
522
523=item Load PG.pl and dangerousMacros.pl
524
525These macros must be loaded without opcode masking, so they are loaded here.
526
527=item Set the opcode mask
528
529Set the opcode mask to the default specified by WeBWorK::PG::Translator.
530
531=item Load the problem source
532
533Give the problem source to the translator.
534
535=item Install a safety filter
536
537The safety filter is used to preprocess student input before evaluation. The
538default safety filter, &WeBWorK::PG::safetyFilter, is used.
539
540=item Translate the problem source
541
542Call &WeBWorK::PG::Translator::translate to render the problem source into the
543format given by the display mode.
544
545=item Process student answers
546
547Use form field inputs to evaluate student answers.
548
549=item Load the problem state
550
551Use values from the database to initialize the problem state, so that the
552grader will have a point of reference.
553
554=item Determine an entry order
555
556Use the ANSWER_ENTRY_ORDER flag to determine the order of answers in the
557problem. This is important for problems with dependancies among parts.
558
559=item Install a grader
560
561Use the PROBLEM_GRADER_TO_USE flag, or a default from the course environment,
562to install a grader.
563
564=item Grade the problem
565
566Use the selected grader to grade the problem.
567
568=back
569
570=head1 AUTHOR
571
572Written by Sam Hathaway, sh002i (at) math.rochester.edu.
573
574=cut

Legend:
Removed from v.434  
changed lines
  Added in v.494

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9