[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 36 - (download) (as text) (annotate)
Wed Jun 20 20:01:26 2001 UTC (11 years, 11 months ago) by gage
File size: 13299 byte(s)
Simplified some of the scripts.  Using forking there is no need
to evaluate $main:: everytime, since it remains the same for both
the parent (where the script is compiled) and in the child where
the script is executed.

There were other minor fixes to work around bugs in 5.6.0 which were
fixed in 5.6.1

    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::solutionExists =0;
  136     %main::gifs_created = ();
  137 
  138     die "The environment variable envir has not been defined" unless defined(%main::envir);
  139     #};
  140    foreach my $var ( keys %main::envir ) {
  141        eval("\$main::$var =\$main::envir{'$var'}");
  142        warn "Problem defining ", q{\$main::$var}, " while inititializing the PG problem: $@" if $@;
  143     }
  144     #eval q{
  145     @main::submittedAnswers = @{$main::refSubmittedAnswers} if defined($main::refSubmittedAnswers);
  146     $main::PG_original_problemSeed = $main::problemSeed;
  147     $main::PG_random_generator = new PGrandom($main::problemSeed) || die "Can't create random number generator.";
  148     $main::ans_rule_count = 0;  # counts questions
  149     #};
  150   #warn "key1", join( "<>",keys %main::);
  151   #warn "key2", join( "<>",eval q{ keys %main::});
  152     # end unpacking of environment variables.
  153 }
  154 
  155 # HEADER_TEXT is for material which is destined to be placed in the header of the html problem -- such
  156 #   as javaScript code.
  157 
  158 =head2 HEADER_TEXT()
  159 
  160 
  161   HEADER_TEXT("string1", "string2", "string3");
  162 
  163 The C<HEADER_TEXT()>
  164 function concatenates its arguments and places them in the output
  165 header text string.  It is used for material which is destined to be placed in
  166 the header of the html problem -- such as javaScript code.
  167  It can be used more than once in a file.
  168 
  169 
  170 =cut
  171 
  172 sub HEADER_TEXT {
  173   my @in = @_;
  174   $STRINGforHEADER_TEXT .= join(" ",@in);
  175   }
  176 
  177 # TEXT is the function which defines text which will appear in the problem.
  178 # All text must be an argument to this function.  Any other statements
  179 #   are calculations (done in perl) which will not directly appear in the
  180 # output.  Think of this as the "print" function for the .pg language.
  181 # It can be used more than once in a file.
  182 
  183 =head2 TEXT()
  184 
  185   TEXT("string1", "string2", "string3");
  186 
  187 The C<TEXT()> function concatenates its arguments and places them in the output
  188 text string. C<TEXT()> is the function which defines text which will appear in the problem.
  189 All text must be an argument to this function.  Any other statements
  190 are calculations (done in perl) which will not directly appear in the
  191 output.  Think of this as the "print" function for the .pg language.
  192 It can be used more than once in a file.
  193 
  194 =cut
  195 
  196 sub TEXT {
  197   my @in = @_;
  198   $STRINGforOUTPUT .= join(" ",@in);
  199   }
  200 
  201 
  202 
  203 =head2 ANS()
  204 
  205   ANS(answer_evaluator1, answer_evaluator2, answer_evaluator3,...)
  206 
  207 Places the answer evaluators in the unlabeled answer_evaluator queue.  They will be paired
  208 with unlabeled answer rules (answer entry blanks) in the order entered.  This is the standard
  209 method for entering answers.
  210 
  211   LABELED_ANS(answer_evaluater_name1, answer_evaluator1, answer_evaluater_name2,answer_evaluator2,...)
  212 
  213 Places the answer evaluators in the labeled answer_evaluator hash.  This allows pairing of
  214 labeled answer evaluators and labeled answer rules which may not have been entered in the same
  215 order.
  216 
  217 =cut
  218 
  219 sub ANS{             # store answer evaluators which have not been explicitly labeled
  220   my @in = @_;
  221   while (@in ) {
  222          warn("<BR><B>Error in ANS:$in[0]</B> -- inputs must be references to
  223                       subroutines<BR>")
  224       unless ref($in[0]);
  225       push(@PG_ANSWERS, shift @in );
  226       }
  227 }
  228 
  229 sub NAMED_ANS{     # store answer evaluators which have been explicitly labeled (submitted in a hash)
  230   my @in = @_;
  231   while (@in ) {
  232     my $label = shift @in;
  233     my $ans_eval = shift @in;
  234     TEXT("<BR><B>Error in NAMED_ANS:$in[0]</B>
  235           -- inputs must be references to subroutines<BR>")
  236       unless ref($ans_eval);
  237     $PG_ANSWERS_HASH{$label}= $ans_eval;
  238   }
  239 }
  240 sub RECORD_ANS_NAME {     # this maintains the order in which the answer rules are printed.
  241   my $label = shift;
  242   push(@main::PG_ANSWER_ENTRY_ORDER, $label);
  243   $label;
  244 }
  245 
  246 sub NEW_ANS_NAME {        # this keeps track of the answers which are entered implicitly,
  247                           # rather than with a specific label
  248     my $number=shift;
  249     my $label = "$main::ANSWER_PREFIX$number";
  250     push(@PG_UNLABELED_ANSWERS,$label);
  251     $label;
  252 }
  253 sub ANS_NUM_TO_NAME {     # This converts a number to an answer label for use in
  254                           # radio button and check box answers. No new answer
  255                           # name is recorded.
  256     my $number=shift;
  257     my $label = "$main::ANSWER_PREFIX$number";
  258     $label;
  259 }
  260 
  261 # ENDDOCUMENT must come at the end of every .pg file.
  262 #   It exports the resulting text of the problem, the text to be used in HTML header material
  263 #   (for javaScript), the list of answer evaluators and any other flags.  It can appear only once and
  264 #   it MUST be the last statement in the problem.
  265 
  266 =head2 ENDDOCUMENT()
  267 
  268 ENDDOCUMENT() must the last executable statement in any problem template.  It can
  269 only appear once.  It returns
  270 an array consisting of
  271 
  272   A reference to a string containing the rendered text of the problem.
  273   A reference to a string containing text to be placed in the header
  274                (for javaScript)
  275   A reference to the array containing the answer evaluators.
  276                (May be changed to a hash soon.)
  277   A reference to an associative array (hash) containing various flags.
  278 
  279   The following flags are set by ENDDOCUMENT:
  280   (1) showPartialCorrectAnswers  -- determines whether students are told which
  281       of their answers in a problem are wrong.
  282   (2) recordSubmittedAnswers  -- determines whether students submitted answers
  283       are saved.
  284       recordSubmittedAnswers
  285   (3) solutionExits   -- indicates the existence of a solution.
  286   (4) PROBLEM_GRADER_TO_USE -- chooses the problem grader to be used in this order
  287     (a) A problem grader specified by the problem using:
  288         install_problem_grader(\&grader);
  289     (b) One of the standard problem graders defined in PGanswermacros.pl when set to
  290         'std_problem_grader' or 'avg_problem_grader' by the environment variable
  291         $PG_environment{PROBLEM_GRADER_TO_USE}
  292     (c) A subroutine referenced by $PG_environment{PROBLEM_GRADER_TO_USE}
  293     (d) The default &std_problem_grader defined in PGanswermacros.pl
  294 
  295 
  296 =cut
  297 
  298 sub ENDDOCUMENT {
  299 
  300     my $index=0;
  301     foreach my $label (@PG_UNLABELED_ANSWERS) {
  302         if ( defined($PG_ANSWERS[$index]) ) {
  303         $PG_ANSWERS_HASH{"$label"}= $PG_ANSWERS[$index];
  304       } else {
  305         warn "No answer provided by instructor for answer $label";
  306       }
  307       $index++;
  308     }
  309 
  310     $STRINGforOUTPUT .="\n";
  311    ##eval q{  #make sure that "main" points to the current safe compartment by evaluating these lines.
  312     $main::PG_FLAGS{'showPartialCorrectAnswers'} = $main::showPartialCorrectAnswers;
  313     $main::PG_FLAGS{'recordSubmittedAnswers'} = $main::recordSubmittedAnswers;
  314   # $main::PG_FLAGS{'hintExists'} = $main::hintExists;
  315     $main::PG_FLAGS{'solutionExists'} = $main::solutionExists;
  316     $main::PG_FLAGS{ANSWER_ENTRY_ORDER} = \@main::PG_ANSWER_ENTRY_ORDER;
  317     $main::PG_FLAGS{ANSWER_PREFIX} = $main::ANSWER_PREFIX;
  318     # install problem grader
  319     if (defined($main::PG_FLAGS{PROBLEM_GRADER_TO_USE}) ) {
  320       # problem grader defined within problem -- no further action needed
  321     } elsif ( defined( $main::envir{PROBLEM_GRADER_TO_USE} ) ) {
  322       if (ref($main::envir{PROBLEM_GRADER_TO_USE}) eq 'CODE' ) {         # user defined grader
  323         $main::PG_FLAGS{PROBLEM_GRADER_TO_USE} = $main::envir{PROBLEM_GRADER_TO_USE};
  324       } elsif ($main::envir{PROBLEM_GRADER_TO_USE} eq 'std_problem_grader' ) {
  325         if (defined(&std_problem_grader) ){
  326           $main::PG_FLAGS{PROBLEM_GRADER_TO_USE} = \&std_problem_grader; # defined in PGanswermacros.pl
  327         } # std_problem_grader is the default in any case so don't give a warning.
  328       } elsif ($main::envir{PROBLEM_GRADER_TO_USE} eq 'avg_problem_grader' ) {
  329         if (defined(&avg_problem_grader) ){
  330           $main::PG_FLAGS{PROBLEM_GRADER_TO_USE} = \&avg_problem_grader; # defined in PGanswermacros.pl
  331         } else {
  332           warn "The problem grader 'avg_problem_grader' has not been defined.  Has PGanswermacros.pl been loaded?";
  333         }
  334       } else {
  335         warn "Error:  $main::PG_FLAGS{PROBLEM_GRADER_TO_USE} is not a known program grader.";
  336       }
  337     } elsif (defined(&std_problem_grader)) {
  338       $main::PG_FLAGS{PROBLEM_GRADER_TO_USE} = \&std_problem_grader; # defined in PGanswermacros.pl
  339     } else {
  340       # PGtranslator will install its default problem grader
  341     }
  342   ##};
  343     warn "ERROR: The problem grader is not a subroutine" unless ref( $main::PG_FLAGS{PROBLEM_GRADER_TO_USE}) eq 'CODE';
  344      # return results
  345   (\$STRINGforOUTPUT, \$STRINGforHEADER_TEXT,\%PG_ANSWERS_HASH,\%main::PG_FLAGS);
  346 }
  347 
  348 
  349 
  350 =head2 INITIALIZE_PG()
  351 
  352 This is executed each C<DOCUMENT()> is called.  For backward compatibility
  353 C<loadMacros> also checks whether the C<macroDirectory> has been defined
  354 and if not, it runs C<INITIALIZE_PG()> and issues a warning.
  355 
  356 =cut
  357 
  358 ################################################################################
  359 # Initialize the global variables to be used in PG
  360 #########
  361 
  362 #HACK -- fix this
  363 #unless (defined(&PGrandom::srand) ) {
  364 #
  365 # do "$main::envir{courseScriptsDirectory}PGrandom.pm" ||
  366 #         die "Can't read $main::envir{courseScriptsDirectory}PGrandom.pm";
  367 #}
  368 #
  369 
  370 
  371 #########
  372 # Initialization is complete
  373 ################################################################################
  374 
  375 1;

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9