[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 6248 - (download) (as text) (annotate)
Fri May 14 01:17:21 2010 UTC (9 years, 6 months ago) by gage
File size: 30629 byte(s)
major update which adds objective methods to the basic code of PG.
HEAD should be considered more beta than usual for a few days until minor glitches
are shaken out.
new modules needed:

PGcore PGalias PGresource PGloadfiles PGanswergroup PGresponsegroup  Tie::IxHash

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

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9