qti 0.9.12 → 0.9.13
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/models/base.rb +1 -1
- data/lib/qti/models/manifest.rb +6 -6
- data/lib/qti/v1/models/interactions.rb +3 -3
- data/lib/qti/v1/models/interactions/base_fill_blank_interaction.rb +49 -0
- data/lib/qti/v1/models/interactions/base_interaction.rb +1 -1
- data/lib/qti/v1/models/interactions/canvas_multiple_dropdown.rb +84 -0
- data/lib/qti/v1/models/interactions/fill_blank_interaction.rb +21 -53
- data/lib/qti/v1/models/interactions/formula_interaction.rb +5 -7
- data/lib/qti/v1/models/interactions/upload_interaction.rb +34 -0
- data/lib/qti/version.rb +1 -1
- data/spec/fixtures/items_1.2/canvas_multiple_dropdown.xml +167 -0
- data/spec/fixtures/items_1.2/canvas_multiple_dropdowns.xml +167 -0
- data/spec/fixtures/items_1.2/upload.xml +34 -0
- data/spec/gemfiles/nokogiri-1.8.gemfile.lock +4 -4
- data/spec/lib/qti/v1/models/interactions/canvas_multiple_dropdown_spec.rb +106 -0
- data/spec/lib/qti/v1/models/interactions/fill_blank_interaction_spec.rb +6 -6
- data/spec/lib/qti/v1/models/interactions/formula_interaction_spec.rb +14 -10
- data/spec/lib/qti/v1/models/interactions/upload_interaction_spec.rb +32 -0
- data/spec/lib/qti/v1/models/numerics/precision_spec.rb +4 -8
- data/spec/lib/qti/v2/models/assessment_item_spec.rb +2 -0
- data/spec/lib/qti/v2/models/assessment_test_spec.rb +2 -0
- data/spec/lib/qti/v2/models/non_assessment_test_spec.rb +0 -2
- data/spec/lib/qti/v2/models/stimulus_item_spec.rb +4 -0
- metadata +15 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a8a20f28fe6f8aeded9fd3282dccc970983a3234
|
4
|
+
data.tar.gz: 054ff6d10ef0da8fbde0e8b583ed40eb9f49b2e6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f0ba4fa3e613ee9bcf93afd69f02ce855688f1849e5613cfd224a706cc6f556b99fac43048b2cf6769bd66dcee03a9cf8db31615edae3a3d8c0c51b82d4b982b
|
7
|
+
data.tar.gz: 5df6efce6e7f3d33b1934752075c251bd9c43aafce275ada3c5f177cf858f2e587bff5223aef40b0d29d03ecc1872262453cac2b90f45d098314b2fed6db7124
|
data/lib/qti/models/base.rb
CHANGED
@@ -74,7 +74,7 @@ module Qti
|
|
74
74
|
nodes.each do |node|
|
75
75
|
# convert all #160 space to regular #32 whitespace
|
76
76
|
# latex parser won't work for #160 space
|
77
|
-
text = node.text.
|
77
|
+
text = node.text.tr("\u00a0", ' ')
|
78
78
|
latex_string = " \\(#{text}\\) "
|
79
79
|
node.replace(latex_string)
|
80
80
|
end
|
data/lib/qti/models/manifest.rb
CHANGED
@@ -10,8 +10,8 @@ module Qti
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def qti_1_href
|
13
|
-
test_path = xmlns_resource(
|
14
|
-
xmlns_resource(
|
13
|
+
test_path = xmlns_resource('[@type="imsqti_xmlv1p2"]/@href') ||
|
14
|
+
xmlns_resource('[@type="imsqti_xmlv1p2"]/xmlns:file/@href')
|
15
15
|
return unless test_path
|
16
16
|
Qti::V1::Models::Assessment.from_path!(
|
17
17
|
remap_href_path(test_path), @package_root
|
@@ -19,8 +19,8 @@ module Qti
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def qti_2_x_href
|
22
|
-
test_path = xmlns_resource(
|
23
|
-
xmlns_resource(
|
22
|
+
test_path = xmlns_resource('[@type="imsqti_test_xmlv2p1"]/@href') ||
|
23
|
+
xmlns_resource('[@type="imsqti_test_xmlv2p2"]/@href')
|
24
24
|
return unless test_path
|
25
25
|
Qti::V2::Models::AssessmentTest.from_path!(
|
26
26
|
remap_href_path(test_path), @package_root
|
@@ -29,8 +29,8 @@ module Qti
|
|
29
29
|
|
30
30
|
def qti_2_non_assessment_href
|
31
31
|
Qti::V2::Models::NonAssessmentTest.from_path!(@path, @package_root) if
|
32
|
-
xmlns_resource_count(
|
33
|
-
xmlns_resource_count(
|
32
|
+
xmlns_resource_count('[@type="imsqti_item_xmlv2p1"]/@href').positive? ||
|
33
|
+
xmlns_resource_count('[@type="imsqti_item_xmlv2p2"]/@href').positive?
|
34
34
|
end
|
35
35
|
|
36
36
|
def unknown_type
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require 'active_support/core_ext/hash/except'
|
2
2
|
# Populate the subclasses
|
3
3
|
Dir["#{__dir__}/interactions/*.rb"].each { |f| load f }
|
4
4
|
|
@@ -8,8 +8,8 @@ module Qti
|
|
8
8
|
module Interactions
|
9
9
|
# This one finds the correct parsing model based on the provided xml node
|
10
10
|
def self.interaction_model(node, parent)
|
11
|
-
ordered_classes = [ FormulaInteraction, NumericInteraction
|
12
|
-
ordered_classes.each do |
|
11
|
+
ordered_classes = [CanvasMultipleDropdownInteraction, FormulaInteraction, NumericInteraction]
|
12
|
+
ordered_classes.each do |interaction_class|
|
13
13
|
match = interaction_class.matches(node, parent)
|
14
14
|
return match if match
|
15
15
|
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Qti
|
2
|
+
module V1
|
3
|
+
module Models
|
4
|
+
module Interactions
|
5
|
+
class BaseFillBlankInteraction < BaseInteraction
|
6
|
+
CANVAS_REGEX = /(\[.+?\])/
|
7
|
+
|
8
|
+
def canvas_stem_items(item_prompt)
|
9
|
+
item_prompt.split(CANVAS_REGEX).map.with_index do |stem_item, index|
|
10
|
+
if stem_item.match CANVAS_REGEX
|
11
|
+
stem_blank(index, canvas_blank_id(stem_item))
|
12
|
+
else
|
13
|
+
stem_text(index, stem_item)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def stem_blank(index, value)
|
19
|
+
{
|
20
|
+
id: "stem_#{index}",
|
21
|
+
position: index + 1,
|
22
|
+
type: 'blank',
|
23
|
+
blank_id: value
|
24
|
+
}
|
25
|
+
end
|
26
|
+
|
27
|
+
def stem_text(index, value)
|
28
|
+
{
|
29
|
+
id: "stem_#{index}",
|
30
|
+
position: index + 1,
|
31
|
+
type: 'text',
|
32
|
+
value: value
|
33
|
+
}
|
34
|
+
end
|
35
|
+
|
36
|
+
def canvas_blank_id(stem_item)
|
37
|
+
blank_id = nil
|
38
|
+
node.xpath('.//xmlns:response_lid').children.map do |response_lid_node|
|
39
|
+
if stem_item.include?(response_lid_node.text)
|
40
|
+
blank_id = response_lid_node.parent.attributes['ident']&.value
|
41
|
+
end
|
42
|
+
end
|
43
|
+
blank_id
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -12,7 +12,7 @@ module Qti
|
|
12
12
|
def self.canvas_multiple_fib?(node)
|
13
13
|
matches = node.xpath('.//xmlns:response_lid')
|
14
14
|
return false if matches.count <= 1
|
15
|
-
node.at_xpath('.//xmlns:fieldentry').text ==
|
15
|
+
node.at_xpath('.//xmlns:fieldentry').text == 'fill_in_multiple_blanks_question'
|
16
16
|
end
|
17
17
|
|
18
18
|
def initialize(node, parent)
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module Qti
|
2
|
+
module V1
|
3
|
+
module Models
|
4
|
+
module Interactions
|
5
|
+
class CanvasMultipleDropdownInteraction < BaseFillBlankInteraction
|
6
|
+
# This will know if a class matches
|
7
|
+
def self.matches(node, parent)
|
8
|
+
field_entry = node.xpath('.//xmlns:fieldentry')[0]
|
9
|
+
return false unless field_entry&.text == 'multiple_dropdowns_question'
|
10
|
+
new(node, parent)
|
11
|
+
end
|
12
|
+
|
13
|
+
def stem_items
|
14
|
+
canvas_stem_items(node.at_xpath('.//xmlns:presentation/xmlns:material/xmlns:mattext').text)
|
15
|
+
end
|
16
|
+
|
17
|
+
def blanks
|
18
|
+
@blanks = node.xpath('.//xmlns:response_lid').map do |resp|
|
19
|
+
index = 0
|
20
|
+
{
|
21
|
+
id: resp[:ident],
|
22
|
+
choices:
|
23
|
+
resp.xpath('.//xmlns:response_label').map do |bnode|
|
24
|
+
blank_choice(bnode, index += 1)
|
25
|
+
end
|
26
|
+
}
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def scoring_data_structs
|
31
|
+
answers.map do |answer|
|
32
|
+
ScoringData.new(
|
33
|
+
{
|
34
|
+
id: answer[:entry_id],
|
35
|
+
position: position_for_entry(answer[:entry_id]),
|
36
|
+
item_body: answer[:blank_text]
|
37
|
+
},
|
38
|
+
rcardinality,
|
39
|
+
id: answer[:value]
|
40
|
+
)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def text_for_entry(entry_id)
|
45
|
+
blanks
|
46
|
+
@blank_choices[entry_id][:item_body]
|
47
|
+
end
|
48
|
+
|
49
|
+
def position_for_entry(entry_id)
|
50
|
+
blanks
|
51
|
+
@blank_choices[entry_id][:position]
|
52
|
+
end
|
53
|
+
|
54
|
+
def answers
|
55
|
+
@node.xpath('.//xmlns:respcondition/xmlns:setvar[@varname="SCORE"]').map do |points|
|
56
|
+
entry = points.at_xpath('preceding-sibling::xmlns:conditionvar/xmlns:varequal')
|
57
|
+
{
|
58
|
+
value: entry[:respident],
|
59
|
+
entry_id: entry.text,
|
60
|
+
blank_text: text_for_entry(entry.text),
|
61
|
+
action: points[:action],
|
62
|
+
point_value: points.text
|
63
|
+
}
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
def blank_choice(bnode, index)
|
70
|
+
bnode_id = bnode[:ident]
|
71
|
+
choice = {
|
72
|
+
id: bnode_id,
|
73
|
+
position: index + 1,
|
74
|
+
item_body: bnode.at_xpath('.//xmlns:mattext').text
|
75
|
+
}
|
76
|
+
@blank_choices ||= {}
|
77
|
+
@blank_choices[bnode_id] = choice
|
78
|
+
choice
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -2,19 +2,19 @@ module Qti
|
|
2
2
|
module V1
|
3
3
|
module Models
|
4
4
|
module Interactions
|
5
|
-
class FillBlankInteraction <
|
6
|
-
CANVAS_REGEX = /(\[.+?\])
|
5
|
+
class FillBlankInteraction < BaseFillBlankInteraction
|
6
|
+
CANVAS_REGEX = /(\[.+?\])/
|
7
7
|
|
8
8
|
# This will know if a class matches
|
9
9
|
def self.matches(node, parent)
|
10
10
|
return false if node.at_xpath('.//xmlns:other').present?
|
11
11
|
match = if BaseInteraction.canvas_multiple_fib?(node)
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
12
|
+
node.at_xpath('.//xmlns:response_lid')
|
13
|
+
else
|
14
|
+
node.at_xpath('.//xmlns:render_fib')
|
15
|
+
end
|
16
16
|
return false if match.blank? ||
|
17
|
-
|
17
|
+
match.attributes['fibtype']&.value == 'Decimal'
|
18
18
|
new(node, parent)
|
19
19
|
end
|
20
20
|
|
@@ -24,59 +24,19 @@ module Qti
|
|
24
24
|
|
25
25
|
def stem_items
|
26
26
|
if canvas_multiple_fib?
|
27
|
-
canvas_stem_items
|
27
|
+
canvas_stem_items(node.at_xpath('.//xmlns:mattext').text)
|
28
28
|
else
|
29
29
|
qti_stem_items
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
33
|
-
def canvas_stem_items
|
34
|
-
@response_lid_nodes = node.xpath('.//xmlns:response_lid')
|
35
|
-
item_prompt = node.at_xpath('.//xmlns:mattext').text
|
36
|
-
item_prompt_words = item_prompt.split(CANVAS_REGEX)
|
37
|
-
item_prompt_words.map.with_index do |stem_item, index|
|
38
|
-
if stem_item.match CANVAS_REGEX
|
39
|
-
@response_lid_nodes.children.map do |response_lid_node|
|
40
|
-
if stem_item.include?(response_lid_node.text)
|
41
|
-
@blank_id = response_lid_node.parent.attributes['ident']&.value
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
{
|
46
|
-
id: "stem_#{index}",
|
47
|
-
position: index + 1,
|
48
|
-
type: 'blank',
|
49
|
-
blank_id: @blank_id
|
50
|
-
}
|
51
|
-
else
|
52
|
-
{
|
53
|
-
id: "stem_#{index}",
|
54
|
-
position: index + 1,
|
55
|
-
type: 'text',
|
56
|
-
value: stem_item
|
57
|
-
}
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
|
63
33
|
def qti_stem_items
|
64
34
|
stem_item_nodes = node.xpath('.//xmlns:presentation').children
|
65
35
|
stem_item_nodes.map.with_index do |stem_item, index|
|
66
36
|
if stem_item.xpath('./xmlns:render_fib').present?
|
67
|
-
|
68
|
-
id: "stem_#{index}",
|
69
|
-
position: index + 1,
|
70
|
-
type: 'blank',
|
71
|
-
blank_id: stem_item.attributes['ident'].value
|
72
|
-
}
|
37
|
+
stem_blank(index, stem_item.attributes['ident'].value)
|
73
38
|
else
|
74
|
-
|
75
|
-
id: "stem_#{index}",
|
76
|
-
position: index + 1,
|
77
|
-
type: 'text',
|
78
|
-
value: stem_item.children.text
|
79
|
-
}
|
39
|
+
stem_text(index, stem_item.children.text)
|
80
40
|
end
|
81
41
|
end
|
82
42
|
end
|
@@ -116,9 +76,9 @@ module Qti
|
|
116
76
|
ScoringData.new(
|
117
77
|
value_node.content,
|
118
78
|
rcardinality,
|
119
|
-
id: value_node
|
120
|
-
case: value_node
|
121
|
-
parent_identifier: value_node.parent.parent.attributes['ident']&.value
|
79
|
+
id: scoring_data_id(value_node),
|
80
|
+
case: scoring_data_case(value_node),
|
81
|
+
parent_identifier: value_node.parent.parent.attributes['ident']&.value
|
122
82
|
)
|
123
83
|
end
|
124
84
|
end
|
@@ -137,6 +97,14 @@ module Qti
|
|
137
97
|
@node.xpath('.//xmlns:varequal')
|
138
98
|
end
|
139
99
|
end
|
100
|
+
|
101
|
+
def scoring_data_id(node)
|
102
|
+
node.attributes['respident']&.value || node.attributes['ident']&.value
|
103
|
+
end
|
104
|
+
|
105
|
+
def scoring_data_case(node)
|
106
|
+
node.attributes['case']&.value || 'no'
|
107
|
+
end
|
140
108
|
end
|
141
109
|
end
|
142
110
|
end
|
@@ -15,7 +15,7 @@ module Qti
|
|
15
15
|
ScoringData.new(
|
16
16
|
answer[:output],
|
17
17
|
rcardinality,
|
18
|
-
|
18
|
+
id: answer[:id]
|
19
19
|
)
|
20
20
|
end
|
21
21
|
end
|
@@ -46,10 +46,10 @@ module Qti
|
|
46
46
|
end
|
47
47
|
|
48
48
|
def margin_of_error
|
49
|
-
if answer_tolerance.ends_with?
|
50
|
-
return {margin: answer_tolerance[0..-2], margin_type:'percent'}
|
49
|
+
if answer_tolerance.ends_with? '%'
|
50
|
+
return { margin: answer_tolerance[0..-2], margin_type: 'percent' }
|
51
51
|
end
|
52
|
-
{margin: answer_tolerance, margin_type:'absolute'}
|
52
|
+
{ margin: answer_tolerance, margin_type: 'absolute' }
|
53
53
|
end
|
54
54
|
|
55
55
|
def formula_decimal_places
|
@@ -57,9 +57,7 @@ module Qti
|
|
57
57
|
end
|
58
58
|
|
59
59
|
def formulas
|
60
|
-
node.xpath('.//xmlns:formula').map
|
61
|
-
fnode.text
|
62
|
-
end
|
60
|
+
node.xpath('.//xmlns:formula').map(&:text)
|
63
61
|
end
|
64
62
|
|
65
63
|
private
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Qti
|
2
|
+
module V1
|
3
|
+
module Models
|
4
|
+
module Interactions
|
5
|
+
class UploadInteraction < BaseInteraction
|
6
|
+
# This will know if a class matches
|
7
|
+
def self.matches(node, parent)
|
8
|
+
meta_node = node.at_xpath(
|
9
|
+
'.//xmlns:qtimetadatafield[./xmlns:fieldlabel/text()="question_type"]'
|
10
|
+
)
|
11
|
+
return false unless meta_node.present?
|
12
|
+
type_node = meta_node.at_xpath('.//xmlns:fieldentry')
|
13
|
+
return false unless type_node&.text() == 'file_upload_question'
|
14
|
+
new(node, parent)
|
15
|
+
end
|
16
|
+
|
17
|
+
def item_body
|
18
|
+
@item_body ||= begin
|
19
|
+
node = @node.dup
|
20
|
+
presentation = node.at_xpath('.//xmlns:presentation')
|
21
|
+
mattext = presentation.at_xpath('.//xmlns:mattext')
|
22
|
+
inner_content = return_inner_content!(mattext)
|
23
|
+
sanitize_content!(inner_content)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def scoring_data_structs
|
28
|
+
{ value: '' }
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/lib/qti/version.rb
CHANGED
@@ -0,0 +1,167 @@
|
|
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
|
+
<assessment ident="ie797010092a6c1798006e216ba4c9c90" title="Multiple Drop Down">
|
4
|
+
<qtimetadata>
|
5
|
+
<qtimetadatafield>
|
6
|
+
<fieldlabel>cc_maxattempts</fieldlabel>
|
7
|
+
<fieldentry>1</fieldentry>
|
8
|
+
</qtimetadatafield>
|
9
|
+
</qtimetadata>
|
10
|
+
<section ident="root_section">
|
11
|
+
<item ident="id9d8b63d85a03f2987646622805b61cf" title="Question">
|
12
|
+
<itemmetadata>
|
13
|
+
<qtimetadata>
|
14
|
+
<qtimetadatafield>
|
15
|
+
<fieldlabel>question_type</fieldlabel>
|
16
|
+
<fieldentry>multiple_dropdowns_question</fieldentry>
|
17
|
+
</qtimetadatafield>
|
18
|
+
<qtimetadatafield>
|
19
|
+
<fieldlabel>points_possible</fieldlabel>
|
20
|
+
<fieldentry>1.0</fieldentry>
|
21
|
+
</qtimetadatafield>
|
22
|
+
<qtimetadatafield>
|
23
|
+
<fieldlabel>assessment_question_identifierref</fieldlabel>
|
24
|
+
<fieldentry>i7ad7f9841cc58f0a1392816b78aaa878</fieldentry>
|
25
|
+
</qtimetadatafield>
|
26
|
+
</qtimetadata>
|
27
|
+
</itemmetadata>
|
28
|
+
<presentation>
|
29
|
+
<material>
|
30
|
+
<mattext texttype="text/html"><div><p>Roses are [color1], violets are [color2].</p></div></mattext>
|
31
|
+
</material>
|
32
|
+
<response_lid ident="response_color1">
|
33
|
+
<material>
|
34
|
+
<mattext>color1</mattext>
|
35
|
+
</material>
|
36
|
+
<render_choice>
|
37
|
+
<response_label ident="6548">
|
38
|
+
<material>
|
39
|
+
<mattext texttype="text/plain">red</mattext>
|
40
|
+
</material>
|
41
|
+
</response_label>
|
42
|
+
<response_label ident="5550">
|
43
|
+
<material>
|
44
|
+
<mattext texttype="text/plain">plaid</mattext>
|
45
|
+
</material>
|
46
|
+
</response_label>
|
47
|
+
</render_choice>
|
48
|
+
</response_lid>
|
49
|
+
<response_lid ident="response_color2">
|
50
|
+
<material>
|
51
|
+
<mattext>color2</mattext>
|
52
|
+
</material>
|
53
|
+
<render_choice>
|
54
|
+
<response_label ident="6951">
|
55
|
+
<material>
|
56
|
+
<mattext texttype="text/plain">blue</mattext>
|
57
|
+
</material>
|
58
|
+
</response_label>
|
59
|
+
<response_label ident="4500">
|
60
|
+
<material>
|
61
|
+
<mattext texttype="text/plain">paisely</mattext>
|
62
|
+
</material>
|
63
|
+
</response_label>
|
64
|
+
</render_choice>
|
65
|
+
</response_lid>
|
66
|
+
</presentation>
|
67
|
+
<resprocessing>
|
68
|
+
<outcomes>
|
69
|
+
<decvar maxvalue="100" minvalue="0" varname="SCORE" vartype="Decimal"/>
|
70
|
+
</outcomes>
|
71
|
+
<respcondition continue="Yes">
|
72
|
+
<conditionvar>
|
73
|
+
<other/>
|
74
|
+
</conditionvar>
|
75
|
+
<displayfeedback feedbacktype="Response" linkrefid="general_fb"/>
|
76
|
+
</respcondition>
|
77
|
+
<respcondition continue="Yes">
|
78
|
+
<conditionvar>
|
79
|
+
<varequal respident="response_color1">6548</varequal>
|
80
|
+
</conditionvar>
|
81
|
+
<displayfeedback feedbacktype="Response" linkrefid="6548_fb"/>
|
82
|
+
</respcondition>
|
83
|
+
<respcondition continue="Yes">
|
84
|
+
<conditionvar>
|
85
|
+
<varequal respident="response_color1">5550</varequal>
|
86
|
+
</conditionvar>
|
87
|
+
<displayfeedback feedbacktype="Response" linkrefid="5550_fb"/>
|
88
|
+
</respcondition>
|
89
|
+
<respcondition continue="Yes">
|
90
|
+
<conditionvar>
|
91
|
+
<varequal respident="response_color2">6951</varequal>
|
92
|
+
</conditionvar>
|
93
|
+
<displayfeedback feedbacktype="Response" linkrefid="6951_fb"/>
|
94
|
+
</respcondition>
|
95
|
+
<respcondition continue="Yes">
|
96
|
+
<conditionvar>
|
97
|
+
<varequal respident="response_color2">4500</varequal>
|
98
|
+
</conditionvar>
|
99
|
+
<displayfeedback feedbacktype="Response" linkrefid="4500_fb"/>
|
100
|
+
</respcondition>
|
101
|
+
<respcondition>
|
102
|
+
<conditionvar>
|
103
|
+
<varequal respident="response_color1">6548</varequal>
|
104
|
+
</conditionvar>
|
105
|
+
<setvar varname="SCORE" action="Add">50.00</setvar>
|
106
|
+
</respcondition>
|
107
|
+
<respcondition>
|
108
|
+
<conditionvar>
|
109
|
+
<varequal respident="response_color2">6951</varequal>
|
110
|
+
</conditionvar>
|
111
|
+
<setvar varname="SCORE" action="Add">50.00</setvar>
|
112
|
+
</respcondition>
|
113
|
+
</resprocessing>
|
114
|
+
<itemfeedback ident="general_fb">
|
115
|
+
<flow_mat>
|
116
|
+
<material>
|
117
|
+
<mattext texttype="text/html"><p>Roses come in many colors, violets probably do too.</p>
|
118
|
+
<p>Never the less, the correct answers were <strong>red</strong> and <strong>blue</strong>.</p></mattext>
|
119
|
+
</material>
|
120
|
+
</flow_mat>
|
121
|
+
</itemfeedback>
|
122
|
+
<itemfeedback ident="correct_fb">
|
123
|
+
<flow_mat>
|
124
|
+
<material>
|
125
|
+
<mattext texttype="text/html"><p>Completing the poem, is left to you.</p></mattext>
|
126
|
+
</material>
|
127
|
+
</flow_mat>
|
128
|
+
</itemfeedback>
|
129
|
+
<itemfeedback ident="general_incorrect_fb">
|
130
|
+
<flow_mat>
|
131
|
+
<material>
|
132
|
+
<mattext texttype="text/html"><p>Those aren't colors, you meant <strong>red</strong> and <strong>blue</strong>.</p></mattext>
|
133
|
+
</material>
|
134
|
+
</flow_mat>
|
135
|
+
</itemfeedback>
|
136
|
+
<itemfeedback ident="6548_fb">
|
137
|
+
<flow_mat>
|
138
|
+
<material>
|
139
|
+
<mattext texttype="text/html"><p>Yes! <strong>Red</strong>.</p></mattext>
|
140
|
+
</material>
|
141
|
+
</flow_mat>
|
142
|
+
</itemfeedback>
|
143
|
+
<itemfeedback ident="5550_fb">
|
144
|
+
<flow_mat>
|
145
|
+
<material>
|
146
|
+
<mattext texttype="text/html"><p>I'm pretty sure you meant <strong>red.</strong></p></mattext>
|
147
|
+
</material>
|
148
|
+
</flow_mat>
|
149
|
+
</itemfeedback>
|
150
|
+
<itemfeedback ident="6951_fb">
|
151
|
+
<flow_mat>
|
152
|
+
<material>
|
153
|
+
<mattext texttype="text/html"><p>Yes, <strong>blue</strong>!</p></mattext>
|
154
|
+
</material>
|
155
|
+
</flow_mat>
|
156
|
+
</itemfeedback>
|
157
|
+
<itemfeedback ident="4500_fb">
|
158
|
+
<flow_mat>
|
159
|
+
<material>
|
160
|
+
<mattext texttype="text/html"><p>Did you also chose plaid? You wanted to <strong>blue</strong>.</p></mattext>
|
161
|
+
</material>
|
162
|
+
</flow_mat>
|
163
|
+
</itemfeedback>
|
164
|
+
</item>
|
165
|
+
</section>
|
166
|
+
</assessment>
|
167
|
+
</questestinterop>
|
@@ -0,0 +1,167 @@
|
|
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
|
+
<assessment ident="ie797010092a6c1798006e216ba4c9c90" title="Multiple Drop Down">
|
4
|
+
<qtimetadata>
|
5
|
+
<qtimetadatafield>
|
6
|
+
<fieldlabel>cc_maxattempts</fieldlabel>
|
7
|
+
<fieldentry>1</fieldentry>
|
8
|
+
</qtimetadatafield>
|
9
|
+
</qtimetadata>
|
10
|
+
<section ident="root_section">
|
11
|
+
<item ident="id9d8b63d85a03f2987646622805b61cf" title="Question">
|
12
|
+
<itemmetadata>
|
13
|
+
<qtimetadata>
|
14
|
+
<qtimetadatafield>
|
15
|
+
<fieldlabel>question_type</fieldlabel>
|
16
|
+
<fieldentry>multiple_dropdowns_question</fieldentry>
|
17
|
+
</qtimetadatafield>
|
18
|
+
<qtimetadatafield>
|
19
|
+
<fieldlabel>points_possible</fieldlabel>
|
20
|
+
<fieldentry>1.0</fieldentry>
|
21
|
+
</qtimetadatafield>
|
22
|
+
<qtimetadatafield>
|
23
|
+
<fieldlabel>assessment_question_identifierref</fieldlabel>
|
24
|
+
<fieldentry>i7ad7f9841cc58f0a1392816b78aaa878</fieldentry>
|
25
|
+
</qtimetadatafield>
|
26
|
+
</qtimetadata>
|
27
|
+
</itemmetadata>
|
28
|
+
<presentation>
|
29
|
+
<material>
|
30
|
+
<mattext texttype="text/html"><div><p>Roses are [color1], violets are [color2].</p></div></mattext>
|
31
|
+
</material>
|
32
|
+
<response_lid ident="response_color1">
|
33
|
+
<material>
|
34
|
+
<mattext>color1</mattext>
|
35
|
+
</material>
|
36
|
+
<render_choice>
|
37
|
+
<response_label ident="6548">
|
38
|
+
<material>
|
39
|
+
<mattext texttype="text/plain">red</mattext>
|
40
|
+
</material>
|
41
|
+
</response_label>
|
42
|
+
<response_label ident="5550">
|
43
|
+
<material>
|
44
|
+
<mattext texttype="text/plain">plaid</mattext>
|
45
|
+
</material>
|
46
|
+
</response_label>
|
47
|
+
</render_choice>
|
48
|
+
</response_lid>
|
49
|
+
<response_lid ident="response_color2">
|
50
|
+
<material>
|
51
|
+
<mattext>color2</mattext>
|
52
|
+
</material>
|
53
|
+
<render_choice>
|
54
|
+
<response_label ident="6951">
|
55
|
+
<material>
|
56
|
+
<mattext texttype="text/plain">blue</mattext>
|
57
|
+
</material>
|
58
|
+
</response_label>
|
59
|
+
<response_label ident="4500">
|
60
|
+
<material>
|
61
|
+
<mattext texttype="text/plain">paisely</mattext>
|
62
|
+
</material>
|
63
|
+
</response_label>
|
64
|
+
</render_choice>
|
65
|
+
</response_lid>
|
66
|
+
</presentation>
|
67
|
+
<resprocessing>
|
68
|
+
<outcomes>
|
69
|
+
<decvar maxvalue="100" minvalue="0" varname="SCORE" vartype="Decimal"/>
|
70
|
+
</outcomes>
|
71
|
+
<respcondition continue="Yes">
|
72
|
+
<conditionvar>
|
73
|
+
<other/>
|
74
|
+
</conditionvar>
|
75
|
+
<displayfeedback feedbacktype="Response" linkrefid="general_fb"/>
|
76
|
+
</respcondition>
|
77
|
+
<respcondition continue="Yes">
|
78
|
+
<conditionvar>
|
79
|
+
<varequal respident="response_color1">6548</varequal>
|
80
|
+
</conditionvar>
|
81
|
+
<displayfeedback feedbacktype="Response" linkrefid="6548_fb"/>
|
82
|
+
</respcondition>
|
83
|
+
<respcondition continue="Yes">
|
84
|
+
<conditionvar>
|
85
|
+
<varequal respident="response_color1">5550</varequal>
|
86
|
+
</conditionvar>
|
87
|
+
<displayfeedback feedbacktype="Response" linkrefid="5550_fb"/>
|
88
|
+
</respcondition>
|
89
|
+
<respcondition continue="Yes">
|
90
|
+
<conditionvar>
|
91
|
+
<varequal respident="response_color2">6951</varequal>
|
92
|
+
</conditionvar>
|
93
|
+
<displayfeedback feedbacktype="Response" linkrefid="6951_fb"/>
|
94
|
+
</respcondition>
|
95
|
+
<respcondition continue="Yes">
|
96
|
+
<conditionvar>
|
97
|
+
<varequal respident="response_color2">4500</varequal>
|
98
|
+
</conditionvar>
|
99
|
+
<displayfeedback feedbacktype="Response" linkrefid="4500_fb"/>
|
100
|
+
</respcondition>
|
101
|
+
<respcondition>
|
102
|
+
<conditionvar>
|
103
|
+
<varequal respident="response_color1">6548</varequal>
|
104
|
+
</conditionvar>
|
105
|
+
<setvar varname="SCORE" action="Add">50.00</setvar>
|
106
|
+
</respcondition>
|
107
|
+
<respcondition>
|
108
|
+
<conditionvar>
|
109
|
+
<varequal respident="response_color2">6951</varequal>
|
110
|
+
</conditionvar>
|
111
|
+
<setvar varname="SCORE" action="Add">50.00</setvar>
|
112
|
+
</respcondition>
|
113
|
+
</resprocessing>
|
114
|
+
<itemfeedback ident="general_fb">
|
115
|
+
<flow_mat>
|
116
|
+
<material>
|
117
|
+
<mattext texttype="text/html"><p>Roses come in many colors, violets probably do too.</p>
|
118
|
+
<p>Never the less, the correct answers were <strong>red</strong> and <strong>blue</strong>.</p></mattext>
|
119
|
+
</material>
|
120
|
+
</flow_mat>
|
121
|
+
</itemfeedback>
|
122
|
+
<itemfeedback ident="correct_fb">
|
123
|
+
<flow_mat>
|
124
|
+
<material>
|
125
|
+
<mattext texttype="text/html"><p>Completing the poem, is left to you.</p></mattext>
|
126
|
+
</material>
|
127
|
+
</flow_mat>
|
128
|
+
</itemfeedback>
|
129
|
+
<itemfeedback ident="general_incorrect_fb">
|
130
|
+
<flow_mat>
|
131
|
+
<material>
|
132
|
+
<mattext texttype="text/html"><p>Those aren't colors, you meant <strong>red</strong> and <strong>blue</strong>.</p></mattext>
|
133
|
+
</material>
|
134
|
+
</flow_mat>
|
135
|
+
</itemfeedback>
|
136
|
+
<itemfeedback ident="6548_fb">
|
137
|
+
<flow_mat>
|
138
|
+
<material>
|
139
|
+
<mattext texttype="text/html"><p>Yes! <strong>Red</strong>.</p></mattext>
|
140
|
+
</material>
|
141
|
+
</flow_mat>
|
142
|
+
</itemfeedback>
|
143
|
+
<itemfeedback ident="5550_fb">
|
144
|
+
<flow_mat>
|
145
|
+
<material>
|
146
|
+
<mattext texttype="text/html"><p>I'm pretty sure you meant <strong>red.</strong></p></mattext>
|
147
|
+
</material>
|
148
|
+
</flow_mat>
|
149
|
+
</itemfeedback>
|
150
|
+
<itemfeedback ident="6951_fb">
|
151
|
+
<flow_mat>
|
152
|
+
<material>
|
153
|
+
<mattext texttype="text/html"><p>Yes, <strong>blue</strong>!</p></mattext>
|
154
|
+
</material>
|
155
|
+
</flow_mat>
|
156
|
+
</itemfeedback>
|
157
|
+
<itemfeedback ident="4500_fb">
|
158
|
+
<flow_mat>
|
159
|
+
<material>
|
160
|
+
<mattext texttype="text/html"><p>Did you also chose plaid? You wanted to <strong>blue</strong>.</p></mattext>
|
161
|
+
</material>
|
162
|
+
</flow_mat>
|
163
|
+
</itemfeedback>
|
164
|
+
</item>
|
165
|
+
</section>
|
166
|
+
</assessment>
|
167
|
+
</questestinterop>
|
@@ -0,0 +1,34 @@
|
|
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
|
+
<qtimetadata>
|
4
|
+
<qtimetadatafield>
|
5
|
+
<fieldlabel>cc_maxattempts</fieldlabel>
|
6
|
+
<fieldentry>1</fieldentry>
|
7
|
+
</qtimetadatafield>
|
8
|
+
</qtimetadata>
|
9
|
+
<section ident="root_section">
|
10
|
+
<item ident="i53d46f6a4edbfcefd662489e9f2a970a" title="Question">
|
11
|
+
<itemmetadata>
|
12
|
+
<qtimetadata>
|
13
|
+
<qtimetadatafield>
|
14
|
+
<fieldlabel>question_type</fieldlabel>
|
15
|
+
<fieldentry>file_upload_question</fieldentry>
|
16
|
+
</qtimetadatafield>
|
17
|
+
<qtimetadatafield>
|
18
|
+
<fieldlabel>points_possible</fieldlabel>
|
19
|
+
<fieldentry>1.0</fieldentry>
|
20
|
+
</qtimetadatafield>
|
21
|
+
<qtimetadatafield>
|
22
|
+
<fieldlabel>assessment_question_identifierref</fieldlabel>
|
23
|
+
<fieldentry>i2b5557c31dcad5441b956ebb83d06915</fieldentry>
|
24
|
+
</qtimetadatafield>
|
25
|
+
</qtimetadata>
|
26
|
+
</itemmetadata>
|
27
|
+
<presentation>
|
28
|
+
<material>
|
29
|
+
<mattext texttype="text/html">Upload a file that is a CSV</mattext>
|
30
|
+
</material>
|
31
|
+
</presentation>
|
32
|
+
</item>
|
33
|
+
</section>
|
34
|
+
</questestinterop>
|
@@ -1,7 +1,10 @@
|
|
1
1
|
PATH
|
2
2
|
remote: ../..
|
3
3
|
specs:
|
4
|
-
|
4
|
+
mathml2latex (0.1.2)
|
5
|
+
activesupport (>= 4.2.9, < 5.2)
|
6
|
+
nokogiri (>= 1.6.8)
|
7
|
+
qti (0.9.13)
|
5
8
|
actionview (>= 4.2.0)
|
6
9
|
activesupport (>= 4.2.9, < 5.2)
|
7
10
|
dry-struct (~> 0.2.1)
|
@@ -67,9 +70,6 @@ GEM
|
|
67
70
|
loofah (2.2.2)
|
68
71
|
crass (~> 1.0.2)
|
69
72
|
nokogiri (>= 1.5.9)
|
70
|
-
mathml2latex (0.1.1)
|
71
|
-
activesupport (>= 4.2.9, < 5.2)
|
72
|
-
nokogiri (~> 1.8)
|
73
73
|
method_source (0.9.0)
|
74
74
|
mini_portile2 (2.3.0)
|
75
75
|
minitest (5.11.3)
|
@@ -0,0 +1,106 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Qti::V1::Models::Interactions::CanvasMultipleDropdownInteraction 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, test_object) }
|
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(expected_blanks)
|
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).to eq(expected_answers)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
shared_examples_for 'stem_items' do
|
29
|
+
it 'returns the stem_items' do
|
30
|
+
expect(loaded_class.stem_items).to eq(expected_stem_items)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
shared_examples_for 'scoring_data_structs' do
|
35
|
+
it 'returns the scoring_data_structs' do
|
36
|
+
expect(loaded_class.scoring_data_structs.map(&:id)).to eq(scoring_data_ids)
|
37
|
+
expect(loaded_class.scoring_data_structs.map(&:values)).to eq(scoring_data_values)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
context 'canvas_multiple_dropdowns.xml' do
|
42
|
+
let(:file_path) { File.join(fixtures_path, 'canvas_multiple_dropdowns.xml') }
|
43
|
+
let(:shuffle_value) { false }
|
44
|
+
let(:answer_count) { 2 }
|
45
|
+
let(:scoring_data_ids) { %w[response_color1 response_color2] }
|
46
|
+
let(:scoring_data_values) do
|
47
|
+
[
|
48
|
+
{ id: '6548', position: 2, item_body: 'red' },
|
49
|
+
{ id: '6951', position: 2, item_body: 'blue' }
|
50
|
+
]
|
51
|
+
end
|
52
|
+
let(:expected_blanks) do
|
53
|
+
[
|
54
|
+
{
|
55
|
+
id: 'response_color1',
|
56
|
+
choices:
|
57
|
+
[
|
58
|
+
{ id: '6548', position: 2, item_body: 'red' },
|
59
|
+
{ id: '5550', position: 3, item_body: 'plaid' }
|
60
|
+
]
|
61
|
+
},
|
62
|
+
{
|
63
|
+
id: 'response_color2',
|
64
|
+
choices:
|
65
|
+
[
|
66
|
+
{ id: '6951', position: 2, item_body: 'blue' },
|
67
|
+
{ id: '4500', position: 3, item_body: 'paisely' }
|
68
|
+
]
|
69
|
+
}
|
70
|
+
]
|
71
|
+
end
|
72
|
+
let(:expected_stem_items) do
|
73
|
+
[
|
74
|
+
{ id: 'stem_0', position: 1, type: 'text', value: '<div><p>Roses are ' },
|
75
|
+
{ id: 'stem_1', position: 2, type: 'blank', blank_id: 'response_color1' },
|
76
|
+
{ id: 'stem_2', position: 3, type: 'text', value: ', violets are ' },
|
77
|
+
{ id: 'stem_3', position: 4, type: 'blank', blank_id: 'response_color2' },
|
78
|
+
{ id: 'stem_4', position: 5, type: 'text', value: '.</p></div>' }
|
79
|
+
]
|
80
|
+
end
|
81
|
+
let('expected_answers') do
|
82
|
+
[
|
83
|
+
{
|
84
|
+
value: 'response_color1',
|
85
|
+
entry_id: '6548',
|
86
|
+
blank_text: 'red',
|
87
|
+
action: 'Add',
|
88
|
+
point_value: '50.00'
|
89
|
+
},
|
90
|
+
{
|
91
|
+
value: 'response_color2',
|
92
|
+
entry_id: '6951',
|
93
|
+
blank_text: 'blue',
|
94
|
+
action: 'Add',
|
95
|
+
point_value: '50.00'
|
96
|
+
}
|
97
|
+
]
|
98
|
+
end
|
99
|
+
|
100
|
+
include_examples 'shuffled?'
|
101
|
+
include_examples 'answers'
|
102
|
+
include_examples 'blanks'
|
103
|
+
include_examples 'stem_items'
|
104
|
+
include_examples 'scoring_data_structs'
|
105
|
+
end
|
106
|
+
end
|
@@ -45,11 +45,11 @@ describe Qti::V1::Models::Interactions::FillBlankInteraction do
|
|
45
45
|
let(:scoring_data_values) { %w[Illinois illinois] }
|
46
46
|
let(:scoring_data_case) { %w[no no] }
|
47
47
|
let(:answer_count) { 2 }
|
48
|
-
let(:expected_blanks) {[{ id: 'response1' }]}
|
48
|
+
let(:expected_blanks) { [{ id: 'response1' }] }
|
49
49
|
let(:expected_stem_items) do
|
50
50
|
[
|
51
|
-
{:
|
52
|
-
{:
|
51
|
+
{ id: 'stem_0', position: 1, type: 'text', value: '<div><p>Chicago is in what state?</p></div>' },
|
52
|
+
{ id: 'stem_1', position: 2, type: 'blank', blank_id: 'response1' }
|
53
53
|
]
|
54
54
|
end
|
55
55
|
|
@@ -70,14 +70,14 @@ describe Qti::V1::Models::Interactions::FillBlankInteraction do
|
|
70
70
|
let(:scoring_data_values) { %w[red Red blue Blue] }
|
71
71
|
let(:scoring_data_case) { %w[no no no no] }
|
72
72
|
let(:answer_count) { 4 }
|
73
|
-
let(:expected_blanks) {[{id: '9799'}, {id: '5231'}, {id: '5939'}, {id: '6364'}]}
|
73
|
+
let(:expected_blanks) { [{ id: '9799' }, { id: '5231' }, { id: '5939' }, { id: '6364' }] }
|
74
74
|
let(:expected_stem_items) do
|
75
75
|
[
|
76
76
|
{ id: 'stem_0', position: 1, type: 'text', value: '<div><p><span>Roses are ' },
|
77
77
|
{ id: 'stem_1', position: 2, type: 'blank', blank_id: 'response_color1' },
|
78
78
|
{ id: 'stem_2', position: 3, type: 'text', value: ', violets are ' },
|
79
79
|
{ id: 'stem_3', position: 4, type: 'blank', blank_id: 'response_color2' },
|
80
|
-
{ id:
|
80
|
+
{ id: 'stem_4', position: 5, type: 'text', value: '</span></p></div>' }
|
81
81
|
]
|
82
82
|
end
|
83
83
|
|
@@ -99,7 +99,7 @@ describe Qti::V1::Models::Interactions::FillBlankInteraction do
|
|
99
99
|
let(:scoring_data_values) { %w[Winter Summer York] }
|
100
100
|
let(:scoring_data_case) { %w[Yes Yes Yes] }
|
101
101
|
let(:answer_count) { 3 }
|
102
|
-
let(:expected_blanks) {[{ id: 'FIB01' }, { id: 'FIB02' }, { id: 'FIB03' }]}
|
102
|
+
let(:expected_blanks) { [{ id: 'FIB01' }, { id: 'FIB02' }, { id: 'FIB03' }] }
|
103
103
|
let(:expected_stem_items) do
|
104
104
|
[
|
105
105
|
{ id: 'stem_0', position: 1, type: 'text', value: 'Fill-in-the blanks in this text from Richard III: ' },
|
@@ -45,9 +45,9 @@ describe Qti::V1::Models::Interactions::FormulaInteraction do
|
|
45
45
|
let(:formula_decimal_places) { '0' }
|
46
46
|
let(:formula_formulas) { ['x'] }
|
47
47
|
|
48
|
-
let(:item_title) {'<div><p>What number is [x]</p></div>'}
|
48
|
+
let(:item_title) { '<div><p>What number is [x]</p></div>' }
|
49
49
|
|
50
|
-
let(:variables) { [
|
50
|
+
let(:variables) { [{ name: 'x', min: '1.0', max: '10.0', precision: '0' }] }
|
51
51
|
|
52
52
|
include_examples 'scoring_data_structs'
|
53
53
|
include_examples 'reading_formulas'
|
@@ -65,10 +65,12 @@ describe Qti::V1::Models::Interactions::FormulaInteraction do
|
|
65
65
|
let(:formula_decimal_places) { '0' }
|
66
66
|
let(:formula_formulas) { ['x+y'] }
|
67
67
|
|
68
|
-
let(:item_title) {'<div><p>[x] + [y]</p></div>'}
|
68
|
+
let(:item_title) { '<div><p>[x] + [y]</p></div>' }
|
69
69
|
|
70
|
-
let(:variables)
|
71
|
-
|
70
|
+
let(:variables) do
|
71
|
+
[{ name: 'x', min: '1.0', max: '10.0', precision: '0' },
|
72
|
+
{ name: 'y', min: '1.0', max: '10.0', precision: '0' }]
|
73
|
+
end
|
72
74
|
|
73
75
|
include_examples 'scoring_data_structs'
|
74
76
|
include_examples 'answer_tolerance'
|
@@ -86,12 +88,14 @@ describe Qti::V1::Models::Interactions::FormulaInteraction do
|
|
86
88
|
let(:formula_decimal_places) { '2' }
|
87
89
|
let(:formula_formulas) { ['x=n*x', 'y=m*y', 'x+y'] }
|
88
90
|
|
89
|
-
let(:item_title) {'<div><p>[n][x] + [m][y]</p></div>'}
|
91
|
+
let(:item_title) { '<div><p>[n][x] + [m][y]</p></div>' }
|
90
92
|
|
91
|
-
let(:variables)
|
92
|
-
|
93
|
-
|
94
|
-
|
93
|
+
let(:variables) do
|
94
|
+
[{ name: 'y', min: '1.0', max: '10.0', precision: '2' },
|
95
|
+
{ name: 'x', min: '1.0', max: '10.0', precision: '2' },
|
96
|
+
{ name: 'n', min: '1.0', max: '10.0', precision: '2' },
|
97
|
+
{ name: 'm', min: '1.0', max: '10.0', precision: '2' }]
|
98
|
+
end
|
95
99
|
|
96
100
|
include_examples 'scoring_data_structs'
|
97
101
|
include_examples 'answer_tolerance'
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Qti::V1::Models::Interactions::UploadInteraction 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, test_object) }
|
8
|
+
|
9
|
+
context 'upload.xml' do
|
10
|
+
let(:file_path) { File.join(fixtures_path, 'upload.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
|
+
|
17
|
+
context '#item_body' do
|
18
|
+
let(:loaded_class) { described_class.new(assessment_item_refs.first, test_object) }
|
19
|
+
it 'returns right title' do
|
20
|
+
expect(loaded_class.item_body).to eq 'Upload a file that is a CSV'
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe '#scoring_data_structs' do
|
25
|
+
it 'grabs scoring data value for matching questions' do
|
26
|
+
expect(loaded_class.scoring_data_structs).to eq(
|
27
|
+
value: ''
|
28
|
+
)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -71,18 +71,14 @@ describe Qti::V1::Models::Numerics::Precision do
|
|
71
71
|
|
72
72
|
context '#significant_digits' do
|
73
73
|
it 'returns correct number for leading zeros' do
|
74
|
-
expect(described_class.significant_digits('0.0000123')).
|
75
|
-
to eq(3)
|
74
|
+
expect(described_class.significant_digits('0.0000123')).to eq(3)
|
76
75
|
end
|
77
76
|
it 'returns correct number for trailing zeros' do
|
78
|
-
expect(described_class.significant_digits('0.0000123000')).
|
79
|
-
to eq(3)
|
77
|
+
expect(described_class.significant_digits('0.0000123000')).to eq(3)
|
80
78
|
end
|
81
79
|
it 'returns correct number for zeros in the middle' do
|
82
|
-
expect(described_class.significant_digits('0.000012003')).
|
83
|
-
|
84
|
-
expect(described_class.significant_digits('15.000012003')).
|
85
|
-
to eq(11)
|
80
|
+
expect(described_class.significant_digits('0.000012003')).to eq(5)
|
81
|
+
expect(described_class.significant_digits('15.000012003')).to eq(11)
|
86
82
|
end
|
87
83
|
end
|
88
84
|
end
|
@@ -86,7 +86,9 @@ describe Qti::V2::Models::AssessmentItem do
|
|
86
86
|
|
87
87
|
# it 'removes the passage from the item_body' do
|
88
88
|
# item = test_object.create_assessment_item(item_ref)
|
89
|
+
# rubocop:disable AsciiComments
|
89
90
|
# expect(item.item_body).not_to include '¡El equipo de hockey te necesita!'
|
91
|
+
# rubocop:enable AsciiComments
|
90
92
|
# end
|
91
93
|
# end
|
92
94
|
end
|
@@ -86,7 +86,9 @@ describe Qti::V2::Models::AssessmentTest do
|
|
86
86
|
# 'passages', '0cfd5cf7-2c91-4b35-a57a-9f5d1709f68f.html'
|
87
87
|
# )
|
88
88
|
# stimulus = loaded_class.create_stimulus(stimulus_path)
|
89
|
+
# rubocop:disable AsciiComments
|
89
90
|
# expect(stimulus.title).to eq '¡El equipo de hockey te necesita!'
|
91
|
+
# rubocop:enable AsciiComments
|
90
92
|
# end
|
91
93
|
# end
|
92
94
|
end
|
@@ -13,13 +13,17 @@
|
|
13
13
|
# end
|
14
14
|
|
15
15
|
# it 'has the title' do
|
16
|
+
# rubocop:disable AsciiComments
|
16
17
|
# expect(loaded_class.title).to eq '¡El equipo de hockey te necesita!'
|
18
|
+
# rubocop:enable AsciiComments
|
17
19
|
# end
|
18
20
|
|
19
21
|
# it 'has sanitized item_body' do
|
20
22
|
# expect(loaded_class.body).to include '<div'
|
21
23
|
# expect(loaded_class.body).to include 'Listen to the audio passage.'
|
24
|
+
# rubocop:disable AsciiComments
|
22
25
|
# expect(loaded_class.body).to include '¡'
|
26
|
+
# rubocop:enable AsciiComments
|
23
27
|
# end
|
24
28
|
|
25
29
|
# it 'has the identifier used to identify it in manifest file' do
|
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.9.
|
4
|
+
version: 0.9.13
|
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: 2018-04-
|
12
|
+
date: 2018-04-16 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activesupport
|
@@ -296,7 +296,9 @@ files:
|
|
296
296
|
- lib/qti/v1/models/choices/fill_blank_choice.rb
|
297
297
|
- lib/qti/v1/models/choices/logical_identifier_choice.rb
|
298
298
|
- lib/qti/v1/models/interactions.rb
|
299
|
+
- lib/qti/v1/models/interactions/base_fill_blank_interaction.rb
|
299
300
|
- lib/qti/v1/models/interactions/base_interaction.rb
|
301
|
+
- lib/qti/v1/models/interactions/canvas_multiple_dropdown.rb
|
300
302
|
- lib/qti/v1/models/interactions/choice_interaction.rb
|
301
303
|
- lib/qti/v1/models/interactions/fill_blank_interaction.rb
|
302
304
|
- lib/qti/v1/models/interactions/formula_interaction.rb
|
@@ -304,6 +306,7 @@ files:
|
|
304
306
|
- lib/qti/v1/models/interactions/numeric_interaction.rb
|
305
307
|
- lib/qti/v1/models/interactions/ordering_interaction.rb
|
306
308
|
- lib/qti/v1/models/interactions/string_interaction.rb
|
309
|
+
- lib/qti/v1/models/interactions/upload_interaction.rb
|
307
310
|
- lib/qti/v1/models/numerics/exact_match.rb
|
308
311
|
- lib/qti/v1/models/numerics/margin_error.rb
|
309
312
|
- lib/qti/v1/models/numerics/precision.rb
|
@@ -333,6 +336,8 @@ files:
|
|
333
336
|
- lib/qti/v2/models/scoring_data.rb
|
334
337
|
- lib/qti/v2/models/stimulus_item.rb
|
335
338
|
- lib/qti/version.rb
|
339
|
+
- spec/fixtures/items_1.2/canvas_multiple_dropdown.xml
|
340
|
+
- spec/fixtures/items_1.2/canvas_multiple_dropdowns.xml
|
336
341
|
- spec/fixtures/items_1.2/canvas_multiple_fib.xml
|
337
342
|
- spec/fixtures/items_1.2/choice.xml
|
338
343
|
- spec/fixtures/items_1.2/essay.xml
|
@@ -352,6 +357,7 @@ files:
|
|
352
357
|
- spec/fixtures/items_1.2/ordering.xml
|
353
358
|
- spec/fixtures/items_1.2/single_fib.xml
|
354
359
|
- spec/fixtures/items_1.2/true_false.xml
|
360
|
+
- spec/fixtures/items_1.2/upload.xml
|
355
361
|
- spec/fixtures/items_2.1/Example02-feedbackInline.xml
|
356
362
|
- spec/fixtures/items_2.1/categorization.xml
|
357
363
|
- spec/fixtures/items_2.1/choice.xml
|
@@ -570,6 +576,7 @@ files:
|
|
570
576
|
- spec/lib/qti/v1/models/choices/fill_blank_choice_spec.rb
|
571
577
|
- spec/lib/qti/v1/models/choices/logical_identifier_choice_spec.rb
|
572
578
|
- spec/lib/qti/v1/models/interactions/base_interaction_spec.rb
|
579
|
+
- spec/lib/qti/v1/models/interactions/canvas_multiple_dropdown_spec.rb
|
573
580
|
- spec/lib/qti/v1/models/interactions/choice_interaction_spec.rb
|
574
581
|
- spec/lib/qti/v1/models/interactions/fill_blank_interaction_spec.rb
|
575
582
|
- spec/lib/qti/v1/models/interactions/formula_interaction_spec.rb
|
@@ -577,6 +584,7 @@ files:
|
|
577
584
|
- spec/lib/qti/v1/models/interactions/numeric_interaction_spec.rb
|
578
585
|
- spec/lib/qti/v1/models/interactions/ordering_interaction_spec.rb
|
579
586
|
- spec/lib/qti/v1/models/interactions/string_interaction_spec.rb
|
587
|
+
- spec/lib/qti/v1/models/interactions/upload_interaction_spec.rb
|
580
588
|
- spec/lib/qti/v1/models/numerics/exact_match_spec.rb
|
581
589
|
- spec/lib/qti/v1/models/numerics/margin_error_spec.rb
|
582
590
|
- spec/lib/qti/v1/models/numerics/precision_spec.rb
|
@@ -626,6 +634,8 @@ signing_key:
|
|
626
634
|
specification_version: 4
|
627
635
|
summary: QTI 1.2 and 2.1 import and export models
|
628
636
|
test_files:
|
637
|
+
- spec/fixtures/items_1.2/canvas_multiple_dropdown.xml
|
638
|
+
- spec/fixtures/items_1.2/canvas_multiple_dropdowns.xml
|
629
639
|
- spec/fixtures/items_1.2/canvas_multiple_fib.xml
|
630
640
|
- spec/fixtures/items_1.2/choice.xml
|
631
641
|
- spec/fixtures/items_1.2/essay.xml
|
@@ -645,6 +655,7 @@ test_files:
|
|
645
655
|
- spec/fixtures/items_1.2/ordering.xml
|
646
656
|
- spec/fixtures/items_1.2/single_fib.xml
|
647
657
|
- spec/fixtures/items_1.2/true_false.xml
|
658
|
+
- spec/fixtures/items_1.2/upload.xml
|
648
659
|
- spec/fixtures/items_2.1/Example02-feedbackInline.xml
|
649
660
|
- spec/fixtures/items_2.1/categorization.xml
|
650
661
|
- spec/fixtures/items_2.1/choice.xml
|
@@ -863,6 +874,7 @@ test_files:
|
|
863
874
|
- spec/lib/qti/v1/models/choices/fill_blank_choice_spec.rb
|
864
875
|
- spec/lib/qti/v1/models/choices/logical_identifier_choice_spec.rb
|
865
876
|
- spec/lib/qti/v1/models/interactions/base_interaction_spec.rb
|
877
|
+
- spec/lib/qti/v1/models/interactions/canvas_multiple_dropdown_spec.rb
|
866
878
|
- spec/lib/qti/v1/models/interactions/choice_interaction_spec.rb
|
867
879
|
- spec/lib/qti/v1/models/interactions/fill_blank_interaction_spec.rb
|
868
880
|
- spec/lib/qti/v1/models/interactions/formula_interaction_spec.rb
|
@@ -870,6 +882,7 @@ test_files:
|
|
870
882
|
- spec/lib/qti/v1/models/interactions/numeric_interaction_spec.rb
|
871
883
|
- spec/lib/qti/v1/models/interactions/ordering_interaction_spec.rb
|
872
884
|
- spec/lib/qti/v1/models/interactions/string_interaction_spec.rb
|
885
|
+
- spec/lib/qti/v1/models/interactions/upload_interaction_spec.rb
|
873
886
|
- spec/lib/qti/v1/models/numerics/exact_match_spec.rb
|
874
887
|
- spec/lib/qti/v1/models/numerics/margin_error_spec.rb
|
875
888
|
- spec/lib/qti/v1/models/numerics/precision_spec.rb
|