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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 455 - (download) (as text) (annotate)
Mon Aug 5 21:34:18 2002 UTC (10 years, 9 months ago) by sh002i
File size: 16117 byte(s)
"normalized" files:
- (c) header on all files
- standard order of preamble lines:
	1. (c) header
	2. package PACKAGENAME;
	3. short summary of the package (pod's NAME section)
	4. use - pragmatic modules
	5. use - standard perl modules
	6. use - CPAN modules
	7. use - webwork modules
- ALWAYS use strict and use warnings
- use "use base" rather than "our @ISA"
so now we can be happy.
-sam

    1 ################################################################################
    2 # WeBWorK mod_perl (c) 1995-2002 WeBWorK Team, Univeristy of Rochester
    3 # $Id$
    4 ################################################################################
    5 
    6 package WeBWorK::PG;
    7 
    8 =head1 NAME
    9 
   10 WeBWorK::PG - Wrap the action of the PG Translator in an easy-to-use API
   11 
   12 =cut
   13 
   14 use strict;
   15 use warnings;
   16 use WeBWorK::DB::Classlist;
   17 use WeBWorK::DB::WW;
   18 use WeBWorK::PG::Translator;
   19 use WeBWorK::Utils qw(readFile formatDateTime);
   20 
   21 sub new($$$$$$$$) {
   22   my $invocant = shift;
   23   my $class = ref($invocant) || $invocant;
   24   my (
   25     $courseEnv,
   26     $userName,
   27     $key,
   28     $setName,
   29     $problemNumber,
   30     $translationOptions, # hashref containing options for the
   31                          # translator, such as whether to show
   32              # hints and the display mode to use
   33     $formFields, # in CGI::Vars format
   34   ) = @_;
   35 
   36   # get database information
   37   my $classlist = WeBWorK::DB::Classlist->new($courseEnv);
   38   my $wwdb = WeBWorK::DB::WW->new($courseEnv);
   39   my $user = $classlist->getUser($userName);
   40   my $set = $wwdb->getSet($userName, $setName);
   41   my $problem = $wwdb->getProblem($userName, $setName, $problemNumber);
   42   my $psvn = $wwdb->getPSVN($userName, $setName);
   43 
   44   # create a Translator
   45   warn "PG: creating a Translator\n";
   46   my $translator = WeBWorK::PG::Translator->new;
   47 
   48   # set the directory hash
   49   warn "PG: setting the directory hash\n";
   50   $translator->rh_directories({
   51     courseScriptsDirectory => $courseEnv->{webworkDirs}->{macros},
   52     macroDirectory         => $courseEnv->{courseDirs}->{macros},
   53     templateDirectory      => $courseEnv->{courseDirs}->{templates},
   54     tempDirectory          => $courseEnv->{courseDirs}->{html_temp},
   55   });
   56 
   57   # evaluate modules and "extra packages"
   58   warn "PG: evaluating modules and \"extra packages\"\n";
   59   my @modules = @{ $courseEnv->{pg}->{modules} };
   60   foreach my $module_packages (@modules) {
   61     # the first item in $module_packages is the main package
   62     $translator->evaluate_modules(shift @$module_packages);
   63     # the remaining items are "extra" packages
   64     $translator->load_extra_packages(@$module_packages);
   65   }
   66 
   67   # set the environment (from defineProblemEnvir)
   68   warn "PG: setting the environment (from defineProblemEnvir)\n";
   69   $translator->environment(defineProblemEnvir(
   70     $courseEnv, $user, $key, $set, $problem, $psvn, $formFields, $translationOptions));
   71 
   72   # initialize the Translator
   73   warn "PG: initializing the Translator\n";
   74   $translator->initialize();
   75 
   76   # load PG.pl and dangerousMacros.pl using unrestricted_load
   77   # i'd like to change this at some point to have the same sort of interface to global.conf
   78   # that the module loading does -- have a list of macros to load unrestrictedly.
   79   warn "PG: loading PG.pl and dangerousMacros.pl using unrestricted_load\n";
   80   my $pg_pl = $courseEnv->{webworkDirs}->{macros} . "/PG.pl";
   81   my $dangerousMacros_pl = $courseEnv->{webworkDirs}->{macros} . "/dangerousMacros.pl";
   82   my $err = $translator->unrestricted_load($pg_pl);
   83   warn "Error while loading $pg_pl: $err" if $err;
   84   $err = $translator->unrestricted_load($dangerousMacros_pl);
   85   warn "Error while loading $dangerousMacros_pl: $err" if $err;
   86 
   87   # set the opcode mask (using default values)
   88   warn "PG: setting the opcode mask (using default values)\n";
   89   $translator->set_mask();
   90 
   91   # store the problem source
   92   warn "PG: storing the problem source\n";
   93   my $sourceFile = $courseEnv->{courseDirs}->{templates}."/".$problem->source_file;
   94   $translator->source_string(readFile($sourceFile));
   95 
   96   # install a safety filter (&safetyFilter)
   97   warn "PG: installing a safety filter\n";
   98   $translator->rf_safety_filter(\&safetyFilter);
   99 
  100   # translate the PG source into text
  101   warn "PG: translating the PG source into text\n";
  102   $translator->translate();
  103 
  104   # [in Problem.pm and processProblem8.pl, "install a grader" is here]
  105 
  106   # process student answers
  107   warn "PG: processing student answers\n";
  108   $translator->process_answers($formFields);
  109 
  110   # retrieve the problem state and give it to the translator
  111   warn "PG: retrieving the problem state and giving it to the translator\n";
  112   $translator->rh_problem_state({
  113     recorded_score =>       $problem->status,
  114     num_of_correct_ans =>   $problem->num_correct,
  115     num_of_incorrect_ans => $problem->num_incorrect,
  116   });
  117 
  118   # determine an entry order -- the ANSWER_ENTRY_ORDER flag is built by
  119   # the PG macro package (PG.pl)
  120   warn "PG: determining an entry order\n";
  121   my @answerOrder =
  122     $translator->rh_flags->{ANSWER_ENTRY_ORDER}
  123       ? @{ $translator->rh_flags->{ANSWER_ENTRY_ORDER} }
  124       : keys %{ $translator->rh_evaluated_answers };
  125 
  126   # install a grader -- use the one specified in the problem,
  127   # or fall back on the default from the course environment.
  128   # (two magic strings are accepted, to avoid having to
  129   # reference code when it would be difficult.)
  130   warn "PG: installing a grader\n";
  131   my $grader = $translator->rh_flags->{PROBLEM_GRADER_TO_USE}
  132     || $courseEnv->{pg}->{options}->{grader};
  133   $grader = $translator->rf_std_problem_grader
  134     if $grader eq "std_problem_grader";
  135   $grader = $translator->rf_avg_problem_grader
  136     if $grader eq "avg_problem_grader";
  137   die "Problem grader $grader is not a CODE reference."
  138     unless ref $grader eq "CODE";
  139   $translator->rf_problem_grader($grader);
  140 
  141   # grade the problem
  142   warn "PG: grading the problem\n";
  143   my ($result, $state) = $translator->grade_problem(
  144     answers_submitted  => $translationOptions->{processAnswers},
  145     ANSWER_ENTRY_ORDER => \@answerOrder,
  146   );
  147 
  148   # return an object which contains the translator and the results of
  149   # the translation process. this is DIFFERENT from the "format expected
  150   # by Webwork.pm (and I believe processProblem8, but check.)"
  151   return bless {
  152     translator => $translator,
  153     head_text  => ${ $translator->r_header },
  154     body_text  => ${ $translator->r_text   },
  155     answers    => $translator->rh_evaluated_answers,
  156     result     => $result,
  157     state      => $state,
  158     errors     => $translator->errors, # *** what is this doing?
  159     warnings   => undef, # *** gotta catch warnings eventually...
  160     flags      => $translator->rh_flags,
  161   }, $class;
  162 }
  163 
  164 # -----
  165 
  166 sub defineProblemEnvir($$$$$$$) {
  167   my (
  168     $courseEnv,
  169     $user,
  170     $key,
  171     $set,
  172     $problem,
  173     $psvn,
  174     $formFields,
  175     $options,
  176   ) = @_;
  177 
  178   my %envir;
  179 
  180   # PG environment variables
  181   # from docs/pglanguage/pgreference/environmentvariables as of 06/25/2002
  182   # any changes are noted by "ADDED:" or "REMOVED:"
  183 
  184   # Vital state information
  185   # ADDED: displayHintsQ, displaySolutionsQ
  186 
  187   $envir{psvn}              = $psvn;
  188   $envir{psvnNumber}        = $envir{psvn};
  189   $envir{probNum}           = $problem->id;
  190   $envir{questionNumber}    = $envir{probNum};
  191   $envir{fileName}          = $problem->source_file;
  192   $envir{probFileName}      = $envir{fileName};
  193   $envir{problemSeed}       = $problem->problem_seed;
  194   $envir{displayMode}       = translateDisplayModeNames($options->{displayMode});
  195   $envir{languageMode}      = $envir{displayMode};
  196   $envir{outputMode}        = $envir{displayMode};
  197   $envir{displayHintsQ}     = $options->{hints};
  198   $envir{displaySolutionsQ} = $options->{solutions};
  199   $envir{refreshMath2img}   = $options->{refreshMath2img};
  200 
  201   # Problem Information
  202   # ADDED: courseName
  203 
  204   $envir{openDate}            = $set->open_date;
  205   $envir{formattedOpenDate}   = formatDateTime($envir{openDate});
  206   $envir{dueDate}             = $set->due_date;
  207   $envir{formattedDueDate}    = formatDateTime($envir{dueDate});
  208   $envir{answerDate}          = $set->answer_date;
  209   $envir{formattedAnswerDate} = formatDateTime($envir{answerDate});
  210   $envir{numOfAttempts}       = $problem->num_correct + $problem->num_incorrect;
  211   $envir{problemValue}        = $problem->value;
  212   $envir{sessionKey}          = $key;
  213   $envir{courseName}          = $courseEnv->{courseName};
  214 
  215   # Student Information
  216   # ADDED: studentID
  217 
  218   $envir{sectionName}      = $user->section;
  219   $envir{sectionNumber}    = $envir{sectionName};
  220   $envir{recitationName}   = $user->recitation;
  221   $envir{recitationNumber} = $envir{recitationName};
  222   $envir{setNumber}        = $set->id;
  223   $envir{studentLogin}     = $user->id;
  224   $envir{studentName}      = $user->first_name . " " . $user->last_name;
  225   $envir{studentID}        = $user->student_id;
  226 
  227   # Answer Information
  228   # REMOVED: refSubmittedAnswers
  229 
  230   $envir{inputs_ref} = $formFields;
  231 
  232   # External Programs
  233 
  234   $envir{externalTTHPath}      = $courseEnv->{externalPrograms}->{tth};
  235   $envir{externalMath2imgPath} = $courseEnv->{externalPrograms}->{math2img};
  236 
  237   # Directories and URLs
  238   # REMOVED: courseName
  239 
  240   $envir{cgiDirectory}           = undef;
  241   $envir{cgiURL}                 = undef;
  242   $envir{classDirectory}         = undef;
  243   $envir{courseScriptsDirectory} = $courseEnv->{webworkDirs}->{macros}."/";
  244   $envir{htmlDirectory}          = $courseEnv->{courseDirs}->{html}."/";
  245   $envir{htmlURL}                = $courseEnv->{courseURLs}->{html};
  246   $envir{macroDirectory}         = $courseEnv->{courseDirs}->{macros}."/";
  247   $envir{templateDirectory}      = $courseEnv->{courseDirs}->{templates}."/";
  248   $envir{tempDirectory}          = $courseEnv->{courseDirs}->{html_temp}."/";
  249   $envir{tempURL}                = $courseEnv->{courseURLs}->{html_temp};
  250   $envir{scriptDirectory}        = undef;
  251   $envir{webworkDocsURL}         = $courseEnv->{webworkURLs}->{docs};
  252 
  253   # Default values for evaluating answers
  254 
  255   my $ansEvalDefaults = $courseEnv->{pg}->{ansEvalDefaults};
  256   $envir{$_} = $ansEvalDefaults->{$_} foreach (keys %$ansEvalDefaults);
  257 
  258   # Other things...
  259 
  260   $envir{PROBLEM_GRADER_TO_USE} = $courseEnv->{pg}->{options}->{grader};
  261 
  262   return \%envir;
  263 }
  264 
  265 sub translateDisplayModeNames($) {
  266   my $name = shift;
  267   return {
  268     plainText     => "HTML",
  269     formattedText => "HTML_tth",
  270     images        => "HTML_img"
  271   }->{$name};
  272 }
  273 
  274 sub safetyFilter {
  275   my $answer = shift; # accepts one answer and checks it
  276   my $submittedAnswer = $answer;
  277   $answer = '' unless defined $answer;
  278   my ($errorno);
  279   $answer =~ tr/\000-\037/ /;
  280   # Return if answer field is empty
  281   unless ($answer =~ /\S/) {
  282     #$errorno = "<BR>No answer was submitted.";
  283     $errorno = 0;  ## don't report blank answer as error
  284     return ($answer,$errorno);
  285   }
  286   # replace ^ with **    (for exponentiation)
  287   # $answer =~ s/\^/**/g;
  288   # Return if  forbidden characters are found
  289   unless ($answer =~ /^[a-zA-Z0-9_\-\+ \t\/@%\*\.\n^\(\)]+$/ )  {
  290     $answer =~ tr/a-zA-Z0-9_\-\+ \t\/@%\*\.\n^\(\)/#/c;
  291     $errorno = "<BR>There are forbidden characters in your answer: $submittedAnswer<BR>";
  292     return ($answer,$errorno);
  293   }
  294   $errorno = 0;
  295   return($answer, $errorno);
  296 }
  297 
  298 1;
  299 
  300 __END__
  301 
  302 =head1 SYNOPSIS
  303 
  304  $pg = WeBWorK::PG->new(
  305    $courseEnv, # a WeBWorK::CourseEnvironment object
  306    $userName,
  307    $sessionKey,
  308    $setName,
  309    $problemNumber,
  310    { # translation options
  311      displayMode     => "images", # (plainText|formattedText|images)
  312      showHints       => 1,        # (0|1)
  313      showSolutions   => 0,        # (0|1)
  314      refreshMath2img => 0,        # (0|1)
  315      processAnswers  => 1,        # (0|1)
  316    },
  317    $formFields # in WeBWorK::Form::Vars format
  318  );
  319 
  320  $translator = $pg->{translator}; # WeBWorK::PG::Translator
  321  $body       = $pg->{body_text};  # text string
  322  $header     = $pg->{head_text};  # text string
  323  $answerHash = $pg->{answers};    # WeBWorK::PG::AnswerHash
  324  $result     = $pg->{result};     # hash reference
  325  $state      = $pg->{state};      # hash reference
  326  $errors     = $pg->{errors};     # text string
  327  $warnings   = $pg->{warnings};   # text string
  328  $flags      = $pg->{flags};      # hash reference
  329 
  330 =head1 DESCRIPTION
  331 
  332 WeBWorK::PG encapsulates the PG translation process, making multiple calls to
  333 WeBWorK::PG::Translator. Much of the flexibility of the Translator is hidden,
  334 instead making choices that are appropriate for the webwork-modperl system.
  335 
  336 =head1 CONSTRUCTION
  337 
  338 =over
  339 
  340 =item new (ENVIRONMENT, USER, KEY, SET, PROBLEM, OPTIONS, FIELDS)
  341 
  342 The C<new> method creates a translator, initializes it using the parameters
  343 specified, translates a PG file, and processes answers. It returns a reference
  344 to a blessed hash containing the results of the translation process.
  345 
  346 =back
  347 
  348 =head2 Parameters
  349 
  350 =over
  351 
  352 =item ENVIRONMENT
  353 
  354 a WeBWorK::CourseEnvironment object
  355 
  356 =item USER
  357 
  358 the name of the user for whom to render
  359 
  360 =item KEY
  361 
  362 the session key of the current session
  363 
  364 =item SET
  365 
  366 the name of the problem set from which to get the problem
  367 
  368 =item PROBLEM
  369 
  370 the number of the problem to render
  371 
  372 =item OPTIONS
  373 
  374 a reference to a hash containing the following data:
  375 
  376 =over
  377 
  378 =item displayMode
  379 
  380 one of "plainText", "formattedText", or "images"
  381 
  382 =item showHints
  383 
  384 boolean, render hints
  385 
  386 =item showSolutions
  387 
  388 boolean, render solutions
  389 
  390 =item refreshMath2img
  391 
  392 boolean, force images created by math2img (in "images" mode) to be recreated,
  393 even if the PG source has not been updated.
  394 
  395 =item processAnswers
  396 
  397 boolean, call answer evaluators and graders
  398 
  399 =back
  400 
  401 =item FIELDS
  402 
  403 a reference to a hash (as returned by &WeBWorK::Form::Vars) containing form
  404 fields submitted by a problem processor. The translator will look for fields
  405 like "AnSwEr[0-9]" containing submitted student answers.
  406 
  407 =back
  408 
  409 =head2 RETURN VALUE
  410 
  411 The C<new> method returns a blessed hash reference containing the following
  412 fields. More information can be found in the documentation for
  413 WeBWorK::PG::Translator.
  414 
  415 =over
  416 
  417 =item translator
  418 
  419 The WeBWorK::PG::Translator object used to render the problem.
  420 
  421 =item head_text
  422 
  423 HTML code for the E<lt>headE<gt> block of an resulting web page. Used for
  424 JavaScript features.
  425 
  426 =item body_text
  427 
  428 HTML code for the E<lt>bodyE<gt> block of an resulting web page.
  429 
  430 =item answers
  431 
  432 An C<AnswerHash> object containing submitted answers, and results of answer
  433 evaluation.
  434 
  435 =item result
  436 
  437 A hash containing the results of grading the problem.
  438 
  439 =item state
  440 
  441 A hash containing the new problem state.
  442 
  443 =item errors
  444 
  445 A string containing any errors encountered while rendering the problem.
  446 
  447 =item warnings
  448 
  449 A string containing any warnings encountered while rendering the problem.
  450 
  451 =item flags
  452 
  453 A hash containing PG_flags (see the Translator docs).
  454 
  455 =back
  456 
  457 =head1 OPERATION
  458 
  459 WeBWorK::PG goes through the following operations when constructed:
  460 
  461 =over
  462 
  463 =item Get database information
  464 
  465 Retrieve information about the current user, set, and problem from the
  466 database.
  467 
  468 =item Create a translator
  469 
  470 Instantiate a WeBWorK::PG::Translator object.
  471 
  472 =item Set the directory hash
  473 
  474 Set the translator's directory hash (courseScripts, macros, templates, and temp
  475 directories) from the course environment.
  476 
  477 =item Evaluate PG modules
  478 
  479 Using the module list from the course environment (pg->modules), perform a
  480 "use"-like operation to evaluate modules at runtime.
  481 
  482 =item Set the problem environment
  483 
  484 Use data from the user, set, and problem, as well as the course environemnt and
  485 translation options, to set the problem environment.
  486 
  487 =item Initialize the translator
  488 
  489 Call &WeBWorK::PG::Translator::initialize. What more do you want?
  490 
  491 =item Load PG.pl and dangerousMacros.pl
  492 
  493 These macros must be loaded without opcode masking, so they are loaded here.
  494 
  495 =item Set the opcode mask
  496 
  497 Set the opcode mask to the default specified by WeBWorK::PG::Translator.
  498 
  499 =item Load the problem source
  500 
  501 Give the problem source to the translator.
  502 
  503 =item Install a safety filter
  504 
  505 The safety filter is used to preprocess student input before evaluation. The
  506 default safety filter, &WeBWorK::PG::safetyFilter, is used.
  507 
  508 =item Translate the problem source
  509 
  510 Call &WeBWorK::PG::Translator::translate to render the problem source into the
  511 format given by the display mode.
  512 
  513 =item Process student answers
  514 
  515 Use form field inputs to evaluate student answers.
  516 
  517 =item Load the problem state
  518 
  519 Use values from the database to initialize the problem state, so that the
  520 grader will have a point of reference.
  521 
  522 =item Determine an entry order
  523 
  524 Use the ANSWER_ENTRY_ORDER flag to determine the order of answers in the
  525 problem. This is important for problems with dependancies among parts.
  526 
  527 =item Install a grader
  528 
  529 Use the PROBLEM_GRADER_TO_USE flag, or a default from the course environment,
  530 to install a grader.
  531 
  532 =item Grade the problem
  533 
  534 Use the selected grader to grade the problem.
  535 
  536 =back
  537 
  538 =head1 AUTHOR
  539 
  540 Written by Sam Hathaway, sh002i (at) math.rochester.edu.
  541 
  542 =cut

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9