Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rework the persistence hash and add new scaffold preview option. #1165

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 15 additions & 21 deletions lib/PGcore.pm
Original file line number Diff line number Diff line change
Expand Up @@ -75,18 +75,17 @@ sub new {

# Holds other data, besides answers, which persists during a session and beyond.
PERSISTENCE_HASH => $envir->{PERSISTENCE_HASH} // {}, # Main data, received from DB
PERSISTENCE_HASH_UPDATED => {}, # Keys whose updated values should be saved by the DB
answer_name_count => 0,
implicit_named_answer_stack => [],
implicit_answer_eval_stack => [],
explicit_answer_name_evals => {},
KEPT_EXTRA_ANSWERS => [],
ANSWER_PREFIX => 'AnSwEr',
ARRAY_PREFIX => 'ArRaY',
vec_num => 0, # for distinguishing matrices
vec_num => 0, # for distinguishing matrices
QUIZ_PREFIX => $envir->{QUIZ_PREFIX},
PG_VERSION => $ENV{PG_VERSION},
PG_ACTIVE => 1, # toggle to zero to stop processing
PG_ACTIVE => 1, # toggle to zero to stop processing
submittedAnswers => 0, # have any answers been submitted? is this the first time this session?
PG_session_persistence_hash => {}, # stores data from one invoction of the session to the next.
PG_original_problem_seed => 0,
Expand Down Expand Up @@ -477,25 +476,20 @@ sub extend_ans_group { # modifies the group type
return $label;
}

sub store_persistent_data { # will store strings only (so far)
my ($self, $label, @values) = @_;
if (defined($self->{PERSISTENCE_HASH}->{$label})) {
warn "can' overwrite $label in persistent data";
} else {
$self->{PERSISTENCE_HASH_UPDATED}{$label} = 1;
$self->{PERSISTENCE_HASH}{$label} = join("", @values);
# Save to or retrieve data from the persistence hash. The $label parameter is the key in the persistence hash. If the
# $value parameter is not given then the value of the $label key in the hash will be returned. If the $value parameter
# is given then the value of the $label key in the hash will be saved or updated. Note that if the $value parameter is
# given but is undefined then the $label key will be deleted from the hash. Anything that can be JSON encoded can be
# stored.
sub persistent_data {
my ($self, $label, $value) = @_;
if (@_ > 2) {
if (defined $value) {
$self->{PERSISTENCE_HASH}{$label} = $value;
} else {
delete $self->{PERSISTENCE_HASH}{$label};
}
}
$label;
}

sub update_persistent_data { # will store strings only (so far)
my ($self, $label, @values) = @_;
$self->{PERSISTENCE_HASH_UPDATED}{$label} = 1;
$self->{PERSISTENCE_HASH}{$label} = join("", @values);
}

sub get_persistent_data {
my ($self, $label) = @_;
return $self->{PERSISTENCE_HASH}{$label};
}

Expand Down
4 changes: 0 additions & 4 deletions lib/WeBWorK/PG.pm
Original file line number Diff line number Diff line change
Expand Up @@ -264,10 +264,6 @@ sub defineProblemEnvironment ($pg_envir, $options = {}, $image_generator = undef
showMessages => $options->{showMessages} // 1,
showCorrectAnswers => $options->{showCorrectAnswers} // 0,

# The next has marks what data was updated and needs to be saved
# by the front end.
PERSISTENCE_HASH_UPDATED => {},

inputs_ref => $options->{inputs_ref},

(map { $_ => $ansEvalDefaults->{$_} } keys %$ansEvalDefaults),
Expand Down
34 changes: 31 additions & 3 deletions macros/PG.pl
Original file line number Diff line number Diff line change
Expand Up @@ -545,19 +545,47 @@ sub ANS_NUM_TO_NAME {
$PG->new_label(@_);
}

=head2 persistent_data

Save to or retrieve data from the persistence hash. The persistence hash is data
that will persist for this problem. It is saved when answers are submitted, and
can be retrieved and used within a problem.

persistent_data($label);
persistent_data($label, $value);

The C<$label> parameter is the key in the persistence hash. If the C<$value>
parameter is not given then the value of the C<$label> key in the hash will be
returned. If the C<$value> parameter is given then the value of the C<$label>
key in the hash will be saved or updated. Note that if the C<$value> parameter
is given but is undefined then the C<$label> key will be deleted from the hash.
Anything that can be JSON encoded can be stored.

=cut

sub persistent_data {
my ($label, @value) = @_;
return $PG->persistent_data($label, @value);
}

# The store_persistent_data, update_persistent_data, and get_persistent_data methods are deprecated and are only still
# here for backward compatability. Use the persistent_data method instead which can do everything these three methods
# can do. Note that if you use the persistent_data method, then you will need to join the values as strings if you want
# that. Even better pass the persistent_data method an array reference containing the values so you can avoid the hassle
# of splitting the values when they are retrieved.
sub store_persistent_data {
my ($label, @values) = @_;
$PG->store_persistent_data($label, @values);
return $PG->persistent_data($label, join('', @values));
}

sub update_persistent_data {
my ($label, @values) = @_;
$PG->update_persistent_data($label, @values);
return $PG->persistent_data($label, join('', @values));
}

sub get_persistent_data {
my ($label) = @_;
return $PG->get_persistent_data($label);
return $PG->persistent_data($label);
}

sub add_content_post_processor {
Expand Down
25 changes: 22 additions & 3 deletions macros/core/scaffold.pl
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,16 @@ =head1 DESCRIPTION
have the student open it by hand before anwering the questions. In
this case, set this value to 0 (it is 1 by default).

=item C<S<< preview_can_change_state => 0 or 1 >>

This determines if scaffold state can be changed when a preview occurs
(i.e., when the "Preview My Answers" button is used). If this is 0,
then when a preview occurs any scaffold sections that were open before
the preview will remain open, and any scaffold sections that were closed
before the preview will remain closed. If this is 1, then the rules
described above will be applied using the scores of the answers in the
parts. This is 1 by default.

=item C<S<< numbered => 0 or 1 >>>

This determines whether each section is automatically numbered before
Expand Down Expand Up @@ -353,6 +363,7 @@ sub new {
hardcopy_is_open => "always", # open all possible sections in hardcopy
open_first_section => 1, # 0 means don't open any sections initially
numbered => 0, # 1 means sections will be printed with their number
preview_can_change_state => 1,
%options,
number => ++$scaffold_no, # the number for this scaffold
depth => $scaffold_depth, # the nesting depth for this scaffold
Expand Down Expand Up @@ -536,16 +547,24 @@ sub add_container {
# Nothing needs to be done for the PTX display mode.
return if $Scaffold::isPTX;

my $scaffoldScores = main::persistent_data('_scaffold_scores') // {};

# Provide a "scaffold_force" option in the AnswerHash that can be used to force
# Scaffold to consider the score to be 1. This is used by PGessaymacros.pl.
# Also, if answers are being previewed and the preview_can_change_state option is 0, then use the scores saved
# in the persistent data hash form the last answer submission (if there is no data for an answer, then the
# anwser is considered blank).
for (@{ $self->{ans_names} }) {
next unless defined $PG_ANSWERS_HASH->{$_};
$scaffold->{scores}{$_} =
$PG_ANSWERS_HASH->{$_}{ans_eval}{rh_ans}{scaffold_force}
? 1
$scaffold->{scores}{$_} = $scaffoldScores->{$_} =
$PG_ANSWERS_HASH->{$_}{ans_eval}{rh_ans}{scaffold_force} ? 1
: !$scaffold->{preview_can_change_state} && $PG_ANSWERS_HASH->{$_}{ans_eval}{rh_ans}{isPreview}
? $scaffoldScores->{$_}
: $PG_ANSWERS_HASH->{$_}{ans_eval}{rh_ans}{score};
}

main::persistent_data(_scaffold_scores => $scaffoldScores);

# Set the active scaffold to the scaffold for this section so that is_correct, can_open,
# and is_open methods use the correct one.
$Scaffold::scaffold = $scaffold;
Expand Down