qti 0.4.16 → 0.5.16
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/qti.rb +0 -1
- data/lib/qti/v1/models/interactions/match_interaction.rb +0 -6
- data/lib/qti/v2/models/choices/simple_associable_choice.rb +7 -0
- data/lib/qti/v2/models/choices/simple_choice.rb +1 -0
- data/lib/qti/v2/models/interactions.rb +7 -3
- data/lib/qti/v2/models/interactions/categorization_interaction.rb +69 -0
- data/lib/qti/v2/models/interactions/match_interaction.rb +29 -32
- data/lib/qti/v2/models/interactions/match_item_tag_processors/associate_interaction_tag_processor.rb +75 -0
- data/lib/qti/v2/models/interactions/match_item_tag_processors/match_interaction_tag_processor.rb +67 -0
- data/lib/qti/v2/models/scoring_data.rb +3 -3
- data/spec/fixtures/items_2.1/categorization.xml +35 -0
- data/spec/fixtures/items_2.1/match.xml +19 -26
- data/spec/fixtures/items_2.1/match2.xml +119 -0
- data/spec/lib/qti/v1/models/interactions/match_interaction_spec.rb +44 -0
- data/spec/lib/qti/v2/models/assessment_item_spec.rb +0 -24
- data/spec/lib/qti/v2/models/choices/simple_associable_choice_spec.rb +21 -0
- data/spec/lib/qti/v2/models/interactions/categorization_interaction_spec.rb +23 -0
- data/spec/lib/qti/v2/models/interactions/match_interaction_spec.rb +71 -7
- data/spec/support/monkey_patches.rb +14 -0
- metadata +31 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4883be4fd0b3c4f0f662068c6b7d42e2cfee0645
|
4
|
+
data.tar.gz: 262e1f6ad0e5d3d80c844d30084bcb6eb461fcf0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: beddd3cfcec82686646a5635773414d32502f58ea993719afb175f4ca9adaeed7ee9f6a622016618497a0a6f474915a0ff205d80fd0984f610ce1093675270ba
|
7
|
+
data.tar.gz: 81bc3c599b5c15b0c1437d1abf2fe985676d1f9d2ec2e433f5be5d1cac458822a113eb1e5e6290d995315a05984cf541a89453e4a900597bd5fc5d799762184b
|
data/lib/qti.rb
CHANGED
@@ -62,7 +62,6 @@ require 'qti/v1/models/choices/fill_blank_choice'
|
|
62
62
|
require 'qti/v1/models/scoring_data'
|
63
63
|
|
64
64
|
require 'qti/v2/models/base'
|
65
|
-
require 'qti/v2/models/interactions/base_interaction'
|
66
65
|
require 'qti/v2/models/choices/simple_choice'
|
67
66
|
require 'qti/v2/models/choices/simple_associable_choice'
|
68
67
|
require 'qti/v2/models/choices/gap_match_choice'
|
@@ -3,18 +3,12 @@ module Qti
|
|
3
3
|
module Models
|
4
4
|
module Interactions
|
5
5
|
class MatchInteraction < BaseInteraction
|
6
|
-
attr_reader :node
|
7
|
-
|
8
6
|
def self.matches(node)
|
9
7
|
matches = node.xpath('.//xmlns:response_lid')
|
10
8
|
return false if matches.count <= 1
|
11
9
|
new(node)
|
12
10
|
end
|
13
11
|
|
14
|
-
def initialize(node)
|
15
|
-
@node = node
|
16
|
-
end
|
17
|
-
|
18
12
|
def answers
|
19
13
|
@answers ||= answer_nodes.map do |node|
|
20
14
|
V1::Models::Choices::LogicalIdentifierChoice.new(node)
|
@@ -5,6 +5,13 @@ module Qti
|
|
5
5
|
module Models
|
6
6
|
module Choices
|
7
7
|
class SimpleAssociableChoice < SimpleChoice
|
8
|
+
def match_max
|
9
|
+
@_match_max ||= @node.attributes['matchMax'].value || 0
|
10
|
+
end
|
11
|
+
|
12
|
+
def match_min
|
13
|
+
@_match_min ||= @node.attributes['matchMin'].value || 0
|
14
|
+
end
|
8
15
|
end
|
9
16
|
end
|
10
17
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
require 'qti/v2/models/interactions/base_interaction'
|
2
2
|
Dir["#{__dir__}/interactions/*.rb"].each { |f| load f }
|
3
3
|
|
4
4
|
module Qti
|
@@ -7,8 +7,6 @@ module Qti
|
|
7
7
|
module Interactions
|
8
8
|
# This one finds the correct parsing model based on the provided xml node
|
9
9
|
def self.interaction_model(node)
|
10
|
-
subclasses = constants.map { |c| const_get(c) }
|
11
|
-
|
12
10
|
# Check for matches
|
13
11
|
matches = subclasses.each_with_object([]) do |interaction_class, result|
|
14
12
|
match = interaction_class.matches(node)
|
@@ -19,6 +17,12 @@ module Qti
|
|
19
17
|
|
20
18
|
matches.first
|
21
19
|
end
|
20
|
+
|
21
|
+
def self.subclasses
|
22
|
+
constants.map { |c| const_get(c) }
|
23
|
+
.reject { |c| c.name =~ /Implementations|Base/ }
|
24
|
+
.select { |c| c.name =~ /^Qti::V2.*Interaction$/ }
|
25
|
+
end
|
22
26
|
end
|
23
27
|
end
|
24
28
|
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require_relative 'match_interaction'
|
2
|
+
|
3
|
+
module Qti
|
4
|
+
module V2
|
5
|
+
module Models
|
6
|
+
module Interactions
|
7
|
+
class CategorizationInteraction < MatchInteraction
|
8
|
+
def self.matches(node)
|
9
|
+
if use_match_interaction_implementation?(node)
|
10
|
+
new(node, MatchItemTagProcesssors::MatchInteractionTagProcessor)
|
11
|
+
else
|
12
|
+
false
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.use_match_interaction_implementation?(node)
|
17
|
+
MatchItemTagProcesssors::MatchInteractionTagProcessor.match_interaction_tag?(node) &&
|
18
|
+
MatchItemTagProcesssors::MatchInteractionTagProcessor.number_of_questions_per_answer(node)
|
19
|
+
.any? { |n| n != 1 }
|
20
|
+
end
|
21
|
+
|
22
|
+
def scoring_data_structs
|
23
|
+
questions_categories_choices_hash.map do |category_choice, questions_choices|
|
24
|
+
ScoringData.new(category_choice.text, 'directedPair',
|
25
|
+
id: node_identifier(category_choice),
|
26
|
+
questions_ids: questions_choices.map { |q| node_identifier(q) })
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def questions_categories_choices_hash
|
33
|
+
category_choices.each_with_object({}) do |category_choice, hash|
|
34
|
+
hash[category_choice] = questions_for_category_choice(category_choice)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def questions_for_category_choice(choice)
|
39
|
+
choice_identifier = node_identifier(choice)
|
40
|
+
category_questions_ids = implementation.question_response_pairs
|
41
|
+
.select { |_, category_id| category_id == choice_identifier }
|
42
|
+
.map { |question_id, _| question_id }
|
43
|
+
question_choices.select { |q| category_questions_ids.include? node_identifier(q) }
|
44
|
+
end
|
45
|
+
|
46
|
+
def category_choices
|
47
|
+
@_category_choices ||= implementation.choices.select { |c| categories_ids.include? node_identifier(c) }
|
48
|
+
end
|
49
|
+
|
50
|
+
def question_choices
|
51
|
+
@_question_choices ||= implementation.choices.select { |c| questions_ids.include? node_identifier(c) }
|
52
|
+
end
|
53
|
+
|
54
|
+
def categories_ids
|
55
|
+
@_categories_ids ||= implementation.question_response_pairs.map { |_, category_id| category_id }.uniq
|
56
|
+
end
|
57
|
+
|
58
|
+
def questions_ids
|
59
|
+
@_questions_ids ||= implementation.question_response_pairs.map { |question_id, _| question_id }.uniq
|
60
|
+
end
|
61
|
+
|
62
|
+
def node_identifier(node)
|
63
|
+
node.attributes['identifier'].value
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -1,51 +1,48 @@
|
|
1
|
+
require_relative 'match_item_tag_processors/match_interaction_tag_processor'
|
2
|
+
require_relative 'match_item_tag_processors/associate_interaction_tag_processor'
|
3
|
+
|
1
4
|
module Qti
|
2
5
|
module V2
|
3
6
|
module Models
|
4
7
|
module Interactions
|
5
8
|
class MatchInteraction < BaseInteraction
|
6
|
-
|
7
|
-
matches = node.xpath('//xmlns:matchInteraction')
|
8
|
-
return false if matches.count != 1
|
9
|
-
new(node)
|
10
|
-
end
|
9
|
+
extend Forwardable
|
11
10
|
|
12
|
-
|
13
|
-
node.xpath('.//xmlns:correctResponse//xmlns:value')
|
14
|
-
.map { |value| value.content.split.first }
|
15
|
-
.map { |id| { id: id, question_body: choices_by_identifier[id].content } }
|
16
|
-
end
|
11
|
+
attr_reader :implementation
|
17
12
|
|
18
|
-
def
|
19
|
-
node
|
13
|
+
def initialize(node, implementation)
|
14
|
+
super(node)
|
15
|
+
@implementation = implementation.new(node)
|
20
16
|
end
|
21
17
|
|
22
|
-
|
23
|
-
answer_nodes.map { |node| Choices::SimpleAssociableChoice.new(node) }
|
24
|
-
end
|
18
|
+
def_delegators :@implementation, :answers, :questions, :shuffled?
|
25
19
|
|
26
20
|
def scoring_data_structs
|
27
|
-
|
28
|
-
value.content.split
|
29
|
-
end
|
30
|
-
question_response_id_mapping = Hash[question_response_pairs]
|
31
|
-
data = question_response_id_mapping.reduce({}) do |acc, pair|
|
32
|
-
question_id, answer_id = pair
|
33
|
-
acc.update question_id => choices_by_identifier[answer_id].content
|
34
|
-
end
|
35
|
-
[ScoringData.new(data, 'directedPair')]
|
21
|
+
implementation.scoring_data_structs
|
36
22
|
end
|
37
23
|
|
38
|
-
|
24
|
+
def self.matches(node)
|
25
|
+
implementation =
|
26
|
+
if use_associate_interaction_implementation?(node)
|
27
|
+
MatchItemTagProcesssors::AssociateInteractionTagProcessor
|
28
|
+
elsif use_match_interaction_implementation?(node)
|
29
|
+
MatchItemTagProcesssors::MatchInteractionTagProcessor
|
30
|
+
end
|
31
|
+
|
32
|
+
return false unless implementation.present?
|
33
|
+
new(node, implementation)
|
34
|
+
end
|
39
35
|
|
40
|
-
def
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
end
|
36
|
+
def self.use_associate_interaction_implementation?(node)
|
37
|
+
MatchItemTagProcesssors::AssociateInteractionTagProcessor.associate_interaction_tag?(node) &&
|
38
|
+
MatchItemTagProcesssors::AssociateInteractionTagProcessor.number_of_questions_per_answer(node)
|
39
|
+
.all? { |n| n == 1 }
|
45
40
|
end
|
46
41
|
|
47
|
-
def
|
48
|
-
|
42
|
+
def self.use_match_interaction_implementation?(node)
|
43
|
+
MatchItemTagProcesssors::MatchInteractionTagProcessor.match_interaction_tag?(node) &&
|
44
|
+
MatchItemTagProcesssors::MatchInteractionTagProcessor.number_of_questions_per_answer(node)
|
45
|
+
.all? { |n| n == 1 }
|
49
46
|
end
|
50
47
|
end
|
51
48
|
end
|
data/lib/qti/v2/models/interactions/match_item_tag_processors/associate_interaction_tag_processor.rb
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
module Qti
|
2
|
+
module V2
|
3
|
+
module Models
|
4
|
+
module Interactions
|
5
|
+
module MatchItemTagProcesssors
|
6
|
+
class AssociateInteractionTagProcessor < Interactions::BaseInteraction
|
7
|
+
def self.associate_interaction_tag?(node)
|
8
|
+
node.xpath('.//xmlns:associateInteraction').count == 1
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.number_of_questions_per_answer(node)
|
12
|
+
question_response_pairs = node.xpath('.//xmlns:correctResponse//xmlns:value').map do |value|
|
13
|
+
value.content.split
|
14
|
+
end
|
15
|
+
count = Hash.new { 0 }
|
16
|
+
question_response_pairs.reduce(count) do |acc, pair|
|
17
|
+
acc.update pair.last => acc[pair.last] + 1
|
18
|
+
end
|
19
|
+
count.values
|
20
|
+
end
|
21
|
+
|
22
|
+
def shuffled?
|
23
|
+
node.at_xpath('.//xmlns:associateInteraction').attributes['shuffle']&.value.try(:downcase) == 'true'
|
24
|
+
end
|
25
|
+
|
26
|
+
def questions
|
27
|
+
questions_ids.map { |id| { id: id, question_body: choices_by_identifier[id].content } }
|
28
|
+
end
|
29
|
+
|
30
|
+
def answers
|
31
|
+
answer_nodes.map { |node| Choices::SimpleAssociableChoice.new(node) }
|
32
|
+
end
|
33
|
+
|
34
|
+
def scoring_data_structs
|
35
|
+
question_response_pairs.map do |question_id, answer_id|
|
36
|
+
content = choices_by_identifier[answer_id].content
|
37
|
+
ScoringData.new(content, 'Pair', id: answer_id, question_id: question_id)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def choices_by_identifier
|
44
|
+
@_choices_by_identifier ||= choices.reduce({}) do |acc, choice|
|
45
|
+
acc.update choice.attributes['identifier'].value => choice
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def answer_nodes
|
50
|
+
@_answer_nodes ||= choices.select { |c| answer_ids.include?(c.attributes['identifier'].value) }
|
51
|
+
end
|
52
|
+
|
53
|
+
def questions_ids
|
54
|
+
@_questions_ids ||= question_response_pairs.map { |question_id, _| question_id }
|
55
|
+
end
|
56
|
+
|
57
|
+
def answer_ids
|
58
|
+
@_answer_ids ||= question_response_pairs.map { |_, answer_id| answer_id }
|
59
|
+
end
|
60
|
+
|
61
|
+
def choices
|
62
|
+
node.xpath('.//xmlns:simpleAssociableChoice')
|
63
|
+
end
|
64
|
+
|
65
|
+
def question_response_pairs
|
66
|
+
node.xpath('.//xmlns:correctResponse//xmlns:value').map do |value|
|
67
|
+
value.content.split
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
data/lib/qti/v2/models/interactions/match_item_tag_processors/match_interaction_tag_processor.rb
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
module Qti
|
2
|
+
module V2
|
3
|
+
module Models
|
4
|
+
module Interactions
|
5
|
+
module MatchItemTagProcesssors
|
6
|
+
class MatchInteractionTagProcessor < Interactions::BaseInteraction
|
7
|
+
def self.match_interaction_tag?(node)
|
8
|
+
node.xpath('//xmlns:matchInteraction').count == 1
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.number_of_questions_per_answer(node)
|
12
|
+
correct_categories = node.xpath('.//xmlns:correctResponse//xmlns:value')
|
13
|
+
.map { |value| value.content.split.last }
|
14
|
+
|
15
|
+
correct_categories.each_with_object(Hash.new(0)) { |category_id, counts| counts[category_id] += 1 }.values
|
16
|
+
end
|
17
|
+
|
18
|
+
def questions
|
19
|
+
questions_ids.map { |id| { id: id, question_body: choices_by_identifier[id].content } }
|
20
|
+
end
|
21
|
+
|
22
|
+
def shuffled?
|
23
|
+
node.at_xpath('.//xmlns:matchInteraction').attributes['shuffle']&.value.try(:downcase) == 'true'
|
24
|
+
end
|
25
|
+
|
26
|
+
def answers
|
27
|
+
answer_nodes.map { |node| Choices::SimpleAssociableChoice.new(node) }
|
28
|
+
end
|
29
|
+
|
30
|
+
def scoring_data_structs
|
31
|
+
question_response_pairs.map do |question_id, answer_id|
|
32
|
+
content = choices_by_identifier[answer_id].content
|
33
|
+
ScoringData.new(content, 'Pair', id: answer_id, question_id: question_id)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def choices
|
38
|
+
node.xpath('.//xmlns:simpleAssociableChoice')
|
39
|
+
end
|
40
|
+
|
41
|
+
def question_response_pairs
|
42
|
+
node.xpath('.//xmlns:correctResponse//xmlns:value').map do |value|
|
43
|
+
value.content.split
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def questions_ids
|
50
|
+
@_questions_ids ||= question_response_pairs.map { |question_id, _| question_id }
|
51
|
+
end
|
52
|
+
|
53
|
+
def choices_by_identifier
|
54
|
+
@choices_by_identifier ||= choices.reduce({}) do |acc, choice|
|
55
|
+
acc.update choice.attributes['identifier'].value => choice
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def answer_nodes
|
60
|
+
node.xpath('.//xmlns:matchInteraction//xmlns:simpleMatchSet[2]//xmlns:simpleAssociableChoice')
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -1,9 +1,9 @@
|
|
1
1
|
module Qti
|
2
2
|
module V2
|
3
3
|
module Models
|
4
|
-
ScoringData = Struct.new(:values, :type, :id, :case) do
|
5
|
-
def initialize(values,
|
6
|
-
super(values,
|
4
|
+
ScoringData = Struct.new(:values, :type, :id, :case, :question_id, :questions_ids) do
|
5
|
+
def initialize(values, type, options={})
|
6
|
+
super(values, type, options[:id], options[:case], options[:question_id], options[:questions_ids])
|
7
7
|
end
|
8
8
|
end
|
9
9
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<assessmentItem xmlns="http://www.imsglobal.org/xsd/imsqti_v2p2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.imsglobal.org/xsd/imsqti_v2p2 http://www.imsglobal.org/xsd/qti/qtiv2p2/imsqti_v2p2.xsd" identifier="match" title="Characters and Plays" adaptive="false" timeDependent="false">
|
3
|
+
<responseDeclaration identifier="RESPONSE" cardinality="multiple" baseType="directedPair">
|
4
|
+
<correctResponse>
|
5
|
+
<value>C R</value>
|
6
|
+
<value>D M</value>
|
7
|
+
<value>L M</value>
|
8
|
+
<value>P T</value>
|
9
|
+
</correctResponse>
|
10
|
+
<mapping defaultValue="0">
|
11
|
+
<mapEntry mapKey="C R" mappedValue="1"/>
|
12
|
+
<mapEntry mapKey="D M" mappedValue="0.5"/>
|
13
|
+
<mapEntry mapKey="L M" mappedValue="0.5"/>
|
14
|
+
<mapEntry mapKey="P T" mappedValue="1"/>
|
15
|
+
</mapping>
|
16
|
+
</responseDeclaration>
|
17
|
+
<outcomeDeclaration identifier="SCORE" cardinality="single" baseType="float"/>
|
18
|
+
<itemBody>
|
19
|
+
<matchInteraction responseIdentifier="RESPONSE" shuffle="true" maxAssociations="4">
|
20
|
+
<prompt>Match the following characters to the Shakespeare play they appeared in:</prompt>
|
21
|
+
<simpleMatchSet>
|
22
|
+
<simpleAssociableChoice identifier="C" matchMax="1">Capulet</simpleAssociableChoice>
|
23
|
+
<simpleAssociableChoice identifier="D" matchMax="1">Demetrius</simpleAssociableChoice>
|
24
|
+
<simpleAssociableChoice identifier="L" matchMax="1">Lysander</simpleAssociableChoice>
|
25
|
+
<simpleAssociableChoice identifier="P" matchMax="1">Prospero</simpleAssociableChoice>
|
26
|
+
</simpleMatchSet>
|
27
|
+
<simpleMatchSet>
|
28
|
+
<simpleAssociableChoice identifier="M" matchMax="4">A Midsummer-Night's Dream</simpleAssociableChoice>
|
29
|
+
<simpleAssociableChoice identifier="R" matchMax="4">Romeo and Juliet</simpleAssociableChoice>
|
30
|
+
<simpleAssociableChoice identifier="T" matchMax="4">The Tempest</simpleAssociableChoice>
|
31
|
+
</simpleMatchSet>
|
32
|
+
</matchInteraction>
|
33
|
+
</itemBody>
|
34
|
+
<responseProcessing template="http://www.imsglobal.org/question/qti_v2p2/rptemplates/map_response"/>
|
35
|
+
</assessmentItem>
|
@@ -1,35 +1,28 @@
|
|
1
|
-
<?xml version="1.0" encoding="
|
2
|
-
<assessmentItem xmlns="http://www.imsglobal.org/xsd/
|
3
|
-
<responseDeclaration identifier="RESPONSE" cardinality="multiple" baseType="
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
2
|
+
<assessmentItem xmlns="http://www.imsglobal.org/xsd/imsqti_v2p1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.imsglobal.org/xsd/imsqti_v2p1 http://www.imsglobal.org/xsd/qti/qtiv2p1/imsqti_v2p1p2.xsd" identifier="associate" title="Shakespearian Rivals" adaptive="false" timeDependent="false">
|
3
|
+
<responseDeclaration identifier="RESPONSE" cardinality="multiple" baseType="pair">
|
4
4
|
<correctResponse>
|
5
|
-
<value>
|
6
|
-
<value>
|
7
|
-
<value>L
|
8
|
-
<value>P T</value>
|
5
|
+
<value>A P</value>
|
6
|
+
<value>C M</value>
|
7
|
+
<value>D L</value>
|
9
8
|
</correctResponse>
|
10
9
|
<mapping defaultValue="0">
|
11
|
-
<mapEntry mapKey="
|
12
|
-
<mapEntry mapKey="
|
13
|
-
<mapEntry mapKey="L
|
14
|
-
<mapEntry mapKey="P T" mappedValue="1"/>
|
10
|
+
<mapEntry mapKey="A P" mappedValue="2"/>
|
11
|
+
<mapEntry mapKey="C M" mappedValue="1"/>
|
12
|
+
<mapEntry mapKey="D L" mappedValue="1"/>
|
15
13
|
</mapping>
|
16
14
|
</responseDeclaration>
|
17
15
|
<outcomeDeclaration identifier="SCORE" cardinality="single" baseType="float"/>
|
18
16
|
<itemBody>
|
19
|
-
<
|
20
|
-
<prompt>
|
21
|
-
<
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
</
|
27
|
-
|
28
|
-
<simpleAssociableChoice identifier="M" matchMax="4">A Midsummer-Night's Dream</simpleAssociableChoice>
|
29
|
-
<simpleAssociableChoice identifier="R" matchMax="4">Romeo and Juliet</simpleAssociableChoice>
|
30
|
-
<simpleAssociableChoice identifier="T" matchMax="4">The Tempest</simpleAssociableChoice>
|
31
|
-
</simpleMatchSet>
|
32
|
-
</matchInteraction>
|
17
|
+
<associateInteraction responseIdentifier="RESPONSE" shuffle="true" maxAssociations="3">
|
18
|
+
<prompt>Hidden in this list of characters from famous Shakespeare plays are three pairs of rivals. Can you match each character to his adversary?</prompt>
|
19
|
+
<simpleAssociableChoice identifier="A" matchMax="1">Antonio</simpleAssociableChoice>
|
20
|
+
<simpleAssociableChoice identifier="C" matchMax="1">Capulet</simpleAssociableChoice>
|
21
|
+
<simpleAssociableChoice identifier="D" matchMax="1">Demetrius</simpleAssociableChoice>
|
22
|
+
<simpleAssociableChoice identifier="L" matchMax="1">Lysander</simpleAssociableChoice>
|
23
|
+
<simpleAssociableChoice identifier="M" matchMax="1">Montague</simpleAssociableChoice>
|
24
|
+
<simpleAssociableChoice identifier="P" matchMax="1">Prospero</simpleAssociableChoice>
|
25
|
+
</associateInteraction>
|
33
26
|
</itemBody>
|
34
|
-
<responseProcessing template="http://www.imsglobal.org/question/
|
27
|
+
<responseProcessing template="http://www.imsglobal.org/question/qti_v2p1/rptemplates/map_response"/>
|
35
28
|
</assessmentItem>
|
@@ -0,0 +1,119 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<!--This file was created using: Onyx Editor, Version 3.4.3 (Full, licensed version), (c)2012 BPS Bildungsportal Sachsen GmbH-->
|
3
|
+
<assessmentItem xmlns="http://www.imsglobal.org/xsd/imsqti_v2p2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.imsglobal.org/xsd/imsqti_v2p2 http://www.imsglobal.org/xsd/qti/qtiv2p2/imsqti_v2p2.xsd" identifier="Matchsingle_143114773" title="match (single)" adaptive="false" timeDependent="false">
|
4
|
+
<responseDeclaration identifier="RESPONSE" cardinality="multiple" baseType="directedPair">
|
5
|
+
<correctResponse>
|
6
|
+
<value>Match28433682 Match2675678</value>
|
7
|
+
<value>Match7191791 Match9372581</value>
|
8
|
+
<value>Match20473010 Match22744006</value>
|
9
|
+
<value>Match6429655 Match17943221</value>
|
10
|
+
</correctResponse>
|
11
|
+
</responseDeclaration>
|
12
|
+
<outcomeDeclaration identifier="SCORE" cardinality="single" baseType="float">
|
13
|
+
<defaultValue>
|
14
|
+
<value>0.0</value>
|
15
|
+
</defaultValue>
|
16
|
+
</outcomeDeclaration>
|
17
|
+
<outcomeDeclaration identifier="MAXSCORE" cardinality="single" baseType="float">
|
18
|
+
<defaultValue>
|
19
|
+
<value>1.0</value>
|
20
|
+
</defaultValue>
|
21
|
+
</outcomeDeclaration>
|
22
|
+
<outcomeDeclaration identifier="FEEDBACKBASIC" cardinality="single" baseType="identifier">
|
23
|
+
<defaultValue>
|
24
|
+
<value>empty</value>
|
25
|
+
</defaultValue>
|
26
|
+
</outcomeDeclaration>
|
27
|
+
<outcomeDeclaration identifier="FEEDBACKMODAL" cardinality="multiple" baseType="identifier" view="testConstructor"/>
|
28
|
+
<itemBody>
|
29
|
+
<div>Der wichtigste, größte und einzig schiffbare Fluss des Bundeslandes Sachsens ist die
|
30
|
+
Elbe. Die verschiedene Quellflüsse der Elbe durchziehen die sächsischen Städte.
|
31
|
+
<br/>Ordne anhand des Flusslaufs die Quellflüsse den gegebenen Städten zu.</div>
|
32
|
+
<matchInteraction responseIdentifier="RESPONSE" shuffle="true" maxAssociations="0">
|
33
|
+
<simpleMatchSet>
|
34
|
+
<simpleAssociableChoice identifier="Match28433682" fixed="false" matchMin="1" matchMax="1">Weißeritz</simpleAssociableChoice>
|
35
|
+
<simpleAssociableChoice identifier="Match7191791" fixed="false" matchMin="1" matchMax="1">Mulde</simpleAssociableChoice>
|
36
|
+
<simpleAssociableChoice identifier="Match20473010" fixed="false" matchMin="1" matchMax="1">Saale</simpleAssociableChoice>
|
37
|
+
<simpleAssociableChoice identifier="Match6429655" fixed="false" matchMin="1" matchMax="1">Spree</simpleAssociableChoice>
|
38
|
+
</simpleMatchSet>
|
39
|
+
<simpleMatchSet>
|
40
|
+
<simpleAssociableChoice identifier="Match2675678" fixed="false" matchMin="1" matchMax="1">Dresden</simpleAssociableChoice>
|
41
|
+
<simpleAssociableChoice identifier="Match9372581" fixed="false" matchMin="1" matchMax="1">Leipzig</simpleAssociableChoice>
|
42
|
+
<simpleAssociableChoice identifier="Match22744006" fixed="false" matchMin="1" matchMax="1">Halle</simpleAssociableChoice>
|
43
|
+
<simpleAssociableChoice identifier="Match17943221" fixed="false" matchMin="1" matchMax="1">Bautzen</simpleAssociableChoice>
|
44
|
+
</simpleMatchSet>
|
45
|
+
</matchInteraction>
|
46
|
+
</itemBody>
|
47
|
+
<responseProcessing>
|
48
|
+
<responseCondition>
|
49
|
+
<responseIf>
|
50
|
+
<isNull>
|
51
|
+
<variable identifier="RESPONSE"/>
|
52
|
+
</isNull>
|
53
|
+
<setOutcomeValue identifier="FEEDBACKBASIC">
|
54
|
+
<baseValue baseType="identifier">empty</baseValue>
|
55
|
+
</setOutcomeValue>
|
56
|
+
</responseIf>
|
57
|
+
<responseElseIf>
|
58
|
+
<match>
|
59
|
+
<variable identifier="RESPONSE"/>
|
60
|
+
<correct identifier="RESPONSE"/>
|
61
|
+
</match>
|
62
|
+
<setOutcomeValue identifier="SCORE">
|
63
|
+
<sum>
|
64
|
+
<variable identifier="SCORE"/>
|
65
|
+
<variable identifier="MAXSCORE"/>
|
66
|
+
</sum>
|
67
|
+
</setOutcomeValue>
|
68
|
+
<setOutcomeValue identifier="FEEDBACKBASIC">
|
69
|
+
<baseValue baseType="identifier">correct</baseValue>
|
70
|
+
</setOutcomeValue>
|
71
|
+
</responseElseIf>
|
72
|
+
<responseElse>
|
73
|
+
<setOutcomeValue identifier="FEEDBACKBASIC">
|
74
|
+
<baseValue baseType="identifier">incorrect</baseValue>
|
75
|
+
</setOutcomeValue>
|
76
|
+
</responseElse>
|
77
|
+
</responseCondition>
|
78
|
+
<responseCondition>
|
79
|
+
<responseIf>
|
80
|
+
<and>
|
81
|
+
<match>
|
82
|
+
<baseValue baseType="identifier">correct</baseValue>
|
83
|
+
<variable identifier="FEEDBACKBASIC"/>
|
84
|
+
</match>
|
85
|
+
</and>
|
86
|
+
<setOutcomeValue identifier="FEEDBACKMODAL">
|
87
|
+
<multiple>
|
88
|
+
<variable identifier="FEEDBACKMODAL"/>
|
89
|
+
<baseValue baseType="identifier">FEEDBACK_27448254</baseValue>
|
90
|
+
</multiple>
|
91
|
+
</setOutcomeValue>
|
92
|
+
</responseIf>
|
93
|
+
</responseCondition>
|
94
|
+
<responseCondition>
|
95
|
+
<responseIf>
|
96
|
+
<and>
|
97
|
+
<match>
|
98
|
+
<baseValue baseType="identifier">incorrect</baseValue>
|
99
|
+
<variable identifier="FEEDBACKBASIC"/>
|
100
|
+
</match>
|
101
|
+
</and>
|
102
|
+
<setOutcomeValue identifier="FEEDBACKMODAL">
|
103
|
+
<multiple>
|
104
|
+
<variable identifier="FEEDBACKMODAL"/>
|
105
|
+
<baseValue baseType="identifier">FEEDBACK_16479834</baseValue>
|
106
|
+
</multiple>
|
107
|
+
</setOutcomeValue>
|
108
|
+
</responseIf>
|
109
|
+
</responseCondition>
|
110
|
+
</responseProcessing>
|
111
|
+
<modalFeedback identifier="FEEDBACK_27448254" outcomeIdentifier="FEEDBACKMODAL" showHide="show" title="Richtig!">Die Elbe durchzieht den Freistaat von Südosten nach Nordwesten. Wichtige
|
112
|
+
Quellflüsse sind die Mulde, die Weißeritz, die Zschopau, die Weiße Elster und die Spree,
|
113
|
+
deren allgemeine Fließrichtung Norden ist und die ebenfalls zum Fluss-System der Elbe
|
114
|
+
gehören.</modalFeedback>
|
115
|
+
<modalFeedback identifier="FEEDBACK_16479834" outcomeIdentifier="FEEDBACKMODAL" showHide="show" title="Leider Falsch!">Die Elbe durchzieht den Freistaat von Südosten nach Nordwesten.
|
116
|
+
Wichtige Quellflüsse sind die Mulde, die Weißeritz, die Zschopau, die Weiße Elster und die
|
117
|
+
Spree, deren allgemeine Fließrichtung Norden ist und die ebenfalls zum Fluss-System der Elbe
|
118
|
+
gehören.</modalFeedback>
|
119
|
+
</assessmentItem>
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Qti::V1::Models::Interactions::MatchInteraction do
|
4
|
+
let(:file) { File.join('spec', 'fixtures', 'items_1.2', 'matching.xml') }
|
5
|
+
let(:assessment) { Qti::V1::Models::Assessment.from_path!(file) }
|
6
|
+
let(:item) { assessment.assessment_items.first }
|
7
|
+
subject { described_class.new(item) }
|
8
|
+
|
9
|
+
it 'returns shuffle setting' do
|
10
|
+
expect(subject.shuffled?).to eq false
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'returns the answers' do
|
14
|
+
expect(subject.answers.map(&:item_body)).to eq(
|
15
|
+
['Magnify up to about 400 times. Sometimes requires colored staining of cells.',
|
16
|
+
"Uses a beam of electrons. Can provide details of cells' internal structure.",
|
17
|
+
'A distractor answer.']
|
18
|
+
)
|
19
|
+
end
|
20
|
+
|
21
|
+
describe '.matches' do
|
22
|
+
it 'matches the item in file' do
|
23
|
+
expect(described_class.matches(item)).to be_truthy
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe '#scoring_data_structs' do
|
28
|
+
it 'grabs scoring data value for matching questions' do
|
29
|
+
expect(subject.scoring_data_structs.first.values).to eq(
|
30
|
+
'question_1' => 'Magnify up to about 400 times. Sometimes requires colored staining of cells.',
|
31
|
+
'question_2' => "Uses a beam of electrons. Can provide details of cells' internal structure."
|
32
|
+
)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe '#questions' do
|
37
|
+
it 'returns the questions' do
|
38
|
+
expect(subject.questions).to eq(
|
39
|
+
[{ id: 'question_1', question_body: 'Light Microscope' },
|
40
|
+
{ id: 'question_2', question_body: 'Electron Microscopes' }]
|
41
|
+
)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -64,28 +64,4 @@ describe Qti::V2::Models::AssessmentItem do
|
|
64
64
|
end
|
65
65
|
end
|
66
66
|
end
|
67
|
-
|
68
|
-
describe '#scoring_data_structs' do
|
69
|
-
it 'grabs scoring data value for matching questions' do
|
70
|
-
assessment_item = Qti::V2::Models::AssessmentItem.from_path! 'spec/fixtures/items_2.1/match.xml'
|
71
|
-
expect(assessment_item.interaction_model).to be_instance_of Qti::V2::Models::Interactions::MatchInteraction
|
72
|
-
expect(assessment_item.scoring_data_structs.first.values).to eq(
|
73
|
-
'C' => 'Romeo and Juliet',
|
74
|
-
'D' => "A Midsummer-Night's Dream",
|
75
|
-
'L' => "A Midsummer-Night's Dream",
|
76
|
-
'P' => 'The Tempest'
|
77
|
-
)
|
78
|
-
expect(assessment_item.interaction_model.questions).to eq(
|
79
|
-
[{ id: 'C', question_body: 'Capulet' },
|
80
|
-
{ id: 'D', question_body: 'Demetrius' },
|
81
|
-
{ id: 'L', question_body: 'Lysander' },
|
82
|
-
{ id: 'P', question_body: 'Prospero' }]
|
83
|
-
)
|
84
|
-
expect(assessment_item.interaction_model.answers.map(&:item_body)).to eq(
|
85
|
-
["A Midsummer-Night's Dream",
|
86
|
-
'Romeo and Juliet',
|
87
|
-
'The Tempest']
|
88
|
-
)
|
89
|
-
end
|
90
|
-
end
|
91
67
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Qti::V2::Models::Choices::SimpleAssociableChoice do
|
4
|
+
let(:io) { File.read('spec/fixtures/items_2.1/match2.xml') }
|
5
|
+
let(:nodes) { Nokogiri::XML(io).xpath('//xmlns:simpleAssociableChoice') }
|
6
|
+
let(:choices) { nodes.map { |node| described_class.new(node) } }
|
7
|
+
|
8
|
+
it 'returns the expected attributes' do
|
9
|
+
expected_attrs = [
|
10
|
+
%w(Match28433682 1 1 Weißeritz),
|
11
|
+
%w(Match7191791 1 1 Mulde),
|
12
|
+
%w(Match20473010 1 1 Saale),
|
13
|
+
%w(Match6429655 1 1 Spree),
|
14
|
+
%w(Match2675678 1 1 Dresden),
|
15
|
+
%w(Match9372581 1 1 Leipzig),
|
16
|
+
%w(Match22744006 1 1 Halle),
|
17
|
+
%w(Match17943221 1 1 Bautzen)
|
18
|
+
]
|
19
|
+
expect(choices.map { |c| [c.identifier, c.match_min, c.match_max, c.item_body] }).to eq expected_attrs
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Qti::V2::Models::Interactions::CategorizationInteraction do
|
4
|
+
let(:assessment_item) { Qti::V2::Models::AssessmentItem.from_path! 'spec/fixtures/items_2.1/categorization.xml' }
|
5
|
+
subject { assessment_item.interaction_model }
|
6
|
+
|
7
|
+
it { is_expected.to be_an_instance_of(described_class) }
|
8
|
+
|
9
|
+
it 'returns shuffle setting' do
|
10
|
+
expect(subject.shuffled?).to eq true
|
11
|
+
end
|
12
|
+
|
13
|
+
describe '#scoring_data_structs' do
|
14
|
+
it 'returns the scoring data for categorization questions' do
|
15
|
+
expected_scoring_data_structs = [
|
16
|
+
Qti::V2::Models::ScoringData.new("A Midsummer-Night's Dream", "directedPair", id: "M", questions_ids: ["D", "L"]),
|
17
|
+
Qti::V2::Models::ScoringData.new('Romeo and Juliet', "directedPair", id: "R", questions_ids: ['C']),
|
18
|
+
Qti::V2::Models::ScoringData.new('The Tempest', "directedPair", id: "T", questions_ids: ['P']),
|
19
|
+
]
|
20
|
+
expect(subject.scoring_data_structs).to eq expected_scoring_data_structs
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -1,15 +1,79 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Qti::V2::Models::Interactions::MatchInteraction do
|
4
|
-
|
5
|
-
|
6
|
-
|
4
|
+
context 'assessmentItem is implemented with <associateInteraction>' do
|
5
|
+
let(:assessment_item) { Qti::V2::Models::AssessmentItem.from_path! 'spec/fixtures/items_2.1/match.xml' }
|
6
|
+
subject { assessment_item.interaction_model }
|
7
7
|
|
8
|
-
|
9
|
-
|
8
|
+
it { is_expected.to be_an_instance_of(described_class) }
|
9
|
+
|
10
|
+
it 'returns shuffle setting' do
|
11
|
+
expect(subject.shuffled?).to eq true
|
12
|
+
end
|
13
|
+
|
14
|
+
describe '#scoring_data_structs' do
|
15
|
+
it 'grabs scoring data value for matching questions' do
|
16
|
+
expect(subject.scoring_data_structs).to eq [
|
17
|
+
Qti::V2::Models::ScoringData.new('Prospero', 'Pair', id: 'P', question_id: 'A'),
|
18
|
+
Qti::V2::Models::ScoringData.new('Montague', 'Pair', id: 'M', question_id: 'C'),
|
19
|
+
Qti::V2::Models::ScoringData.new('Lysander', 'Pair', id: 'L', question_id: 'D')
|
20
|
+
]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe '#answers' do
|
25
|
+
it 'returns the correct_answers' do
|
26
|
+
expect(subject.answers.map(&:item_body)).to eq(%w[Lysander Montague Prospero])
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe '#questions' do
|
31
|
+
it 'returns the questions' do
|
32
|
+
expect(subject.questions).to eq(
|
33
|
+
[{ id: 'A', question_body: 'Antonio' },
|
34
|
+
{ id: 'C', question_body: 'Capulet' },
|
35
|
+
{ id: 'D', question_body: 'Demetrius' }]
|
36
|
+
)
|
37
|
+
end
|
38
|
+
end
|
10
39
|
end
|
11
40
|
|
12
|
-
|
13
|
-
|
41
|
+
context 'assessmentItem is implemented with <matchInteraction>' do
|
42
|
+
let(:assessment_item) { Qti::V2::Models::AssessmentItem.from_path! 'spec/fixtures/items_2.1/match2.xml' }
|
43
|
+
subject { assessment_item.interaction_model }
|
44
|
+
|
45
|
+
it { is_expected.to be_an_instance_of(described_class) }
|
46
|
+
|
47
|
+
it 'returns shuffle setting' do
|
48
|
+
expect(subject.shuffled?).to eq true
|
49
|
+
end
|
50
|
+
|
51
|
+
describe '#scoring_data_structs' do
|
52
|
+
it 'grabs scoring data value for matching questions' do
|
53
|
+
expect(subject.scoring_data_structs).to eq [
|
54
|
+
Qti::V2::Models::ScoringData.new('Dresden', 'Pair', id: 'Match2675678', question_id: 'Match28433682'),
|
55
|
+
Qti::V2::Models::ScoringData.new('Leipzig', 'Pair', id: 'Match9372581', question_id: 'Match7191791'),
|
56
|
+
Qti::V2::Models::ScoringData.new('Halle' , 'Pair', id: 'Match22744006', question_id: 'Match20473010'),
|
57
|
+
Qti::V2::Models::ScoringData.new('Bautzen', 'Pair', id: 'Match17943221', question_id: 'Match6429655')
|
58
|
+
]
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe '#answers' do
|
63
|
+
it 'returns the correct_answers' do
|
64
|
+
expect(subject.answers.map(&:item_body)).to eq %w[Dresden Leipzig Halle Bautzen]
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
describe '#questions' do
|
69
|
+
it 'returns the questions' do
|
70
|
+
expect(subject.questions).to eq(
|
71
|
+
[{ id: 'Match28433682', question_body: 'Weißeritz' },
|
72
|
+
{ id: 'Match7191791', question_body: 'Mulde' },
|
73
|
+
{ id: 'Match20473010', question_body: 'Saale' },
|
74
|
+
{ id: 'Match6429655', question_body: 'Spree' }]
|
75
|
+
)
|
76
|
+
end
|
77
|
+
end
|
14
78
|
end
|
15
79
|
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# ObjectSpace.each_object(Class).select { |c| c.name =~ /V1.*(?<!Base)Interaction$/ }.each do |klass|
|
2
|
+
# klass.class_eval do
|
3
|
+
# class << self
|
4
|
+
# alias_method :old_matches?, :matches?
|
5
|
+
# def matches?(node)
|
6
|
+
# raise ArgumentError.new("Expected Nokogiri::XML::Element and got #{node.class}") unless item_element?(node)
|
7
|
+
# old_matches?(node)
|
8
|
+
# end
|
9
|
+
# def item_element?(node)
|
10
|
+
# node.class == Nokogiri::XML::Element && node.name == 'item'
|
11
|
+
# end
|
12
|
+
# end
|
13
|
+
# end
|
14
|
+
# end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: qti
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.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-
|
12
|
+
date: 2017-05-17 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activesupport
|
@@ -165,6 +165,20 @@ dependencies:
|
|
165
165
|
- - ">="
|
166
166
|
- !ruby/object:Gem::Version
|
167
167
|
version: '0'
|
168
|
+
- !ruby/object:Gem::Dependency
|
169
|
+
name: rubocop
|
170
|
+
requirement: !ruby/object:Gem::Requirement
|
171
|
+
requirements:
|
172
|
+
- - ">="
|
173
|
+
- !ruby/object:Gem::Version
|
174
|
+
version: '0'
|
175
|
+
type: :development
|
176
|
+
prerelease: false
|
177
|
+
version_requirements: !ruby/object:Gem::Requirement
|
178
|
+
requirements:
|
179
|
+
- - ">="
|
180
|
+
- !ruby/object:Gem::Version
|
181
|
+
version: '0'
|
168
182
|
- !ruby/object:Gem::Dependency
|
169
183
|
name: simplecov
|
170
184
|
requirement: !ruby/object:Gem::Requirement
|
@@ -223,10 +237,13 @@ files:
|
|
223
237
|
- lib/qti/v2/models/choices/simple_choice.rb
|
224
238
|
- lib/qti/v2/models/interactions.rb
|
225
239
|
- lib/qti/v2/models/interactions/base_interaction.rb
|
240
|
+
- lib/qti/v2/models/interactions/categorization_interaction.rb
|
226
241
|
- lib/qti/v2/models/interactions/choice_interaction.rb
|
227
242
|
- lib/qti/v2/models/interactions/extended_text_interaction.rb
|
228
243
|
- lib/qti/v2/models/interactions/gap_match_interaction.rb
|
229
244
|
- lib/qti/v2/models/interactions/match_interaction.rb
|
245
|
+
- lib/qti/v2/models/interactions/match_item_tag_processors/associate_interaction_tag_processor.rb
|
246
|
+
- lib/qti/v2/models/interactions/match_item_tag_processors/match_interaction_tag_processor.rb
|
230
247
|
- lib/qti/v2/models/scoring_data.rb
|
231
248
|
- spec/fixtures/items_1.2/choice.xml
|
232
249
|
- spec/fixtures/items_1.2/essay.xml
|
@@ -247,6 +264,7 @@ files:
|
|
247
264
|
- spec/fixtures/items_2.1/adaptive_template.xml
|
248
265
|
- spec/fixtures/items_2.1/associate.xml
|
249
266
|
- spec/fixtures/items_2.1/audio-video.xml
|
267
|
+
- spec/fixtures/items_2.1/categorization.xml
|
250
268
|
- spec/fixtures/items_2.1/choice.xml
|
251
269
|
- spec/fixtures/items_2.1/choice_aria.xml
|
252
270
|
- spec/fixtures/items_2.1/choice_fixed.xml
|
@@ -304,6 +322,7 @@ files:
|
|
304
322
|
- spec/fixtures/items_2.1/inline_choice_math.xml
|
305
323
|
- spec/fixtures/items_2.1/likert.xml
|
306
324
|
- spec/fixtures/items_2.1/match.xml
|
325
|
+
- spec/fixtures/items_2.1/match2.xml
|
307
326
|
- spec/fixtures/items_2.1/math.xml
|
308
327
|
- spec/fixtures/items_2.1/mc_calc3.xml
|
309
328
|
- spec/fixtures/items_2.1/mc_calc5.xml
|
@@ -422,11 +441,14 @@ files:
|
|
422
441
|
- spec/lib/qti/v1/models/choices/logical_identifier_choice_spec.rb
|
423
442
|
- spec/lib/qti/v1/models/interactions/choice_interaction_spec.rb
|
424
443
|
- spec/lib/qti/v1/models/interactions/fill_blank_interaction_spec.rb
|
444
|
+
- spec/lib/qti/v1/models/interactions/match_interaction_spec.rb
|
425
445
|
- spec/lib/qti/v1/models/interactions/string_interaction_spec.rb
|
426
446
|
- spec/lib/qti/v2/models/assessment_item_spec.rb
|
427
447
|
- spec/lib/qti/v2/models/assessment_test_spec.rb
|
428
448
|
- spec/lib/qti/v2/models/choices/gap_match_choice_spec.rb
|
449
|
+
- spec/lib/qti/v2/models/choices/simple_associable_choice_spec.rb
|
429
450
|
- spec/lib/qti/v2/models/choices/simple_choice_spec.rb
|
451
|
+
- spec/lib/qti/v2/models/interactions/categorization_interaction_spec.rb
|
430
452
|
- spec/lib/qti/v2/models/interactions/choice_interaction_spec.rb
|
431
453
|
- spec/lib/qti/v2/models/interactions/extended_text_interaction_spec.rb
|
432
454
|
- spec/lib/qti/v2/models/interactions/gap_match_interaction_spec.rb
|
@@ -434,6 +456,7 @@ files:
|
|
434
456
|
- spec/lib/qti_spec.rb
|
435
457
|
- spec/spec_helper.rb
|
436
458
|
- spec/support/custom_matchers.rb
|
459
|
+
- spec/support/monkey_patches.rb
|
437
460
|
homepage:
|
438
461
|
licenses: []
|
439
462
|
metadata: {}
|
@@ -477,6 +500,7 @@ test_files:
|
|
477
500
|
- spec/fixtures/items_2.1/adaptive_template.xml
|
478
501
|
- spec/fixtures/items_2.1/associate.xml
|
479
502
|
- spec/fixtures/items_2.1/audio-video.xml
|
503
|
+
- spec/fixtures/items_2.1/categorization.xml
|
480
504
|
- spec/fixtures/items_2.1/choice.xml
|
481
505
|
- spec/fixtures/items_2.1/choice_aria.xml
|
482
506
|
- spec/fixtures/items_2.1/choice_fixed.xml
|
@@ -534,6 +558,7 @@ test_files:
|
|
534
558
|
- spec/fixtures/items_2.1/inline_choice_math.xml
|
535
559
|
- spec/fixtures/items_2.1/likert.xml
|
536
560
|
- spec/fixtures/items_2.1/match.xml
|
561
|
+
- spec/fixtures/items_2.1/match2.xml
|
537
562
|
- spec/fixtures/items_2.1/math.xml
|
538
563
|
- spec/fixtures/items_2.1/mc_calc3.xml
|
539
564
|
- spec/fixtures/items_2.1/mc_calc5.xml
|
@@ -652,11 +677,14 @@ test_files:
|
|
652
677
|
- spec/lib/qti/v1/models/choices/logical_identifier_choice_spec.rb
|
653
678
|
- spec/lib/qti/v1/models/interactions/choice_interaction_spec.rb
|
654
679
|
- spec/lib/qti/v1/models/interactions/fill_blank_interaction_spec.rb
|
680
|
+
- spec/lib/qti/v1/models/interactions/match_interaction_spec.rb
|
655
681
|
- spec/lib/qti/v1/models/interactions/string_interaction_spec.rb
|
656
682
|
- spec/lib/qti/v2/models/assessment_item_spec.rb
|
657
683
|
- spec/lib/qti/v2/models/assessment_test_spec.rb
|
658
684
|
- spec/lib/qti/v2/models/choices/gap_match_choice_spec.rb
|
685
|
+
- spec/lib/qti/v2/models/choices/simple_associable_choice_spec.rb
|
659
686
|
- spec/lib/qti/v2/models/choices/simple_choice_spec.rb
|
687
|
+
- spec/lib/qti/v2/models/interactions/categorization_interaction_spec.rb
|
660
688
|
- spec/lib/qti/v2/models/interactions/choice_interaction_spec.rb
|
661
689
|
- spec/lib/qti/v2/models/interactions/extended_text_interaction_spec.rb
|
662
690
|
- spec/lib/qti/v2/models/interactions/gap_match_interaction_spec.rb
|
@@ -664,3 +692,4 @@ test_files:
|
|
664
692
|
- spec/lib/qti_spec.rb
|
665
693
|
- spec/spec_helper.rb
|
666
694
|
- spec/support/custom_matchers.rb
|
695
|
+
- spec/support/monkey_patches.rb
|