qti 2.15.4 → 2.16.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f4084fe51b2f6fe08be8575473463acf9654f015d2e314ac7dc5b0cc66bbc7a0
4
- data.tar.gz: 7aef361ec589ca5656e4bb6c0850593e3a0014e1b5e59c06a3f84cc762ca4b49
3
+ metadata.gz: c06cc4e78f29ecb23354e39dc3e93ac5da9600f0b09284a59b1202c553eb0c93
4
+ data.tar.gz: b91ded981174a7822c7b6756f69e4a30daf5c6845f004a9a05da4a3f23a6af28
5
5
  SHA512:
6
- metadata.gz: fccaad1a37691535248d7f2f6c8f587c9cbf319f4db2abd918f682e4a78a9a8351ab3b42e75a2e78f38557babbd437de049bcfb8c4d6b8aea8ed3a407a6355ab
7
- data.tar.gz: 31746c6c8de63f0d854a329b9932245c36b19fb32dbb0e1183d8ff20f04c2ca2f93bf4fd63192083c8cbdd67e749bc46c9cc07fc4b50809ba0d4015f56bf8a5e
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
@@ -1,3 +1,3 @@
1
1
  module Qti
2
- VERSION = '2.15.4'.freeze
2
+ VERSION = '2.16.0'.freeze
3
3
  end
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">&lt;p&gt;point something on the image&lt;/p&gt;</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">&lt;p&gt;point something on the image&lt;/p&gt;</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">&lt;p&gt;point something on the image&lt;/p&gt;</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.15.4
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-27 00:00:00.000000000 Z
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