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

View of /branches/gage_dev/pg/macros/PG.pl

Parent Directory Parent Directory | Revision Log Revision Log


Revision 6322 - (download) (as text) (annotate)
Wed Jul 7 01:34:38 2010 UTC (2 years, 10 months ago) by gage
File size: 31867 byte(s)
modifications so that the number of points plotted is not so flakey


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

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9