qti 2.9.2 → 2.10.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: d2dc18241493cc73026c3aa2c51534c22d8b880b4e5405659b875e03354c4164
4
- data.tar.gz: 19381b84fe5cff67721722d8329ad82399a7cd75bd1ae6a972b566b594b9ec97
3
+ metadata.gz: 4ae3526adbf70df2b7523f98526a3b9f7afd575ec1787d77cd434857b1e017a9
4
+ data.tar.gz: 76a12f92afbeda2ab3da260bc6cb8d5633ea731d38659c924662177fdb81e771
5
5
  SHA512:
6
- metadata.gz: cbe4b4ea5336f9f76e219c5045f3182f9fa1ea18372dd796cb7ecb43bf4787633d1692e28d505c35231c62d6432c9691826fdda1cabdb3543afb991731dc8ebf
7
- data.tar.gz: 18c96ba1be32ba9fdbdc90dc8678668395ac723f26c76283182f2e597318ab8844071c5908d5ea0638ad61e02362e8079a6da7d51c0c527abc283cdb0a2e4732
6
+ metadata.gz: a95ea76601e38f46c327770bea336a02c5762bee4ea88afc41587aea2cfd640de4f9aecdf5f404a724d97f49758a43fc35f8fe281abcf151a3c412581f8d00ac
7
+ data.tar.gz: f5be814d3d040ce676fda735fd8f9816f563b89526ac8750ba02061477d07bee26f98b59198290feb569caf391502f1b4ffa51da73e44b79ce17f042ccec7fd9
@@ -1,12 +1,22 @@
1
1
  module Qti
2
2
  module ContentPackaging
3
3
  class AssessmentItem < Dry::Struct
4
- constructor_type :schema
4
+ transform_keys(&:to_sym)
5
+
6
+ transform_types do |type|
7
+ if type.default?
8
+ type.constructor do |value|
9
+ value.nil? ? Dry::Types::Undefined : value
10
+ end
11
+ else
12
+ type
13
+ end
14
+ end
5
15
 
6
16
  attribute :identifier, Types::Strict::String
7
17
  attribute :title, Types::Strict::String
8
18
  attribute :interaction, ContentPackaging::ChoiceInteraction
9
- attribute :response, Types::Strict::Array.of(String) | Types::Strict::String
19
+ attribute :response, Types::Strict::Array.of(Types::Strict::String) | Types::Strict::String
10
20
  end
11
21
  end
12
22
  end
@@ -1,8 +1,17 @@
1
1
  module Qti
2
2
  module ContentPackaging
3
3
  class AssessmentTest < Dry::Struct
4
- constructor_type :schema
4
+ transform_keys(&:to_sym)
5
5
 
6
+ transform_types do |type|
7
+ if type.default?
8
+ type.constructor do |value|
9
+ value.nil? ? Dry::Types::Undefined : value
10
+ end
11
+ else
12
+ type
13
+ end
14
+ end
6
15
  attribute :identifier, Types::Strict::String
7
16
  attribute :title, Types::Strict::String
8
17
  attribute :items, Types::Strict::Array.of(ContentPackaging::AssessmentItem)
@@ -1,8 +1,17 @@
1
1
  module Qti
2
2
  module ContentPackaging
3
3
  class ChoiceInteraction < Dry::Struct
4
- constructor_type :schema
4
+ transform_keys(&:to_sym)
5
5
 
6
+ transform_types do |type|
7
+ if type.default?
8
+ type.constructor do |value|
9
+ value.nil? ? Dry::Types::Undefined : value
10
+ end
11
+ else
12
+ type
13
+ end
14
+ end
6
15
  attribute :prompt, Types::Strict::String
7
16
  attribute :shuffle, Types::Strict::Bool.default(false)
8
17
  attribute :maxChoices, Types::Coercible::Integer
@@ -1,8 +1,17 @@
1
1
  module Qti
2
2
  module ContentPackaging
3
3
  class OutcomeDeclaration < Dry::Struct
4
- constructor_type :schema
4
+ transform_keys(&:to_sym)
5
5
 
6
+ transform_types do |type|
7
+ if type.default?
8
+ type.constructor do |value|
9
+ value.nil? ? Dry::Types::Undefined : value
10
+ end
11
+ else
12
+ type
13
+ end
14
+ end
6
15
  attribute :identifier, Types::Strict::String
7
16
  attribute :baseType, Types::Strict::String
8
17
  attribute :cardinality, Types::Strict::String
@@ -1,8 +1,17 @@
1
1
  module Qti
2
2
  module ContentPackaging
3
3
  class SimpleChoice < Dry::Struct
4
- constructor_type :schema
4
+ transform_keys(&:to_sym)
5
5
 
6
+ transform_types do |type|
7
+ if type.default?
8
+ type.constructor do |value|
9
+ value.nil? ? Dry::Types::Undefined : value
10
+ end
11
+ else
12
+ type
13
+ end
14
+ end
6
15
  attribute :body, Types::Strict::String
7
16
  attribute :identifier, Types::Strict::String
8
17
  attribute :fixed, Types::Strict::Bool.default(true)
@@ -1,7 +1,7 @@
1
1
  module Qti
2
2
  module ContentPackaging
3
3
  module Types
4
- include Dry::Types.module
4
+ include Dry.Types()
5
5
  end
6
6
  end
7
7
  end
@@ -9,20 +9,23 @@ module Qti
9
9
  item_prompt.split(CANVAS_REGEX).map.with_index do |stem_item, index|
10
10
  if canvas_fib_response_ids.include?(stem_item)
11
11
  # Strip the brackets before searching
12
- stem_blank(index, stem_item[1..-2])
12
+ value = stem_item[1..-2]
13
+ blank_id = blank_id(value)
14
+ blank_name = blank_value(blank_id) || value
15
+ stem_blank(index, blank_id, blank_name)
13
16
  else
14
17
  stem_text(index, stem_item)
15
18
  end
16
19
  end
17
20
  end
18
21
 
19
- def stem_blank(index, value)
22
+ def stem_blank(index, blank_id, blank_name)
20
23
  {
21
24
  id: "stem_#{index}",
22
25
  position: index + 1,
23
26
  type: 'blank',
24
- blank_id: blank_id(value),
25
- blank_name: value
27
+ blank_id: blank_id,
28
+ blank_name: blank_name
26
29
  }
27
30
  end
28
31
 
@@ -40,6 +43,11 @@ module Qti
40
43
  canvas_blank_id(stem_item)
41
44
  end
42
45
 
46
+ def blank_value(blank_id)
47
+ blank = canvas_fib_responses.find { |response| response[:id] == blank_id }
48
+ blank&.dig(:choices, 0, :item_body)
49
+ end
50
+
43
51
  def canvas_custom_fitb?
44
52
  @canvas_custom_fitb ||= BaseInteraction.canvas_custom_fitb?(@node)
45
53
  end
@@ -112,7 +112,10 @@ module Qti
112
112
 
113
113
  def qti_stem_item(index, stem_item)
114
114
  if stem_item.xpath('./xmlns:render_fib').present?
115
- stem_blank(index, stem_item.attributes['ident'].value)
115
+ blank_id = stem_item.attributes['ident'].value
116
+ blank_answer = answers.find { |answer| answer.identifier == blank_id }
117
+ blank_name = blank_answer&.item_body || blank_id
118
+ stem_blank(index, blank_id, blank_name)
116
119
  else
117
120
  stem_text(index, sanitize_content!(stem_item.children.text))
118
121
  end
@@ -4,6 +4,10 @@ module Qti
4
4
  class NonAssessmentTest < Qti::V2::Models::AssessmentTest
5
5
  include Qti::Models::ResourceGroup
6
6
 
7
+ QTIV2_TITLE_PATHS = [
8
+ "//*[local-name()='title' and namespace-uri()='http://ltsc.ieee.org/xsd/LOM']/*[local-name()='string']/text()"
9
+ ].freeze
10
+
7
11
  def assessment_items
8
12
  # Return the xml files we should be parsing
9
13
  @assessment_items ||= begin
@@ -21,6 +25,14 @@ module Qti
21
25
  href = xpath_with_single_check("//xmlns:resource[@identifier='#{dependencies.first}']/@href")
22
26
  remap_href_path(href)
23
27
  end
28
+
29
+ def title
30
+ @title ||= begin
31
+ QTIV2_TITLE_PATHS.map do |path|
32
+ xpath_with_single_check(path)&.content
33
+ end.compact.first
34
+ end || super
35
+ end
24
36
  end
25
37
  end
26
38
  end
data/lib/qti/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Qti
2
- VERSION = '2.9.2'.freeze
2
+ VERSION = '2.10.0'.freeze
3
3
  end
@@ -19,11 +19,11 @@
19
19
  </itemmetadata>
20
20
  <presentation>
21
21
  <material>
22
- <mattext texttype="text/html">&lt;div&gt;&lt;p&gt;Bird, bird, bird, bird is the [word]&lt;/p&gt;&lt;/div&gt;</mattext>
22
+ <mattext texttype="text/html">&lt;div&gt;&lt;p&gt;Bird, bird, bird, bird is the [blank1]&lt;/p&gt;&lt;/div&gt;</mattext>
23
23
  </material>
24
- <response_lid ident="response_word">
24
+ <response_lid ident="response_blank1">
25
25
  <material>
26
- <mattext>word</mattext>
26
+ <mattext>blank1</mattext>
27
27
  </material>
28
28
  <render_choice>
29
29
  <response_label ident="3537">
@@ -7,6 +7,13 @@ identifier="non-assessment-item">
7
7
  <metadata>
8
8
  <schema>QTIv2.2 Package</schema>
9
9
  <schemaversion>1.0.0</schemaversion>
10
+ <lom xmlns="http://ltsc.ieee.org/xsd/LOM">
11
+ <general>
12
+ <title>
13
+ <string>1027TestTitle12</string>
14
+ </title>
15
+ </general>
16
+ </lom>
10
17
  </metadata>
11
18
  <organizations/>
12
19
  <resources>
@@ -12,11 +12,11 @@ describe Qti::V1::Models::Interactions::BaseFillBlankInteraction do
12
12
 
13
13
  context 'canvas_stem_items' do
14
14
  let(:file_path) { File.join(fixtures_path, 'canvas_multiple_fib_as_single.xml') }
15
- let(:simple_prompt) { 'fill in the [blank]' }
15
+ let(:simple_prompt) { 'fill in the [blank1]' }
16
16
  let(:simple_expected) do
17
17
  [
18
18
  { id: 'stem_0', position: 1, type: 'text', value: 'fill in the ' },
19
- { id: 'stem_1', position: 2, type: 'text', value: '[blank]' }
19
+ { id: 'stem_1', position: 2, type: 'blank', blank_id: 'response_blank1', blank_name: 'word' }
20
20
  ]
21
21
  end
22
22
  let(:embedded_prompt) { '[[embedded] [groups]]' }
@@ -92,7 +92,7 @@ describe Qti::V1::Models::Interactions::BaseFillBlankInteraction do
92
92
  let(:expected_blanks) do
93
93
  [
94
94
  {
95
- id: 'response_word',
95
+ id: 'response_blank1',
96
96
  choices:
97
97
  [
98
98
  { id: '3537', item_body: 'word', position: 2 }
@@ -44,9 +44,9 @@ describe Qti::V1::Models::Interactions::CanvasMultipleDropdownInteraction do
44
44
  let(:expected_stem_items) do
45
45
  [
46
46
  { id: 'stem_0', position: 1, type: 'text', value: '<div><p>Roses are ' },
47
- { id: 'stem_1', position: 2, type: 'blank', blank_id: 'response_color1', blank_name: 'color1' },
47
+ { id: 'stem_1', position: 2, type: 'blank', blank_id: 'response_color1', blank_name: 'red' },
48
48
  { id: 'stem_2', position: 3, type: 'text', value: ', violets are ' },
49
- { id: 'stem_3', position: 4, type: 'blank', blank_id: 'response_color2', blank_name: 'color2' },
49
+ { id: 'stem_3', position: 4, type: 'blank', blank_id: 'response_color2', blank_name: 'blue' },
50
50
  { id: 'stem_4', position: 5, type: 'text', value: '.</p></div>' }
51
51
  ]
52
52
  end
@@ -47,7 +47,7 @@ describe Qti::V1::Models::Interactions::FillBlankInteraction do
47
47
  let(:expected_stem_items) do
48
48
  [
49
49
  { id: 'stem_0', position: 1, type: 'text', value: '<div><p>Chicago is in what state?</p></div>' },
50
- { id: 'stem_1', position: 2, type: 'blank', blank_id: 'response1', blank_name: 'response1' }
50
+ { id: 'stem_1', position: 2, type: 'blank', blank_id: 'response1', blank_name: 'Illinois' }
51
51
  ]
52
52
  end
53
53
 
@@ -72,9 +72,9 @@ describe Qti::V1::Models::Interactions::FillBlankInteraction do
72
72
  let(:expected_stem_items) do
73
73
  [
74
74
  { id: 'stem_0', position: 1, type: 'text', value: '<div><p><span>Roses are ' },
75
- { id: 'stem_1', position: 2, type: 'blank', blank_id: 'response_color1', blank_name: 'color1' },
75
+ { id: 'stem_1', position: 2, type: 'blank', blank_id: 'response_color1', blank_name: 'red' },
76
76
  { id: 'stem_2', position: 3, type: 'text', value: ', violets are ' },
77
- { id: 'stem_3', position: 4, type: 'blank', blank_id: 'response_color2', blank_name: 'color2' },
77
+ { id: 'stem_3', position: 4, type: 'blank', blank_id: 'response_color2', blank_name: 'blue' },
78
78
  { id: 'stem_4', position: 5, type: 'text', value: '</span></p></div>' }
79
79
  ]
80
80
  end
@@ -102,11 +102,11 @@ describe Qti::V1::Models::Interactions::FillBlankInteraction do
102
102
  [
103
103
  { id: 'stem_0', position: 1, type: 'text', value: 'Fill-in-the blanks in this text from Richard III: ' },
104
104
  { id: 'stem_1', position: 2, type: 'text', value: 'Now is the ' },
105
- { id: 'stem_2', position: 3, type: 'blank', blank_id: 'FIB01', blank_name: 'FIB01' },
105
+ { id: 'stem_2', position: 3, type: 'blank', blank_id: 'FIB01', blank_name: 'Winter' },
106
106
  { id: 'stem_3', position: 4, type: 'text', value: ' of our discontent made glorious ' },
107
- { id: 'stem_4', position: 5, type: 'blank', blank_id: 'FIB02', blank_name: 'FIB02' },
107
+ { id: 'stem_4', position: 5, type: 'blank', blank_id: 'FIB02', blank_name: 'Summer' },
108
108
  { id: 'stem_5', position: 6, type: 'text', value: ' by these sons of ' },
109
- { id: 'stem_6', position: 7, type: 'blank', blank_id: 'FIB03', blank_name: 'FIB03' }
109
+ { id: 'stem_6', position: 7, type: 'blank', blank_id: 'FIB03', blank_name: 'York' }
110
110
  ]
111
111
  end
112
112
 
@@ -165,11 +165,11 @@ describe Qti::V1::Models::Interactions::FillBlankInteraction do
165
165
  [
166
166
  { id: 'stem_0', position: 1, type: 'text', value: 'Fill-in-the blanks in this text from Richard III: ' },
167
167
  { id: 'stem_1', position: 2, type: 'text', value: 'Now is the ' },
168
- { id: 'stem_2', position: 3, type: 'blank', blank_id: 'FIB01', blank_name: 'FIB01' },
168
+ { id: 'stem_2', position: 3, type: 'blank', blank_id: 'FIB01', blank_name: 'Winter' },
169
169
  { id: 'stem_3', position: 4, type: 'text', value: ' of our discontent made glorious ' },
170
- { id: 'stem_4', position: 5, type: 'blank', blank_id: 'FIB02', blank_name: 'FIB02' },
170
+ { id: 'stem_4', position: 5, type: 'blank', blank_id: 'FIB02', blank_name: 'Summer' },
171
171
  { id: 'stem_5', position: 6, type: 'text', value: ' by these sons of ' },
172
- { id: 'stem_6', position: 7, type: 'blank', blank_id: 'FIB03', blank_name: 'FIB03' }
172
+ { id: 'stem_6', position: 7, type: 'blank', blank_id: 'FIB03', blank_name: 'York' }
173
173
  ]
174
174
  end
175
175
 
@@ -195,7 +195,7 @@ describe Qti::V1::Models::Interactions::FillBlankInteraction do
195
195
  let(:expected_stem_items) do
196
196
  [
197
197
  { id: 'stem_0', position: 1, type: 'text', value: '<div><p>Bird, bird, bird, bird is the ' },
198
- { id: 'stem_1', position: 2, type: 'blank', blank_id: 'response_word', blank_name: 'word' },
198
+ { id: 'stem_1', position: 2, type: 'blank', blank_id: 'response_blank1', blank_name: 'word' },
199
199
  { id: 'stem_2', position: 3, type: 'text', value: '</p></div>' }
200
200
  ]
201
201
  end
@@ -11,11 +11,16 @@ describe Qti::V2::Models::NonAssessmentTest do
11
11
  it 'expects at least one assement item' do
12
12
  expect(loaded_class.assessment_items.count)
13
13
  end
14
+
15
+ it 'imports title' do
16
+ expect(loaded_class.title).to eq(title)
17
+ end
14
18
  end
15
19
 
16
20
  describe '2.2' do
17
21
  let(:path) { File.join(fixtures_path, 'no_assessment_xml', 'imsmanifest.xml') }
18
22
  let(:loaded_class) { described_class.from_path!(path) }
23
+ let(:title) { '1027TestTitle12' }
19
24
 
20
25
  include_examples 'loading_a_non-assessment'
21
26
  end
@@ -23,6 +28,7 @@ describe Qti::V2::Models::NonAssessmentTest do
23
28
  describe 'package_shared' do
24
29
  let(:path) { File.join(fixtures_path, 'package_shared', 'imsmanifest.xml') }
25
30
  let(:loaded_class) { described_class.from_path!(path) }
31
+ let(:title) { 'imsmanifest' }
26
32
 
27
33
  include_examples 'loading_a_non-assessment'
28
34
  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.9.2
4
+ version: 2.10.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: 2022-05-09 00:00:00.000000000 Z
15
+ date: 2022-09-09 00:00:00.000000000 Z
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
18
18
  name: actionview
@@ -60,28 +60,28 @@ dependencies:
60
60
  requirements:
61
61
  - - "~>"
62
62
  - !ruby/object:Gem::Version
63
- version: 0.4.0
63
+ version: 1.4.0
64
64
  type: :runtime
65
65
  prerelease: false
66
66
  version_requirements: !ruby/object:Gem::Requirement
67
67
  requirements:
68
68
  - - "~>"
69
69
  - !ruby/object:Gem::Version
70
- version: 0.4.0
70
+ version: 1.4.0
71
71
  - !ruby/object:Gem::Dependency
72
72
  name: dry-types
73
73
  requirement: !ruby/object:Gem::Requirement
74
74
  requirements:
75
75
  - - "~>"
76
76
  - !ruby/object:Gem::Version
77
- version: 0.14.0
77
+ version: 1.5.1
78
78
  type: :runtime
79
79
  prerelease: false
80
80
  version_requirements: !ruby/object:Gem::Requirement
81
81
  requirements:
82
82
  - - "~>"
83
83
  - !ruby/object:Gem::Version
84
- version: 0.14.0
84
+ version: 1.5.1
85
85
  - !ruby/object:Gem::Dependency
86
86
  name: mathml2latex
87
87
  requirement: !ruby/object:Gem::Requirement
@@ -701,7 +701,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
701
701
  - !ruby/object:Gem::Version
702
702
  version: '0'
703
703
  requirements: []
704
- rubygems_version: 3.1.6
704
+ rubygems_version: 3.3.7
705
705
  signing_key:
706
706
  specification_version: 4
707
707
  summary: QTI 1.2 and 2.1 import and export models