[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 6281 - (download) (as text) (annotate)
Thu May 27 03:53:23 2010 UTC (9 years, 6 months ago) by gage
File size: 31402 byte(s)
corrected typos.

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

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9