qti 2.6.0 → 2.8.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -2
  3. data/lib/qti/exporter.rb +5 -7
  4. data/lib/qti/models/base.rb +6 -2
  5. data/lib/qti/models/manifest.rb +3 -2
  6. data/lib/qti/models/resource.rb +6 -3
  7. data/lib/qti/sanitizer.rb +14 -1
  8. data/lib/qti/v1/models/assessment_item.rb +2 -2
  9. data/lib/qti/v1/models/interactions/base_fill_blank_interaction.rb +1 -1
  10. data/lib/qti/v1/models/interactions.rb +1 -2
  11. data/lib/qti/v1/models/numerics/exact_match.rb +0 -4
  12. data/lib/qti/v1/models/numerics/margin_error.rb +0 -4
  13. data/lib/qti/v1/models/numerics/precision.rb +0 -4
  14. data/lib/qti/v1/models/numerics/scoring_data.rb +1 -0
  15. data/lib/qti/v1/models/numerics/within_range.rb +0 -4
  16. data/lib/qti/v1/models/object_bank.rb +13 -0
  17. data/lib/qti/v1/models/question_group.rb +8 -0
  18. data/lib/qti/v2/models/assessment_test.rb +2 -1
  19. data/lib/qti/v2/models/interactions/match_interaction.rb +1 -1
  20. data/lib/qti/version.rb +1 -1
  21. data/lib/qti.rb +13 -3
  22. data/spec/fixtures/items_1.2/question_group.xml +2 -0
  23. data/spec/fixtures/items_1.2/true_false.xml +1 -1
  24. data/spec/gemfiles/{rails-5.1.gemfile → rails-6.1.gemfile} +1 -1
  25. data/spec/lib/qti/models/base_spec.rb +2 -2
  26. data/spec/lib/qti/v1/models/assessment_item_spec.rb +12 -0
  27. data/spec/lib/qti/v1/models/interactions/base_fill_blank_interaction_spec.rb +25 -0
  28. data/spec/lib/qti/v1/models/object_bank_spec.rb +24 -0
  29. data/spec/lib/qti/v1/models/question_group_spec.rb +2 -0
  30. data/spec/lib/qti/v2/models/assessment_item_spec.rb +2 -2
  31. data/spec/lib/qti/v2/models/assessment_test_spec.rb +2 -2
  32. data/spec/lib/qti/v2/models/stimulus_item_spec.rb +4 -4
  33. data/spec/lib/qti_spec.rb +3 -3
  34. data/spec/spec_helper.rb +6 -2
  35. metadata +34 -20
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cb32e14ee86e7c85cf22b461d411e17321ebe7a96c5727fd78df4f70adee12f0
4
- data.tar.gz: 40d79b54aa1c73109512a9b40761ca2d9af1e71bfddca3881d4a8bd921dad381
3
+ metadata.gz: 54df1ca504a8dea01a48ad17e4e8e106fb44b85d45c32e2755713ac635314144
4
+ data.tar.gz: a464fc49887753cfc9d73679439d5f81ead4cbd9c6fa66d67e0b319f7dafa3fd
5
5
  SHA512:
6
- metadata.gz: 14938cdfe0af943580f0d6af4429b0942a57e8f2b6c5083a65efa49832b6b01fd063444ab5a7a5b51416f12603698d799e62f00cc1aacfb120580e2ca31cf7fd
7
- data.tar.gz: bce723b2da53fa956f2ae7b7f76d8ce6ae24fd253e991016ddfc049ff7c9618255e6e9979b0e0d233ff6176d1b2a4d65ae2744e36b108f59dab9e4be2db8892a
6
+ metadata.gz: 826397ae8d2beca0fc36f2baa4e85329728c628809aa60863abeca662e4b2238a8724823a50758835e72ecf3bee05848758e128af38a5cded27e5c07e0281535
7
+ data.tar.gz: 1180b3f0f9725d2cc6888a528a584d3b0e436bfef6885c0a7216a3cede6b4123b21c7529dd45d69c543d8e44eeb442e5ae8557a913e0caa53cad86cfe65e33d6
data/README.md CHANGED
@@ -80,8 +80,8 @@ cached, making additional runs significantly faster.
80
80
  Individual spec runs can be started like so:
81
81
 
82
82
  ```bash
83
- docker-compose run --rm app /bin/bash -l -c \
84
- "BUNDLE_GEMFILE=spec/gemfiles/rails-6.0.gemfile rvm-exec 2.5 rspec"
83
+ docker-compose run --rm app bash -lc \
84
+ "BUNDLE_GEMFILE=spec/gemfiles/rails-6.1.gemfile rvm-exec 2.7 rspec"
85
85
  ```
86
86
 
87
87
  If you'd like to mount your git checkout within the docker container running
data/lib/qti/exporter.rb CHANGED
@@ -7,7 +7,7 @@ module Qti
7
7
  @assessment_test = assessment_test
8
8
  @package_root_path = args[:package_root_path] || '.'
9
9
  @exported_file_path =
10
- File.join(File.expand_path('..', package_root_path), File.basename(export_file_name)) + '.zip'
10
+ "#{File.join(File.expand_path('..', package_root_path), File.basename(export_file_name))}.zip"
11
11
  end
12
12
 
13
13
  def export
@@ -167,12 +167,10 @@ module Qti
167
167
 
168
168
  def add_all_files(zipfile, package_root_path)
169
169
  Dir["#{package_root_path}/**/**"].each do |file|
170
- begin
171
- entry = file.sub(package_root_path + '/', '')
172
- zipfile.add(entry, file)
173
- rescue Zip::EntryExistsError
174
- logger.info("#{file} already exists")
175
- end
170
+ entry = file.sub("#{package_root_path}/", '')
171
+ zipfile.add(entry, file)
172
+ rescue Zip::EntryExistsError
173
+ logger.info("#{file} already exists")
176
174
  end
177
175
  end
178
176
  end
@@ -1,19 +1,22 @@
1
1
  module Qti
2
2
  class ParseError < StandardError; end
3
+
3
4
  class SpecificationViolation < StandardError; end
5
+
4
6
  class UnsupportedSchema < StandardError; end
5
7
 
6
8
  module Models
7
9
  class Base
8
10
  attr_reader :doc, :path, :package_root, :resource
9
11
  attr_accessor :manifest
12
+
10
13
  delegate :metadata, to: :@resource, allow_nil: true
11
14
 
12
15
  def sanitize_content!(html)
13
16
  sanitizer.clean(html)
14
17
  end
15
18
 
16
- def self.from_path!(path, package_root = nil, resource = nil)
19
+ def self.from_path!(path, package_root: nil, resource: nil)
17
20
  new(path: path, package_root: package_root, resource: resource)
18
21
  end
19
22
 
@@ -82,7 +85,8 @@ module Qti
82
85
  def package_root=(package_root)
83
86
  @package_root = package_root
84
87
  return unless @package_root
85
- @package_root = Pathname.new(@package_root).cleanpath.to_s + '/'
88
+
89
+ @package_root = "#{Pathname.new(@package_root).cleanpath}/"
86
90
  end
87
91
 
88
92
  def relative_path
@@ -24,7 +24,8 @@ module Qti
24
24
  builder = ASSESSMENT_CLASSES[version.split('/').first]
25
25
  raise_unsupported unless builder
26
26
  rsc = resource_for(identifier, version)
27
- assessment = builder.from_path!(remap_href_path(asset_resource_for(rsc)), @package_root, rsc)
27
+ assessment = builder.from_path!(remap_href_path(asset_resource_for(rsc)), package_root: @package_root,
28
+ resource: rsc)
28
29
  assessment.canvas_meta_data(rsc.canvas_metadata)
29
30
  assessment
30
31
  end
@@ -46,7 +47,7 @@ module Qti
46
47
  end
47
48
 
48
49
  def embedded_non_assessment
49
- Qti::V2::Models::NonAssessmentTest.from_path!(@path, @package_root)
50
+ Qti::V2::Models::NonAssessmentTest.from_path!(@path, package_root: @package_root)
50
51
  end
51
52
  end
52
53
  end
@@ -91,7 +91,7 @@ module Qti
91
91
  Resource.new(resource_node(base_xpath), self)
92
92
  end
93
93
 
94
- def assessment_identifiers(embedded_as_assessment = true)
94
+ def assessment_identifiers(embedded_as_assessment: true)
95
95
  id_list = identifier_list('/assessment')
96
96
  return id_list + [EMBEDDED_NON_ASSESSMENT_ID] if embedded_as_assessment && embedded_non_assessment?
97
97
  id_list
@@ -109,13 +109,16 @@ module Qti
109
109
  doc = load_asset_resource(rsc_path)
110
110
 
111
111
  # There are other types, but all we support right now are object banks...
112
- Qti::V1::Models::ObjectBank.from_path!(rsc_path, @package_root, rsc) unless doc.search('objectbank').empty?
112
+ unless doc.search('objectbank').empty?
113
+ Qti::V1::Models::ObjectBank.from_path!(rsc_path, package_root: @package_root,
114
+ resource: rsc)
115
+ end
113
116
  end.reject(&:nil?)
114
117
  end
115
118
 
116
119
  def objectbanks
117
120
  load_associated_content.select do |c|
118
- c.class == Qti::V1::Models::ObjectBank
121
+ c.instance_of?(Qti::V1::Models::ObjectBank)
119
122
  end
120
123
  end
121
124
 
data/lib/qti/sanitizer.rb CHANGED
@@ -37,6 +37,18 @@ module Qti
37
37
 
38
38
  private
39
39
 
40
+ def convert_canvas_math_images(env)
41
+ node = env[:node]
42
+ node_name = env[:node_name]
43
+ latex = node['data-equation-content']
44
+
45
+ return if env[:is_whitelisted] || !env[:node].element?
46
+ return unless node_name == 'img'
47
+ return unless latex
48
+
49
+ node.replace("\\(#{latex}\\)")
50
+ end
51
+
40
52
  def object_tag_transformer
41
53
  lambda do |env|
42
54
  return unless env[:node_name] == 'object'
@@ -73,6 +85,7 @@ module Qti
73
85
  transformers << src_transformers
74
86
  transformers << object_tag_transformer if import_objects
75
87
  transformers << remap_unknown_tags_transformer
88
+ transformers << method(:convert_canvas_math_images) if Qti.configuration.extract_latex_from_image_tags
76
89
  Sanitize::Config::RELAXED.merge transformers: transformers
77
90
  end
78
91
 
@@ -93,7 +106,7 @@ module Qti
93
106
  path = remap_href_path(node[:data])
94
107
  if path
95
108
  case node[:type]
96
- when %r{^image\/}
109
+ when %r{^image/}
97
110
  return replace_with_image(node, node[:data])
98
111
  when 'text/html'
99
112
  return replace_with_html(node, path)
@@ -2,8 +2,8 @@ module Qti
2
2
  module V1
3
3
  module Models
4
4
  class AssessmentItem < Qti::V1::Models::Base
5
- attr_reader :doc
6
- attr_reader :resource
5
+ attr_reader :doc, :resource
6
+
7
7
  delegate :metadata, to: :@resource
8
8
 
9
9
  def initialize(item, package_root = nil, resource = nil)
@@ -3,7 +3,7 @@ module Qti
3
3
  module Models
4
4
  module Interactions
5
5
  class BaseFillBlankInteraction < BaseInteraction
6
- CANVAS_REGEX ||= /(\[.+?\])/.freeze
6
+ CANVAS_REGEX ||= /(\[[A-Za-z0-9_\-.]+\])/.freeze
7
7
 
8
8
  def canvas_stem_items(item_prompt)
9
9
  item_prompt.split(CANVAS_REGEX).map.with_index do |stem_item, index|
@@ -56,11 +56,10 @@ module Qti
56
56
  end
57
57
 
58
58
  def self.get_matches(node, parent, classlist)
59
- matches = classlist.each_with_object([]) do |interaction_class, result|
59
+ classlist.each_with_object([]) do |interaction_class, result|
60
60
  match = interaction_class.matches(node, parent)
61
61
  result << match if match
62
62
  end
63
- matches
64
63
  end
65
64
  end
66
65
  end
@@ -3,10 +3,6 @@ module Qti
3
3
  module Models
4
4
  module Numerics
5
5
  class ExactMatch < ScoringBase
6
- def initialize(scoring_node)
7
- super(scoring_node)
8
- end
9
-
10
6
  def scoring_data
11
7
  return unless valid?
12
8
  Struct.new(
@@ -3,10 +3,6 @@ module Qti
3
3
  module Models
4
4
  module Numerics
5
5
  class MarginError < ScoringBase
6
- def initialize(scoring_node)
7
- super(scoring_node)
8
- end
9
-
10
6
  def scoring_data
11
7
  return unless valid?
12
8
  Struct.new(
@@ -5,10 +5,6 @@ module Qti
5
5
  class Precision < ScoringBase
6
6
  include ActionView::Helpers::NumberHelper
7
7
 
8
- def initialize(scoring_node)
9
- super(scoring_node)
10
- end
11
-
12
8
  def scoring_data
13
9
  return unless equal_node && gt_node && lte_node
14
10
  Struct.new(
@@ -4,6 +4,7 @@ module Qti
4
4
  module Numerics
5
5
  class ScoringData
6
6
  class UnsupportedNumreicType < StandardError; end
7
+
7
8
  def initialize(node)
8
9
  @scoring_node = ScoringNode.new(node)
9
10
  end
@@ -3,10 +3,6 @@ module Qti
3
3
  module Models
4
4
  module Numerics
5
5
  class WithinRange < ScoringBase
6
- def initialize(scoring_node)
7
- super(scoring_node)
8
- end
9
-
10
6
  def scoring_data
11
7
  return unless valid?
12
8
  Struct.new(
@@ -12,6 +12,19 @@ module Qti
12
12
  def identifier
13
13
  @identifier ||= xpath_with_single_check('.//xmlns:objectbank/@ident')&.content
14
14
  end
15
+
16
+ # tells us whether the bank was an account or course bank
17
+ def bank_type
18
+ @bank_type ||= xpath_with_single_check(
19
+ './/xmlns:qtimetadatafield/xmlns:fieldlabel[text()="bank_type"]/../xmlns:fieldentry'
20
+ )&.content
21
+ end
22
+
23
+ def bank_context_uuid
24
+ @bank_context_uuid ||= xpath_with_single_check(
25
+ './/xmlns:qtimetadatafield/xmlns:fieldlabel[text()="bank_context_uuid"]/../xmlns:fieldentry'
26
+ )&.content
27
+ end
15
28
  end
16
29
  end
17
30
  end
@@ -34,6 +34,14 @@ module Qti
34
34
  selection&.xpath('xmlns:selection_number')&.text&.to_i
35
35
  end
36
36
 
37
+ def sourcebank_ref
38
+ selection&.xpath('xmlns:sourcebank_ref')&.text
39
+ end
40
+
41
+ def sourcebank_export_id
42
+ selection&.xpath('xmlns:sourcebank_export_id')&.text
43
+ end
44
+
37
45
  def points_per_item
38
46
  selection.xpath('xmlns:selection_extension/xmlns:points_per_item')&.text&.to_f
39
47
  end
@@ -31,7 +31,8 @@ module Qti
31
31
  end
32
32
 
33
33
  def create_assessment_item(ref)
34
- item = Qti::V2::Models::AssessmentItem.from_path!(ref[:path], @package_root, ref[:resource])
34
+ item = Qti::V2::Models::AssessmentItem.from_path!(ref[:path], package_root: @package_root,
35
+ resource: ref[:resource])
35
36
  item.manifest = manifest
36
37
  item
37
38
  end
@@ -6,7 +6,7 @@ module Qti
6
6
  module Models
7
7
  module Interactions
8
8
  class MatchInteraction < BaseInteraction
9
- extend Forwardable
9
+ extend ::Forwardable
10
10
 
11
11
  attr_reader :implementation
12
12
 
data/lib/qti/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Qti
2
- VERSION = '2.6.0'.freeze
2
+ VERSION = '2.8.1'.freeze
3
3
  end
data/lib/qti.rb CHANGED
@@ -4,7 +4,9 @@ require 'active_support/core_ext/string'
4
4
  require 'active_support/core_ext/hash/except'
5
5
  require 'active_support/core_ext/module/delegation'
6
6
  require 'dry-struct'
7
+ require 'ostruct'
7
8
  require 'find'
9
+ require 'forwardable'
8
10
  require 'mathml2latex'
9
11
  require 'nokogiri'
10
12
  require 'pathname'
@@ -14,8 +16,8 @@ require 'zip'
14
16
 
15
17
  module Qti
16
18
  class Importer
17
- attr_reader :package_root
18
- attr_reader :assessment_id
19
+ attr_reader :package_root, :assessment_id
20
+
19
21
  delegate :assessment_identifiers, to: :@manifest
20
22
  delegate :question_bank_identifiers, to: :@manifest
21
23
 
@@ -39,7 +41,7 @@ module Qti
39
41
  def self.manifest(path)
40
42
  mpath = manifest_path(path)
41
43
  package_root = File.dirname(mpath)
42
- manifest = Qti::Models::Manifest.from_path!(mpath, package_root = package_root)
44
+ manifest = Qti::Models::Manifest.from_path!(mpath, package_root: package_root)
43
45
  [mpath, package_root, manifest]
44
46
  end
45
47
 
@@ -67,6 +69,14 @@ module Qti
67
69
  @import.create_question_group(question_group_ref)
68
70
  end
69
71
  end
72
+
73
+ def self.configuration
74
+ @configuration ||= OpenStruct.new
75
+ end
76
+
77
+ def self.configure
78
+ yield(configuration)
79
+ end
70
80
  end
71
81
 
72
82
  # The load order of all of these is important.
@@ -15,6 +15,8 @@
15
15
  <selection_extension>
16
16
  <points_per_item>1.0</points_per_item>
17
17
  </selection_extension>
18
+ <sourcebank_ref>sourcebank_reference_uuid</sourcebank_ref>
19
+ <sourcebank_export_id>sourcebank_export_id_test</sourcebank_export_id>
18
20
  </selection>
19
21
  </selection_ordering>
20
22
  <item ident="i09d4a5492a38a5b4d1533b8fdbdf7376" title="Question">
@@ -5,7 +5,7 @@
5
5
  <item title="Grading - specific - 3 pt score" ident="QUE_1003">
6
6
  <presentation>
7
7
  <material>
8
- <mattext texttype="text/html"><![CDATA[If I get a 3, I must have done something wrong. <img align="bottom" alt="image.png" src="org0/images/image.png" border="0"/>]]></mattext>
8
+ <mattext texttype="text/html"><![CDATA[If I get a 3, I must have done something wrong. <img data-equation-content="sample equation" script="alert('bad')" align="bottom" alt="image.png" src="org0/images/image.png" border="0"/> <img script="alert('bad')" align="bottom" alt="image.png" src="org0/images/image.png" border="0"/>]]></mattext>
9
9
  </material>
10
10
  <response_lid ident="QUE_1004_RL" rcardinality="Single" rtiming="No">
11
11
  <render_choice shuffle="Yes">
@@ -2,4 +2,4 @@ source 'https://rubygems.org'
2
2
 
3
3
  gemspec path: '../../'
4
4
 
5
- gem 'rails', '~> 5.1.4'
5
+ gem 'rails', '~> 6.1.0'
@@ -118,7 +118,7 @@ describe Qti::Models::Base do
118
118
  context 'with explicit package root' do
119
119
  let(:package_root) { File.join('spec', 'fixtures', 'test_qti_2.2') }
120
120
  let(:item_path) { File.join(package_root, 'true-false', 'true-false.xml') }
121
- let(:item) { described_class.from_path!(item_path, package_root) }
121
+ let(:item) { described_class.from_path!(item_path, package_root: package_root) }
122
122
 
123
123
  it 'allows safe .. hrefs' do
124
124
  expect do
@@ -135,7 +135,7 @@ describe Qti::Models::Base do
135
135
 
136
136
  context 'with nil package root' do
137
137
  let(:item_path) { File.join('spec', 'fixtures', 'test_qti_2.2', 'true-false', 'true-false.xml') }
138
- let(:item) { described_class.from_path!(item_path, nil) }
138
+ let(:item) { described_class.from_path!(item_path, package_root: nil) }
139
139
 
140
140
  it 'rejects .. hrefs' do
141
141
  expect do
@@ -29,6 +29,18 @@ describe Qti::V1::Models::AssessmentItem do
29
29
  it 'has sanitized item_body' do
30
30
  expect(loaded_class.item_body).to include '<img'
31
31
  expect(loaded_class.item_body).to include 'If I get a 3, I must have done something wrong.'
32
+ expect(loaded_class.item_body).not_to include 'script="alert(\'bad\')"'
33
+ end
34
+
35
+ it 'transforms canvas math content when conversion is enabled' do
36
+ expect(loaded_class.item_body).to include '\(sample equation\)'
37
+ end
38
+
39
+ it 'does not transform math content when conversion is Disabled' do
40
+ Qti.configure do |config|
41
+ config.extract_latex_from_image_tags = false
42
+ end
43
+ expect(loaded_class.item_body).not_to include '"sample equation"'
32
44
  end
33
45
 
34
46
  describe '#points_possible' do
@@ -10,6 +10,31 @@ describe Qti::V1::Models::Interactions::BaseFillBlankInteraction do
10
10
  end
11
11
  end
12
12
 
13
+ context 'canvas_stem_items' do
14
+ let(:file_path) { File.join(fixtures_path, 'canvas_multiple_fib_as_single.xml') }
15
+ let(:simple_prompt) { 'fill in the [blank]' }
16
+ let(:simple_expected) do
17
+ [
18
+ { id: 'stem_0', position: 1, type: 'text', value: 'fill in the ' },
19
+ { id: 'stem_1', position: 2, type: 'text', value: '[blank]' }
20
+ ]
21
+ end
22
+ let(:embedded_prompt) { '[[embedded] [groups]]' }
23
+ let(:embedded_expected) do
24
+ [
25
+ { id: 'stem_0', position: 1, type: 'text', value: '[' },
26
+ { id: 'stem_1', position: 2, type: 'text', value: '[embedded]' },
27
+ { id: 'stem_2', position: 3, type: 'text', value: ' ' },
28
+ { id: 'stem_3', position: 4, type: 'text', value: '[groups]' },
29
+ { id: 'stem_4', position: 5, type: 'text', value: ']' }
30
+ ]
31
+ end
32
+ it 'decomposes item prompts' do
33
+ expect(loaded_class.canvas_stem_items(simple_prompt)).to eq(simple_expected)
34
+ expect(loaded_class.canvas_stem_items(embedded_prompt)).to eq(embedded_expected)
35
+ end
36
+ end
37
+
13
38
  context 'canvas_multiple_dropdowns.xml' do
14
39
  let(:file_path) { File.join(fixtures_path, 'canvas_multiple_dropdowns.xml') }
15
40
  let(:expected_blanks) do
@@ -9,6 +9,14 @@ describe Qti::V1::Models::ObjectBank do
9
9
  <fieldlabel>not_a_bank_title</fieldlabel>
10
10
  <fieldentry>A different metadata entry</fieldentry>
11
11
  </qtimetadatafield>
12
+ <qtimetadatafield>
13
+ <fieldlabel>bank_type</fieldlabel>
14
+ <fieldentry>account</fieldentry>
15
+ </qtimetadatafield>
16
+ <qtimetadatafield>
17
+ <fieldlabel>bank_context_uuid</fieldlabel>
18
+ <fieldentry>oAORQgMEvQquzZyKIW6Usg6CFveihQH5pOqHadsb</fieldentry>
19
+ </qtimetadatafield>
12
20
  </qtimetadata>
13
21
  </objectbank>
14
22
  </questestinterop>
@@ -48,4 +56,20 @@ describe Qti::V1::Models::ObjectBank do
48
56
  expect(objectbank.identifier).to eq 'gooblegobble12345'
49
57
  end
50
58
  end
59
+
60
+ describe '#bank_type' do
61
+ it 'has the bank_type attribute' do
62
+ allow(File).to receive(:read).and_return(doc)
63
+ objectbank = described_class.new path: '/etc/FakeBank008.xml'
64
+ expect(objectbank.bank_type).to eq 'account'
65
+ end
66
+ end
67
+
68
+ describe '#bank_context_uuid' do
69
+ it 'has the bank_context_uuid attribute' do
70
+ allow(File).to receive(:read).and_return(doc)
71
+ objectbank = described_class.new path: '/etc/FakeBank008.xml'
72
+ expect(objectbank.bank_context_uuid).to eq 'oAORQgMEvQquzZyKIW6Usg6CFveihQH5pOqHadsb'
73
+ end
74
+ end
51
75
  end
@@ -7,6 +7,8 @@ describe Qti::V1::Models::QuestionGroup do
7
7
  it 'configures a group correctly' do
8
8
  expect(loaded_class.title).to eq('Group 1 (1/4)')
9
9
  expect(loaded_class.identifier).to eq('i4663897607358cfba8636ed6127b9466')
10
+ expect(loaded_class.sourcebank_ref).to eq('sourcebank_reference_uuid')
11
+ expect(loaded_class.sourcebank_export_id).to eq('sourcebank_export_id_test')
10
12
  expect(loaded_class.items.count).to eq(4)
11
13
  expect(loaded_class.selection_number).to eq(1)
12
14
  expect(loaded_class.points_per_item).to eq(1)
@@ -84,9 +84,9 @@ describe Qti::V2::Models::AssessmentItem do
84
84
 
85
85
  # it 'removes the passage from the item_body' do
86
86
  # item = test_object.create_assessment_item(item_ref)
87
- # rubocop:disable AsciiComments
87
+ # rubocop:disable Style/AsciiComments
88
88
  # expect(item.item_body).not_to include '¡El equipo de hockey te necesita!'
89
- # rubocop:enable AsciiComments
89
+ # rubocop:enable Style/AsciiComments
90
90
  # end
91
91
  # end
92
92
  end
@@ -87,9 +87,9 @@ describe Qti::V2::Models::AssessmentTest do
87
87
  # 'passages', '0cfd5cf7-2c91-4b35-a57a-9f5d1709f68f.html'
88
88
  # )
89
89
  # stimulus = loaded_class.create_stimulus(stimulus_path)
90
- # rubocop:disable AsciiComments
90
+ # rubocop:disable Style/AsciiComments
91
91
  # expect(stimulus.title).to eq '¡El equipo de hockey te necesita!'
92
- # rubocop:enable AsciiComments
92
+ # rubocop:enable Style/AsciiComments
93
93
  # end
94
94
  # end
95
95
  end
@@ -11,17 +11,17 @@
11
11
  # end
12
12
 
13
13
  # it 'has the title' do
14
- # rubocop:disable AsciiComments
14
+ # rubocop:disable Style/AsciiComments
15
15
  # expect(loaded_class.title).to eq '¡El equipo de hockey te necesita!'
16
- # rubocop:enable AsciiComments
16
+ # rubocop:enable Style/AsciiComments
17
17
  # end
18
18
 
19
19
  # it 'has sanitized item_body' do
20
20
  # expect(loaded_class.body).to include '<div'
21
21
  # expect(loaded_class.body).to include 'Listen to the audio passage.'
22
- # rubocop:disable AsciiComments
22
+ # rubocop:disable Style/AsciiComments
23
23
  # expect(loaded_class.body).to include '¡'
24
- # rubocop:enable AsciiComments
24
+ # rubocop:enable Style/AsciiComments
25
25
  # end
26
26
 
27
27
  # it 'has the identifier used to identify it in manifest file' do
data/spec/lib/qti_spec.rb CHANGED
@@ -40,8 +40,8 @@ describe Qti::Importer do
40
40
 
41
41
  it 'sets the path and package root properly' do
42
42
  item = importer.create_assessment_item(importer.assessment_item_refs.first)
43
- expect(item.path).to eq file_path + '/quiz.xml'
44
- expect(item.package_root).to eq file_path + '/'
43
+ expect(item.path).to eq "#{file_path}/quiz.xml"
44
+ expect(item.package_root).to eq "#{file_path}/"
45
45
  end
46
46
  end
47
47
 
@@ -64,7 +64,7 @@ describe Qti::Importer do
64
64
  ref = importer.assessment_item_refs.first
65
65
  item = importer.create_assessment_item(ref)
66
66
  expect(item.path).to eq ref[:path]
67
- expect(item.package_root).to eq file_path + '/'
67
+ expect(item.package_root).to eq "#{file_path}/"
68
68
  expect(item.manifest).not_to be_nil
69
69
  end
70
70
  end
data/spec/spec_helper.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  require 'byebug'
2
2
 
3
3
  # Limit coverage reporting to one build:
4
- if /^2\.6/ =~ RUBY_VERSION && /rails-6\.0/ =~ ENV['BUNDLE_GEMFILE']
4
+ if /^2\.7/ =~ RUBY_VERSION && /rails-6\.1/ =~ ENV['BUNDLE_GEMFILE']
5
5
  require 'simplecov'
6
6
 
7
7
  SimpleCov.start do
@@ -16,7 +16,11 @@ end
16
16
  $LOAD_PATH.unshift File.expand_path('../lib', __dir__)
17
17
  require 'qti'
18
18
 
19
- Dir['./spec/support/**/*.rb'].each { |f| require f }
19
+ Qti.configure do |config|
20
+ config.extract_latex_from_image_tags = true
21
+ end
22
+
23
+ Dir['./spec/support/**/*.rb'].sort.each { |f| require f }
20
24
 
21
25
  RSpec.configure do |config|
22
26
  config.expect_with :rspec do |expectations|
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.6.0
4
+ version: 2.8.1
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: 2021-10-12 00:00:00.000000000 Z
12
+ date: 2022-02-01 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: actionview
@@ -17,40 +17,40 @@ dependencies:
17
17
  requirements:
18
18
  - - ">="
19
19
  - !ruby/object:Gem::Version
20
- version: 5.1.7
20
+ version: '5.2'
21
21
  - - "<"
22
22
  - !ruby/object:Gem::Version
23
- version: '6.1'
23
+ version: '6.2'
24
24
  type: :runtime
25
25
  prerelease: false
26
26
  version_requirements: !ruby/object:Gem::Requirement
27
27
  requirements:
28
28
  - - ">="
29
29
  - !ruby/object:Gem::Version
30
- version: 5.1.7
30
+ version: '5.2'
31
31
  - - "<"
32
32
  - !ruby/object:Gem::Version
33
- version: '6.1'
33
+ version: '6.2'
34
34
  - !ruby/object:Gem::Dependency
35
35
  name: activesupport
36
36
  requirement: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: 5.1.7
40
+ version: '5.2'
41
41
  - - "<"
42
42
  - !ruby/object:Gem::Version
43
- version: '6.1'
43
+ version: '6.2'
44
44
  type: :runtime
45
45
  prerelease: false
46
46
  version_requirements: !ruby/object:Gem::Requirement
47
47
  requirements:
48
48
  - - ">="
49
49
  - !ruby/object:Gem::Version
50
- version: 5.1.7
50
+ version: '5.2'
51
51
  - - "<"
52
52
  - !ruby/object:Gem::Version
53
- version: '6.1'
53
+ version: '6.2'
54
54
  - !ruby/object:Gem::Dependency
55
55
  name: dry-struct
56
56
  requirement: !ruby/object:Gem::Requirement
@@ -141,14 +141,14 @@ dependencies:
141
141
  requirements:
142
142
  - - "~>"
143
143
  - !ruby/object:Gem::Version
144
- version: '1.17'
144
+ version: '2.1'
145
145
  type: :development
146
146
  prerelease: false
147
147
  version_requirements: !ruby/object:Gem::Requirement
148
148
  requirements:
149
149
  - - "~>"
150
150
  - !ruby/object:Gem::Version
151
- version: '1.17'
151
+ version: '2.1'
152
152
  - !ruby/object:Gem::Dependency
153
153
  name: byebug
154
154
  requirement: !ruby/object:Gem::Requirement
@@ -183,14 +183,14 @@ dependencies:
183
183
  requirements:
184
184
  - - "~>"
185
185
  - !ruby/object:Gem::Version
186
- version: '12.3'
186
+ version: '13.0'
187
187
  type: :development
188
188
  prerelease: false
189
189
  version_requirements: !ruby/object:Gem::Requirement
190
190
  requirements:
191
191
  - - "~>"
192
192
  - !ruby/object:Gem::Version
193
- version: '12.3'
193
+ version: '13.0'
194
194
  - !ruby/object:Gem::Dependency
195
195
  name: rspec
196
196
  requirement: !ruby/object:Gem::Requirement
@@ -225,14 +225,28 @@ dependencies:
225
225
  requirements:
226
226
  - - "~>"
227
227
  - !ruby/object:Gem::Version
228
- version: 0.74.0
228
+ version: 1.8.1
229
229
  type: :development
230
230
  prerelease: false
231
231
  version_requirements: !ruby/object:Gem::Requirement
232
232
  requirements:
233
233
  - - "~>"
234
234
  - !ruby/object:Gem::Version
235
- version: 0.74.0
235
+ version: 1.8.1
236
+ - !ruby/object:Gem::Dependency
237
+ name: rubocop-rails
238
+ requirement: !ruby/object:Gem::Requirement
239
+ requirements:
240
+ - - "~>"
241
+ - !ruby/object:Gem::Version
242
+ version: 2.9.1
243
+ type: :development
244
+ prerelease: false
245
+ version_requirements: !ruby/object:Gem::Requirement
246
+ requirements:
247
+ - - "~>"
248
+ - !ruby/object:Gem::Version
249
+ version: 2.9.1
236
250
  - !ruby/object:Gem::Dependency
237
251
  name: simplecov
238
252
  requirement: !ruby/object:Gem::Requirement
@@ -613,9 +627,9 @@ files:
613
627
  - spec/fixtures/with_banks/non_cc_assessments/g9a20cf3af178b54e4792cbe992f65790.xml.qti
614
628
  - spec/fixtures/with_banks/non_cc_assessments/gab22de457404cb5cf022078f1e4da75e.xml.qti
615
629
  - spec/fixtures/with_banks/non_cc_assessments/gf3edf8167be16b3a65a00ca923132b07.xml.qti
616
- - spec/gemfiles/rails-5.1.gemfile
617
630
  - spec/gemfiles/rails-5.2.gemfile
618
631
  - spec/gemfiles/rails-6.0.gemfile
632
+ - spec/gemfiles/rails-6.1.gemfile
619
633
  - spec/lib/qti/assessment_item_exporter_spec.rb
620
634
  - spec/lib/qti/exporter_spec.rb
621
635
  - spec/lib/qti/models/assessment_meta_spec.rb
@@ -678,14 +692,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
678
692
  requirements:
679
693
  - - ">="
680
694
  - !ruby/object:Gem::Version
681
- version: '2.4'
695
+ version: '2.6'
682
696
  required_rubygems_version: !ruby/object:Gem::Requirement
683
697
  requirements:
684
698
  - - ">="
685
699
  - !ruby/object:Gem::Version
686
700
  version: '0'
687
701
  requirements: []
688
- rubygems_version: 3.0.3
702
+ rubygems_version: 3.1.4
689
703
  signing_key:
690
704
  specification_version: 4
691
705
  summary: QTI 1.2 and 2.1 import and export models
@@ -965,9 +979,9 @@ test_files:
965
979
  - spec/fixtures/with_banks/non_cc_assessments/g9a20cf3af178b54e4792cbe992f65790.xml.qti
966
980
  - spec/fixtures/with_banks/non_cc_assessments/gab22de457404cb5cf022078f1e4da75e.xml.qti
967
981
  - spec/fixtures/with_banks/non_cc_assessments/gf3edf8167be16b3a65a00ca923132b07.xml.qti
968
- - spec/gemfiles/rails-5.1.gemfile
969
982
  - spec/gemfiles/rails-5.2.gemfile
970
983
  - spec/gemfiles/rails-6.0.gemfile
984
+ - spec/gemfiles/rails-6.1.gemfile
971
985
  - spec/lib/qti/assessment_item_exporter_spec.rb
972
986
  - spec/lib/qti/exporter_spec.rb
973
987
  - spec/lib/qti/models/assessment_meta_spec.rb