qti 2.28.0 → 2.30.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/qti/v1/models/assessment_item.rb +21 -0
- data/lib/qti/v1/models/interactions/numeric_interaction.rb +27 -0
- data/lib/qti/version.rb +1 -1
- data/spec/fixtures/items_1.2/nq_multiple_fib_case_sensitive.xml +134 -0
- data/spec/fixtures/items_1.2/numeric_answer_feedback.xml +189 -0
- data/spec/lib/qti/v1/models/assessment_item_spec.rb +20 -0
- data/spec/lib/qti/v1/models/interactions/numeric_interaction_spec.rb +58 -0
- metadata +7 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5faafa20e505881d4e305e9346f24060883b8cf86b1861f08021f6def9329ea9
|
|
4
|
+
data.tar.gz: 69bbc14fecc3909cfc905102433e2ae1631261cf56fcda2c13035a35583a9682
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 43f8a769c16f2a2671219c7f2f3b4e25a3c8321dfed55d17035d1b3eab2238dcbae93f8b669e4393971a31c9607cfb3f2ca78ba454538bcfd279673f2f271eae
|
|
7
|
+
data.tar.gz: d51c5c66f01164d227c38ebb3098787096ce1b1257737ffe42ae70db5af39c8e09157b87c6469e7b66599803547c3bf92b6c0c9cacb667ef490e15bec86e27df
|
|
@@ -105,6 +105,27 @@ module Qti
|
|
|
105
105
|
end
|
|
106
106
|
end
|
|
107
107
|
|
|
108
|
+
def case_sensitive
|
|
109
|
+
@case_sensitive ||= begin
|
|
110
|
+
if case_sensitive_metadata?
|
|
111
|
+
case_sensitive_metadata_label = qti_metadata_children.children.find do |node|
|
|
112
|
+
node.text == 'case_sensitive'
|
|
113
|
+
end
|
|
114
|
+
case_sensitive_metadata_label.next.text
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def case_sensitive_metadata?
|
|
120
|
+
if @doc.at_xpath('.//xmlns:qtimetadata').present?
|
|
121
|
+
qti_metadata_children.children.find do |node|
|
|
122
|
+
node.text == 'case_sensitive'
|
|
123
|
+
end.present?
|
|
124
|
+
else
|
|
125
|
+
false
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
108
129
|
def decvar_maxvalue
|
|
109
130
|
@doc.at_xpath('.//xmlns:decvar/@maxvalue')&.value&.to_i ||
|
|
110
131
|
@doc.at_xpath('.//xmlns:decvar/@defaultval')&.value&.to_i || 0
|
|
@@ -29,8 +29,35 @@ module Qti
|
|
|
29
29
|
end
|
|
30
30
|
end
|
|
31
31
|
|
|
32
|
+
# Numeric answers cannot be paired with their comment through a
|
|
33
|
+
# `varequal`, the way the base implementation does it: exact and
|
|
34
|
+
# precision answers nest it inside an `or`, and range answers have no
|
|
35
|
+
# single value to emit one for. Canvas instead puts each answer's
|
|
36
|
+
# `displayfeedback` in the same `respcondition` that carries its
|
|
37
|
+
# `setvar SCORE`, so pair them by that node and key the result on the
|
|
38
|
+
# position within `answer_nodes` -- the same list, in the same order,
|
|
39
|
+
# that `scoring_data_structs` is built from.
|
|
40
|
+
def answer_feedback
|
|
41
|
+
answers = answer_nodes.filter_map.with_index do |answer_node, index|
|
|
42
|
+
numeric_answer_feedback_entry(answer_node, index)
|
|
43
|
+
end
|
|
44
|
+
answers unless answers.empty?
|
|
45
|
+
end
|
|
46
|
+
|
|
32
47
|
private
|
|
33
48
|
|
|
49
|
+
def numeric_answer_feedback_entry(answer_node, index)
|
|
50
|
+
refid = answer_node.xpath('./xmlns:displayfeedback[not (@linkrefid="correct_fb" or ' \
|
|
51
|
+
'@linkrefid="general_incorrect_fb" or @linkrefid="general_fb")]').first&.[](:linkrefid)
|
|
52
|
+
feedback = get_feedback(refid)
|
|
53
|
+
return nil unless feedback
|
|
54
|
+
{
|
|
55
|
+
response_index: index,
|
|
56
|
+
texttype: feedback[:texttype],
|
|
57
|
+
feedback: feedback.text
|
|
58
|
+
}
|
|
59
|
+
end
|
|
60
|
+
|
|
34
61
|
def answer_nodes
|
|
35
62
|
@node.xpath('.//xmlns:respcondition/xmlns:setvar[@varname="SCORE"]/..')
|
|
36
63
|
end
|
data/lib/qti/version.rb
CHANGED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="ISO-8859-1"?>
|
|
2
|
+
<questestinterop xmlns="http://www.imsglobal.org/xsd/ims_qtiasiv1p2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.imsglobal.org/xsd/ims_qtiasiv1p2 http://www.imsglobal.org/xsd/ims_qtiasiv1p2p1.xsd">
|
|
3
|
+
<item ident="97b0baae152f137d14503e2a2125c4d0" title="NQ Fill in Multiple Blanks Case Sensitive">
|
|
4
|
+
<itemmetadata>
|
|
5
|
+
<qtimetadata>
|
|
6
|
+
<qtimetadatafield>
|
|
7
|
+
<fieldlabel>question_type</fieldlabel>
|
|
8
|
+
<fieldentry>fill_in_multiple_blanks_question</fieldentry>
|
|
9
|
+
</qtimetadatafield>
|
|
10
|
+
<qtimetadatafield>
|
|
11
|
+
<fieldlabel>points_possible</fieldlabel>
|
|
12
|
+
<fieldentry>1.0</fieldentry>
|
|
13
|
+
</qtimetadatafield>
|
|
14
|
+
<qtimetadatafield>
|
|
15
|
+
<fieldlabel>original_answer_ids</fieldlabel>
|
|
16
|
+
<fieldentry>["bafd8242-ecdb-4158-a6d3-4ff15e016cb8-0", "d719aee0-6ce0-462c-9c0d-be63ba8d3408-0", "ce47aaf6-c1dd-4db8-9a9f-7f5c131d8a90-0", "41dfd716-8fd9-466a-97fa-33d353e44b42-0", "41dfd716-8fd9-466a-97fa-33d353e44b42-1", "a053119f-6a61-4372-ac79-4b2a7de0232f-0"]</fieldentry>
|
|
17
|
+
</qtimetadatafield>
|
|
18
|
+
<qtimetadatafield>
|
|
19
|
+
<fieldlabel>assessment_question_identifierref</fieldlabel>
|
|
20
|
+
<fieldentry>eaeec2d07f83998ee7b317ffde86dbc0</fieldentry>
|
|
21
|
+
</qtimetadatafield>
|
|
22
|
+
<qtimetadatafield>
|
|
23
|
+
<fieldlabel>case_sensitive</fieldlabel>
|
|
24
|
+
<fieldentry>true</fieldentry>
|
|
25
|
+
</qtimetadatafield>
|
|
26
|
+
</qtimetadata>
|
|
27
|
+
</itemmetadata>
|
|
28
|
+
<presentation>
|
|
29
|
+
<material>
|
|
30
|
+
<mattext texttype="text/html"><p>Roses are [bafd8242-ecdb-4158-a6d3-4ff15e016cb8], [d719aee0-6ce0-462c-9c0d-be63ba8d3408], [ce47aaf6-c1dd-4db8-9a9f-7f5c131d8a90], [41dfd716-8fd9-466a-97fa-33d353e44b42], and [a053119f-6a61-4372-ac79-4b2a7de0232f].</p></mattext>
|
|
31
|
+
</material>
|
|
32
|
+
<response_lid ident="response_bafd8242-ecdb-4158-a6d3-4ff15e016cb8">
|
|
33
|
+
<material>
|
|
34
|
+
<mattext>red</mattext>
|
|
35
|
+
</material>
|
|
36
|
+
<render_choice>
|
|
37
|
+
<response_label ident="bafd8242-ecdb-4158-a6d3-4ff15e016cb8-0" scoring_algorithm='TextContainsAnswer' answer_type='openEntry'>
|
|
38
|
+
<material>
|
|
39
|
+
<mattext texttype="text/plain">red</mattext>
|
|
40
|
+
</material>
|
|
41
|
+
</response_label>
|
|
42
|
+
</render_choice>
|
|
43
|
+
</response_lid>
|
|
44
|
+
<response_lid ident="response_d719aee0-6ce0-462c-9c0d-be63ba8d3408">
|
|
45
|
+
<material>
|
|
46
|
+
<mattext>blue</mattext>
|
|
47
|
+
</material>
|
|
48
|
+
<render_choice>
|
|
49
|
+
<response_label ident="d719aee0-6ce0-462c-9c0d-be63ba8d3408-0" scoring_algorithm='TextCloseEnough' answer_type='openEntry' levenshtein_distance='1' ignore_case='true'>
|
|
50
|
+
<material>
|
|
51
|
+
<mattext texttype="text/plain">blue</mattext>
|
|
52
|
+
</material>
|
|
53
|
+
</response_label>
|
|
54
|
+
</render_choice>
|
|
55
|
+
</response_lid>
|
|
56
|
+
<response_lid ident="response_ce47aaf6-c1dd-4db8-9a9f-7f5c131d8a90">
|
|
57
|
+
<material>
|
|
58
|
+
<mattext>green</mattext>
|
|
59
|
+
</material>
|
|
60
|
+
<render_choice>
|
|
61
|
+
<response_label ident="ce47aaf6-c1dd-4db8-9a9f-7f5c131d8a90-0" scoring_algorithm='TextEquivalence' answer_type='openEntry'>
|
|
62
|
+
<material>
|
|
63
|
+
<mattext texttype="text/plain">green</mattext>
|
|
64
|
+
</material>
|
|
65
|
+
</response_label>
|
|
66
|
+
</render_choice>
|
|
67
|
+
</response_lid>
|
|
68
|
+
<response_lid ident="response_41dfd716-8fd9-466a-97fa-33d353e44b42">
|
|
69
|
+
<material>
|
|
70
|
+
<mattext>yellow</mattext>
|
|
71
|
+
</material>
|
|
72
|
+
<render_choice>
|
|
73
|
+
<response_label ident="41dfd716-8fd9-466a-97fa-33d353e44b42-0" scoring_algorithm='TextInChoices' answer_type='openEntry'>
|
|
74
|
+
<material>
|
|
75
|
+
<mattext texttype="text/plain">yellow</mattext>
|
|
76
|
+
</material>
|
|
77
|
+
</response_label>
|
|
78
|
+
<response_label ident="41dfd716-8fd9-466a-97fa-33d353e44b42-1" scoring_algorithm='TextInChoices' answer_type='openEntry'>
|
|
79
|
+
<material>
|
|
80
|
+
<mattext texttype="text/plain">teal</mattext>
|
|
81
|
+
</material>
|
|
82
|
+
</response_label>
|
|
83
|
+
</render_choice>
|
|
84
|
+
</response_lid>
|
|
85
|
+
<response_lid ident="response_a053119f-6a61-4372-ac79-4b2a7de0232f">
|
|
86
|
+
<material>
|
|
87
|
+
<mattext>^orange<s>$</mattext>
|
|
88
|
+
</material>
|
|
89
|
+
<render_choice>
|
|
90
|
+
<response_label ident="a053119f-6a61-4372-ac79-4b2a7de0232f-0" scoring_algorithm='TextRegex' answer_type='openEntry'>
|
|
91
|
+
<material>
|
|
92
|
+
<mattext texttype="text/plain">^orange<s>$</mattext>
|
|
93
|
+
</material>
|
|
94
|
+
</response_label>
|
|
95
|
+
</render_choice>
|
|
96
|
+
</response_lid>
|
|
97
|
+
</presentation>
|
|
98
|
+
<resprocessing>
|
|
99
|
+
<outcomes>
|
|
100
|
+
<decvar maxvalue="100" minvalue="0" varname="SCORE" vartype="Decimal"/>
|
|
101
|
+
</outcomes>
|
|
102
|
+
<respcondition>
|
|
103
|
+
<conditionvar>
|
|
104
|
+
<varequal respident="response_bafd8242-ecdb-4158-a6d3-4ff15e016cb8">bafd8242-ecdb-4158-a6d3-4ff15e016cb8-0</varequal>
|
|
105
|
+
</conditionvar>
|
|
106
|
+
<setvar action="Add" varname="SCORE">20.00</setvar>
|
|
107
|
+
</respcondition>
|
|
108
|
+
<respcondition>
|
|
109
|
+
<conditionvar>
|
|
110
|
+
<varequal respident="response_d719aee0-6ce0-462c-9c0d-be63ba8d3408">d719aee0-6ce0-462c-9c0d-be63ba8d3408-0</varequal>
|
|
111
|
+
</conditionvar>
|
|
112
|
+
<setvar action="Add" varname="SCORE">20.00</setvar>
|
|
113
|
+
</respcondition>
|
|
114
|
+
<respcondition>
|
|
115
|
+
<conditionvar>
|
|
116
|
+
<varequal respident="response_ce47aaf6-c1dd-4db8-9a9f-7f5c131d8a90">ce47aaf6-c1dd-4db8-9a9f-7f5c131d8a90-0</varequal>
|
|
117
|
+
</conditionvar>
|
|
118
|
+
<setvar action="Add" varname="SCORE">20.00</setvar>
|
|
119
|
+
</respcondition>
|
|
120
|
+
<respcondition>
|
|
121
|
+
<conditionvar>
|
|
122
|
+
<varequal respident="response_41dfd716-8fd9-466a-97fa-33d353e44b42">41dfd716-8fd9-466a-97fa-33d353e44b42-0</varequal>
|
|
123
|
+
</conditionvar>
|
|
124
|
+
<setvar action="Add" varname="SCORE">20.00</setvar>
|
|
125
|
+
</respcondition>
|
|
126
|
+
<respcondition>
|
|
127
|
+
<conditionvar>
|
|
128
|
+
<varequal respident="response_a053119f-6a61-4372-ac79-4b2a7de0232f">a053119f-6a61-4372-ac79-4b2a7de0232f-0</varequal>
|
|
129
|
+
</conditionvar>
|
|
130
|
+
<setvar action="Add" varname="SCORE">20.00</setvar>
|
|
131
|
+
</respcondition>
|
|
132
|
+
</resprocessing>
|
|
133
|
+
</item>
|
|
134
|
+
</questestinterop>
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<!--
|
|
3
|
+
Numeric per-answer feedback fixture. Question1 covers all four numeric answer
|
|
4
|
+
types (exact, precision, margin of error, range) plus item level feedback that
|
|
5
|
+
must be ignored; Question2 has comments on only the first and third of three
|
|
6
|
+
answers, covering index alignment with scoring_data_structs.
|
|
7
|
+
-->
|
|
8
|
+
<questestinterop xmlns="http://www.imsglobal.org/xsd/ims_qtiasiv1p2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.imsglobal.org/xsd/ims_qtiasiv1p2 http://www.imsglobal.org/xsd/ims_qtiasiv1p2p1.xsd">
|
|
9
|
+
<assessment ident="i98661073a66c6b2567c8f9b1a22c2989" title="Numeric feedback">
|
|
10
|
+
<section ident="root_section">
|
|
11
|
+
<item ident="ia63b6a115fa68a555398a58626a62f82" title="Question1">
|
|
12
|
+
<presentation>
|
|
13
|
+
<material>
|
|
14
|
+
<mattext texttype="text/html"><div><p>question 1</p></div></mattext>
|
|
15
|
+
</material>
|
|
16
|
+
<response_str ident="response1" rcardinality="Single">
|
|
17
|
+
<render_fib fibtype="Decimal">
|
|
18
|
+
<response_label ident="answer1"/>
|
|
19
|
+
</render_fib>
|
|
20
|
+
</response_str>
|
|
21
|
+
</presentation>
|
|
22
|
+
<resprocessing>
|
|
23
|
+
<outcomes>
|
|
24
|
+
<decvar maxvalue="100" minvalue="0" varname="SCORE" vartype="Decimal"/>
|
|
25
|
+
</outcomes>
|
|
26
|
+
<respcondition continue="No">
|
|
27
|
+
<conditionvar>
|
|
28
|
+
<or>
|
|
29
|
+
<varequal respident="response1">42.0</varequal>
|
|
30
|
+
<and>
|
|
31
|
+
<vargte respident="response1">42.0</vargte>
|
|
32
|
+
<varlte respident="response1">42.0</varlte>
|
|
33
|
+
</and>
|
|
34
|
+
</or>
|
|
35
|
+
</conditionvar>
|
|
36
|
+
<setvar action="Set" varname="SCORE">100</setvar>
|
|
37
|
+
<displayfeedback feedbacktype="Response" linkrefid="1001_fb"/>
|
|
38
|
+
<displayfeedback feedbacktype="Response" linkrefid="correct_fb"/>
|
|
39
|
+
</respcondition>
|
|
40
|
+
<respcondition continue="No">
|
|
41
|
+
<conditionvar>
|
|
42
|
+
<or>
|
|
43
|
+
<varequal respident="response1">1000.00</varequal>
|
|
44
|
+
<and>
|
|
45
|
+
<vargt respident="response1">999.995</vargt>
|
|
46
|
+
<varlte respident="response1">1000.005</varlte>
|
|
47
|
+
</and>
|
|
48
|
+
</or>
|
|
49
|
+
</conditionvar>
|
|
50
|
+
<setvar action="Set" varname="SCORE">100</setvar>
|
|
51
|
+
<displayfeedback feedbacktype="Response" linkrefid="1002_fb"/>
|
|
52
|
+
</respcondition>
|
|
53
|
+
<respcondition continue="No">
|
|
54
|
+
<conditionvar>
|
|
55
|
+
<or>
|
|
56
|
+
<varequal respident="response1">77.0</varequal>
|
|
57
|
+
<and>
|
|
58
|
+
<vargte respident="response1">70.0</vargte>
|
|
59
|
+
<varlte respident="response1">84.0</varlte>
|
|
60
|
+
</and>
|
|
61
|
+
</or>
|
|
62
|
+
</conditionvar>
|
|
63
|
+
<setvar action="Set" varname="SCORE">100</setvar>
|
|
64
|
+
<displayfeedback feedbacktype="Response" linkrefid="1003_fb"/>
|
|
65
|
+
</respcondition>
|
|
66
|
+
<respcondition continue="No">
|
|
67
|
+
<conditionvar>
|
|
68
|
+
<vargte respident="response1">3.9</vargte>
|
|
69
|
+
<varlte respident="response1">4.1</varlte>
|
|
70
|
+
</conditionvar>
|
|
71
|
+
<setvar action="Set" varname="SCORE">100</setvar>
|
|
72
|
+
<displayfeedback feedbacktype="Response" linkrefid="1004_fb"/>
|
|
73
|
+
</respcondition>
|
|
74
|
+
</resprocessing>
|
|
75
|
+
<itemfeedback ident="1001_fb">
|
|
76
|
+
<flow_mat>
|
|
77
|
+
<material>
|
|
78
|
+
<mattext texttype="text/html"><p>Exact answer comment</p></mattext>
|
|
79
|
+
</material>
|
|
80
|
+
</flow_mat>
|
|
81
|
+
</itemfeedback>
|
|
82
|
+
<itemfeedback ident="1002_fb">
|
|
83
|
+
<flow_mat>
|
|
84
|
+
<material>
|
|
85
|
+
<mattext texttype="text/html"><p>Precision answer comment</p></mattext>
|
|
86
|
+
</material>
|
|
87
|
+
</flow_mat>
|
|
88
|
+
</itemfeedback>
|
|
89
|
+
<itemfeedback ident="1003_fb">
|
|
90
|
+
<flow_mat>
|
|
91
|
+
<material>
|
|
92
|
+
<mattext texttype="text/html"><p>Margin of error answer comment</p></mattext>
|
|
93
|
+
</material>
|
|
94
|
+
</flow_mat>
|
|
95
|
+
</itemfeedback>
|
|
96
|
+
<itemfeedback ident="1004_fb">
|
|
97
|
+
<flow_mat>
|
|
98
|
+
<material>
|
|
99
|
+
<mattext texttype="text/html"><p>Range answer comment</p></mattext>
|
|
100
|
+
</material>
|
|
101
|
+
</flow_mat>
|
|
102
|
+
</itemfeedback>
|
|
103
|
+
<itemfeedback ident="correct_fb">
|
|
104
|
+
<flow_mat>
|
|
105
|
+
<material>
|
|
106
|
+
<mattext texttype="text/html"><p>General Correct Feedback</p></mattext>
|
|
107
|
+
</material>
|
|
108
|
+
</flow_mat>
|
|
109
|
+
</itemfeedback>
|
|
110
|
+
<itemfeedback ident="general_fb">
|
|
111
|
+
<flow_mat>
|
|
112
|
+
<material>
|
|
113
|
+
<mattext texttype="text/html"><p>General Feedback</p></mattext>
|
|
114
|
+
</material>
|
|
115
|
+
</flow_mat>
|
|
116
|
+
</itemfeedback>
|
|
117
|
+
</item>
|
|
118
|
+
<item ident="ia63b6a115fa68a555398a58626a62f83" title="Question2">
|
|
119
|
+
<presentation>
|
|
120
|
+
<material>
|
|
121
|
+
<mattext texttype="text/html"><div><p>question 2</p></div></mattext>
|
|
122
|
+
</material>
|
|
123
|
+
<response_str ident="response1" rcardinality="Single">
|
|
124
|
+
<render_fib fibtype="Decimal">
|
|
125
|
+
<response_label ident="answer1"/>
|
|
126
|
+
</render_fib>
|
|
127
|
+
</response_str>
|
|
128
|
+
</presentation>
|
|
129
|
+
<resprocessing>
|
|
130
|
+
<outcomes>
|
|
131
|
+
<decvar maxvalue="100" minvalue="0" varname="SCORE" vartype="Decimal"/>
|
|
132
|
+
</outcomes>
|
|
133
|
+
<respcondition continue="No">
|
|
134
|
+
<conditionvar>
|
|
135
|
+
<or>
|
|
136
|
+
<varequal respident="response1">10.0</varequal>
|
|
137
|
+
<and>
|
|
138
|
+
<vargte respident="response1">10.0</vargte>
|
|
139
|
+
<varlte respident="response1">10.0</varlte>
|
|
140
|
+
</and>
|
|
141
|
+
</or>
|
|
142
|
+
</conditionvar>
|
|
143
|
+
<setvar action="Set" varname="SCORE">100</setvar>
|
|
144
|
+
<displayfeedback feedbacktype="Response" linkrefid="2001_fb"/>
|
|
145
|
+
</respcondition>
|
|
146
|
+
<respcondition continue="No">
|
|
147
|
+
<conditionvar>
|
|
148
|
+
<or>
|
|
149
|
+
<varequal respident="response1">20.0</varequal>
|
|
150
|
+
<and>
|
|
151
|
+
<vargte respident="response1">20.0</vargte>
|
|
152
|
+
<varlte respident="response1">20.0</varlte>
|
|
153
|
+
</and>
|
|
154
|
+
</or>
|
|
155
|
+
</conditionvar>
|
|
156
|
+
<setvar action="Set" varname="SCORE">100</setvar>
|
|
157
|
+
</respcondition>
|
|
158
|
+
<respcondition continue="No">
|
|
159
|
+
<conditionvar>
|
|
160
|
+
<or>
|
|
161
|
+
<varequal respident="response1">30.0</varequal>
|
|
162
|
+
<and>
|
|
163
|
+
<vargte respident="response1">30.0</vargte>
|
|
164
|
+
<varlte respident="response1">30.0</varlte>
|
|
165
|
+
</and>
|
|
166
|
+
</or>
|
|
167
|
+
</conditionvar>
|
|
168
|
+
<setvar action="Set" varname="SCORE">100</setvar>
|
|
169
|
+
<displayfeedback feedbacktype="Response" linkrefid="2003_fb"/>
|
|
170
|
+
</respcondition>
|
|
171
|
+
</resprocessing>
|
|
172
|
+
<itemfeedback ident="2001_fb">
|
|
173
|
+
<flow_mat>
|
|
174
|
+
<material>
|
|
175
|
+
<mattext texttype="text/html"><p>First answer comment</p></mattext>
|
|
176
|
+
</material>
|
|
177
|
+
</flow_mat>
|
|
178
|
+
</itemfeedback>
|
|
179
|
+
<itemfeedback ident="2003_fb">
|
|
180
|
+
<flow_mat>
|
|
181
|
+
<material>
|
|
182
|
+
<mattext texttype="text/html"><p>Third answer comment</p></mattext>
|
|
183
|
+
</material>
|
|
184
|
+
</flow_mat>
|
|
185
|
+
</itemfeedback>
|
|
186
|
+
</item>
|
|
187
|
+
</section>
|
|
188
|
+
</assessment>
|
|
189
|
+
</questestinterop>
|
|
@@ -135,6 +135,26 @@ describe Qti::V1::Models::AssessmentItem do
|
|
|
135
135
|
end
|
|
136
136
|
end
|
|
137
137
|
|
|
138
|
+
describe '#case_sensitive' do
|
|
139
|
+
let(:test_object) { Qti::V1::Models::Assessment.from_path!(file_path) }
|
|
140
|
+
let(:assessment_item_refs) { test_object.assessment_items }
|
|
141
|
+
let(:loaded_class) { described_class.new(assessment_item_refs) }
|
|
142
|
+
|
|
143
|
+
context 'when it does not contain case_sensitive metadata' do
|
|
144
|
+
let(:file_path) { File.join('spec', 'fixtures', 'items_1.2', 'nq_multiple_fib_scoring_algorithms.xml') }
|
|
145
|
+
it 'returns nil' do
|
|
146
|
+
expect(loaded_class.case_sensitive).to be_nil
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
context 'when it contains case_sensitive metadata' do
|
|
151
|
+
let(:file_path) { File.join('spec', 'fixtures', 'items_1.2', 'nq_multiple_fib_case_sensitive.xml') }
|
|
152
|
+
it 'returns the case_sensitive value' do
|
|
153
|
+
expect(loaded_class.case_sensitive).to eq 'true'
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
|
|
138
158
|
describe '#scoring_data_structs' do
|
|
139
159
|
it 'grabs the rcardinality and scoring data value' do
|
|
140
160
|
struct = loaded_class.send(:scoring_data_structs)
|
|
@@ -140,4 +140,62 @@ describe Qti::V1::Models::Interactions::NumericInteraction do
|
|
|
140
140
|
end
|
|
141
141
|
end
|
|
142
142
|
end
|
|
143
|
+
|
|
144
|
+
context 'answer feedback' do
|
|
145
|
+
let(:xml_file_name) { 'numeric_answer_feedback.xml' }
|
|
146
|
+
|
|
147
|
+
context 'a question with a comment on every answer type' do
|
|
148
|
+
let(:loaded_class) { described_class.new(assessment_item_refs.first, test_object) }
|
|
149
|
+
|
|
150
|
+
it 'returns a comment for the exact, precision, margin of error and range answers' do
|
|
151
|
+
expect(loaded_class.answer_feedback).to eq(
|
|
152
|
+
[
|
|
153
|
+
{ response_index: 0, texttype: 'text/html', feedback: '<p>Exact answer comment</p>' },
|
|
154
|
+
{ response_index: 1, texttype: 'text/html', feedback: '<p>Precision answer comment</p>' },
|
|
155
|
+
{ response_index: 2, texttype: 'text/html', feedback: '<p>Margin of error answer comment</p>' },
|
|
156
|
+
{ response_index: 3, texttype: 'text/html', feedback: '<p>Range answer comment</p>' }
|
|
157
|
+
]
|
|
158
|
+
)
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
it 'aligns every response_index with the matching scoring_data_struct' do
|
|
162
|
+
structs = loaded_class.scoring_data_structs
|
|
163
|
+
expect(structs.map(&:type)).to eq(
|
|
164
|
+
%w[exactResponse preciseResponse marginOfError withinARange]
|
|
165
|
+
)
|
|
166
|
+
expect(loaded_class.answer_feedback.map { |fb| structs[fb[:response_index]].type }).to eq(
|
|
167
|
+
%w[exactResponse preciseResponse marginOfError withinARange]
|
|
168
|
+
)
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
it 'ignores the item level feedback' do
|
|
172
|
+
expect(loaded_class.answer_feedback.map { |fb| fb[:feedback] }).not_to include(
|
|
173
|
+
'<p>General Correct Feedback</p>', '<p>General Feedback</p>'
|
|
174
|
+
)
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
context 'a question where only some answers have a comment' do
|
|
179
|
+
let(:loaded_class) { described_class.new(assessment_item_refs[1], test_object) }
|
|
180
|
+
|
|
181
|
+
it 'keeps the index of the commented answers aligned with scoring_data_structs' do
|
|
182
|
+
expect(loaded_class.answer_feedback).to eq(
|
|
183
|
+
[
|
|
184
|
+
{ response_index: 0, texttype: 'text/html', feedback: '<p>First answer comment</p>' },
|
|
185
|
+
{ response_index: 2, texttype: 'text/html', feedback: '<p>Third answer comment</p>' }
|
|
186
|
+
]
|
|
187
|
+
)
|
|
188
|
+
expect(loaded_class.scoring_data_structs.map(&:value)).to eq(%w[10.0 20.0 30.0])
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
context 'without answer feedback' do
|
|
194
|
+
let(:xml_file_name) { 'numeric_exact_match.xml' }
|
|
195
|
+
let(:loaded_class) { described_class.new(assessment_item_refs[1], test_object) }
|
|
196
|
+
|
|
197
|
+
it 'returns nil' do
|
|
198
|
+
expect(loaded_class.answer_feedback).to be_nil
|
|
199
|
+
end
|
|
200
|
+
end
|
|
143
201
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: qti
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.30.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Adrian Diaz
|
|
@@ -12,7 +12,7 @@ authors:
|
|
|
12
12
|
autorequire:
|
|
13
13
|
bindir: bin
|
|
14
14
|
cert_chain: []
|
|
15
|
-
date:
|
|
15
|
+
date: 2026-09-07 00:00:00.000000000 Z
|
|
16
16
|
dependencies:
|
|
17
17
|
- !ruby/object:Gem::Dependency
|
|
18
18
|
name: actionview
|
|
@@ -410,7 +410,9 @@ files:
|
|
|
410
410
|
- spec/fixtures/items_1.2/multiple_answer_canvas.xml
|
|
411
411
|
- spec/fixtures/items_1.2/multiple_choice.xml
|
|
412
412
|
- spec/fixtures/items_1.2/nq_multiple_fib_answer_types.xml
|
|
413
|
+
- spec/fixtures/items_1.2/nq_multiple_fib_case_sensitive.xml
|
|
413
414
|
- spec/fixtures/items_1.2/nq_multiple_fib_scoring_algorithms.xml
|
|
415
|
+
- spec/fixtures/items_1.2/numeric_answer_feedback.xml
|
|
414
416
|
- spec/fixtures/items_1.2/numeric_exact_match.xml
|
|
415
417
|
- spec/fixtures/items_1.2/numeric_margin_error.xml
|
|
416
418
|
- spec/fixtures/items_1.2/numeric_margin_error_percent.xml
|
|
@@ -743,7 +745,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
743
745
|
- !ruby/object:Gem::Version
|
|
744
746
|
version: '0'
|
|
745
747
|
requirements: []
|
|
746
|
-
rubygems_version: 3.
|
|
748
|
+
rubygems_version: 3.5.22
|
|
747
749
|
signing_key:
|
|
748
750
|
specification_version: 4
|
|
749
751
|
summary: QTI 1.2 and 2.1 import and export models
|
|
@@ -794,7 +796,9 @@ test_files:
|
|
|
794
796
|
- spec/fixtures/items_1.2/multiple_answer_canvas.xml
|
|
795
797
|
- spec/fixtures/items_1.2/multiple_choice.xml
|
|
796
798
|
- spec/fixtures/items_1.2/nq_multiple_fib_answer_types.xml
|
|
799
|
+
- spec/fixtures/items_1.2/nq_multiple_fib_case_sensitive.xml
|
|
797
800
|
- spec/fixtures/items_1.2/nq_multiple_fib_scoring_algorithms.xml
|
|
801
|
+
- spec/fixtures/items_1.2/numeric_answer_feedback.xml
|
|
798
802
|
- spec/fixtures/items_1.2/numeric_exact_match.xml
|
|
799
803
|
- spec/fixtures/items_1.2/numeric_margin_error.xml
|
|
800
804
|
- spec/fixtures/items_1.2/numeric_margin_error_percent.xml
|