[system] / trunk / webwork / system / courseScripts / PG.pl Repository:
ViewVC logotype

View of /trunk/webwork/system/courseScripts/PG.pl

Parent Directory Parent Directory | Revision Log Revision Log


Revision 123 - (download) (as text) (annotate)
Mon Aug 13 16:07:32 2001 UTC (18 years, 6 months ago) by gage
File size: 13830 byte(s)
Removed warning message about avg_problem_grader, since now
avg_problem_grader is also installed in PGtranslator and can
be used as a default grader. (std_problem_grader can also be
used as a default).

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

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9