NAME

PG.pl - Provides core Program Generation Language functionality.

SYNPOSIS

In a PG problem:

DOCUMENT();             # should be the first statment in the problem

loadMacros(.....);      # (optional) load other macro files if needed.

HEADER_TEXT(...);       # (optional) used only for inserting javaScript into problems.

TEXT(                   # insert text of problems
    "Problem text to be displayed. ",
    "Enter 1 in this blank:",
    ans_rule(30)        # ans_rule(30) defines an answer blank 30 characters long.
                        # It is defined in PGbasicmacros.pl.
);

ANS(answer_evalutors);  # see PGanswermacros.pl for examples of answer evaluatiors.

ENDDOCUMENT()           # must be the last statement in the problem

DESCRIPTION

This file provides the fundamental macros that define the PG language. It maintains a problem's text, header text, and answers:

MACROS

This file is automatically loaded into the namespace of every PG problem. The macros within can then be called to define the structure of the problem.

DOCUMENT

DOCUMENT() should be the first executable statement in any problem. It initializes variables and defines the problem environment.

TEXT

TEXT() concatenates its arguments and appends them to the stored problem text string. It is used to define the text which will appear in the body of the problem. It can be used more than once in a file. For example,

TEXT("string1", "string2", "string3");

This macro has no effect if rendering has been stopped with the STOP_RENDERING() macro.

This macro defines text which will appear in the problem. All text must be passed to this macro, passed to another macro that calls this macro, or included via a BEGIN_TEXT/END_TEXT or BEGIN_PGML/END_PGML block which uses this macro internally. No other statements in a PG file will directly appear in the output. Think of this as the "print" function for the PG language.

Spaces are placed between the arguments during concatenation, but no spaces are introduced between the existing content of the header text string and the new content being appended.

HEADER_TEXT

HEADER_TEXT() concatenates its arguments and appends them to the stored header text string. It can be used more than once in a file. For example,

HEADER_TEXT("string1", "string2", "string3");

The macro is used for material which is destined to be placed in the HEAD of the page when in HTML mode, such as JavaScript code.

Spaces are placed between the arguments during concatenation, but no spaces are introduced between the existing content of the header text string and the new content being appended.

POST_HEADER_TEXT

DEPRECATED

Content added by this method is appended just after the page head. This method should no longer be used. There is no valid reason to add content after the page head, and not in the problem itself.

SET_PROBLEM_LANGUAGE

Valid HTML language codes are expected, but a region code or other settings may be included. See https://www.w3.org/International/questions/qa-choosing-language-tags.

SET_PROBLEM_LANGUAGE($language)

Example language codes: en-US, en-UK, he-IL

Some special language codes (e.g. zh-Hans) are longer. See the following references.

There is a tester located at https://r12a.github.io/app-subtags/

SET_PROBLEM_TEXTDIRECTION

Call SET_PROBLEM_TEXTDIRECTION to set the HTML dir attribute to be applied to the div element containing the problem.

SET_PROBLEM_TEXTDIRECTION($dir)

Only valid settings for the HTML dir attribute are permitted.

dir="ltr|rtl|auto"

See https://www.w3schools.com/tags/att_global_dir.asp.

It is likely that only problems written in RTL scripts will need to call the following function to set the base text direction for the problem.

Note the flag may not be set, and then the default behavior will be used.

ADD_CSS_FILE

Request that the problem HTML page also include additional CSS files from the pg/htdocs directory or from an external location.

ADD_CSS_FILE($file, $external);

If external is 1, it is assumed the full URL is provided. If external is 0 or not given, then file will be served from the pg/htdocs directory (if found).

For example:

ADD_CSS_FILE("css/rtl.css");
ADD_CSS_FILE("https://external.domain.com/path/to/file.css", 1);

ADD_JS_FILE

Request that the problem HTML page also include additional JavaScript files from the pg/htdocs directory or from an external location.

ADD_JS_FILE($file, $external);

If external is 1, it is assumed the full URL is provided. If external is 0 or not given, then file name will be served from the pg/htdocs directory (if found).

Additional attributes can be passed as a hash reference in the optional third argument. These attributes will be added as attributes to the script tag.

For example:

ADD_JS_FILE("js/Base64/Base64.js");
ADD_JS_FILE("https://cdn.geogebra.org/apps/deployggb.js", 1);
ADD_JS_FILE("js/GraphTool/graphtool.js", 0, { id => "gt_script", defer => undef });

NAMED_ANS

Associates answer names with answer evaluators. If the given anwer name has a response group in the PG_ANSWERS_HASH, then the evaluator is added to that response group. Otherwise the name and evaluator are added to the hash of explicitly named answer evaluators. They will be paired with exlplicitly named answer rules by name. This allows pairing of answer evaluators and answer rules that may not have been entered in the same order.

An example of the usage is:

TEXT(NAMED_ANS_RULE("name1"), NAMED_ANS_RULE("name2"));
NAMED_ANS(name1 => answer_evaluator1, name2 => answer_evaluator2);

LABELED_ANS

Alias for NAMED_ANS

ANS

Registers answer evaluators to be implicitly associated with answer names. If there is an answer name in the implicit answer name stack, then a given answer evaluator will be paired with the first name in the stack. Otherwise the evaluator will be pushed onto the implicit answer evaluator stack. This is the standard method for entering answers.

An example of the usage is:

TEXT(ans_rule(), ans_rule(), ans_rule());
ANS($answer_evaluator1, $answer_evaluator2, $answer_evaluator3);

In the above example, answer_evaluator1 will be associated with the first answer rule, answer_evaluator2 with the second, and answer_evaluator3 with the third. In practice, the arguments to ANS() will usually be calls to an answer evaluator generator such as the cmp() method of MathObjects or the num_cmp() macro in PGanswermacros.pl.

RECORD_ANS_NAME

Records the name for an answer blank. Used internally by PGbasicmacros.pl to record the order of answer blanks. All answer blanks must eventually be recorded via this method.

RECORD_ANS_NAME('name', 'VALUE');

RECORD_IMPLICIT_ANS_NAME

Records the name for an answer blank that is implicitly named. Used internally by PGbasicmacros.pl to record the order of answer blanks that are implicitly nameed. This must also be called by a macro for answer blanks created by it that need to be implicitly named.

RECORD_IMPLICIT_ANS_NAME('name');

NEW_ANS_NAME

Generates an anonymous answer name from the internal count. This method takes no arguments.

ANS_NUM_TO_NAME

Generates an answer name from the supplied answer number, but does not add it to the list of implicitly-named answers. This is deprecated, and most likely will not give something useful.

ANS_NUM_TO_NAME($num);

RECORD_FORM_LABEL

Stores the name of a form field in the "extra" answers list. This is used to keep track of answer blanks that are not associated with an answer evaluator.

RECORD_FORM_LABEL("name");

NEW_ANS_ARRAY_NAME_EXTENSION

Generate an additional answer name for an existing array (vector) element and add it to the list of "extra" answers.

NEW_ANS_ARRAY_NAME_EXTENSION($row, $col);

ENDDOCUMENT

When PG problems are evaluated, the result of evaluating the entire problem is interpreted as the return value of ENDDOCUMENT(). Furthermore, a post processing hook is added that injects feedback into the problem text. Therefore, ENDDOCUMENT() must be the last executable statement of every problem. It can only appear once. It returns a list consisting of:

The post processing hook added in this method adds a feedback button for each answer response group that when clicked opens a popover containing feedback for the answer. A result class is also added to each feedbackElement (see this option below) for coloring answer rules via CSS. In addition visually hidden spans are added that provide feedback for screen reader users. Each feedbackElement will be aria-describedby these spans.

When and what feedback is shown is determined by translator options described in "OPTIONS" in WeBWorK::PG as well as options described below. The hook handles standard answer types effectively, but macros that add special answer types and in some case problems (particularly those that use MultiAnswer questions with singleResult true) may need to help the method for proper placement of the feedback button and other aspects of feedback.

There are several options that can be modified, and a few different ways to make these modifications. Unfortunately, this is perhaps a little bit complicated to understand, and that really can not be helped. The reason for this is the extremely loose connection between answer rules, answer labels, and answer evaluators in PG.

How these options are set can be controlled in three ways.

First, an answer hash can have the feedback_options key set to a CODE reference. If this is the case, then the subroutine referenced by this key will be called and passed the answer hash itself, a reference to the hash of options described below (any of which can be modified by this subroutine), and a Mojo::DOM object containing the problem text. Note that if this method sets the insertElement option, then the other ways of controlling how these options are set will not be used.

Second, an element can be added to the DOM that contains an answer rule that has the class ww-feedback-container, and if that answer rule is initially chosen to be the insertElement and that is not set by the feedback_options method, then this added element will replace it as the insertElement.

Third, data attributes may be added to elements in the DOM will affect where the feedback button will be placed. The following data attributes are honored.

The options that can be modified are as follows.

includePGproblem

Essentially runs the pg problem specified by $filePath, which is a path relative to the top of the templates directory. The output of that problem appears in the given problem.

includePGproblem($filePath);

FILTER UTILITIES

These two subroutines can be used in filters to set default options. They help make filters perform in uniform, predictable ways, and also make it easy to recognize from the code which options a given filter expects.

assign_option_aliases

Use this to assign aliases for the standard options. It must come before set_default_options within the subroutine.

assign_option_aliases(\%options,
    alias1 => 'option5'
    alias2 => 'option7'
);

If the subroutine is called with an option alias1 => 23 it will behave as if it had been called with the option option5 => 23.

set_default_options

set_default_options(\%options,
    _filter_name          => 'filter',
    option5               => .0001,
    option7               => 'ascii',
    allow_unknown_options => 0,
}

Note that the first entry is a reference to the options with which the filter was called.

The option5 is set to .0001 unless the option is explicitly set when the subroutine is called.

The _filter_name option should always be set, although there is no error if it is missing. It is used mainly for debugging answer evaluators and allows you to keep track of which filter is currently processing the answer.

If allow_unknown_options is set to 0 then if the filter is called with options which do NOT appear in the set_default_options list an error will be signaled and a warning message will be printed out. This provides error checking against misspelling an option and is generally what is desired for most filters.

Occasionally one wants to write a filter which accepts a long list of options, not all of which are known in advance, but only uses a subset of the options provided. In this case, setting allow_unkown_options to 1 prevents the error from being signaled.

SEE ALSO

PGbasicmacros.pl, PGanswermacros.pl.