qti 0.3.16 → 0.4.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 09a38606bbf7afefc7b808dd338055b24375193b
4
- data.tar.gz: 1dcad5866f62bd26d1dd48ab3f3ab6646de5eddc
3
+ metadata.gz: 4f6c8a03de219970a4b393485157b90247559323
4
+ data.tar.gz: b92d0b520d3b4ed2f18ad89eb25c4b77435c55e1
5
5
  SHA512:
6
- metadata.gz: 952002458866f648ca5c473608a232e46fda37ae6e31cc273d48f25d4449eb4fc8f7f0d020069abb7f4593e72f1a71aaf706841aad90d48a761f0350c4477733
7
- data.tar.gz: b38e9b92eda87771d2b8a9b4bcda1eb052540841b146bcc3c410bc2d67ca1b0ba9f38a2611f5caa579a269aaee55e00216f0b2e79151c38769554b369ed866da
6
+ metadata.gz: f1d379ca58f26bdb0d92db3a3f3929f90774a05104381c9653246a228d9dd3998b78c77b660fb74ae1a049e846bdf2eb8b042d0dcef27ee59781622efcdae95f
7
+ data.tar.gz: 70bba648502519b9d9f6a43c7cdf97dddb141e5359e0e1391ea3db138397a4d0dfd630b593abe6d9a505f48e4bfdb728fc051177848e395f07a5dba6895fdf60
data/lib/qti.rb CHANGED
@@ -65,6 +65,7 @@ require 'qti/v2/models/base'
65
65
  require 'qti/v2/models/interactions/base_interaction'
66
66
  require 'qti/v2/models/choices/simple_choice'
67
67
  require 'qti/v2/models/choices/simple_associable_choice'
68
+ require 'qti/v2/models/choices/gap_match_choice'
68
69
  require 'qti/v2/models/assessment_item'
69
70
  require 'qti/v2/models/assessment_test'
70
71
  require 'qti/v2/models/scoring_data'
@@ -0,0 +1,28 @@
1
+ require 'qti/v2/models/base'
2
+
3
+ module Qti
4
+ module V2
5
+ module Models
6
+ module Choices
7
+ class GapMatchChoice < Qti::V2::Models::Base
8
+ PROHIBITED_NODE_NAMES = 'feedbackInline'.freeze
9
+ def initialize(node)
10
+ @node = node
11
+ end
12
+
13
+ def identifier
14
+ @identifier ||= @node.attributes['identifier'].value
15
+ end
16
+
17
+ def item_body
18
+ @item_body ||= begin
19
+ node = @node.dup
20
+ node.children.filter(PROHIBITED_NODE_NAMES).each(&:unlink)
21
+ node.content.strip.gsub(/\s+/, ' ')
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -2,30 +2,122 @@ module Qti
2
2
  module V2
3
3
  module Models
4
4
  module Interactions
5
- class GapMatchInteraction < Qti::V2::Models::Base
6
- NODE_NAME = 'gapMatchInteraction'.freeze
7
- # This will know if a class matches
5
+ class GapMatchInteraction < BaseInteraction
8
6
  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)
7
+ matches = node.xpath('.//xmlns:gapMatchInteraction')
8
+ return false if matches.count != 1
9
+ new(node)
14
10
  end
15
11
 
16
12
  def initialize(node)
17
13
  @node = node
18
14
  end
19
15
 
20
- def gap_max_count
21
- @node.attributes['gapMax']&.value&.to_i
16
+ def shuffled?
17
+ @node.at_xpath('.//xmlns:gapMatchInteraction').attributes['shuffle']&.value.try(:downcase) == 'true'
18
+ end
19
+
20
+ def clean_stem_items
21
+ @clean_stem_items ||= begin
22
+ node = @node.dup
23
+ gap_node = node.xpath('.//xmlns:gapMatchInteraction')
24
+ gap_node.children.filter('gapText').each(&:remove)
25
+
26
+ gap_node.children.each do |child|
27
+ if child.inner_text.strip.empty?
28
+ child.remove
29
+ end
30
+ end
31
+
32
+ gap_node
33
+ end
34
+ end
35
+
36
+ def prompt
37
+ clean_stem_items.children.filter('prompt')
38
+ end
39
+
40
+ def stem_items
41
+ if prompt.present?
42
+ stem_text_with_prompt = stem_text.unshift(prompt_hash)
43
+ stem_items_with_id_and_position(stem_text_with_prompt)
44
+ else
45
+ stem_items_with_id_and_position(stem_text)
46
+ end
47
+ end
48
+
49
+ def stem_items_with_id_and_position(stem_text)
50
+ stem_text.map.with_index do |stem_item, index|
51
+ stem_item.merge(
52
+ id: "stem_#{index}",
53
+ position: index + 1
54
+ )
55
+ end
22
56
  end
23
57
 
24
- def gap_min_count
25
- @node.attributes['gapMin']&.value&.to_i
58
+ def prompt_hash
59
+ {
60
+ type: 'text',
61
+ value: prompt.first.text
62
+ }
26
63
  end
27
64
 
28
- def gap_choice
65
+ def stem_text
66
+ clean_stem_items.search('p').children.map do |stem_item|
67
+ if stem_item.name == 'gap'
68
+ {
69
+ type: 'blank',
70
+ blank_id: stem_item.attributes['identifier'].value
71
+ }
72
+ else
73
+ {
74
+ type: 'text',
75
+ value: stem_item.text.empty? ? " " : stem_item.text
76
+ }
77
+ end
78
+ end
79
+ end
80
+
81
+ def blanks
82
+ node.xpath('.//xmlns:gapText').map do |blank|
83
+ { id: blank.attributes['identifier'].value }
84
+ end
85
+ end
86
+
87
+ def answers
88
+ @answers ||= answer_nodes.map do |node|
89
+ V2::Models::Choices::GapMatchChoice.new(node)
90
+ end
91
+ end
92
+
93
+ def scoring_data_structs
94
+ question_response_pairs = node.xpath('.//xmlns:correctResponse//xmlns:value').map do |value|
95
+ value.content.split
96
+ end
97
+ question_response_pairs.map!{ |qrp| qrp.reverse }
98
+ question_response_id_mapping = Hash[question_response_pairs]
99
+ answer_nodes.map { |value_node|
100
+ node_id = value_node.attributes['identifier']&.value
101
+ answer_choice = choices.find{ |choice| choice.attributes['identifier']&.value == question_response_id_mapping[node_id] }
102
+ ScoringData.new(
103
+ answer_choice.content,
104
+ 'directedPair',
105
+ {
106
+ id: node_id,
107
+ case: false
108
+ }
109
+ )
110
+ }
111
+ end
112
+
113
+ def choices
114
+ @node.xpath('.//xmlns:gapText')
115
+ end
116
+
117
+ private
118
+
119
+ def answer_nodes
120
+ @node.xpath('.//xmlns:gap')
29
121
  end
30
122
  end
31
123
  end
@@ -1,7 +1,11 @@
1
1
  module Qti
2
2
  module V2
3
3
  module Models
4
- ScoringData = Struct.new(:values, :type)
4
+ ScoringData = Struct.new(:values, :type, :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
@@ -1,33 +1,33 @@
1
1
  <?xml version="1.0" encoding="UTF-8"?>
2
2
  <assessmentItem xmlns="http://www.imsglobal.org/xsd/imsqti_v2p2"
3
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4
- xsi:schemaLocation="http://www.imsglobal.org/xsd/imsqti_v2p2 http://www.imsglobal.org/xsd/qti/qtiv2p2/imsqti_v2p2.xsd"
5
- identifier="gapMatch" title="Richard III (Take 1)" adaptive="false" timeDependent="false">
6
- <responseDeclaration identifier="RESPONSE" cardinality="multiple" baseType="directedPair">
7
- <correctResponse>
8
- <value>W G1</value>
9
- <value>Su G2</value>
10
- </correctResponse>
11
- <mapping defaultValue="-1" lowerBound="0">
12
- <mapEntry mapKey="W G1" mappedValue="1"/>
13
- <mapEntry mapKey="Su G2" mappedValue="2"/>
14
- </mapping>
15
- </responseDeclaration>
16
- <outcomeDeclaration identifier="SCORE" cardinality="single" baseType="float"/>
17
- <itemBody>
18
- <gapMatchInteraction responseIdentifier="RESPONSE" shuffle="false">
19
- <prompt>Identify the missing words in this famous quote from Shakespeare's Richard III.</prompt>
20
- <gapText identifier="W" matchMax="1">winter</gapText>
21
- <gapText identifier="Sp" matchMax="1">spring</gapText>
22
- <gapText identifier="Su" matchMax="1">summer</gapText>
23
- <gapText identifier="A" matchMax="1">autumn</gapText>
24
- <blockquote>
25
- <p>Now is the <gap identifier="G1"/> of our discontent<br/> Made glorious <gap
26
- identifier="G2"/> by this sun of York;<br/> And all the clouds that lour'd
27
- upon our house<br/> In the deep bosom of the ocean buried.</p>
28
- </blockquote>
29
- </gapMatchInteraction>
30
- </itemBody>
31
- <responseProcessing
32
- template="http://www.imsglobal.org/question/qti_v2p2/rptemplates/map_response"/>
3
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4
+ xsi:schemaLocation="http://www.imsglobal.org/xsd/imsqti_v2p2 http://www.imsglobal.org/xsd/qti/qtiv2p2/imsqti_v2p2.xsd"
5
+ identifier="gapMatch" title="Richard III (Take 1)" adaptive="false" timeDependent="false">
6
+ <responseDeclaration identifier="RESPONSE" cardinality="multiple" baseType="directedPair">
7
+ <correctResponse>
8
+ <value>W G1</value>
9
+ <value>Su G2</value>
10
+ </correctResponse>
11
+ <mapping defaultValue="-1" lowerBound="0">
12
+ <mapEntry mapKey="W G1" mappedValue="1"/>
13
+ <mapEntry mapKey="Su G2" mappedValue="2"/>
14
+ </mapping>
15
+ </responseDeclaration>
16
+ <outcomeDeclaration identifier="SCORE" cardinality="single" baseType="float"/>
17
+ <itemBody>
18
+ <gapMatchInteraction responseIdentifier="RESPONSE" shuffle="false">
19
+ <prompt>Identify the missing words in this famous quote from Shakespeare's Richard III.</prompt>
20
+ <gapText identifier="W" matchMax="1">winter</gapText>
21
+ <gapText identifier="Sp" matchMax="1">spring</gapText>
22
+ <gapText identifier="Su" matchMax="1">summer</gapText>
23
+ <gapText identifier="A" matchMax="1">autumn</gapText>
24
+ <blockquote>
25
+ <p>Now is the <gap identifier="G1"/> of our discontent<br/> Made glorious <gap
26
+ identifier="G2"/> by this sun of York;<br/> And all the clouds that lour'd
27
+ upon our house<br/> In the deep bosom of the ocean buried.</p>
28
+ </blockquote>
29
+ </gapMatchInteraction>
30
+ </itemBody>
31
+ <responseProcessing
32
+ template="http://www.imsglobal.org/question/qti_v2p2/rptemplates/map_response"/>
33
33
  </assessmentItem>
@@ -1,27 +1,27 @@
1
1
  <?xml version="1.0" encoding="UTF-8"?>
2
2
  <assessmentItem xmlns="http://www.imsglobal.org/xsd/imsqti_v2p2"
3
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4
- xsi:schemaLocation="http://www.imsglobal.org/xsd/imsqti_v2p2 http://www.imsglobal.org/xsd/qti/qtiv2p2/imsqti_v2p2.xsd"
5
- identifier="textEntry" title="Richard III (Take 3)" adaptive="false" timeDependent="false">
6
- <responseDeclaration identifier="RESPONSE" cardinality="single" baseType="string">
7
- <correctResponse>
8
- <value>York</value>
9
- </correctResponse>
10
- <mapping defaultValue="0">
11
- <mapEntry mapKey="York" mappedValue="1"/>
12
- <mapEntry mapKey="york" mappedValue="0.5"/>
13
- </mapping>
14
- </responseDeclaration>
15
- <outcomeDeclaration identifier="SCORE" cardinality="single" baseType="float"/>
16
- <itemBody>
17
- <p>Identify the missing word in this famous quote from Shakespeare's Richard III.</p>
18
- <blockquote>
19
- <p>Now is the winter of our discontent<br/> Made glorious summer by this sun of
20
- <textEntryInteraction responseIdentifier="RESPONSE" expectedLength="15"/>;<br/>
21
- And all the clouds that lour'd upon our house<br/> In the deep bosom of the ocean
22
- buried.</p>
23
- </blockquote>
24
- </itemBody>
25
- <responseProcessing
26
- template="http://www.imsglobal.org/question/qti_v2p2/rptemplates/map_response"/>
3
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4
+ xsi:schemaLocation="http://www.imsglobal.org/xsd/imsqti_v2p2 http://www.imsglobal.org/xsd/qti/qtiv2p2/imsqti_v2p2.xsd"
5
+ identifier="textEntry" title="Richard III (Take 3)" adaptive="false" timeDependent="false">
6
+ <responseDeclaration identifier="RESPONSE" cardinality="single" baseType="string">
7
+ <correctResponse>
8
+ <value>York</value>
9
+ </correctResponse>
10
+ <mapping defaultValue="0">
11
+ <mapEntry mapKey="York" mappedValue="1"/>
12
+ <mapEntry mapKey="york" mappedValue="0.5"/>
13
+ </mapping>
14
+ </responseDeclaration>
15
+ <outcomeDeclaration identifier="SCORE" cardinality="single" baseType="float"/>
16
+ <itemBody>
17
+ <p>Identify the missing word in this famous quote from Shakespeare's Richard III.</p>
18
+ <blockquote>
19
+ <p>Now is the winter of our discontent<br/> Made glorious summer by this sun of
20
+ <textEntryInteraction responseIdentifier="RESPONSE" expectedLength="15"/>;<br/>
21
+ And all the clouds that lour'd upon our house<br/> In the deep bosom of the ocean
22
+ buried.</p>
23
+ </blockquote>
24
+ </itemBody>
25
+ <responseProcessing
26
+ template="http://www.imsglobal.org/question/qti_v2p2/rptemplates/map_response"/>
27
27
  </assessmentItem>
@@ -0,0 +1,33 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <assessmentItem xmlns="http://www.imsglobal.org/xsd/imsqti_v2p2"
3
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4
+ xsi:schemaLocation="http://www.imsglobal.org/xsd/imsqti_v2p2 http://www.imsglobal.org/xsd/qti/qtiv2p2/imsqti_v2p2.xsd"
5
+ identifier="gapMatch" title="Richard III (Take 1)" adaptive="false" timeDependent="false">
6
+ <responseDeclaration identifier="RESPONSE" cardinality="multiple" baseType="directedPair">
7
+ <correctResponse>
8
+ <value>W G1</value>
9
+ <value>Su G2</value>
10
+ </correctResponse>
11
+ <mapping defaultValue="-1" lowerBound="0">
12
+ <mapEntry mapKey="W G1" mappedValue="1"/>
13
+ <mapEntry mapKey="Su G2" mappedValue="2"/>
14
+ </mapping>
15
+ </responseDeclaration>
16
+ <outcomeDeclaration identifier="SCORE" cardinality="single" baseType="float" normalMaximum="2.0"/>
17
+ <itemBody>
18
+ <gapMatchInteraction responseIdentifier="RESPONSE" shuffle="false">
19
+ <prompt>Identify the missing words in this famous quote from Shakespeare's Richard III.</prompt>
20
+ <gapText identifier="W" matchMax="1">winter</gapText>
21
+ <gapText identifier="Sp" matchMax="1">spring</gapText>
22
+ <gapText identifier="Su" matchMax="1">summer</gapText>
23
+ <gapText identifier="A" matchMax="1">autumn</gapText>
24
+ <blockquote>
25
+ <p>Now is the <gap identifier="G1"/> of our discontent<br/> Made glorious <gap
26
+ identifier="G2"/> by this sun of York;<br/> And all the clouds that lour'd
27
+ upon our house<br/> In the deep bosom of the ocean buried.</p>
28
+ </blockquote>
29
+ </gapMatchInteraction>
30
+ </itemBody>
31
+ <responseProcessing
32
+ template="http://www.imsglobal.org/question/qti_v2p2/rptemplates/map_response"/>
33
+ </assessmentItem>
@@ -155,6 +155,7 @@
155
155
  <file href="multiple-choice/multiple-choice.xml"/>
156
156
  <file href="text-entry/text-entry.xml"/>
157
157
  <file href="true-false/true-false.xml"/>
158
+ <file href="fib/fib.xml"/>
158
159
  <file href="images/sign.png"/>
159
160
  </resource>
160
161
  </resources>
@@ -0,0 +1,22 @@
1
+ require 'spec_helper'
2
+
3
+ describe Qti::V2::Models::Choices::GapMatchChoice do
4
+ context 'choice.xml' do
5
+ let(:io) { File.read(File.join('spec', 'fixtures', 'items_2.1', 'gap_match.xml')) }
6
+ let(:nodes) { Nokogiri::XML(io).xpath('//xmlns:gapText') }
7
+
8
+ let(:choices) { nodes.map { |node| described_class.new(node) } }
9
+
10
+ it 'returns the right identifier' do
11
+ expect(choices.map(&:identifier)).to eq %w(W Sp Su A)
12
+ end
13
+
14
+ it 'returns the item body text' do
15
+ expect(choices.map(&:item_body).map(&:empty?).any?).to eq false
16
+ end
17
+
18
+ it 'removes inline feedback elements from item_body' do
19
+ expect(choices.map(&:item_body).map { |text| text.include? 'correct' }.any?).to eq false
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,58 @@
1
+ require 'spec_helper'
2
+
3
+ describe Qti::V2::Models::Interactions::GapMatchInteraction do
4
+ context 'gap_match.xml' do
5
+ let(:io) { File.read(File.join('spec', 'fixtures', 'items_2.1', 'gap_match.xml')) }
6
+ let(:node) { Nokogiri::XML(io) }
7
+ let(:loaded_class) { described_class.new(node) }
8
+
9
+ let(:expected_stem_items) {[
10
+ {type: "text",
11
+ value: "Identify the missing words in this famous quote from Shakespeare's Richard III.",
12
+ id: "stem_0", position: 1},
13
+ {type: 'text', value: 'Now is the ', id: 'stem_1', position: 2},
14
+ {type: 'blank', :blank_id=>'G1', id: 'stem_2', position: 3},
15
+ {type: 'text', value: ' of our discontent', id: 'stem_3', position: 4},
16
+ {type: 'text', value: ' ', id: 'stem_4', position: 5},
17
+ {type: 'text', value: ' Made glorious ', id: 'stem_5', position: 6},
18
+ {type: 'blank', :blank_id=>'G2', id: 'stem_6', position: 7},
19
+ {type: 'text', value: ' by this sun of York;', id: 'stem_7', position: 8},
20
+ {type: 'text', value: ' ', id: 'stem_8', position: 9},
21
+ {type: 'text', value: " And all the clouds that lour'd\n upon our house",
22
+ id: 'stem_9', position: 10},
23
+ {type: 'text', value: ' ', id: 'stem_10', position: 11},
24
+ {type: 'text', value: ' In the deep bosom of the ocean buried.',
25
+ id: 'stem_11', position: 12}
26
+ ]}
27
+
28
+ let(:scoring_data_ids) { %w(G1 G2) }
29
+ let(:scoring_data_values) { %w(winter summer) }
30
+
31
+ it 'returns shuffle setting' do
32
+ expect(loaded_class.shuffled?).to eq false
33
+ end
34
+
35
+ it 'returns the blanks' do
36
+ expect(loaded_class.blanks).to eq [{ id: "W" }, { id: "Sp" }, { id: "Su" }, { id: "A" }]
37
+ end
38
+
39
+ it 'returns the stem_items' do
40
+ expect(loaded_class.stem_items).to eq(expected_stem_items)
41
+ end
42
+
43
+ it 'returns the answers' do
44
+ expect(loaded_class.answers.count).to eq 2
45
+ expect(loaded_class.answers.first).to be_an_instance_of(Qti::V2::Models::Choices::GapMatchChoice)
46
+ end
47
+
48
+
49
+ it 'returns the choices' do
50
+ expect(loaded_class.choices.count).to eq 4
51
+ end
52
+
53
+ it 'returns the scoring_data_structs' do
54
+ expect(loaded_class.scoring_data_structs.map(&:id)).to eq(scoring_data_ids)
55
+ expect(loaded_class.scoring_data_structs.map(&:values)).to eq(scoring_data_values)
56
+ end
57
+ end
58
+ 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.3.16
4
+ version: 0.4.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-05-03 00:00:00.000000000 Z
12
+ date: 2017-05-12 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport
@@ -350,6 +350,7 @@ files:
350
350
  - spec/fixtures/test_qti_2.2.zip
351
351
  - spec/fixtures/test_qti_2.2/assessment.xml
352
352
  - spec/fixtures/test_qti_2.2/essay/essay.xml
353
+ - spec/fixtures/test_qti_2.2/fib/fib.xml
353
354
  - spec/fixtures/test_qti_2.2/images/sign.png
354
355
  - spec/fixtures/test_qti_2.2/imsmanifest.xml
355
356
  - spec/fixtures/test_qti_2.2/mathassess.xsd
@@ -424,9 +425,11 @@ files:
424
425
  - spec/lib/qti/v1/models/interactions/string_interaction_spec.rb
425
426
  - spec/lib/qti/v2/models/assessment_item_spec.rb
426
427
  - spec/lib/qti/v2/models/assessment_test_spec.rb
428
+ - spec/lib/qti/v2/models/choices/gap_match_choice_spec.rb
427
429
  - spec/lib/qti/v2/models/choices/simple_choice_spec.rb
428
430
  - spec/lib/qti/v2/models/interactions/choice_interaction_spec.rb
429
431
  - spec/lib/qti/v2/models/interactions/extended_text_interaction_spec.rb
432
+ - spec/lib/qti/v2/models/interactions/gap_match_interaction_spec.rb
430
433
  - spec/lib/qti/v2/models/interactions/match_interaction_spec.rb
431
434
  - spec/lib/qti_spec.rb
432
435
  - spec/spec_helper.rb
@@ -577,6 +580,7 @@ test_files:
577
580
  - spec/fixtures/test_qti_2.2.zip
578
581
  - spec/fixtures/test_qti_2.2/assessment.xml
579
582
  - spec/fixtures/test_qti_2.2/essay/essay.xml
583
+ - spec/fixtures/test_qti_2.2/fib/fib.xml
580
584
  - spec/fixtures/test_qti_2.2/images/sign.png
581
585
  - spec/fixtures/test_qti_2.2/imsmanifest.xml
582
586
  - spec/fixtures/test_qti_2.2/mathassess.xsd
@@ -651,9 +655,11 @@ test_files:
651
655
  - spec/lib/qti/v1/models/interactions/string_interaction_spec.rb
652
656
  - spec/lib/qti/v2/models/assessment_item_spec.rb
653
657
  - spec/lib/qti/v2/models/assessment_test_spec.rb
658
+ - spec/lib/qti/v2/models/choices/gap_match_choice_spec.rb
654
659
  - spec/lib/qti/v2/models/choices/simple_choice_spec.rb
655
660
  - spec/lib/qti/v2/models/interactions/choice_interaction_spec.rb
656
661
  - spec/lib/qti/v2/models/interactions/extended_text_interaction_spec.rb
662
+ - spec/lib/qti/v2/models/interactions/gap_match_interaction_spec.rb
657
663
  - spec/lib/qti/v2/models/interactions/match_interaction_spec.rb
658
664
  - spec/lib/qti_spec.rb
659
665
  - spec/spec_helper.rb