qti 0.9.16 → 0.9.17

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
  SHA1:
3
- metadata.gz: 9a0c13169b2a41c3d077eee5defae52d8cf5d60e
4
- data.tar.gz: dff7cff54e6307c3f7d0700b85c208ad6e0e95b6
3
+ metadata.gz: '09f2878d599a454231899fde41beea26c04f38fc'
4
+ data.tar.gz: aa579b1c9d7637e0498824eed23fca4fb1d3279d
5
5
  SHA512:
6
- metadata.gz: f7ca63b2d84bc3be43df780a89b27f873b9423e371e8f3c759d4557cb63b90b42f7e8b3629bc23f9c1f9ca5790a75d73d2c30141f399f7ba68125866fa32c7e8
7
- data.tar.gz: 9a837ed2ff4f71e487784fceba65e054ea1db1007846c83f8c6158877d1df4482414bb8e2b244fea21f6f46c0dfa12b1169d5cdad186fc3eb618b682ca29ab55
6
+ metadata.gz: 1b2c438cf24947f35333a90d39a3a833d91edbea2defbe5ab5617a97625cda7a5c730af612ad7ed2e56165e5bd682e558d6c78e465e4f6e7f6e2f3fb26b97551
7
+ data.tar.gz: 1db85799a68254f20845f51477bb21cb73a0e4855665022413ecb382e44f857999fba6b73e4a2490e7289bd5fab51298a6c8d58da54e6c6d23e1181b1b3dcf21
@@ -0,0 +1,154 @@
1
+ require 'qti/v1/models/base'
2
+
3
+ module Qti
4
+ module Models
5
+ class AssessmentMeta < Qti::Models::Base
6
+ def title
7
+ sanitize_content!(tag_under_quiz('title'))
8
+ end
9
+
10
+ def description
11
+ sanitize_content!(tag_under_quiz('description'))
12
+ end
13
+
14
+ def shuffle_answers
15
+ tag_under_quiz('shuffle_answers')
16
+ end
17
+
18
+ def shuffle_answers?
19
+ string_true?(shuffle_answers)
20
+ end
21
+
22
+ def hide_results
23
+ tag_under_quiz('hide_results')
24
+ end
25
+
26
+ def scoring_policy
27
+ tag_under_quiz('scoring_policy')
28
+ end
29
+
30
+ def quiz_type
31
+ tag_under_quiz('quiz_type')
32
+ end
33
+
34
+ def points_possible_raw
35
+ tag_under_quiz('points_possible')
36
+ end
37
+
38
+ def points_possible
39
+ points_possible_raw.to_f
40
+ end
41
+
42
+ def show_correct_anwers
43
+ tag_under_quiz('show_correct_answers')
44
+ end
45
+
46
+ def anonymous_submissions
47
+ tag_under_quiz('anonymous_submissions')
48
+ end
49
+
50
+ def anonymous_submissions?
51
+ string_true?(anonymous_submissions)
52
+ end
53
+
54
+ def could_be_locked
55
+ tag_under_quiz('could_be_locked')
56
+ end
57
+
58
+ def could_be_locked?
59
+ string_true?(could_be_locked)
60
+ end
61
+
62
+ def allowed_attempts_raw
63
+ tag_under_quiz('allowed_attempts')
64
+ end
65
+
66
+ def allowed_attempts
67
+ allowed_attempts_raw.to_i
68
+ end
69
+
70
+ def one_question_at_a_time
71
+ tag_under_quiz('one_question_at_a_time')
72
+ end
73
+
74
+ def one_question_at_a_time?
75
+ one_question_at_a_time == 'true'
76
+ end
77
+
78
+ def cant_go_back
79
+ tag_under_quiz('cant_go_back')
80
+ end
81
+
82
+ def cant_go_back?
83
+ string_true?(cant_go_back)
84
+ end
85
+
86
+ def available
87
+ tag_under_quiz('available')
88
+ end
89
+
90
+ def available?
91
+ string_true?(available)
92
+ end
93
+
94
+ def one_time_results
95
+ tag_under_quiz('one_time_results')
96
+ end
97
+
98
+ def one_time_results?
99
+ string_true?(one_time_results)
100
+ end
101
+
102
+ def show_correct_answers_last_attempt
103
+ tag_under_quiz('show_correct_answers_last_attempt')
104
+ end
105
+
106
+ def show_correct_answers_last_attempt?
107
+ string_true?(show_correct_answers_last_attempt)
108
+ end
109
+
110
+ def only_visible_to_overreides
111
+ tag_under_quiz('only_visible_to_overrides')
112
+ end
113
+
114
+ def only_visible_to_overrides?
115
+ string_true?(only_visible_to_overrides)
116
+ end
117
+
118
+ def module_locked
119
+ tag_under_quiz('module_locked')
120
+ end
121
+
122
+ def module_locked?
123
+ string_true?(module_locked)
124
+ end
125
+
126
+ private
127
+
128
+ def tag_under_quiz(tag)
129
+ @doc.xpath("//xmlns:quiz/xmlns:#{tag}")&.first&.content
130
+ end
131
+
132
+ def string_true?(value)
133
+ value&.casecmp('true')&.zero?
134
+ end
135
+ end
136
+
137
+ module AssessmentMetaBase
138
+ delegate :title, :description,
139
+ :shuffle_answers?, :scoring_policy, :points_possible,
140
+ :hide_results, :quiz_type, :anonymous_submissions?,
141
+ :could_be_locked?, :allowed_attempts, :one_question_at_a_time?,
142
+ :cant_go_back?, :available?, :one_time_results?,
143
+ :show_correct_answers_attempt?, :only_visible_to_overrides?,
144
+ :module_locked?,
145
+ to: :@canvas_meta_data, prefix: :canvas, allow_nil: true
146
+
147
+ alias canvas_instructions canvas_description
148
+
149
+ def canvas_meta_data(meta_data)
150
+ @canvas_meta_data ||= meta_data
151
+ end
152
+ end
153
+ end
154
+ end
@@ -1,4 +1,5 @@
1
1
  require 'qti/v1/models/base'
2
+ require 'qti/models/assessment_meta'
2
3
  require 'qti/v1/models/assessment'
3
4
  require 'qti/v2/models/assessment_test'
4
5
  require 'qti/v2/models/non_assessment_test'
@@ -51,13 +52,15 @@ module Qti
51
52
  return embedded_non_assessment if identifier == EMBEDDED_NON_ASSESSMENT_ID
52
53
  rsc_ver = xpath_with_single_check(xpath_xmlns_resource("[@identifier='#{identifier}']"))&.[](:type)
53
54
  raise_unsupported unless rsc_ver
54
- builder = assessment_class_from_version(rsc_ver)
55
- raise_unsupported unless builder
56
- builder.from_path!(remap_href_path(asset_resource_for(identifier, rsc_ver)), @package_root)
55
+ assessment_from(rsc_ver, identifier)
57
56
  end
58
57
 
59
- def assessment_class_from_version(version)
60
- ASSESSMENT_CLASSES[version.split('/').first]
58
+ def assessment_from(version, identifier)
59
+ builder = ASSESSMENT_CLASSES[version.split('/').first]
60
+ raise_unsupported unless builder
61
+ assessment = builder.from_path!(remap_href_path(asset_resource_for(identifier, version)), @package_root)
62
+ assessment.canvas_meta_data(canvas_meta_data_for(identifier))
63
+ assessment
61
64
  end
62
65
 
63
66
  def asset_resource_for(identifier, qti_type)
@@ -65,6 +68,18 @@ module Qti
65
68
  xmlns_resource(base_xpath + '/@href') || xmlns_resource(base_xpath + '/xmlns:file/@href')
66
69
  end
67
70
 
71
+ def dependency_id(identifier)
72
+ xmlns_resource("[@identifier='#{identifier}']/xmlns:dependency/@identifierref")
73
+ end
74
+
75
+ def canvas_meta_data_for(identifier)
76
+ dep_id = dependency_id(identifier)
77
+ meta_file = xmlns_resource(
78
+ "[@identifier='#{dep_id}']/xmlns:file[#{xpath_endswith('@href', 'assessment_meta.xml')}]/@href"
79
+ )
80
+ return Qti::Models::AssessmentMeta.from_path!(File.join(@package_root, meta_file)) if meta_file
81
+ end
82
+
68
83
  def xmlns_resource(type)
69
84
  xpath_with_single_check(xpath_xmlns_resource(type))&.content
70
85
  end
@@ -81,12 +96,15 @@ module Qti
81
96
  "//xmlns:resources/xmlns:resource#{type}"
82
97
  end
83
98
 
99
+ def xpath_endswith(tag, tail)
100
+ "substring(#{tag}, string-length(#{tag}) - string-length('#{tail}') + 1) = '#{tail}'"
101
+ end
102
+
84
103
  def rtype_predicate(ver, rsc_type)
85
104
  # XPath 2.0 supports ends-with, which is what substring is doing here.
86
105
  # It also support regex matching with matches.
87
106
  # We only have XPath 1.0 available.
88
- cc_match = "starts-with(@type, '#{ver}') and " \
89
- "substring(@type, string-length(@type) - string-length('#{rsc_type}') + 1) = '#{rsc_type}'"
107
+ cc_match = "starts-with(@type, '#{ver}') and " + xpath_endswith('@type', rsc_type)
90
108
  qti_match = "@type='#{ver}'"
91
109
  "#{qti_match} or (#{cc_match})"
92
110
  end
@@ -1,9 +1,11 @@
1
1
  require 'qti/v1/models/base'
2
+ require 'qti/models/assessment_meta'
2
3
 
3
4
  module Qti
4
5
  module V1
5
6
  module Models
6
7
  class Assessment < Qti::V1::Models::Base
8
+ include Qti::Models::AssessmentMetaBase
7
9
  def title
8
10
  @title ||= xpath_with_single_check('.//xmlns:assessment/@title')&.content || File.basename(@path, '.xml')
9
11
  end
@@ -24,7 +24,7 @@ module Qti
24
24
  node.xpath('.//xmlns:var_set').map do |anode|
25
25
  {
26
26
  inputs: vars_at_node(anode),
27
- output: anode.at_xpath('.//xmlns:answer').text
27
+ output: anode.at_xpath('.//xmlns:answer')&.text&.to_f
28
28
  }
29
29
  end
30
30
  end
@@ -66,7 +66,7 @@ module Qti
66
66
  parent_node.xpath('.//xmlns:var').map do |vnode|
67
67
  {
68
68
  name: vnode.attributes['name']&.value,
69
- value: vnode.text
69
+ value: vnode.text&.to_f
70
70
  }
71
71
  end
72
72
  end
@@ -1,9 +1,11 @@
1
1
  require 'qti/v2/models/base'
2
+ require 'qti/models/assessment_meta'
2
3
 
3
4
  module Qti
4
5
  module V2
5
6
  module Models
6
7
  class AssessmentTest < Qti::V2::Models::Base
8
+ include Qti::Models::AssessmentMetaBase
7
9
  def title
8
10
  @title ||= xpath_with_single_check('//xmlns:assessmentTest/@title')&.content || File.basename(@path, '.xml')
9
11
  end
@@ -1,3 +1,3 @@
1
1
  module Qti
2
- VERSION = '0.9.16'.freeze
2
+ VERSION = '0.9.17'.freeze
3
3
  end
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ../..
3
3
  specs:
4
- qti (0.9.16)
4
+ qti (0.9.17)
5
5
  actionview (>= 4.2.0)
6
6
  activesupport (>= 4.2.9, < 5.2)
7
7
  dry-struct (~> 0.2.1)
@@ -114,7 +114,7 @@ GEM
114
114
  unicode-display_width (~> 1.0, >= 1.0.1)
115
115
  ruby-progressbar (1.9.0)
116
116
  rubyzip (1.2.1)
117
- sanitize (4.6.4)
117
+ sanitize (4.6.5)
118
118
  crass (~> 1.0.2)
119
119
  nokogiri (>= 1.4.4)
120
120
  nokogumbo (~> 1.4)
@@ -146,4 +146,4 @@ DEPENDENCIES
146
146
  wwtd (~> 1.3)
147
147
 
148
148
  BUNDLED WITH
149
- 1.16.1
149
+ 1.16.2
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ../..
3
3
  specs:
4
- qti (0.9.16)
4
+ qti (0.9.17)
5
5
  actionview (>= 4.2.0)
6
6
  activesupport (>= 4.2.9, < 5.2)
7
7
  dry-struct (~> 0.2.1)
@@ -114,7 +114,7 @@ GEM
114
114
  unicode-display_width (~> 1.0, >= 1.0.1)
115
115
  ruby-progressbar (1.9.0)
116
116
  rubyzip (1.2.1)
117
- sanitize (4.6.4)
117
+ sanitize (4.6.5)
118
118
  crass (~> 1.0.2)
119
119
  nokogiri (>= 1.4.4)
120
120
  nokogumbo (~> 1.4)
@@ -146,4 +146,4 @@ DEPENDENCIES
146
146
  wwtd (~> 1.3)
147
147
 
148
148
  BUNDLED WITH
149
- 1.16.1
149
+ 1.16.2
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ../..
3
3
  specs:
4
- qti (0.9.16)
4
+ qti (0.9.17)
5
5
  actionview (>= 4.2.0)
6
6
  activesupport (>= 4.2.9, < 5.2)
7
7
  dry-struct (~> 0.2.1)
@@ -165,7 +165,7 @@ GEM
165
165
  unicode-display_width (~> 1.0, >= 1.0.1)
166
166
  ruby-progressbar (1.9.0)
167
167
  rubyzip (1.2.1)
168
- sanitize (4.6.4)
168
+ sanitize (4.6.5)
169
169
  crass (~> 1.0.2)
170
170
  nokogiri (>= 1.4.4)
171
171
  nokogumbo (~> 1.4)
@@ -205,4 +205,4 @@ DEPENDENCIES
205
205
  wwtd (~> 1.3)
206
206
 
207
207
  BUNDLED WITH
208
- 1.16.1
208
+ 1.16.2
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ../..
3
3
  specs:
4
- qti (0.9.16)
4
+ qti (0.9.17)
5
5
  actionview (>= 4.2.0)
6
6
  activesupport (>= 4.2.9, < 5.2)
7
7
  dry-struct (~> 0.2.1)
@@ -168,7 +168,7 @@ GEM
168
168
  unicode-display_width (~> 1.0, >= 1.0.1)
169
169
  ruby-progressbar (1.9.0)
170
170
  rubyzip (1.2.1)
171
- sanitize (4.6.4)
171
+ sanitize (4.6.5)
172
172
  crass (~> 1.0.2)
173
173
  nokogiri (>= 1.4.4)
174
174
  nokogumbo (~> 1.4)
@@ -211,4 +211,4 @@ DEPENDENCIES
211
211
  wwtd (~> 1.3)
212
212
 
213
213
  BUNDLED WITH
214
- 1.16.1
214
+ 1.16.2
@@ -0,0 +1,70 @@
1
+ require 'spec_helper'
2
+
3
+ context 'Canvas Assessment Meta Data' do
4
+ let(:fixtures_path) { File.join('spec', 'fixtures') }
5
+ let(:file_path) { File.join(fixtures_path, qti_file) }
6
+ let(:assessment) { Qti::Importer.new(file_path).test_object }
7
+
8
+ shared_examples 'loads canvas meta data' do
9
+ it 'creates a vaild assessment' do
10
+ expect(assessment).to be_kind_of(assessment_type)
11
+ expect(assessment.canvas_title).to eq(title)
12
+ expect(assessment.canvas_description).to eq(instructions)
13
+ expect(assessment.canvas_instructions).to eq(instructions)
14
+ expect(assessment.canvas_points_possible).to eq(points_possible)
15
+ expect(assessment.canvas_one_question_at_a_time?).to eq(oqaat)
16
+ expect(assessment.canvas_allowed_attempts).to eq(allowed_attempts)
17
+ expect(assessment.canvas_hide_results).to eq(hide_results)
18
+ expect(assessment.canvas_quiz_type).to eq(quiz_type)
19
+ expect(assessment.canvas_anonymous_submissions?).to eq(anon_submissions)
20
+ expect(assessment.canvas_could_be_locked?).to eq(could_be_locked)
21
+ expect(assessment.canvas_cant_go_back?).to eq(nobacktracking)
22
+ expect(assessment.canvas_available?).to eq(available)
23
+ expect(assessment.canvas_one_time_results?).to eq(one_time_results)
24
+ expect(assessment.canvas_scoring_policy).to eq(scoring_policy)
25
+ expect(assessment.canvas_shuffle_answers?).to eq(shuffle_answers)
26
+ end
27
+ end
28
+
29
+ describe 'in a QTI 1.2 container' do
30
+ let(:qti_file) { 'test_qti_1.2_canvas' }
31
+ let(:assessment_type) { Qti::V1::Models::Assessment }
32
+ let(:title) { 'WIJsfijdi' }
33
+ let(:instructions) { '<p>sdvsv</p>' }
34
+ let(:points_possible) { 4.0 }
35
+ let(:oqaat) { false }
36
+ let(:allowed_attempts) { 1 }
37
+ let(:hide_results) { nil }
38
+ let(:quiz_type) { 'assignment' }
39
+ let('anon_submissions') { false }
40
+ let(:could_be_locked) { false }
41
+ let(:nobacktracking) { false }
42
+ let(:available) { true }
43
+ let(:one_time_results) { false }
44
+ let(:scoring_policy) { 'keep_highest' }
45
+ let(:shuffle_answers) { false }
46
+
47
+ include_examples('loads canvas meta data')
48
+ end
49
+
50
+ describe 'in a Common Cartridge container' do
51
+ let(:qti_file) { 'test_imscc_canvas' }
52
+ let(:assessment_type) { Qti::V1::Models::Assessment }
53
+ let(:title) { 'Quiz #1' }
54
+ let(:instructions) { '' }
55
+ let(:points_possible) { 1.0 }
56
+ let(:oqaat) { false }
57
+ let(:allowed_attempts) { 1 }
58
+ let(:hide_results) { '' }
59
+ let(:quiz_type) { 'assignment' }
60
+ let('anon_submissions') { false }
61
+ let(:could_be_locked) { false }
62
+ let(:nobacktracking) { false }
63
+ let(:available) { true }
64
+ let(:one_time_results) { false }
65
+ let(:scoring_policy) { 'keep_highest' }
66
+ let(:shuffle_answers) { false }
67
+
68
+ include_examples('loads canvas meta data')
69
+ end
70
+ end
@@ -38,7 +38,7 @@ describe Qti::V1::Models::Interactions::FormulaInteraction do
38
38
  context 'Simple Formula' do
39
39
  let(:file_path) { File.join(fixtures_path, 'formula.xml') }
40
40
 
41
- let(:scoring_data_values) { %w[9.0 9.0 6.0 2.0 3.0] }
41
+ let(:scoring_data_values) { [9.0, 9.0, 6.0, 2.0, 3.0] }
42
42
 
43
43
  let(:answer_tolerance) { '0' }
44
44
  let(:margin_of_error) { { margin: '0', margin_type: 'absolute' } }
@@ -58,7 +58,7 @@ describe Qti::V1::Models::Interactions::FormulaInteraction do
58
58
  context 'Multiple variable formula' do
59
59
  let(:file_path) { File.join(fixtures_path, 'formula_mvar.xml') }
60
60
 
61
- let(:scoring_data_values) { %w[16.0 7.0 14.0 5.0 7.0 14.0 11.0 7.0 20.0 13.0] }
61
+ let(:scoring_data_values) { [16.0, 7.0, 14.0, 5.0, 7.0, 14.0, 11.0, 7.0, 20.0, 13.0] }
62
62
 
63
63
  let(:answer_tolerance) { '0' }
64
64
  let(:margin_of_error) { { margin: '0', margin_type: 'absolute' } }
@@ -81,7 +81,7 @@ describe Qti::V1::Models::Interactions::FormulaInteraction do
81
81
  context 'Multiple Formula Steps' do
82
82
  let(:file_path) { File.join(fixtures_path, 'formula_mform.xml') }
83
83
 
84
- let(:scoring_data_values) { %w[82.58 23.72 39.75 46.25 41.03] }
84
+ let(:scoring_data_values) { [82.58, 23.72, 39.75, 46.25, 41.03] }
85
85
 
86
86
  let(:answer_tolerance) { '10%' }
87
87
  let(:margin_of_error) { { margin: '10', margin_type: 'percent' } }
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.9.16
4
+ version: 0.9.17
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: 2018-05-15 00:00:00.000000000 Z
12
+ date: 2018-05-18 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport
@@ -288,6 +288,7 @@ files:
288
288
  - lib/qti/content_packaging/outcome_declaration.rb
289
289
  - lib/qti/content_packaging/simple_choice.rb
290
290
  - lib/qti/exporter.rb
291
+ - lib/qti/models/assessment_meta.rb
291
292
  - lib/qti/models/base.rb
292
293
  - lib/qti/models/manifest.rb
293
294
  - lib/qti/v1/models/assessment.rb
@@ -1209,6 +1210,7 @@ files:
1209
1210
  - spec/gemfiles/sanitize-4.5.gemfile.lock
1210
1211
  - spec/lib/qti/assessment_item_exporter_spec.rb
1211
1212
  - spec/lib/qti/exporter_spec.rb
1213
+ - spec/lib/qti/models/assessment_meta_spec.rb
1212
1214
  - spec/lib/qti/models/base_spec.rb
1213
1215
  - spec/lib/qti/models/manifest_spec.rb
1214
1216
  - spec/lib/qti/v1/models/assessment_item_spec.rb
@@ -2147,6 +2149,7 @@ test_files:
2147
2149
  - spec/gemfiles/sanitize-4.5.gemfile.lock
2148
2150
  - spec/lib/qti/assessment_item_exporter_spec.rb
2149
2151
  - spec/lib/qti/exporter_spec.rb
2152
+ - spec/lib/qti/models/assessment_meta_spec.rb
2150
2153
  - spec/lib/qti/models/base_spec.rb
2151
2154
  - spec/lib/qti/models/manifest_spec.rb
2152
2155
  - spec/lib/qti/v1/models/assessment_item_spec.rb