[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 5 - (download) (as text) (annotate)
Thu Jun 14 23:45:41 2001 UTC (12 years ago) by gage
File size: 12693 byte(s)
dev-1-7-01

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

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9