Class ::xowf::test_item::grading::Grading (public)
::nx::Class ::xowf::test_item::grading::Grading
Defined in packages/xowf/tcl/grading-procs.tcl
Superclass representing a generic grading
- Testcases:
- No testcase defined.
Source code: :property {precision ""} :property {title ""} # # The following two properties are specified by the sub-classes # and ensure that no grading is defined accidentally from the # base class. # :property {percentage_boundaries:required} :property {csv:required} :method init {} { # # Provide a default, self-descriptive title # if {${:title} eq ""} { set roundingClass [namespace tail [:info class]] if {$roundingClass ne "GradingRoundNone" && [string match *Round* $roundingClass]} { set round_string "#xowf.Rounding_scheme#: #xowf.Rounding_scheme-$roundingClass#," } else { set round_string "" } if {$roundingClass ne "GradingRoundNone" && ${:precision} ne ""} { set precision "#xowf.Rounding_precision#: ${:precision}," } else { set precision "" } set :title "[namespace tail [self]]: $round_string $precision #xowf.Grade_boundaries#: ${:percentage_boundaries}" ns_log notice "[self] initialized with title ${:title}" } next } :method calc_grade {-percentage -points -achievable_points} { # # Return a numeric grade for an exam submission based on # percentage and the property "percentage_mapping". On # invalid data, return 0. # # When "-percentage" is provided, use this for calculation # Otherwise calculate percentage based on "-points" (which might # be custom rounded) and "-achievable_points". # if {![info exists percentage] && $achievable_points > 0} { set percentage [format %.2f [expr {($points*100/$achievable_points) + 0.00001}]] } if {[info exists percentage]} { set grade 1 set nrGrades [expr {[llength ${:percentage_boundaries}]+1}] if {$nrGrades ne 5} { ns_log warning "grading [self]: unexpected number of grades: $nrGrades" } set gradePos 0 foreach boundary ${:percentage_boundaries} { if {$percentage < $boundary} { set grade [expr {$nrGrades - $gradePos}] break } incr gradePos } } else { set grade 0 } return $grade } :public method grading_dict {achieved_points} { # Important dict members of "achieved_points": # - achievedPoints: points that the student has achieved in her exam # - achievablePoints: points that the student could have achieved so far # - totalPoints: points that the student can achieve when finishing the exam # # achieved_points: {achievedPoints 4.0 achievablePoints 4 totalPoints 4} # percentage_mapping: {50.0 60.0 70.0 80.0} # # While "achievedPoints" and "achievablePoints" are calculated by # iterating over the submitted values, "totalPoints" contains # the sum of points of all questions of the exam, no matter if # these were answered or not. # if {![dict exists $achieved_points achievablePoints] && [dict exists $achieved_points totalPoints]} { ns_log warning "test_item::grading legacy call, use 'achievablePoints' instead of 'totalPoints'" dict set achieved_points achievablePoints [dict get $achieved_points totalPoints] } # # When the "achievedPoints" member is set to empty, and "details" are # provided, the caller can request a new calculation based on # the "details" member. # if {[dict get $achieved_points achievedPoints] eq "" && [dict exists $achieved_points details] } { set achievablePoints 0 set achievedPoints 0 #ns_log notice "RECALC in grading_dict " foreach detail [dict get $achieved_points details] { #ns_log notice "RECALC in grading_dict '$detail'" set achievedPoints [expr {$achievedPoints + [dict get $detail achieved]}] set achievablePoints [expr {$achievablePoints + [dict get $detail achievable]}] } dict set achieved_points achievedPoints $achievedPoints dict set achieved_points achievablePoints $achievablePoints } foreach key { achievedPoints achievablePoints totalPoints } { if {![dict exists $achieved_points $key]} { ns_log warning "test_item::grading dict without $key: $achieved_points" ::xo::show_stack dict set achieved_points $key 0 } } # # Format all values with two comma precision. The values # achievedPointsRounded and "percentageRounded" are rounded to # the custom precision. # dict with achieved_points { dict set achieved_points achievedPointsRounded [format %.${:precision}f $achievedPoints] set achievedPoints [format %.2f $achievedPoints] set percentage [format %.2f [expr {$totalPoints > 0 ? ($achievedPoints*100.0/$totalPoints) : 0}]] dict set achieved_points percentage $percentage dict set achieved_points percentageRounded [format %.${:precision}f $percentage] } #ns_log notice "R=$achieved_points" return $achieved_points } :public method print {-achieved_points:required} { # # Return a dict containing the members "panel" and "csv" # depending on the type of rounding options # set achieved_points [:grading_dict $achieved_points] set grade [:grade -achieved_points $achieved_points] dict with achieved_points { return [list panel [_ xowf.panel_[namespace tail [:info class]]] csv [subst ${:csv}]] } }XQL Not present: Generic, PostgreSQL, Oracle