qti 2.15.4 → 2.16.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/interactions/hot_spot_interaction.rb +71 -0
- data/lib/qti/v1/models/interactions.rb +2 -1
- data/lib/qti/version.rb +1 -1
- data/lib/qti.rb +1 -0
- data/spec/fixtures/items_1.2/hot_spot.xml +124 -0
- data/spec/lib/qti/v1/models/interactions/hot_spot_interaction_spec.rb +57 -0
- metadata +7 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c06cc4e78f29ecb23354e39dc3e93ac5da9600f0b09284a59b1202c553eb0c93
|
4
|
+
data.tar.gz: b91ded981174a7822c7b6756f69e4a30daf5c6845f004a9a05da4a3f23a6af28
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: afcb1b453f47cec30c61b8d56d0a80109b6660a9f71b1e863db23cf8a3f6f79095dffd1512dad87554ba316d512574391dfe1f87da8c4bfa4efbbe74f95fcd2f
|
7
|
+
data.tar.gz: a5acbfc53c6508b9d50e795435476b9aa72e32390f739697fd319dc4e4777037db4f7af5b70acbdc698fadcc5e0251af22e2ea7907cbf5b5ee8a3bed298a0b4b
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module Qti
|
2
|
+
module V1
|
3
|
+
module Models
|
4
|
+
module Interactions
|
5
|
+
class HotSpotInteraction < BaseInteraction
|
6
|
+
def self.matches(node, parent)
|
7
|
+
presentation = node.at_xpath('.//xmlns:presentation')
|
8
|
+
return false unless presentation
|
9
|
+
xy_responses = presentation.xpath('.//xmlns:response_xy')
|
10
|
+
return false unless xy_responses.count.positive?
|
11
|
+
new(node, parent)
|
12
|
+
end
|
13
|
+
|
14
|
+
def item_body
|
15
|
+
@item_body ||= begin
|
16
|
+
node = @node.dup
|
17
|
+
presentation = node.at_xpath('.//xmlns:presentation')
|
18
|
+
mattext = presentation.at_xpath('.//xmlns:mattext')
|
19
|
+
inner_content = return_inner_content!(mattext)
|
20
|
+
sanitize_content!(inner_content)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def image_url
|
25
|
+
@image_url ||= begin
|
26
|
+
node = @node.dup
|
27
|
+
presentation = node.at_xpath('.//xmlns:presentation')
|
28
|
+
matimage = presentation.at_xpath('.//xmlns:matimage')
|
29
|
+
matimage&.attributes&.[]('uri')&.value
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def shape_type
|
34
|
+
@shape_type ||= response_label&.attributes&.[]('rarea')&.value
|
35
|
+
end
|
36
|
+
|
37
|
+
def coordinates
|
38
|
+
@coordinates ||= begin
|
39
|
+
raw_coordinates_array = raw_coordinates.split(',')
|
40
|
+
return [] unless (raw_coordinates_array.length % 2).zero?
|
41
|
+
|
42
|
+
raw_coordinates_array.each_slice(2).map do |point|
|
43
|
+
{ x: point[0].to_f, y: point[1].to_f }
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def response_label
|
51
|
+
@response_label ||= begin
|
52
|
+
node = @node.dup
|
53
|
+
presentation = node.at_xpath('.//xmlns:presentation')
|
54
|
+
presentation.at_xpath('.//xmlns:response_label')
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def raw_coordinates
|
59
|
+
@raw_coordinates ||= response_label&.text || ''
|
60
|
+
end
|
61
|
+
|
62
|
+
def coordinate_hash(coordinate_node)
|
63
|
+
%w[x y].map do |axis|
|
64
|
+
[axis.to_sym, coordinate_node&.attributes&.[](axis)&.value&.to_f]
|
65
|
+
end.to_h
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -16,7 +16,8 @@ module Qti
|
|
16
16
|
'numerical_question' => NumericInteraction,
|
17
17
|
'calculated_question' => FormulaInteraction,
|
18
18
|
'essay_question ' => StringInteraction,
|
19
|
-
'file_upload_question' => UploadInteraction
|
19
|
+
'file_upload_question' => UploadInteraction,
|
20
|
+
'hot_spot_question' => HotSpotInteraction
|
20
21
|
# "text_only_question" => StimulusNoQuestion
|
21
22
|
}.freeze
|
22
23
|
|
data/lib/qti/version.rb
CHANGED
data/lib/qti.rb
CHANGED
@@ -125,6 +125,7 @@ require 'qti/v1/models/interactions/base_fill_blank_interaction'
|
|
125
125
|
require 'qti/v1/models/interactions/canvas_multiple_dropdown'
|
126
126
|
require 'qti/v1/models/interactions/fill_blank_interaction'
|
127
127
|
require 'qti/v1/models/interactions/formula_interaction'
|
128
|
+
require 'qti/v1/models/interactions/hot_spot_interaction'
|
128
129
|
require 'qti/v1/models/interactions/match_interaction'
|
129
130
|
require 'qti/v1/models/interactions/numeric_interaction'
|
130
131
|
require 'qti/v1/models/interactions/ordering_interaction'
|
@@ -0,0 +1,124 @@
|
|
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="id2b817165c302c0c57416146dc94ce47" title="Quiz with hot-spot question">
|
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="g515255148f5a3cae1832584071aa8528" title="this is a hot-spot question">
|
12
|
+
<itemmetadata>
|
13
|
+
<qtimetadata>
|
14
|
+
<qtimetadatafield>
|
15
|
+
<fieldlabel>question_type</fieldlabel>
|
16
|
+
<fieldentry>hot_spot_question</fieldentry>
|
17
|
+
</qtimetadatafield>
|
18
|
+
<qtimetadatafield>
|
19
|
+
<fieldlabel>points_possible</fieldlabel>
|
20
|
+
<fieldentry>1.0</fieldentry>
|
21
|
+
</qtimetadatafield>
|
22
|
+
<qtimetadatafield>
|
23
|
+
<fieldlabel>original_answer_ids</fieldlabel>
|
24
|
+
<fieldentry/>
|
25
|
+
</qtimetadatafield>
|
26
|
+
<qtimetadatafield>
|
27
|
+
<fieldlabel>assessment_question_identifierref</fieldlabel>
|
28
|
+
<fieldentry>gd6ff15355f3dd3f532816fa268230130</fieldentry>
|
29
|
+
</qtimetadatafield>
|
30
|
+
</qtimetadata>
|
31
|
+
</itemmetadata>
|
32
|
+
<presentation>
|
33
|
+
<flow>
|
34
|
+
<response_xy ident="response1" rcardinality="Single" rtiming="No">
|
35
|
+
<material>
|
36
|
+
<mattext texttype="text/html"><p>point something on the image</p></mattext>
|
37
|
+
</material>
|
38
|
+
<render_hotspot>
|
39
|
+
<material>
|
40
|
+
<matimage uri="$IMS-CC-FILEBASE$/Uploaded Media/someuuid"/>
|
41
|
+
</material>
|
42
|
+
<response_label ident="response1" rarea="square">0.372,0.1376,0.616,0.4256</response_label>
|
43
|
+
</render_hotspot>
|
44
|
+
</response_xy>
|
45
|
+
</flow>
|
46
|
+
</presentation>
|
47
|
+
</item>
|
48
|
+
<item ident="g515255148f5a3cae1832584071aa8529" title="hot-spot with invalid coordinates">
|
49
|
+
<itemmetadata>
|
50
|
+
<qtimetadata>
|
51
|
+
<qtimetadatafield>
|
52
|
+
<fieldlabel>question_type</fieldlabel>
|
53
|
+
<fieldentry>hot_spot_question</fieldentry>
|
54
|
+
</qtimetadatafield>
|
55
|
+
<qtimetadatafield>
|
56
|
+
<fieldlabel>points_possible</fieldlabel>
|
57
|
+
<fieldentry>1.0</fieldentry>
|
58
|
+
</qtimetadatafield>
|
59
|
+
<qtimetadatafield>
|
60
|
+
<fieldlabel>original_answer_ids</fieldlabel>
|
61
|
+
<fieldentry/>
|
62
|
+
</qtimetadatafield>
|
63
|
+
<qtimetadatafield>
|
64
|
+
<fieldlabel>assessment_question_identifierref</fieldlabel>
|
65
|
+
<fieldentry>gd6ff15355f3dd3f532816fa268230130</fieldentry>
|
66
|
+
</qtimetadatafield>
|
67
|
+
</qtimetadata>
|
68
|
+
</itemmetadata>
|
69
|
+
<presentation>
|
70
|
+
<flow>
|
71
|
+
<response_xy ident="response1" rcardinality="Single" rtiming="No">
|
72
|
+
<material>
|
73
|
+
<mattext texttype="text/html"><p>point something on the image</p></mattext>
|
74
|
+
</material>
|
75
|
+
<render_hotspot>
|
76
|
+
<material>
|
77
|
+
<matimage uri="$IMS-CC-FILEBASE$/Uploaded Media/someuuid"/>
|
78
|
+
</material>
|
79
|
+
<response_label ident="response1" rarea="square">0.372</response_label>
|
80
|
+
</render_hotspot>
|
81
|
+
</response_xy>
|
82
|
+
</flow>
|
83
|
+
</presentation>
|
84
|
+
</item>
|
85
|
+
<item ident="g515255148f5a3cae1832584071aa8529" title="hot-spot without coordinates">
|
86
|
+
<itemmetadata>
|
87
|
+
<qtimetadata>
|
88
|
+
<qtimetadatafield>
|
89
|
+
<fieldlabel>question_type</fieldlabel>
|
90
|
+
<fieldentry>hot_spot_question</fieldentry>
|
91
|
+
</qtimetadatafield>
|
92
|
+
<qtimetadatafield>
|
93
|
+
<fieldlabel>points_possible</fieldlabel>
|
94
|
+
<fieldentry>1.0</fieldentry>
|
95
|
+
</qtimetadatafield>
|
96
|
+
<qtimetadatafield>
|
97
|
+
<fieldlabel>original_answer_ids</fieldlabel>
|
98
|
+
<fieldentry/>
|
99
|
+
</qtimetadatafield>
|
100
|
+
<qtimetadatafield>
|
101
|
+
<fieldlabel>assessment_question_identifierref</fieldlabel>
|
102
|
+
<fieldentry>gd6ff15355f3dd3f532816fa268230130</fieldentry>
|
103
|
+
</qtimetadatafield>
|
104
|
+
</qtimetadata>
|
105
|
+
</itemmetadata>
|
106
|
+
<presentation>
|
107
|
+
<flow>
|
108
|
+
<response_xy ident="response1" rcardinality="Single" rtiming="No">
|
109
|
+
<material>
|
110
|
+
<mattext texttype="text/html"><p>point something on the image</p></mattext>
|
111
|
+
</material>
|
112
|
+
<render_hotspot>
|
113
|
+
<material>
|
114
|
+
<matimage uri="$IMS-CC-FILEBASE$/Uploaded Media/someuuid"/>
|
115
|
+
</material>
|
116
|
+
<response_label ident="response1" rarea="square"></response_label>
|
117
|
+
</render_hotspot>
|
118
|
+
</response_xy>
|
119
|
+
</flow>
|
120
|
+
</presentation>
|
121
|
+
</item>
|
122
|
+
</section>
|
123
|
+
</assessment>
|
124
|
+
</questestinterop>
|
@@ -0,0 +1,57 @@
|
|
1
|
+
describe Qti::V1::Models::Interactions::HotSpotInteraction do
|
2
|
+
let(:xml_file_name) { 'hot_spot.xml' }
|
3
|
+
let(:fixtures_path) { File.join('spec', 'fixtures', 'items_1.2') }
|
4
|
+
let(:file_path) { File.join(fixtures_path, xml_file_name) }
|
5
|
+
let(:test_object) { Qti::V1::Models::Assessment.from_path!(file_path) }
|
6
|
+
let(:assessment_item_refs) { test_object.assessment_items }
|
7
|
+
|
8
|
+
describe '.matches' do
|
9
|
+
it 'matches the item in file' do
|
10
|
+
expect(described_class.matches(test_object.assessment_items, test_object)).to be_truthy
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe '#item_body' do
|
15
|
+
let(:loaded_class) { described_class.new(assessment_item_refs.first, test_object) }
|
16
|
+
it 'returns correct item body' do
|
17
|
+
expect(loaded_class.item_body).to eq '<p>point something on the image</p>'
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe '#image_url' do
|
22
|
+
let(:loaded_class) { described_class.new(assessment_item_refs.first, test_object) }
|
23
|
+
it 'returns correct image url' do
|
24
|
+
expect(loaded_class.image_url).to eq '$IMS-CC-FILEBASE$/Uploaded Media/someuuid'
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe '#shape_type' do
|
29
|
+
let(:loaded_class) { described_class.new(assessment_item_refs.first, test_object) }
|
30
|
+
it 'returns correct shape type' do
|
31
|
+
expect(loaded_class.shape_type).to eq 'square'
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe '#coordinates' do
|
36
|
+
let(:loaded_class) { described_class.new(assessment_item_refs.first, test_object) }
|
37
|
+
it 'returns correct coordinates' do
|
38
|
+
expect(loaded_class.coordinates).to eq [{ "x": 0.372, "y": 0.1376 }, { "x": 0.616, "y": 0.4256 }]
|
39
|
+
end
|
40
|
+
|
41
|
+
context 'when the response label does not have an even amount of numbers' do
|
42
|
+
let(:loaded_class) { described_class.new(assessment_item_refs[1], test_object) }
|
43
|
+
|
44
|
+
it 'returns an empty array' do
|
45
|
+
expect(loaded_class.coordinates).to eq []
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
context 'when the response label is empty' do
|
50
|
+
let(:loaded_class) { described_class.new(assessment_item_refs[2], test_object) }
|
51
|
+
|
52
|
+
it 'returns an empty array' do
|
53
|
+
expect(loaded_class.coordinates).to eq []
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
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.16.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: 2023-06
|
15
|
+
date: 2023-07-06 00:00:00.000000000 Z
|
16
16
|
dependencies:
|
17
17
|
- !ruby/object:Gem::Dependency
|
18
18
|
name: actionview
|
@@ -335,6 +335,7 @@ files:
|
|
335
335
|
- lib/qti/v1/models/interactions/choice_interaction.rb
|
336
336
|
- lib/qti/v1/models/interactions/fill_blank_interaction.rb
|
337
337
|
- lib/qti/v1/models/interactions/formula_interaction.rb
|
338
|
+
- lib/qti/v1/models/interactions/hot_spot_interaction.rb
|
338
339
|
- lib/qti/v1/models/interactions/match_interaction.rb
|
339
340
|
- lib/qti/v1/models/interactions/numeric_interaction.rb
|
340
341
|
- lib/qti/v1/models/interactions/ordering_interaction.rb
|
@@ -404,6 +405,7 @@ files:
|
|
404
405
|
- spec/fixtures/items_1.2/formula.xml
|
405
406
|
- spec/fixtures/items_1.2/formula_mform.xml
|
406
407
|
- spec/fixtures/items_1.2/formula_mvar.xml
|
408
|
+
- spec/fixtures/items_1.2/hot_spot.xml
|
407
409
|
- spec/fixtures/items_1.2/item_no_title.xml
|
408
410
|
- spec/fixtures/items_1.2/matching.xml
|
409
411
|
- spec/fixtures/items_1.2/matching_feedback.xml
|
@@ -679,6 +681,7 @@ files:
|
|
679
681
|
- spec/lib/qti/v1/models/interactions/choice_interaction_spec.rb
|
680
682
|
- spec/lib/qti/v1/models/interactions/fill_blank_interaction_spec.rb
|
681
683
|
- spec/lib/qti/v1/models/interactions/formula_interaction_spec.rb
|
684
|
+
- spec/lib/qti/v1/models/interactions/hot_spot_interaction_spec.rb
|
682
685
|
- spec/lib/qti/v1/models/interactions/match_interaction_spec.rb
|
683
686
|
- spec/lib/qti/v1/models/interactions/numeric_interaction_spec.rb
|
684
687
|
- spec/lib/qti/v1/models/interactions/ordering_interaction_spec.rb
|
@@ -767,6 +770,7 @@ test_files:
|
|
767
770
|
- spec/fixtures/items_1.2/formula.xml
|
768
771
|
- spec/fixtures/items_1.2/formula_mform.xml
|
769
772
|
- spec/fixtures/items_1.2/formula_mvar.xml
|
773
|
+
- spec/fixtures/items_1.2/hot_spot.xml
|
770
774
|
- spec/fixtures/items_1.2/item_no_title.xml
|
771
775
|
- spec/fixtures/items_1.2/matching.xml
|
772
776
|
- spec/fixtures/items_1.2/matching_feedback.xml
|
@@ -1042,6 +1046,7 @@ test_files:
|
|
1042
1046
|
- spec/lib/qti/v1/models/interactions/choice_interaction_spec.rb
|
1043
1047
|
- spec/lib/qti/v1/models/interactions/fill_blank_interaction_spec.rb
|
1044
1048
|
- spec/lib/qti/v1/models/interactions/formula_interaction_spec.rb
|
1049
|
+
- spec/lib/qti/v1/models/interactions/hot_spot_interaction_spec.rb
|
1045
1050
|
- spec/lib/qti/v1/models/interactions/match_interaction_spec.rb
|
1046
1051
|
- spec/lib/qti/v1/models/interactions/numeric_interaction_spec.rb
|
1047
1052
|
- spec/lib/qti/v1/models/interactions/ordering_interaction_spec.rb
|