qti 0.2.16 → 0.3.16
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/README.md +6 -8
- data/lib/qti.rb +2 -0
- data/lib/qti/v1/models/choices/fill_blank_choice.rb +27 -0
- data/lib/qti/v1/models/interactions/fill_blank_interaction.rb +77 -0
- data/lib/qti/v1/models/interactions/string_interaction.rb +8 -2
- data/lib/qti/v1/models/scoring_data.rb +5 -1
- data/lib/qti/v2/models/choices/gap_match_choice.rb +0 -0
- data/lib/qti/v2/models/interactions/gap_match_interaction.rb +34 -0
- data/spec/fixtures/items_1.2/choice.xml +209 -0
- data/spec/fixtures/items_1.2/essay.xml +25 -0
- data/spec/fixtures/items_1.2/fib.xml +46 -0
- data/spec/fixtures/items_1.2/fib_str.xml +46 -0
- data/spec/fixtures/test_qti_1.2/quiz.xml +46 -0
- data/spec/lib/qti/v1/models/choices/fill_blank_choice_spec.rb +23 -0
- data/spec/lib/qti/v1/models/choices/logical_identifier_choice_spec.rb +1 -1
- data/spec/lib/qti/v1/models/interactions/fill_blank_interaction_spec.rb +64 -0
- data/spec/lib/qti/v1/models/interactions/string_interaction_spec.rb +17 -0
- data/spec/lib/qti_spec.rb +2 -2
- metadata +20 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 09a38606bbf7afefc7b808dd338055b24375193b
|
4
|
+
data.tar.gz: 1dcad5866f62bd26d1dd48ab3f3ab6646de5eddc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 952002458866f648ca5c473608a232e46fda37ae6e31cc273d48f25d4449eb4fc8f7f0d020069abb7f4593e72f1a71aaf706841aad90d48a761f0350c4477733
|
7
|
+
data.tar.gz: b38e9b92eda87771d2b8a9b4bcda1eb052540841b146bcc3c410bc2d67ca1b0ba9f38a2611f5caa579a269aaee55e00216f0b2e79151c38769554b369ed866da
|
data/README.md
CHANGED
@@ -1,7 +1,3 @@
|
|
1
|
-
---
|
2
|
-
content_id: "121077930"
|
3
|
-
title: Qti
|
4
|
-
---
|
5
1
|
# Qti Gem
|
6
2
|
|
7
3
|
The Qti gem supports QTI 1.2 and 2.1. It currently supports the following interaction types:
|
@@ -19,8 +15,10 @@ $ bundle install qti
|
|
19
15
|
|
20
16
|
## Usage
|
21
17
|
|
22
|
-
|
23
|
-
|
18
|
+
```rb
|
19
|
+
require 'qti'
|
20
|
+
@gem = Qti::Importer.new(path_of_quiz)
|
21
|
+
```
|
24
22
|
|
25
23
|
You can use the gem to access the manifest, the assessments, and the assessment items and use it in your own code!
|
26
24
|
|
@@ -53,7 +51,7 @@ Returns the version appropriate AssessmentItem model
|
|
53
51
|
- `title`
|
54
52
|
- `points_possible`
|
55
53
|
- `rcardinality` (QTI 1.2)
|
56
|
-
- `
|
54
|
+
- `interaction_model` (ie Choice Interaction)
|
57
55
|
- `scoring_data_structs`
|
58
56
|
|
59
57
|
## Running Tests
|
@@ -62,7 +60,7 @@ You can run tests with code coverage using the following command:
|
|
62
60
|
|
63
61
|
## Development
|
64
62
|
|
65
|
-
Want to contribute?
|
63
|
+
Want to contribute? Please submit a pull request!
|
66
64
|
|
67
65
|
## To Do
|
68
66
|
- More interaction models!
|
data/lib/qti.rb
CHANGED
@@ -54,9 +54,11 @@ require 'qti/models/base'
|
|
54
54
|
require 'qti/v1/models/base'
|
55
55
|
require 'qti/v1/models/interactions/base_interaction'
|
56
56
|
require 'qti/v1/models/interactions/choice_interaction'
|
57
|
+
|
57
58
|
require 'qti/v1/models/assessment'
|
58
59
|
require 'qti/v1/models/assessment_item'
|
59
60
|
require 'qti/v1/models/choices/logical_identifier_choice'
|
61
|
+
require 'qti/v1/models/choices/fill_blank_choice'
|
60
62
|
require 'qti/v1/models/scoring_data'
|
61
63
|
|
62
64
|
require 'qti/v2/models/base'
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'qti/v1/models/base'
|
2
|
+
|
3
|
+
module Qti
|
4
|
+
module V1
|
5
|
+
module Models
|
6
|
+
module Choices
|
7
|
+
class FillBlankChoice < Qti::V1::Models::Base
|
8
|
+
def initialize(node)
|
9
|
+
@node = node
|
10
|
+
end
|
11
|
+
|
12
|
+
def identifier
|
13
|
+
@identifier ||= @node.attributes['respident']&.value ||
|
14
|
+
@node.attributes['ident']&.value
|
15
|
+
end
|
16
|
+
|
17
|
+
def item_body
|
18
|
+
@item_body ||= begin
|
19
|
+
node = @node.dup
|
20
|
+
node.content.squish
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module Qti
|
2
|
+
module V1
|
3
|
+
module Models
|
4
|
+
module Interactions
|
5
|
+
class FillBlankInteraction < BaseInteraction
|
6
|
+
# This will know if a class matches
|
7
|
+
def self.matches(node)
|
8
|
+
return false if node.xpath('.//xmlns:other').present?
|
9
|
+
matches = node.xpath('.//xmlns:render_fib')
|
10
|
+
return false if matches.empty?
|
11
|
+
new(node)
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize(node)
|
15
|
+
@node = node
|
16
|
+
end
|
17
|
+
|
18
|
+
def stem_items
|
19
|
+
stem_item_nodes = node.xpath('.//xmlns:presentation').children
|
20
|
+
stem_item_nodes.map.with_index do |stem_item, index|
|
21
|
+
if stem_item.xpath('./xmlns:render_fib').present?
|
22
|
+
{
|
23
|
+
id: "stem_#{index}",
|
24
|
+
position: index + 1,
|
25
|
+
type: 'blank',
|
26
|
+
blank_id: stem_item.attributes['ident'].value
|
27
|
+
}
|
28
|
+
else
|
29
|
+
{
|
30
|
+
id: "stem_#{index}",
|
31
|
+
position: index + 1,
|
32
|
+
type: 'text',
|
33
|
+
value: stem_item.children.text
|
34
|
+
}
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def blanks
|
40
|
+
node.xpath('.//xmlns:response_str').map do |blank|
|
41
|
+
{ id: blank.attributes['ident'].value }
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def answers
|
46
|
+
@answers ||= answer_nodes.map do |node|
|
47
|
+
V1::Models::Choices::FillBlankChoice.new(node)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def scoring_data_structs
|
52
|
+
answer_nodes.map { |value_node| ScoringData.new(
|
53
|
+
value_node.content,
|
54
|
+
rcardinality,
|
55
|
+
{
|
56
|
+
id: value_node.attributes['respident']&.value,
|
57
|
+
case: value_node.attributes['case']&.value
|
58
|
+
}
|
59
|
+
)
|
60
|
+
}
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def rcardinality
|
66
|
+
@rcardinality ||= @node.at_xpath('.//xmlns:response_str/@rcardinality')&.value ||
|
67
|
+
@node.at_xpath('.//xmlns:response_num/@rcardinality')&.value
|
68
|
+
end
|
69
|
+
|
70
|
+
def answer_nodes
|
71
|
+
@node.xpath('.//xmlns:varequal')
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -3,10 +3,10 @@ module Qti
|
|
3
3
|
module Models
|
4
4
|
module Interactions
|
5
5
|
class StringInteraction < BaseInteraction
|
6
|
-
@node_name = 'response_str'.freeze
|
7
6
|
# This will know if a class matches
|
8
7
|
def self.matches(node)
|
9
|
-
|
8
|
+
return false unless node.xpath('.//xmlns:other').present?
|
9
|
+
matches = node.xpath('.//xmlns:render_fib')
|
10
10
|
return false if matches.empty?
|
11
11
|
new(matches.first)
|
12
12
|
end
|
@@ -14,6 +14,12 @@ module Qti
|
|
14
14
|
def initialize(node)
|
15
15
|
@node = node
|
16
16
|
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def rcardinality
|
21
|
+
@rcardinality ||= @node.at_xpath('.//xmlns:response_str/@rcardinality').value
|
22
|
+
end
|
17
23
|
end
|
18
24
|
end
|
19
25
|
end
|
@@ -1,7 +1,11 @@
|
|
1
1
|
module Qti
|
2
2
|
module V1
|
3
3
|
module Models
|
4
|
-
ScoringData = Struct.new(:values, :rcardinality)
|
4
|
+
ScoringData = Struct.new(:values, :rcardinality, :id, :case) do
|
5
|
+
def initialize(values, rcardinality, options={})
|
6
|
+
super(values, rcardinality, options[:id], options[:case])
|
7
|
+
end
|
8
|
+
end
|
5
9
|
end
|
6
10
|
end
|
7
11
|
end
|
File without changes
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Qti
|
2
|
+
module V2
|
3
|
+
module Models
|
4
|
+
module Interactions
|
5
|
+
class GapMatchInteraction < Qti::V2::Models::Base
|
6
|
+
NODE_NAME = 'gapMatchInteraction'.freeze
|
7
|
+
# This will know if a class matches
|
8
|
+
def self.matches(node)
|
9
|
+
matches = node.children.filter(INTERACTION_ELEMENTS_CSS).select { |n| n.name == NODE_NAME }
|
10
|
+
return false if matches.empty?
|
11
|
+
|
12
|
+
raise Qti::UnsupportedSchema if matches.size > 1
|
13
|
+
new(matches.first)
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize(node)
|
17
|
+
@node = node
|
18
|
+
end
|
19
|
+
|
20
|
+
def gap_max_count
|
21
|
+
@node.attributes['gapMax']&.value&.to_i
|
22
|
+
end
|
23
|
+
|
24
|
+
def gap_min_count
|
25
|
+
@node.attributes['gapMin']&.value&.to_i
|
26
|
+
end
|
27
|
+
|
28
|
+
def gap_choice
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,209 @@
|
|
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
|
+
<assessment title="1.2 Import Quiz" ident="A1001">
|
4
|
+
<section title="Main" ident="S1002">
|
5
|
+
<item title="Grading - specific - 3 pt score" ident="QUE_1003">
|
6
|
+
<presentation>
|
7
|
+
<material>
|
8
|
+
<mattext texttype="text/html"><![CDATA[If I get a 3, I must have done something wrong. <img align="bottom" alt="image.png" src="org0/images/image.png" border="0"/>]]></mattext>
|
9
|
+
</material>
|
10
|
+
<response_lid ident="QUE_1004_RL" rcardinality="Single" rtiming="No">
|
11
|
+
<render_choice shuffle="Yes">
|
12
|
+
<response_label ident="QUE_1005_A1">
|
13
|
+
<material>
|
14
|
+
<mattext texttype="text/html"><![CDATA[True]]></mattext>
|
15
|
+
</material>
|
16
|
+
</response_label>
|
17
|
+
<response_label ident="QUE_1006_A2">
|
18
|
+
<material>
|
19
|
+
<mattext texttype="text/html"><![CDATA[False]]></mattext>
|
20
|
+
</material>
|
21
|
+
</response_label>
|
22
|
+
</render_choice>
|
23
|
+
</response_lid>
|
24
|
+
</presentation>
|
25
|
+
<resprocessing>
|
26
|
+
<outcomes>
|
27
|
+
<decvar vartype="Decimal" defaultval="0" varname="que_score"/>
|
28
|
+
</outcomes>
|
29
|
+
<respcondition>
|
30
|
+
<conditionvar>
|
31
|
+
<varequal respident="QUE_1004_RL">QUE_1005_A1</varequal>
|
32
|
+
</conditionvar>
|
33
|
+
<setvar varname="que_score" action="Add">0</setvar>
|
34
|
+
</respcondition>
|
35
|
+
<respcondition>
|
36
|
+
<conditionvar>
|
37
|
+
<varequal respident="QUE_1004_RL">QUE_1006_A2</varequal>
|
38
|
+
</conditionvar>
|
39
|
+
<setvar varname="que_score" action="Set">10.00</setvar>
|
40
|
+
</respcondition>
|
41
|
+
</resprocessing>
|
42
|
+
</item>
|
43
|
+
<item title="How much time each week?" ident="QUE_1007">
|
44
|
+
<presentation>
|
45
|
+
<material>
|
46
|
+
<mattext texttype="text/html"><![CDATA[How much time should you spend working on your online course each week in order to earn credit? <img align="bottom" alt="image.png" src="$IMS_CC_FILE_BASE$org1/images/image.png" border="0"/>]]></mattext>
|
47
|
+
</material>
|
48
|
+
<response_lid ident="QUE_1008_RL" rcardinality="Single" rtiming="No">
|
49
|
+
<render_choice>
|
50
|
+
<response_label ident="QUE_1009_A1">
|
51
|
+
<material>
|
52
|
+
<mattext texttype="text/html"><![CDATA[However long it takes]]></mattext>
|
53
|
+
</material>
|
54
|
+
</response_label>
|
55
|
+
<response_label ident="QUE_1010_A2">
|
56
|
+
<material>
|
57
|
+
<mattext texttype="text/html"><![CDATA[30 - 90 minutes]]></mattext>
|
58
|
+
</material>
|
59
|
+
</response_label>
|
60
|
+
<response_label ident="QUE_1011_A3">
|
61
|
+
<material>
|
62
|
+
<mattext texttype="text/html"><![CDATA[1 - 2 hours]]></mattext>
|
63
|
+
</material>
|
64
|
+
</response_label>
|
65
|
+
<response_label ident="QUE_1012_A4">
|
66
|
+
<material>
|
67
|
+
<mattext texttype="text/html"><![CDATA[At least 3 hours]]></mattext>
|
68
|
+
</material>
|
69
|
+
</response_label>
|
70
|
+
<response_label ident="QUE_1013_A5">
|
71
|
+
<material>
|
72
|
+
<mattext texttype="text/html"><![CDATA[6 or more hours]]></mattext>
|
73
|
+
</material>
|
74
|
+
</response_label>
|
75
|
+
</render_choice>
|
76
|
+
</response_lid>
|
77
|
+
</presentation>
|
78
|
+
<resprocessing>
|
79
|
+
<outcomes>
|
80
|
+
<decvar vartype="Decimal" maxvalue="10" defaultval="0" varname="que_score"/>
|
81
|
+
</outcomes>
|
82
|
+
<respcondition>
|
83
|
+
<conditionvar>
|
84
|
+
<varequal respident="QUE_1008_RL">QUE_1009_A1</varequal>
|
85
|
+
</conditionvar>
|
86
|
+
<setvar varname="que_score" action="Add">0</setvar>
|
87
|
+
</respcondition>
|
88
|
+
<respcondition>
|
89
|
+
<conditionvar>
|
90
|
+
<varequal respident="QUE_1008_RL">QUE_1010_A2</varequal>
|
91
|
+
</conditionvar>
|
92
|
+
<setvar varname="que_score" action="Add">0</setvar>
|
93
|
+
</respcondition>
|
94
|
+
<respcondition>
|
95
|
+
<conditionvar>
|
96
|
+
<varequal respident="QUE_1008_RL">QUE_1011_A3</varequal>
|
97
|
+
</conditionvar>
|
98
|
+
<setvar varname="que_score" action="Add">0</setvar>
|
99
|
+
</respcondition>
|
100
|
+
<respcondition>
|
101
|
+
<conditionvar>
|
102
|
+
<varequal respident="QUE_1008_RL">QUE_1012_A4</varequal>
|
103
|
+
</conditionvar>
|
104
|
+
<setvar varname="que_score" action="Set">10.00</setvar>
|
105
|
+
</respcondition>
|
106
|
+
<respcondition>
|
107
|
+
<conditionvar>
|
108
|
+
<varequal respident="QUE_1008_RL">QUE_1013_A5</varequal>
|
109
|
+
</conditionvar>
|
110
|
+
<setvar varname="que_score" action="Add">0</setvar>
|
111
|
+
</respcondition>
|
112
|
+
</resprocessing>
|
113
|
+
</item>
|
114
|
+
<item title="Discussion - content." ident="QUE_1022">
|
115
|
+
<presentation>
|
116
|
+
<material>
|
117
|
+
<mattext texttype="text/html"><![CDATA[A good discussion posting includes which of the following (select all that apply):]]></mattext>
|
118
|
+
</material>
|
119
|
+
<response_lid ident="QUE_1023_RL" rcardinality="Multiple" rtiming="No">
|
120
|
+
<render_choice>
|
121
|
+
<response_label ident="QUE_1024_A1">
|
122
|
+
<material>
|
123
|
+
<mattext texttype="text/html"><![CDATA[Poses a question or invites additional comment from others]]></mattext>
|
124
|
+
</material>
|
125
|
+
</response_label>
|
126
|
+
<response_label ident="QUE_1025_A2">
|
127
|
+
<material>
|
128
|
+
<mattext texttype="text/html"><![CDATA[Attacks another's post to generate controversy]]></mattext>
|
129
|
+
</material>
|
130
|
+
</response_label>
|
131
|
+
<response_label ident="QUE_1026_A3">
|
132
|
+
<material>
|
133
|
+
<mattext texttype="text/html"><![CDATA[Expresses an opinion which may be controversial so that others can agree or disagree]]></mattext>
|
134
|
+
</material>
|
135
|
+
</response_label>
|
136
|
+
<response_label ident="QUE_1027_A4">
|
137
|
+
<material>
|
138
|
+
<mattext texttype="text/html"><![CDATA[Adds information, ideas or suggestions that expand everyone's thinking about the topic]]></mattext>
|
139
|
+
</material>
|
140
|
+
</response_label>
|
141
|
+
<response_label ident="QUE_1028_A5">
|
142
|
+
<material>
|
143
|
+
<mattext texttype="text/html"><![CDATA[Reiterates the consensus or restates the ideas of others without adding independent thought]]></mattext>
|
144
|
+
</material>
|
145
|
+
</response_label>
|
146
|
+
<response_label ident="QUE_1029_A6">
|
147
|
+
<material>
|
148
|
+
<mattext texttype="text/html"><![CDATA[Provides non-specific praise for fellow learners like "good job" or "I loved your idea"]]></mattext>
|
149
|
+
</material>
|
150
|
+
</response_label>
|
151
|
+
<response_label ident="QUE_1030_A7">
|
152
|
+
<material>
|
153
|
+
<mattext texttype="text/html"><![CDATA[Responds positively to a person's comment and includes their name or quote from the original posting that supports your expanded idea]]></mattext>
|
154
|
+
</material>
|
155
|
+
</response_label>
|
156
|
+
</render_choice>
|
157
|
+
</response_lid>
|
158
|
+
</presentation>
|
159
|
+
<resprocessing>
|
160
|
+
<outcomes>
|
161
|
+
<decvar vartype="Decimal" defaultval="0" varname="que_score" maxvalue="10.00" minvalue="0"/>
|
162
|
+
</outcomes>
|
163
|
+
<respcondition>
|
164
|
+
<conditionvar>
|
165
|
+
<varequal respident="QUE_1023_RL">QUE_1024_A1</varequal>
|
166
|
+
</conditionvar>
|
167
|
+
<setvar varname="que_score" action="Add">25.00</setvar>
|
168
|
+
</respcondition>
|
169
|
+
<respcondition>
|
170
|
+
<conditionvar>
|
171
|
+
<varequal respident="QUE_1023_RL">QUE_1025_A2</varequal>
|
172
|
+
</conditionvar>
|
173
|
+
<setvar varname="que_score" action="Add">-10.00</setvar>
|
174
|
+
</respcondition>
|
175
|
+
<respcondition>
|
176
|
+
<conditionvar>
|
177
|
+
<varequal respident="QUE_1023_RL">QUE_1026_A3</varequal>
|
178
|
+
</conditionvar>
|
179
|
+
<setvar varname="que_score" action="Add">25.00</setvar>
|
180
|
+
</respcondition>
|
181
|
+
<respcondition>
|
182
|
+
<conditionvar>
|
183
|
+
<varequal respident="QUE_1023_RL">QUE_1027_A4</varequal>
|
184
|
+
</conditionvar>
|
185
|
+
<setvar varname="que_score" action="Add">25.00</setvar>
|
186
|
+
</respcondition>
|
187
|
+
<respcondition>
|
188
|
+
<conditionvar>
|
189
|
+
<varequal respident="QUE_1023_RL">QUE_1028_A5</varequal>
|
190
|
+
</conditionvar>
|
191
|
+
<setvar varname="que_score" action="Add">-10.00</setvar>
|
192
|
+
</respcondition>
|
193
|
+
<respcondition>
|
194
|
+
<conditionvar>
|
195
|
+
<varequal respident="QUE_1023_RL">QUE_1029_A6</varequal>
|
196
|
+
</conditionvar>
|
197
|
+
<setvar varname="que_score" action="Add">-10.00</setvar>
|
198
|
+
</respcondition>
|
199
|
+
<respcondition>
|
200
|
+
<conditionvar>
|
201
|
+
<varequal respident="QUE_1023_RL">QUE_1030_A7</varequal>
|
202
|
+
</conditionvar>
|
203
|
+
<setvar varname="que_score" action="Add">25.00</setvar>
|
204
|
+
</respcondition>
|
205
|
+
</resprocessing>
|
206
|
+
</item>
|
207
|
+
</section>
|
208
|
+
</assessment>
|
209
|
+
</questestinterop>
|
@@ -0,0 +1,25 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
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="if15fb877c2cde9a14437aa7429360ac6" title="First Essay">
|
4
|
+
<presentation>
|
5
|
+
<material>
|
6
|
+
<mattext texttype="text/html">Here is an essay question</mattext>
|
7
|
+
</material>
|
8
|
+
<response_str ident="response1" rcardinality="Single">
|
9
|
+
<render_fib>
|
10
|
+
<response_label ident="answer1" rshuffle="No"/>
|
11
|
+
</render_fib>
|
12
|
+
</response_str>
|
13
|
+
</presentation>
|
14
|
+
<resprocessing>
|
15
|
+
<outcomes>
|
16
|
+
<decvar maxvalue="100" minvalue="0" varname="SCORE" vartype="Decimal"/>
|
17
|
+
</outcomes>
|
18
|
+
<respcondition continue="No">
|
19
|
+
<conditionvar>
|
20
|
+
<other/>
|
21
|
+
</conditionvar>
|
22
|
+
</respcondition>
|
23
|
+
</resprocessing>
|
24
|
+
</item>
|
25
|
+
</questestinterop>
|
@@ -0,0 +1,46 @@
|
|
1
|
+
<?xml version = "1.0" encoding = "UTF-8" standalone = "no"?>
|
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 title = "Standard FIB string Item" ident = "FIB_STR">
|
4
|
+
<presentation label = "BasicExample013b">
|
5
|
+
<material>
|
6
|
+
<mattext>Fill-in-the blanks in this text from Richard III: </mattext>
|
7
|
+
</material>
|
8
|
+
<material>
|
9
|
+
<mattext>Now is the </mattext>
|
10
|
+
</material>
|
11
|
+
<response_str ident = "FIB01" rcardinality = "Single" rtiming = "No">
|
12
|
+
<render_fib fibtype = "String" prompt = "Dashline" maxchars = "6">
|
13
|
+
<response_label ident = "A"/>
|
14
|
+
</render_fib>
|
15
|
+
</response_str>
|
16
|
+
<material>
|
17
|
+
<mattext> of our discontent made glorious </mattext>
|
18
|
+
</material>
|
19
|
+
<response_str ident = "FIB02" rcardinality = "Single" rtiming = "No">
|
20
|
+
<render_fib fibtype = "String" prompt = "Dashline" maxchars = "6">
|
21
|
+
<response_label ident = "A"/>
|
22
|
+
</render_fib>
|
23
|
+
</response_str>
|
24
|
+
<material>
|
25
|
+
<mattext> by these sons of </mattext>
|
26
|
+
</material>
|
27
|
+
<response_str ident = "FIB03" rcardinality = "Single" rtiming = "No">
|
28
|
+
<render_fib fibtype = "String" prompt = "Dashline" maxchars = "4">
|
29
|
+
<response_label ident = "A"/>
|
30
|
+
</render_fib>
|
31
|
+
</response_str>
|
32
|
+
</presentation>
|
33
|
+
<resprocessing>
|
34
|
+
<outcomes>
|
35
|
+
<decvar varname = "FIBSCORE1" vartype = "Integer" defaultval = "0"/>
|
36
|
+
</outcomes>
|
37
|
+
<respcondition>
|
38
|
+
<conditionvar>
|
39
|
+
<varequal respident = "FIB01" case = "Yes">Winter</varequal>
|
40
|
+
<varequal respident = "FIB02" case = "Yes">Summer</varequal>
|
41
|
+
<varequal respident = "FIB03" case = "Yes">York</varequal>
|
42
|
+
</conditionvar>
|
43
|
+
<setvar action = "Add" varname = "FIBSCORE1">3</setvar>
|
44
|
+
</respcondition>
|
45
|
+
</item>
|
46
|
+
</questestinterop>
|
@@ -0,0 +1,46 @@
|
|
1
|
+
<?xml version = "1.0" encoding = "UTF-8" standalone = "no"?>
|
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 title = "Standard FIB string Item" ident = "FIB_STR">
|
4
|
+
<presentation label = "BasicExample013b">
|
5
|
+
<material>
|
6
|
+
<mattext>Fill-in-the blanks in this text from Richard III: </mattext>
|
7
|
+
</material>
|
8
|
+
<material>
|
9
|
+
<mattext>Now is the </mattext>
|
10
|
+
</material>
|
11
|
+
<response_str ident = "FIB01" rcardinality = "Single" rtiming = "No">
|
12
|
+
<render_fib fibtype = "String" prompt = "Dashline" maxchars = "6">
|
13
|
+
<response_label ident = "A"/>
|
14
|
+
</render_fib>
|
15
|
+
</response_str>
|
16
|
+
<material>
|
17
|
+
<mattext> of our discontent made glorious </mattext>
|
18
|
+
</material>
|
19
|
+
<response_str ident = "FIB02" rcardinality = "Single" rtiming = "No">
|
20
|
+
<render_fib fibtype = "String" prompt = "Dashline" maxchars = "6">
|
21
|
+
<response_label ident = "A"/>
|
22
|
+
</render_fib>
|
23
|
+
</response_str>
|
24
|
+
<material>
|
25
|
+
<mattext> by these sons of </mattext>
|
26
|
+
</material>
|
27
|
+
<response_str ident = "FIB03" rcardinality = "Single" rtiming = "No">
|
28
|
+
<render_fib fibtype = "String" prompt = "Dashline" maxchars = "4">
|
29
|
+
<response_label ident = "A"/>
|
30
|
+
</render_fib>
|
31
|
+
</response_str>
|
32
|
+
</presentation>
|
33
|
+
<resprocessing>
|
34
|
+
<outcomes>
|
35
|
+
<decvar varname = "FIBSCORE1" vartype = "Integer" defaultval = "0"/>
|
36
|
+
</outcomes>
|
37
|
+
<respcondition>
|
38
|
+
<conditionvar>
|
39
|
+
<varequal respident = "FIB01" case = "Yes">Winter</varequal>
|
40
|
+
<varequal respident = "FIB02" case = "Yes">Summer</varequal>
|
41
|
+
<varequal respident = "FIB03" case = "Yes">York</varequal>
|
42
|
+
</conditionvar>
|
43
|
+
<setvar action = "Add" varname = "FIBSCORE1">3</setvar>
|
44
|
+
</respcondition>
|
45
|
+
</item>
|
46
|
+
</questestinterop>
|
@@ -204,6 +204,52 @@
|
|
204
204
|
</respcondition>
|
205
205
|
</resprocessing>
|
206
206
|
</item>
|
207
|
+
<item ident="i25e12fe33ac9d91ff208923796f83d0a" title="Question">
|
208
|
+
<presentation>
|
209
|
+
<material>
|
210
|
+
<mattext texttype="text/html">First color of the rainbow?</mattext>
|
211
|
+
</material>
|
212
|
+
<response_str ident="response1" rcardinality="Single">
|
213
|
+
<render_fib>
|
214
|
+
<response_label ident="answer1" rshuffle="No"/>
|
215
|
+
</render_fib>
|
216
|
+
</response_str>
|
217
|
+
</presentation>
|
218
|
+
<resprocessing>
|
219
|
+
<outcomes>
|
220
|
+
<decvar maxvalue="100" minvalue="0" varname="SCORE" vartype="Decimal"/>
|
221
|
+
</outcomes>
|
222
|
+
<respcondition continue="No">
|
223
|
+
<conditionvar>
|
224
|
+
<varequal respident="response1">Red</varequal>
|
225
|
+
</conditionvar>
|
226
|
+
<setvar action="Set" varname="SCORE">100</setvar>
|
227
|
+
</respcondition>
|
228
|
+
</resprocessing>
|
229
|
+
</item>
|
230
|
+
<item ident="i8c4f92444b901b000087b00d84c3e36c" title="FIB Numeric (Decimal)">
|
231
|
+
<presentation>
|
232
|
+
<material>
|
233
|
+
<mattext texttype="text/html">Give the value of PI to three decimal places and round up.</mattext>
|
234
|
+
</material>
|
235
|
+
<response_num ident="response1" rcardinality="Single">
|
236
|
+
<render_fib>
|
237
|
+
<response_label ident="answer1" rshuffle="No"/>
|
238
|
+
</render_fib>
|
239
|
+
</response_num>
|
240
|
+
</presentation>
|
241
|
+
<resprocessing>
|
242
|
+
<outcomes>
|
243
|
+
<decvar maxvalue="100" minvalue="0" varname="SCORE" vartype="Decimal"/>
|
244
|
+
</outcomes>
|
245
|
+
<respcondition continue="No">
|
246
|
+
<conditionvar>
|
247
|
+
<varequal respident="response1">3.142</varequal>
|
248
|
+
</conditionvar>
|
249
|
+
<setvar action="Set" varname="SCORE">100</setvar>
|
250
|
+
</respcondition>
|
251
|
+
</resprocessing>
|
252
|
+
</item>
|
207
253
|
</section>
|
208
254
|
</assessment>
|
209
255
|
</questestinterop>
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Qti::V1::Models::Choices::FillBlankChoice do
|
4
|
+
context 'fib.xml' do
|
5
|
+
let(:fixtures_path) { File.join('spec', 'fixtures') }
|
6
|
+
let(:file_path) { File.join(fixtures_path, 'items_1.2', 'fib.xml') }
|
7
|
+
let(:test_object) { Qti::V1::Models::Assessment.from_path!(file_path) }
|
8
|
+
let(:nodes) { test_object.assessment_items }
|
9
|
+
let(:choices) { nodes.map { |node| described_class.new(node) } }
|
10
|
+
|
11
|
+
it 'returns the right identifier' do
|
12
|
+
expect(choices.map(&:identifier)).to eq %w(FIB_STR)
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'returns the item body text' do
|
16
|
+
expect(choices.map(&:item_body).map(&:empty?).any?).to eq false
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'removes inline feedback elements from item_body' do
|
20
|
+
expect(choices.map(&:item_body).map { |text| text.include? 'correct' }.any?).to eq false
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -3,7 +3,7 @@ require 'spec_helper'
|
|
3
3
|
describe Qti::V1::Models::Choices::LogicalIdentifierChoice do
|
4
4
|
context 'quiz.xml' do
|
5
5
|
let(:fixtures_path) { File.join('spec', 'fixtures') }
|
6
|
-
let(:file_path) { File.join(fixtures_path, '
|
6
|
+
let(:file_path) { File.join(fixtures_path, 'items_1.2', 'choice.xml') }
|
7
7
|
let(:test_object) { Qti::V1::Models::Assessment.from_path!(file_path) }
|
8
8
|
let(:nodes) { test_object.assessment_items }
|
9
9
|
let(:choices) { nodes.map { |node| described_class.new(node) } }
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Qti::V1::Models::Interactions::FillBlankInteraction do
|
4
|
+
let(:fixtures_path) { File.join('spec', 'fixtures', 'items_1.2') }
|
5
|
+
let(:test_object) { Qti::V1::Models::Assessment.from_path!(file_path) }
|
6
|
+
let(:assessment_item_refs) { test_object.assessment_items }
|
7
|
+
let(:loaded_class) { described_class.new(assessment_item_refs.first) }
|
8
|
+
|
9
|
+
shared_examples_for 'shuffled?' do
|
10
|
+
it 'returns shuffle setting' do
|
11
|
+
expect(loaded_class.shuffled?).to eq shuffle_value
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
shared_examples_for 'blanks' do
|
16
|
+
it 'returns the blanks' do
|
17
|
+
expect(loaded_class.blanks).to eq [{ id: "FIB01" }, { id: "FIB02" }, { id: "FIB03" }]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
shared_examples_for 'answers' do
|
22
|
+
it 'returns the answers' do
|
23
|
+
expect(loaded_class.answers.count).to eq answer_count
|
24
|
+
expect(loaded_class.answers.first).to be_an_instance_of(Qti::V1::Models::Choices::FillBlankChoice)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
shared_examples_for 'scoring_data_structs' do
|
29
|
+
it 'returns the scoring_data_structs' do
|
30
|
+
expect(loaded_class.scoring_data_structs.map(&:id)).to eq(scoring_data_ids)
|
31
|
+
expect(loaded_class.scoring_data_structs.map(&:values)).to eq(scoring_data_values)
|
32
|
+
expect(loaded_class.scoring_data_structs.map(&:case)).to eq(scoring_data_case)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
shared_examples_for 'stem_items' do
|
37
|
+
it 'returns the stem_items' do
|
38
|
+
expect(loaded_class.stem_items).to eq(expected_stem_items)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
context 'fib_str.xml' do
|
43
|
+
let(:file_path) { File.join(fixtures_path, 'fib_str.xml') }
|
44
|
+
let(:shuffle_value) { false }
|
45
|
+
let(:scoring_data_ids) { %w(FIB01 FIB02 FIB03) }
|
46
|
+
let(:scoring_data_values) { %w(Winter Summer York) }
|
47
|
+
let(:scoring_data_case) { %w(Yes Yes Yes) }
|
48
|
+
let(:answer_count) { 3 }
|
49
|
+
let(:expected_stem_items) {[
|
50
|
+
{ id: "stem_0", position: 1, type: "text", value: "Fill-in-the blanks in this text from Richard III: " },
|
51
|
+
{ id: "stem_1", position: 2, type: "text", value: "Now is the " },
|
52
|
+
{ id: "stem_2", position: 3, type: "blank", blank_id: "FIB01" },
|
53
|
+
{ id: "stem_3", position: 4, type: "text", value: " of our discontent made glorious " },
|
54
|
+
{ id: "stem_4", position: 5, type: "blank", blank_id: "FIB02" },
|
55
|
+
{ id: "stem_5", position: 6, type: "text", value: " by these sons of " },
|
56
|
+
{ id: "stem_6", position: 7, type: "blank", blank_id: "FIB03" }
|
57
|
+
]}
|
58
|
+
|
59
|
+
include_examples 'shuffled?'
|
60
|
+
include_examples 'answers'
|
61
|
+
include_examples 'scoring_data_structs'
|
62
|
+
include_examples 'stem_items'
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Qti::V1::Models::Interactions::StringInteraction do
|
4
|
+
let(:fixtures_path) { File.join('spec', 'fixtures', 'items_1.2') }
|
5
|
+
let(:test_object) { Qti::V1::Models::Assessment.from_path!(file_path) }
|
6
|
+
let(:assessment_item_refs) { test_object.assessment_items }
|
7
|
+
let(:loaded_class) { described_class.new(assessment_item_refs.first) }
|
8
|
+
|
9
|
+
context 'essay.xml' do
|
10
|
+
let(:file_path) { File.join(fixtures_path, 'essay.xml') }
|
11
|
+
let(:cardinality) { 'Single' }
|
12
|
+
|
13
|
+
it 'returns loads the correct cardinality' do
|
14
|
+
expect(loaded_class.send(:rcardinality)).to eq(cardinality)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/spec/lib/qti_spec.rb
CHANGED
@@ -30,9 +30,9 @@ describe Qti::Importer do
|
|
30
30
|
it 'create items with correct scoring structs' do
|
31
31
|
assessment = importer.test_object
|
32
32
|
assessment_items = importer.assessment_item_refs.map{ |ref| importer.create_assessment_item(ref) }
|
33
|
-
expect(assessment_items.count).to eq
|
33
|
+
expect(assessment_items.count).to eq 5
|
34
34
|
answer_arity = assessment_items.map{|item| item.scoring_data_structs.count }
|
35
|
-
expect(answer_arity).to eq [1, 1, 4]
|
35
|
+
expect(answer_arity).to eq [1, 1, 4, 1, 1]
|
36
36
|
end
|
37
37
|
end
|
38
38
|
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: 0.
|
4
|
+
version: 0.3.16
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Hannah Bottalla
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2017-
|
12
|
+
date: 2017-05-03 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activesupport
|
@@ -205,10 +205,12 @@ files:
|
|
205
205
|
- lib/qti/v1/models/assessment.rb
|
206
206
|
- lib/qti/v1/models/assessment_item.rb
|
207
207
|
- lib/qti/v1/models/base.rb
|
208
|
+
- lib/qti/v1/models/choices/fill_blank_choice.rb
|
208
209
|
- lib/qti/v1/models/choices/logical_identifier_choice.rb
|
209
210
|
- lib/qti/v1/models/interactions.rb
|
210
211
|
- lib/qti/v1/models/interactions/base_interaction.rb
|
211
212
|
- lib/qti/v1/models/interactions/choice_interaction.rb
|
213
|
+
- lib/qti/v1/models/interactions/fill_blank_interaction.rb
|
212
214
|
- lib/qti/v1/models/interactions/match_interaction.rb
|
213
215
|
- lib/qti/v1/models/interactions/ordering_interaction.rb
|
214
216
|
- lib/qti/v1/models/interactions/string_interaction.rb
|
@@ -216,14 +218,20 @@ files:
|
|
216
218
|
- lib/qti/v2/models/assessment_item.rb
|
217
219
|
- lib/qti/v2/models/assessment_test.rb
|
218
220
|
- lib/qti/v2/models/base.rb
|
221
|
+
- lib/qti/v2/models/choices/gap_match_choice.rb
|
219
222
|
- lib/qti/v2/models/choices/simple_associable_choice.rb
|
220
223
|
- lib/qti/v2/models/choices/simple_choice.rb
|
221
224
|
- lib/qti/v2/models/interactions.rb
|
222
225
|
- lib/qti/v2/models/interactions/base_interaction.rb
|
223
226
|
- lib/qti/v2/models/interactions/choice_interaction.rb
|
224
227
|
- lib/qti/v2/models/interactions/extended_text_interaction.rb
|
228
|
+
- lib/qti/v2/models/interactions/gap_match_interaction.rb
|
225
229
|
- lib/qti/v2/models/interactions/match_interaction.rb
|
226
230
|
- lib/qti/v2/models/scoring_data.rb
|
231
|
+
- spec/fixtures/items_1.2/choice.xml
|
232
|
+
- spec/fixtures/items_1.2/essay.xml
|
233
|
+
- spec/fixtures/items_1.2/fib.xml
|
234
|
+
- spec/fixtures/items_1.2/fib_str.xml
|
227
235
|
- spec/fixtures/items_1.2/matching.xml
|
228
236
|
- spec/fixtures/items_1.2/multiple_answer.xml
|
229
237
|
- spec/fixtures/items_1.2/multiple_choice.xml
|
@@ -409,8 +417,11 @@ files:
|
|
409
417
|
- spec/lib/qti/models/manifest_spec.rb
|
410
418
|
- spec/lib/qti/v1/models/assessment_item_spec.rb
|
411
419
|
- spec/lib/qti/v1/models/assessment_spec.rb
|
420
|
+
- spec/lib/qti/v1/models/choices/fill_blank_choice_spec.rb
|
412
421
|
- spec/lib/qti/v1/models/choices/logical_identifier_choice_spec.rb
|
413
422
|
- spec/lib/qti/v1/models/interactions/choice_interaction_spec.rb
|
423
|
+
- spec/lib/qti/v1/models/interactions/fill_blank_interaction_spec.rb
|
424
|
+
- spec/lib/qti/v1/models/interactions/string_interaction_spec.rb
|
414
425
|
- spec/lib/qti/v2/models/assessment_item_spec.rb
|
415
426
|
- spec/lib/qti/v2/models/assessment_test_spec.rb
|
416
427
|
- spec/lib/qti/v2/models/choices/simple_choice_spec.rb
|
@@ -444,6 +455,10 @@ signing_key:
|
|
444
455
|
specification_version: 4
|
445
456
|
summary: QTI 1.2 and 2.1 import and export models
|
446
457
|
test_files:
|
458
|
+
- spec/fixtures/items_1.2/choice.xml
|
459
|
+
- spec/fixtures/items_1.2/essay.xml
|
460
|
+
- spec/fixtures/items_1.2/fib.xml
|
461
|
+
- spec/fixtures/items_1.2/fib_str.xml
|
447
462
|
- spec/fixtures/items_1.2/matching.xml
|
448
463
|
- spec/fixtures/items_1.2/multiple_answer.xml
|
449
464
|
- spec/fixtures/items_1.2/multiple_choice.xml
|
@@ -629,8 +644,11 @@ test_files:
|
|
629
644
|
- spec/lib/qti/models/manifest_spec.rb
|
630
645
|
- spec/lib/qti/v1/models/assessment_item_spec.rb
|
631
646
|
- spec/lib/qti/v1/models/assessment_spec.rb
|
647
|
+
- spec/lib/qti/v1/models/choices/fill_blank_choice_spec.rb
|
632
648
|
- spec/lib/qti/v1/models/choices/logical_identifier_choice_spec.rb
|
633
649
|
- spec/lib/qti/v1/models/interactions/choice_interaction_spec.rb
|
650
|
+
- spec/lib/qti/v1/models/interactions/fill_blank_interaction_spec.rb
|
651
|
+
- spec/lib/qti/v1/models/interactions/string_interaction_spec.rb
|
634
652
|
- spec/lib/qti/v2/models/assessment_item_spec.rb
|
635
653
|
- spec/lib/qti/v2/models/assessment_test_spec.rb
|
636
654
|
- spec/lib/qti/v2/models/choices/simple_choice_spec.rb
|