[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 6257 - (download) (as text) (annotate)
Fri May 14 16:53:28 2010 UTC (9 years, 8 months ago) by gage
File size: 31077 byte(s)
 correct initialiazation problem for showPartialCorrectAnswers

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

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9