This is accomplished by making a private copy of the Numeric context and then using that when you create your Score object (see the code below). Here, I also remove all the variables and the comma operator, so you can basically only enter numeric values. I'm allowing expressions (including function calls and constants like pi), but you could remove those as well, if you like. You might want to remove the strings, but I haven't done that.
I add the default checker subroutine into the context's cmpDefaults
hash as an alternative to overriding cmp_defaults
. It also returns the underlying Perl real rather than the MathObject, since the scoring code doesn't know about MathObjects.
Finally, I fixed the check for whether the score is between 0 and 1 (you had an "or" when you want an "and").
See if that is more to your liking.
loadMacros("MathObjects.pl"); sub _parserScore_init { main::PG_restricted_eval('sub Score {value::Score->new(@_)}'); } package value::Score; our @ISA = ('Value::Real'); # # A context for score opbjects # my $context = Parser::Context->getCopy('Numeric'); $context->{name} = "Score"; $context->{value}{Real} = 'value::Score'; # real numbers create Score objects $context->variables->clear(); # no formulas in this context $context->operators->undefine(','); # lists not allowed, either $context->{cmpDefaults}{Score} = { checker => sub { my ($correct, $student, $ansHash) = @_; my $score = $student->value; Value::Error('A score must be a real number between 0 and 1') unless $score >= 0 && $score <= 1; return $score; } }; sub new { my $self = shift; my $score = $self->SUPER::new($context, @_); Value::Error("A score must be a real number between 0 and 1") unless Value::isReal($score) && $score->value >= 0 && $score->value <= 1; $score->{isReal} = $score->{isValue} = $score->{isScore} = 1; return $score; } # # Override the class name to get better error messages # sub cmp_class {"a Score Value"} 1;