[system] / trunk / pg / macros / PG.pl Repository:
ViewVC logotype

View of /trunk/pg/macros/PG.pl

Parent Directory Parent Directory | Revision Log Revision Log


Revision 6264 - (download) (as text) (annotate)
Sat May 15 19:38:49 2010 UTC (9 years, 8 months ago) by gage
File size: 31130 byte(s)
commented out a warning about using RCORD_FORM_LABELS  until

I can fix it properly -- it's used by ProblemRandomize for example.

    1 
    2 #use AnswerEvaluator;
    3 
    4 
    5 # provided by the translator
    6 # initialize PGcore and PGrandom
    7 
    8 
    9   $main::VERSION ="WW2";
   10 
   11 sub _PG_init{
   12   $main::VERSION ="WW2.9+";
   13 }
   14 sub not_null {PGcore::not_null(@_)};
   15 
   16 
   17 our $PG;
   18 
   19 sub DEBUG_MESSAGE {
   20   $PG->append_debug_message(@_);
   21 }
   22 
   23 
   24 sub DOCUMENT {
   25 
   26   # get environment
   27   $rh_envir = \%envir;  #KLUDGE FIXME
   28     # warn "rh_envir is ",ref($rh_envir);
   29   $PG = new PGcore($rh_envir, # can add key/value options to modify
   30   );
   31     $PG->clear_internal_debug_messages;
   32 
   33   # initialize main:: variables
   34 
   35   $ANSWER_PREFIX            = $PG->{ANSWER_PREFIX};
   36   $QUIZ_PREFIX              = $PG->{QUIZ_PREFIX};
   37   $showPartialCorrectAnswers  = $PG->{flags}->{showPartialCorrectAnswers};
   38   $showHint                   = $PG->{flags}->{showHint};
   39   $solutionExists           = $PG->{flags}->{solutionExists};
   40   $hintExists               = $PG->{flags}->{hintExists};
   41   $pgComment                  = '';
   42   %gifs_created             = %{ $PG->{gifs_created}};
   43   %external_refs            = %{ $PG->{external_refs}};
   44 
   45   @KEPT_EXTRA_ANSWERS =();   #temporary hack
   46 
   47   my %envir              =   %$rh_envir;
   48   $displayMode           = $PG->{displayMode};
   49   $PG_random_generator        = $PG->{PG_random_generator};
   50   # Save the file name for use in error messages
   51   # Doesn't appear to be used FIXME
   52 #     my ($callpkg,$callfile) = caller(0);
   53 #     $envir{__files__}{$callfile} = $envir{templateDirectory}.$envir{fileName};
   54 
   55  #no strict;
   56     foreach  my  $var (keys %envir) {
   57       PG_restricted_eval(qq!\$main::$var = \$envir{$var}!);  #whew!! makes sure $var is interpolated but $main:: is evaluated at run time.
   58         warn "Problem defining $var  while initializing the PG problem: $@" if $@;
   59     }
   60     #use strict;
   61     #FIXME
   62     # load java script needed for displayModes
   63     if ($envir{displayMode} eq 'HTML_jsMath') {
   64     my $prefix = "";
   65     if (!$envir{jsMath}{reportMissingFonts}) {
   66       $prefix .= '<SCRIPT>noFontMessage = 1</SCRIPT>'."\n";
   67     } elsif ($main::envir{jsMath}{missingFontMessage}) {
   68       $prefix .= '<SCRIPT>missingFontMessage = "'.$main::envir{jsMath}{missingFontMessage}.'"</SCRIPT>'."\n";
   69     }
   70     $prefix .= '<SCRIPT>processDoubleClicks = '.($main::envir{jsMath}{processDoubleClicks}?'1':'0')."</SCRIPT>\n";
   71     TEXT(
   72       $prefix,
   73       '<SCRIPT SRC="'.$envir{jsMathURL}. '"></SCRIPT>' . "\n" ,
   74       '<NOSCRIPT><CENTER><FONT COLOR="#CC0000">' ,
   75         "$BBOLD", 'Warning: the mathematics on this page requires JavaScript.',  ,$BR,
   76           'If your browser supports it, be sure it is enabled.',
   77         "$EBOLD",
   78       '</FONT></CENTER><p>
   79       </NOSCRIPT>'
   80     );
   81     TEXT('<SCRIPT>jsMath.Setup.Script("plugins/noImageFonts.js")</SCRIPT>')
   82         if ($envir{jsMath}{noImageFonts});
   83   } elsif ($envir{displayMode} eq 'HTML_asciimath') {
   84     TEXT('<SCRIPT SRC="'.$main::envir{asciimathURL}.'"></SCRIPT>' . "\n" ,
   85              '<SCRIPT>mathcolor = "black"</SCRIPT>' );
   86     } elsif ($envir{displayMode} eq 'HTML_LaTeXMathML') {
   87       TEXT('<SCRIPT SRC="'.$envir{LaTeXMathMLURL}.'"></SCRIPT>'."\n");
   88 
   89     }
   90 
   91 }
   92 $main::displayMode = $PG->{displayMode};
   93 $main::PG = $PG;
   94 sub TEXT {
   95    $PG->TEXT(@_) ;
   96 }
   97 
   98 sub HEADER_TEXT {
   99   $PG->HEADER_TEXT(@_);
  100 }
  101 
  102 sub LABELED_ANS {
  103   $PG->LABELED_ANS(@_); # returns pointer to the labeled answer group
  104 }
  105 
  106 sub NAMED_ANS {
  107   $PG->LABELED_ANS(@_); # returns pointer to the labeled answer group
  108 }
  109 
  110 sub ANS {
  111     #warn "using PGnew for ANS";
  112   $PG->ANS(@_);     # returns pointer to the labeled answer group
  113 }
  114 
  115 sub RECORD_ANS_NAME {
  116   $PG->record_ans_name(@_);
  117 }
  118 
  119 sub inc_ans_rule_count {
  120    #$PG->{unlabeled_answer_blank_count}++;
  121    #my $num = $PG->{unlabeled_answer_blank_count};
  122    DEBUG_MESSAGE( " using PG to inc_ans_rule_count = $num ", caller(2));
  123    warn " using PG to inc_ans_rule_count = $num ", caller(2);
  124    $PG->{unlabeled_answer_blank_count};
  125 }
  126 sub ans_rule_count {
  127   $PG->{unlabeled_answer_blank_count};
  128 }
  129 sub NEW_ANS_NAME {
  130      return "" if $PG_STOP_FLAG;
  131   #my $number=shift;
  132     # we have an internal count so the number not actually used.
  133   my $name =$PG->record_unlabeled_ans_name();
  134   $name;
  135 }
  136 sub NEW_ARRAY_NAME {
  137      return "" if $PG_STOP_FLAG;
  138   my $name =$PG->record_unlabeled_array_name();
  139   $name;
  140 }
  141 
  142 # new subroutine
  143 sub NEW_ANS_BLANK {
  144     return "" if $PG_STOP_FLAG;
  145   $PG->record_unlabeled_ans_name(@_);
  146 }
  147 
  148 sub ANS_NUM_TO_NAME {
  149   $PG->new_label(@_);  # behaves as in PG.pl
  150 }
  151 
  152 sub store_persistent_data {
  153     $PG->store_persistent_data(@_); #needs testing
  154 }
  155 sub RECORD_FORM_LABEL {              # this stores form data (such as sticky answers), but does nothing more
  156                                      # it's a bit of hack since we are storing these in the
  157                                      # KEPT_EXTRA_ANSWERS queue even if they aren't answers per se.
  158     #FIXME
  159     # warn "Using RECORD_FORM_LABEL -- deprecated? use $PG->store_persistent_data instead.";
  160   RECORD_EXTRA_ANSWERS(@_);
  161 }
  162 
  163 sub RECORD_EXTRA_ANSWERS {
  164   return "" if $PG_STOP_FLAG;
  165   my $label   = shift;             # the label of the input box or textarea
  166     eval(q!push(@main::KEPT_EXTRA_ANSWERS, $label)!); #put the labels into the hash to be caught later for recording purposes
  167     $label;
  168 
  169 }
  170 
  171 
  172 sub NEW_ANS_ARRAY_NAME {  # this keeps track of the answers within an array which are entered implicitly,
  173                           # rather than with a specific label
  174         return "" if $PG_STOP_FLAG;
  175     my $number=shift;
  176     $main::vecnum = -1;
  177     my $row = shift;
  178     my $col = shift;
  179 #       my $array_ans_eval_label = "ArRaY"."$number"."__"."$vecnum".":";
  180     my $label = $PG->{QUIZ_PREFIX}.$PG->{ARRAY_PREFIX}."$number"."__"."$vecnum".":"."$row".":"."$col"."__";
  181 #   my $response_group = new PGresponsegroup($label,undef);
  182 #   $PG->record_ans_name($array_ans_eval_label, $response_group);
  183 #       What does vecnum do?
  184 #       The name is simply so that it won't conflict when placed on the HTML page
  185 #       my $array_label = shift;
  186     $PG->record_array_name($label);  # returns $array_label, $ans_label
  187 }
  188 
  189 sub NEW_ANS_ARRAY_NAME_EXTENSION {
  190   NEW_ANS_ARRAY_ELEMENT_NAME(@_);
  191 }
  192 
  193 sub NEW_ANS_ARRAY_ELEMENT_NAME {   # creates a new array element answer name and records it
  194 
  195         return "" if $PG_STOP_FLAG;
  196     my $number=shift;
  197     my $row_num = shift;
  198     my $col_num = shift;
  199     if( $row_num == 0 && $col_num == 0 ){
  200       $main::vecnum += 1;
  201     }
  202 #   my $ans_label = "ArRaY".sprintf("%04u", $number);
  203     my $ans_label = $PG->new_array_label($number);
  204     my $element_ans_label = $PG->new_array_element_label($ans_label,$row_num, $col_num,vec_num=>$vecnum);
  205     my $response = new PGresponsegroup($ans_label,$element_ans_label, undef);
  206     $PG->extend_ans_group($ans_label,$response);
  207     $element_ans_label;
  208 }
  209 sub NEW_LABELED_ANS_ARRAY {    #not in PG_original
  210     my $ans_label = shift;
  211     my @response_list = @_;
  212     #$PG->extend_ans_group($ans_label,@response_list);
  213     $PG->{PG_ANSWERS_HASH}->{$ans_label}->insert_responses(@response_list);
  214     # should this return an array of labeled answer blanks???
  215 }
  216 sub     EXTEND_ANS_ARRAY {    #not in PG_original
  217     my $ans_label = shift;
  218     my @response_list = @_;
  219     #$PG->extend_ans_group($ans_label,@response_list);
  220     $PG->{PG_ANSWERS_HASH}->{$ans_label}->append_responses(@response_list);
  221 }
  222 sub CLEAR_RESPONSES {
  223   my $ans_label  = shift;
  224 # my $response_label = shift;
  225 # my $ans_value  = shift;
  226   if (defined ($PG->{PG_ANSWERS_HASH}->{$ans_label}) ) {
  227     my $responsegroup = $PG->{PG_ANSWERS_HASH}->{$ans_label}->{response};
  228     if ( ref($responsegroup) ) {
  229       $responsegroup->clear;
  230     } else {
  231       $responsegroup = $PG->{PG_ANSWERS_HASH}->{$ans_label}->{response} = new PGresponsegroup($label);
  232     }
  233   }
  234   '';
  235 }
  236 sub INSERT_RESPONSE {
  237   my $ans_label  = shift;
  238   my $response_label = shift;
  239   my $ans_value  = shift;
  240   my $selected   = shift;
  241   # warn "\n\nanslabel $ans_label responselabel $response_label value $ans_value";
  242   if (defined ($PG->{PG_ANSWERS_HASH}->{$ans_label}) ) {
  243     my $responsegroup = $PG->{PG_ANSWERS_HASH}->{$ans_label}->{response};
  244     $responsegroup->append_response($response_label, $ans_value, $selected);
  245     #warn "\n$responsegroup responses are now ", $responsegroup->responses;
  246   }
  247     '';
  248 }
  249 
  250 sub EXTEND_RESPONSE { # for radio buttons and checkboxes
  251   my $ans_label  = shift;
  252   my $response_label = shift;
  253   my $ans_value  = shift;
  254   my $selected   = shift;
  255   # warn "\n\nanslabel $ans_label responselabel $response_label value $ans_value";
  256   if (defined ($PG->{PG_ANSWERS_HASH}->{$ans_label}) ) {
  257     my $responsegroup = $PG->{PG_ANSWERS_HASH}->{$ans_label}->{response};
  258     $responsegroup->extend_response($response_label, $ans_value,$selected);
  259     #warn "\n$responsegroup responses are now ", pretty_print($response_group);
  260   }
  261     '';
  262 }
  263 sub ENDDOCUMENT {
  264   # check that answers match
  265   # gather up PG_FLAGS elements
  266 
  267     $PG->{flags}->{showPartialCorrectAnswers}      = defined($showPartialCorrectAnswers)?  $showPartialCorrectAnswers : 1 ;
  268   $PG->{flags}->{recordSubmittedAnswers}         = defined($recordSubmittedAnswers)?     $recordSubmittedAnswers    : 1 ;
  269   $PG->{flags}->{refreshCachedImages}            = defined($refreshCachedImages)?        $refreshCachedImages       : 0 ;
  270   $PG->{flags}->{hintExists}                     = defined($hintExists)?                 $hintExists                : 0 ;
  271   $PG->{flags}->{solutionExists}                 = defined($solutionExists)?             $solutionExists            : 0 ;
  272   $PG->{flags}->{comment}                        = defined($pgComment)?                  $pgComment                 :'' ;
  273     $PG->{flags}->{showHintLimit}                  = defined($showHint)?                   $showHint                  : 0 ;
  274 
  275 
  276   # install problem grader
  277   if (defined($PG->{flags}->{PROBLEM_GRADER_TO_USE})  ) {
  278     # problem grader defined within problem -- no further action needed
  279   } elsif ( defined( $rh_envir->{PROBLEM_GRADER_TO_USE} ) ) {
  280     if (ref($rh_envir->{PROBLEM_GRADER_TO_USE}) eq 'CODE' ) {         # user defined grader
  281       $PG->{flags}->{PROBLEM_GRADER_TO_USE} = $rh_envir->{PROBLEM_GRADER_TO_USE};
  282     } elsif ($rh_envir->{PROBLEM_GRADER_TO_USE} eq 'std_problem_grader' ) {
  283       if (defined(&std_problem_grader) ){
  284         $PG->{flags}->{PROBLEM_GRADER_TO_USE} = \&std_problem_grader; # defined in PGanswermacros.pl
  285       } # std_problem_grader is the default in any case so don't give a warning.
  286     } elsif ($rh_envir->{PROBLEM_GRADER_TO_USE} eq 'avg_problem_grader' ) {
  287       if (defined(&avg_problem_grader) ){
  288         $PG->{flags}->{PROBLEM_GRADER_TO_USE} = \&avg_problem_grader; # defined in PGanswermacros.pl
  289       }
  290     } else {
  291       warn "Error:  ". $PG->{flags}->{PROBLEM_GRADER_TO_USE} . "is not a known program grader.";
  292     }
  293   } elsif (defined(&std_problem_grader)) {
  294     $PG->{flags}->{PROBLEM_GRADER_TO_USE} = \&std_problem_grader; # defined in PGanswermacros.pl
  295   } else {
  296     # PGtranslator will install its default problem grader
  297   }
  298 
  299   # add javaScripts
  300   if ($rh_envir->{displayMode} eq 'HTML_jsMath') {
  301     TEXT('<SCRIPT> jsMath.wwProcess() </SCRIPT>');
  302   } elsif ($rh_envir->{displayMode} eq 'HTML_asciimath') {
  303     TEXT('<SCRIPT> translate() </SCRIPT>');
  304     my $STRING = join("", @{$PG->{HEADER_ARRAY} });
  305     unless ($STRING =~ m/mathplayer/) {
  306       HEADER_TEXT('<object id="mathplayer" classid="clsid:32F66A20-7614-11D4-BD11-00104BD3F987">' . "\n" .
  307             '</object><?import namespace="mml" implementation="#mathplayer"?>'
  308       );
  309     }
  310 
  311   }
  312   TEXT( MODES(%{$rh_envir->{problemPostamble}}) );
  313 
  314 
  315 
  316 
  317 
  318   @PG_ANSWERS=();
  319 
  320   #warn keys %{ $PG->{PG_ANSWERS_HASH} };
  321   @PG_ANSWER_ENTRY_ORDER = ();
  322   my $ans_debug = 0;
  323   foreach my $key (keys %{ $PG->{PG_ANSWERS_HASH} }) {
  324           $answergroup = $PG->{PG_ANSWERS_HASH}->{$key};
  325           #warn "$key is defined =", defined($answergroup), "PG object is $PG";
  326           #################
  327           # EXTRA ANSWERS KLUDGE
  328           #################
  329           # The first response in each answer group is placed in @PG_ANSER_ENTRY_ORDER and %PG_ANSWERS_HASH
  330           # The remainder of the response keys are placed in the EXTRA ANSWERS ARRAY
  331           if (defined($answergroup)) {
  332               my @response_keys = $answergroup->{response}->response_labels;
  333               warn pretty_print($answergroup->{response}) if $ans_debug==1;
  334               my $response_key = shift @response_keys;
  335               #unshift @response_keys, $response_key unless ($response_key eq $answer_group->{ans_label});
  336               # don't save the first response key if it is the same as the ans_label
  337               # maybe we should insure that the first response key is always the same as the answer label?
  338               # even if no answer blank is printed for it? or a hidden answer blank?
  339               # this is still a KLUDGE
  340               # for compatibility the first response key is closer to the old method than the $ans_label
  341               # this is because a response key might indicate an array but an answer label won't
  342               push @PG_ANSWERS, $response_key,$answergroup->{ans_eval};
  343               push @PG_ANSWER_ENTRY_ORDER, $response_key;
  344               push @KEPT_EXTRA_ANSWERS, @response_keys;
  345       } else {
  346           #warn "$key is ", join("|",%{$PG->{PG_ANSWERS_HASH}->{$key}});
  347       }
  348   }
  349   push @KEPT_EXTRA_ANSWERS, keys %{$PG->{PERSISTENCE_HASH}};
  350   my %PG_ANSWERS_HASH = @PG_ANSWERS;
  351   $PG->{flags}->{KEPT_EXTRA_ANSWERS} = \@KEPT_EXTRA_ANSWERS;
  352   $PG->{flags}->{ANSWER_ENTRY_ORDER} = \@PG_ANSWER_ENTRY_ORDER;
  353     warn "KEPT_EXTRA_ANSWERS", join(" ", @KEPT_EXTRA_ANSWERS), $BR     if $ans_debug==1;
  354     warn "PG_ANSWER_ENTRY_ORDER",join(" ",@PG_ANSWER_ENTRY_ORDER), $BR if $ans_debug==1;
  355     warn "DEBUG messages", join( "$BR",@{$PG->get_debug_messages} ) if $ans_debug==1;
  356     warn "INTERNAL_DEBUG messages", join( "$BR",@{$PG->get_internal_debug_messages} ) if $ans_debug==1;
  357   $STRINGforOUTPUT      = join("", @{$PG->{OUTPUT_ARRAY} });
  358 
  359 
  360   $STRINGforHEADER_TEXT = join("", @{$PG->{HEADER_ARRAY} });
  361 
  362   # warn pretty_print($PG->{PG_ANSWERS_HASH});
  363   #warn "printing another warning";
  364 
  365   (\$STRINGforOUTPUT, \$STRINGforHEADER_TEXT,\%PG_ANSWERS_HASH,  $PG->{flags} , $PG   );
  366 }
  367 ################################################################################
  368 #
  369 # macros from dangerousMacros
  370 #
  371 ################################################################################
  372 sub alias {
  373     #warn "alias called ",@_;
  374     $PG->{PG_alias}->make_alias(@_)  ;
  375 }
  376 sub insertGraph {
  377   $PG->insertGraph(@_);
  378 }
  379 
  380 sub findMacroFile {
  381   $PG->{PG_alias}->findMacroFile(@_);
  382 }
  383 sub check_url {
  384   $PG->{PG_alias}->check_url(@_);
  385 }
  386 sub findAppletCodebase {
  387   $PG->{PG_alias}->findAppletCodebase(@_);
  388 }
  389 
  390 sub loadMacros {
  391   $PG->{PG_loadMacros}->loadMacros(@_);
  392 }
  393 #  FIXME?  these were taken from the former dangerousMacros.pl file and might have issues when placed here.
  394 #
  395 #  Some constants that can be used in perl experssions
  396 #
  397 
  398 # ^function i
  399 # ^uses $_parser_loaded
  400 # ^uses &Complex::i
  401 # ^uses &Value::Package
  402 sub i () {
  403   #  check if Parser.pl is loaded, otherwise use Complex package
  404   if (!eval(q!$main::_parser_loaded!)) {return Complex::i}
  405   return Value->Package("Formula")->new('i')->eval;
  406 }
  407 
  408 # ^function j
  409 # ^uses $_parser_loaded
  410 # ^uses &Value::Package
  411 sub j () {
  412   if (!eval(q!$main::_parser_loaded!)) {return 'j'}
  413   Value->Package("Formula")->new('j')->eval;
  414 }
  415 
  416 # ^function k
  417 # ^uses $_parser_loaded
  418 # ^uses &Value::Package
  419 sub k () {
  420   if (!eval(q!$main::_parser_loaded!)) {return 'k'}
  421   Value->Package("Formula")->new('k')->eval;
  422 }
  423 
  424 # ^function pi
  425 # ^uses &Value::Package
  426 sub pi () {Value->Package("Formula")->new('pi')->eval}
  427 
  428 # ^function Infinity
  429 # ^uses &Value::Package
  430 sub Infinity () {Value->Package("Infinity")->new()}
  431 
  432 
  433 # ^function abs
  434 # ^function sqrt
  435 # ^function exp
  436 # ^function log
  437 # ^function sin
  438 # ^function cos
  439 # ^function atan2
  440 #
  441 #  Allow these functions to be overridden
  442 #  (needed for log() to implement $useBaseTenLog)
  443 #
  444 use subs 'abs', 'sqrt', 'exp', 'log', 'sin', 'cos', 'atan2';
  445 sub abs($)  {return CORE::abs($_[0])};
  446 sub sqrt($) {return CORE::sqrt($_[0])};
  447 sub exp($)  {return CORE::exp($_[0])};
  448 sub log($)  {return CORE::log($_[0])};
  449 sub sin($)  {return CORE::sin($_[0])};
  450 sub cos($)  {return CORE::cos($_[0])};
  451 sub atan2($$) {return CORE::atan2($_[0],$_[1])};
  452 
  453 sub Parser::defineLog {eval {sub log($) {CommonFunction->Call("log",@_)}}};
  454 =head2 Filter utilities
  455 
  456 These two subroutines can be used in filters to set default options.  They
  457 help make filters perform in uniform, predictable ways, and also make it
  458 easy to recognize from the code which options a given filter expects.
  459 
  460 
  461 =head4 assign_option_aliases
  462 
  463 Use this to assign aliases for the standard options.  It must come before set_default_options
  464 within the subroutine.
  465 
  466     assign_option_aliases(\%options,
  467         'alias1'  => 'option5'
  468         'alias2'  => 'option7'
  469     );
  470 
  471 
  472 If the subroutine is called with an option  " alias1 => 23 " it will behave as if it had been
  473 called with the option " option5 => 23 "
  474 
  475 =cut
  476 
  477 
  478 # ^function assign_option_aliases
  479 sub assign_option_aliases {
  480   my $rh_options = shift;
  481   warn "The first entry to set_default_options must be a reference to the option hash" unless ref($rh_options) eq 'HASH';
  482   my @option_aliases = @_;
  483   while (@option_aliases) {
  484     my $alias = shift @option_aliases;
  485     my $option_key = shift @option_aliases;
  486 
  487     if (defined($rh_options->{$alias} )) {                       # if the alias appears in the option list
  488       if (not defined($rh_options->{$option_key}) ) {          # and the option itself is not defined,
  489         $rh_options->{$option_key} = $rh_options->{$alias};  # insert the value defined by the alias into the option value
  490                                                              # the FIRST alias for a given option takes precedence
  491                                                              # (after the option itself)
  492       } else {
  493         warn "option $option_key is already defined as", $rh_options->{$option_key}, "<br>\n",
  494              "The attempt to override this option with the alias $alias with value ", $rh_options->{$alias},
  495              " was ignored.";
  496       }
  497     }
  498     delete($rh_options->{$alias});                               # remove the alias from the initial list
  499   }
  500 
  501 }
  502 
  503 =head4 set_default_options
  504 
  505     set_default_options(\%options,
  506         '_filter_name'  =>  'filter',
  507         'option5'   =>  .0001,
  508         'option7'   =>  'ascii',
  509         'allow_unknown_options  =>  0,
  510     }
  511 
  512 Note that the first entry is a reference to the options with which the filter was called.
  513 
  514 The option5 is set to .0001 unless the option is explicitly set when the subroutine is called.
  515 
  516 The B<'_filter_name'> option should always be set, although there is no error if it is missing.
  517 It is used mainly for debugging answer evaluators and allows
  518 you to keep track of which filter is currently processing the answer.
  519 
  520 If B<'allow_unknown_options'> is set to 0 then if the filter is called with options which do NOT appear in the
  521 set_default_options list an error will be signaled and a warning message will be printed out.  This provides
  522 error checking against misspelling an option and is generally what is desired for most filters.
  523 
  524 Occasionally one wants to write a filter which accepts a long list of options, not all of which are known in advance,
  525 but only uses a subset of the options
  526 provided.  In this case, setting 'allow_unkown_options' to 1 prevents the error from being signaled.
  527 
  528 =cut
  529 
  530 # ^function set_default_options
  531 # ^uses pretty_print
  532 sub set_default_options {
  533   my $rh_options = shift;
  534   warn "The first entry to set_default_options must be a reference to the option hash" unless ref($rh_options) eq 'HASH';
  535   my %default_options = @_;
  536   unless ( defined($default_options{allow_unknown_options}) and $default_options{allow_unknown_options} == 1 ) {
  537     foreach  my $key1 (keys %$rh_options) {
  538       warn "This option |$key1| is not recognized in this subroutine<br> ", pretty_print($rh_options) unless exists($default_options{$key1});
  539     }
  540   }
  541   foreach my $key (keys %default_options) {
  542     if  ( not defined($rh_options->{$key} ) and defined( $default_options{$key} )  ) {
  543       $rh_options->{$key} = $default_options{$key};  #this allows     tol   => undef to allow the tol option, but doesn't define
  544                                                      # this key unless tol is explicitly defined.
  545     }
  546   }
  547 }
  548 1;
  549 __END__
  550 
  551 ################################################################################
  552 # WeBWorK Online Homework Delivery System
  553 # Copyright © 2000-2007 The WeBWorK Project, http://openwebwork.sf.net/
  554 # $CVSHeader: pg/macros/PG.pl,v 1.44 2010/05/14 16:53:28 gage Exp $
  555 #
  556 # This program is free software; you can redistribute it and/or modify it under
  557 # the terms of either: (a) the GNU General Public License as published by the
  558 # Free Software Foundation; either version 2, or (at your option) any later
  559 # version, or (b) the "Artistic License" which comes with this package.
  560 #
  561 # This program is distributed in the hope that it will be useful, but WITHOUT
  562 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  563 # FOR A PARTICULAR PURPOSE.  See either the GNU General Public License or the
  564 # Artistic License for more details.
  565 ################################################################################
  566 
  567 =head1 NAME
  568 
  569 PG.pl - Provides core Program Generation Language functionality.
  570 
  571 =head1 SYNPOSIS
  572 
  573 In a PG problem:
  574 
  575   DOCUMENT();             # should be the first statment in the problem
  576 
  577   loadMacros(.....);      # (optional) load other macro files if needed.
  578                           # (loadMacros is defined in F<dangerousMacros.pl>)
  579 
  580   HEADER_TEXT(...);       # (optional) used only for inserting javaScript into problems.
  581 
  582   TEXT(                   # insert text of problems
  583     "Problem text to be displayed. ",
  584     "Enter 1 in this blank:",
  585     ANS_RULE(1,30)      # ANS_RULE() defines an answer blank 30 characters long.
  586                       # It is defined in F<PGbasicmacros.pl>
  587   );
  588 
  589   ANS(answer_evalutors);  # see F<PGanswermacros.pl> for examples of answer evaluatiors.
  590 
  591   ENDDOCUMENT()           # must be the last statement in the problem
  592 
  593 =head1 DESCRIPTION
  594 
  595 This file provides the fundamental macros that define the PG language. It
  596 maintains a problem's text, header text, and answers:
  597 
  598 =over
  599 
  600 =item *
  601 
  602 Problem text: The text to appear in the body of the problem. See TEXT()
  603 below.
  604 
  605 =item *
  606 
  607 Header text: When a problem is processed in an HTML-based display mode,
  608 this variable can contain text that the caller should place in the HEAD of the
  609 resulting HTML page. See HEADER_TEXT() below.
  610 
  611 =item *
  612 
  613 Implicitly-labeled answers: Answers that have not been explicitly
  614 assigned names, and are associated with their answer blanks by the order in
  615 which they appear in the problem. These types of answers are designated using
  616 the ANS() macro.
  617 
  618 =item *
  619 
  620 Explicitly-labeled answers: Answers that have been explicitly assigned
  621 names with the LABELED_ANS() macro, or a macro that uses it. An explicitly-
  622 labeled answer is associated with its answer blank by name.
  623 
  624 =item *
  625 
  626 "Extra" answers: Names of answer blanks that do not have a 1-to-1
  627 correspondance to an answer evaluator. For example, in matrix problems, there
  628 will be several input fields that correspond to the same answer evaluator.
  629 
  630 =back
  631 
  632 =head1 USAGE
  633 
  634 This file is automatically loaded into the namespace of every PG problem. The
  635 macros within can then be called to define the structure of the problem.
  636 
  637 DOCUMENT() should be the first executable statement in any problem. It
  638 initializes vriables and defines the problem environment.
  639 
  640 ENDDOCUMENT() must be the last executable statement in any problem. It packs
  641 up the results of problem processing for delivery back to WeBWorK.
  642 
  643 The HEADER_TEXT(), TEXT(), and ANS() macros add to the header text string,
  644 body text string, and answer evaluator queue, respectively.
  645 
  646 =over
  647 
  648 =item HEADER_TEXT()
  649 
  650  HEADER_TEXT("string1", "string2", "string3");
  651 
  652 HEADER_TEXT() concatenates its arguments and appends them to the stored header
  653 text string. It can be used more than once in a file.
  654 
  655 The macro is used for material which is destined to be placed in the HEAD of
  656 the page when in HTML mode, such as JavaScript code.
  657 
  658 Spaces are placed between the arguments during concatenation, but no spaces are
  659 introduced between the existing content of the header text string and the new
  660 content being appended.
  661 
  662 
  663 
  664 =item TEXT()
  665 
  666  TEXT("string1", "string2", "string3");
  667 
  668 TEXT() concatenates its arguments and appends them to the stored problem text
  669 string. It is used to define the text which will appear in the body of the
  670 problem. It can be used more than once in a file.
  671 
  672 This macro has no effect if rendering has been stopped with the STOP_RENDERING()
  673 macro.
  674 
  675 This macro defines text which will appear in the problem. All text must be
  676 passed to this macro, passed to another macro that calls this macro, or included
  677 in a BEGIN_TEXT/END_TEXT block, which uses this macro internally. No other
  678 statements in a PG file will directly appear in the output. Think of this as the
  679 "print" function for the PG language.
  680 
  681 Spaces are placed between the arguments during concatenation, but no spaces are
  682 introduced between the existing content of the header text string and the new
  683 content being appended.
  684 
  685 
  686 
  687 =item ANS()
  688 
  689  TEXT(ans_rule(), ans_rule(), ans_rule());
  690  ANS($answer_evaluator1, $answer_evaluator2, $answer_evaluator3);
  691 
  692 Adds the answer evaluators listed to the list of unlabeled answer evaluators.
  693 They will be paired with unlabeled answer rules (a.k.a. answer blanks) in the
  694 order entered. This is the standard method for entering answers.
  695 
  696 In the above example, answer_evaluator1 will be associated with the first
  697 answer rule, answer_evaluator2 with the second, and answer_evaluator3 with the
  698 third. In practice, the arguments to ANS() will usually be calls to an answer
  699 evaluator generator such as the cmp() method of MathObjects or the num_cmp()
  700 macro in L<PGanswermacros.pl>.
  701 
  702 
  703 
  704 =item LABELED_ANS()
  705 
  706  TEXT(labeled_ans_rule("name1"), labeled_ans_rule("name2"));
  707  LABELED_ANS(name1 => answer_evaluator1, name2 => answer_evaluator2);
  708 
  709 Adds the answer evaluators listed to the list of labeled answer evaluators.
  710 They will be paired with labeled answer rules (a.k.a. answer blanks) in the
  711 order entered. This allows pairing of answer evaluators and answer rules that
  712 may not have been entered in the same order.
  713 
  714 
  715 
  716 
  717 =item STOP_RENDERING()
  718 
  719  STOP_RENDERING() unless all_answers_are_correct();
  720 
  721 Temporarily suspends accumulation of problem text and storing of answer blanks
  722 and answer evaluators until RESUME_RENDERING() is called.
  723 
  724 
  725 
  726 =item RESUME_RENDERING()
  727 
  728  RESUME_RENDERING();
  729 
  730 Resumes accumulating problem text and storing answer blanks and answer
  731 evaluators. Reverses the effect of STOP_RENDERING().
  732 
  733 
  734 
  735 =item ENDDOCUMENT()
  736 
  737  ENDDOCUMENT();
  738 
  739 When PG problems are evaluated, the result of evaluating the entire problem is
  740 interpreted as the return value of ENDDOCUMENT(). Therefore, ENDDOCUMENT() must
  741 be the last executable statement of every problem. It can only appear once. It
  742 returns a list consisting of:
  743 
  744 
  745 
  746 
  747 =item *
  748 
  749 A reference to a string containing the rendered text of the problem.
  750 
  751 =item *
  752 
  753 A reference to a string containing text to be placed in the HEAD block
  754 when in and HTML-based mode (e.g. for JavaScript).
  755 
  756 =item *
  757 
  758 A reference to the hash mapping answer labels to answer evaluators.
  759 
  760 =item *
  761 
  762 A reference to a hash containing various flags:
  763 
  764 
  765 
  766 =item *
  767 
  768 C<showPartialCorrectAnswers>: determines whether students are told which of their answers in a problem are wrong.
  769 
  770 =item *
  771 
  772 C<recordSubmittedAnswers>: determines whether students submitted answers are saved.
  773 
  774 =item *
  775 
  776 C<refreshCachedImages>: determines whether the cached image of the problem in typeset mode is always refreshed
  777 (i.e. setting this to 1 means cached images are not used).
  778 
  779 =item *
  780 
  781 C<solutionExits>: indicates the existence of a solution.
  782 
  783 =item *
  784 
  785 C<hintExits>: indicates the existence of a hint.
  786 
  787 =item *
  788 
  789 C<comment>: contents of COMMENT commands if any.
  790 
  791 =item *
  792 
  793 C<showHintLimit>: determines the number of attempts after which hint(s) will be shown
  794 
  795 =item *
  796 
  797 C<PROBLEM_GRADER_TO_USE>: a reference to the chosen problem grader.
  798 ENDDOCUMENT chooses the problem grader as follows:
  799 
  800 =over
  801 
  802 =item *
  803 
  804 If a problem grader has been chosen in the problem by calling
  805 C<install_problem_grader(\&grader)>, it is used.
  806 
  807 =item *
  808 
  809 Otherwise, if the C<PROBLEM_GRADER_TO_USE> PG environment variable
  810 contains a reference to a subroutine, it is used.
  811 
  812 =item *
  813 
  814 Otherwise, if the C<PROBLEM_GRADER_TO_USE> PG environment variable
  815 contains the string C<std_problem_grader> or the string C<avg_problem_grader>,
  816 C<&std_problem_grader> or C<&avg_problem_grader> are used. These graders are defined
  817 in L<PGanswermacros.pl>.
  818 
  819 =item *
  820 
  821 Otherwise, the PROBLEM_GRADER_TO_USE flag will contain an empty value
  822 and the PG translator should select C<&std_problem_grader>.
  823 
  824 =back
  825 
  826 =back
  827 
  828 
  829 
  830 =cut
  831 
  832 
  833 ################################################################################
  834 
  835 =head1 PRIVATE MACROS
  836 
  837 These macros should only be used by other macro files. In practice, they are
  838 used exclusively by L<PGbasicmacros.pl>.
  839 
  840 =over
  841 
  842 =item inc_ans_rule_count()
  843 
  844  NEW_ANS_NAME();
  845 
  846 Increments the internal count of the number of answer blanks that have been
  847 defined ($ans_rule_count) and returns the new count. This should only be used
  848 when one is about to define a new answer blank, for example with NEW_ANS_NAME().
  849 
  850 =cut
  851 
  852 =item RECORD_ANS_NAME()
  853 
  854  RECORD_ANS_NAME("label", "VALUE");
  855 
  856 Records the label for an answer blank. Used internally by L<PGbasicmacros.pl>
  857 to record the order of explicitly-labelled answer blanks.
  858 
  859 =cut
  860 
  861 =item NEW_ANS_NAME()
  862 
  863  NEW_ANS_NAME();
  864 
  865 Generates an anonymous answer label from the internal count The label is
  866 added to the list of implicity-labeled answers. Used internally by
  867 L<PGbasicmacros.pl> to generate labels for unlabeled answer blanks.
  868 
  869 =cut
  870 
  871 =item ANS_NUM_TO_NAME()
  872 
  873  ANS_NUM_TO_NAME($num);
  874 
  875 Generates an answer label from the supplied answer number, but does not add it
  876 to the list of inplicitly-labeled answers. Used internally by
  877 L<PGbasicmacros.pl> in generating answers blanks that use radio buttons or
  878 check boxes. (This type of answer blank uses multiple HTML INPUT elements with
  879 the same label, but the label should only be added to the list of implicitly-
  880 labeled answers once.)
  881 
  882 =cut
  883 
  884 =item RECORD_FROM_LABEL()
  885 
  886  RECORD_FORM_LABEL("label");
  887 
  888 Stores the label of a form field in the "extra" answers list. This is used to
  889 keep track of answer blanks that are not associated with an answer evaluator.
  890 
  891 =cut
  892 
  893 =item NEW_ANS_ARRAY_NAME()
  894 
  895  NEW_ANS_ARRAY_NAME($num, $row, $col);
  896 
  897 Generates a new answer label for an array (vector) element and adds it to the
  898 list of implicitly-labeled answers.
  899 
  900 =cut
  901 
  902 =item NEW_ANS_ARRAY_NAME_EXTENSION()
  903 
  904  NEW_ANS_ARRAY_NAME_EXTENSION($num, $row, $col);
  905 
  906 Generate an additional answer label for an existing array (vector) element and
  907 add it to the list of "extra" answers.
  908 
  909 =cut
  910 
  911 =item get_PG_ANSWERS_HASH()
  912 
  913  get_PG_ANSWERS_HASH();
  914  get_PG_ANSWERS_HASH($key);
  915 
  916 
  917 
  918 =cut
  919 
  920 =item includePGproblem($filePath)
  921 
  922  includePGproblem($filePath);
  923 
  924  Essentially runs the pg problem specified by $filePath, which is
  925  a path relative to the top of the templates directory.  The output
  926  of that problem appears in the given problem.
  927 
  928 =cut
  929 
  930 =back
  931 
  932 =head1 SEE ALSO
  933 
  934 L<PGbasicmacros.pl>, L<PGanswermacros.pl>.
  935 
  936 =cut
  937 
  938 
  939 
  940 
  941 1;

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9