qti 0.1.2 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/null_logger.rb +7 -0
- data/lib/qti.rb +10 -0
- data/lib/qti/assessment_item_exporter.rb +67 -0
- data/lib/qti/content_packaging.rb +15 -0
- data/lib/qti/content_packaging/assessment_item.rb +10 -0
- data/lib/qti/content_packaging/assessment_test.rb +9 -0
- data/lib/qti/content_packaging/choice_interaction.rb +12 -0
- data/lib/qti/content_packaging/outcome_declaration.rb +10 -0
- data/lib/qti/content_packaging/simple_choice.rb +11 -0
- data/lib/qti/exporter.rb +168 -0
- data/lib/qti/item_exporter_factory.rb +15 -0
- data/lib/qti/true_false_item_exporter.rb +7 -0
- data/spec/qti/exporter_spec.rb +55 -0
- data/spec/spec_helper.rb +2 -0
- metadata +74 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3c740d1b3ac0a16f4661dd5ec3fe25691e3aacc4
|
4
|
+
data.tar.gz: d487bd97b470c0948c4512e52cab356777c28674
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: af2cbeb0a5efc6aefd940b238b57a6bc5c273b0601096323ea6beece7137b6c1fcacaa28c6a98840704d656d22bd3214d2661874bc6ad796a4b68b4813caeb2a
|
7
|
+
data.tar.gz: 4b3b108554561f85eda5915f773b301ea396f6ec7e39ea2c46963498ab479f717b5f9f4198682c0bf86c73730f7f665cf330950fca3a69277c776fafb0bf25bd
|
data/lib/null_logger.rb
ADDED
data/lib/qti.rb
CHANGED
@@ -46,6 +46,8 @@ module Qti
|
|
46
46
|
end
|
47
47
|
end
|
48
48
|
|
49
|
+
require 'active_support/core_ext/string'
|
50
|
+
|
49
51
|
require 'qti/models/manifest'
|
50
52
|
require 'qti/models/base'
|
51
53
|
|
@@ -59,3 +61,11 @@ require 'qti/v2/models/choices/simple_choice'
|
|
59
61
|
require 'qti/v2/models/interactions/choice_interaction'
|
60
62
|
require 'qti/v2/models/assessment_item'
|
61
63
|
require 'qti/v2/models/assessment_test'
|
64
|
+
|
65
|
+
require 'zip'
|
66
|
+
require 'qti/exporter'
|
67
|
+
|
68
|
+
require 'qti/content_packaging'
|
69
|
+
require 'qti/assessment_item_exporter'
|
70
|
+
|
71
|
+
require 'null_logger'
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module Qti
|
2
|
+
class AssessmentItemExporter
|
3
|
+
attr_reader :index, :assessment_item, :package_root_path
|
4
|
+
|
5
|
+
def initialize(index, assessment_item, args = {})
|
6
|
+
@index = index
|
7
|
+
@assessment_item = assessment_item
|
8
|
+
@package_root_path = args[:package_root_path] || '.'
|
9
|
+
end
|
10
|
+
|
11
|
+
def export
|
12
|
+
File.open(File.join(package_root_path, "item-#{index + 1}.xml"), 'wb') do |f|
|
13
|
+
f.write xml_string_for_assessment_item(assessment_item)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def xml_string_for_assessment_item(assessment_item)
|
20
|
+
builder = Nokogiri::XML::Builder.new(encoding: 'UTF-8') do |xml|
|
21
|
+
xml.assessmentItem(assesment_item_attributes) do
|
22
|
+
xml.responseDeclaration('identifier' => 'RESPONSE',
|
23
|
+
'cardinality' => cardinality_for_response(assessment_item),
|
24
|
+
'baseType' => 'identifier') do
|
25
|
+
xml.correctResponse do
|
26
|
+
xml.value assessment_item.response
|
27
|
+
end
|
28
|
+
end
|
29
|
+
xml_assessment_item_body(xml, assessment_item)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
builder.to_xml
|
33
|
+
end
|
34
|
+
|
35
|
+
def cardinality_for_response(assessment_item)
|
36
|
+
if assessment_item.response.is_a? Array
|
37
|
+
'multiple'
|
38
|
+
else
|
39
|
+
'single'
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def xml_assessment_item_body(xml, assessment_item)
|
44
|
+
xml.itemBody do
|
45
|
+
xml.choiceInteraction(interaction_params(assessment_item.interaction)) do
|
46
|
+
xml.prompt assessment_item.interaction.prompt
|
47
|
+
assessment_item.interaction.choices.each do |choice|
|
48
|
+
xml.simpleChoice(choice.body, 'identifier' => choice.identifier, 'fixed' => choice.fixed)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def interaction_params(interaction)
|
55
|
+
{ 'responseIdentifier' => 'RESPONSE',
|
56
|
+
'shuffle' => interaction.shuffle,
|
57
|
+
'maxChoices' => interaction.maxChoices }
|
58
|
+
end
|
59
|
+
|
60
|
+
def assesment_item_attributes
|
61
|
+
{ 'xmlns' => 'http://www.imsglobal.org/xsd/imsqti_v2p2', 'xmlns:xi' => 'http://www.w3.org/2001/XInclude',
|
62
|
+
'xmlns:m' => 'http://www.w3.org/1998/Math/MathML', 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
|
63
|
+
'xsi:schemaLocation' => 'http://www.imsglobal.org/xsd/imsqti_v2p2
|
64
|
+
http://www.imsglobal.org/xsd/qti/qtiv2p2/imsqti_v2p2.xsd' }
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'dry-struct'
|
2
|
+
|
3
|
+
module Qti
|
4
|
+
module ContentPackaging
|
5
|
+
module Types
|
6
|
+
include Dry::Types.module
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
require 'qti/content_packaging/outcome_declaration'
|
12
|
+
require 'qti/content_packaging/simple_choice'
|
13
|
+
require 'qti/content_packaging/choice_interaction'
|
14
|
+
require 'qti/content_packaging/assessment_item'
|
15
|
+
require 'qti/content_packaging/assessment_test'
|
@@ -0,0 +1,10 @@
|
|
1
|
+
module Qti
|
2
|
+
module ContentPackaging
|
3
|
+
class AssessmentItem < Dry::Struct
|
4
|
+
attribute :identifier, Types::Strict::String
|
5
|
+
attribute :title, Types::Strict::String
|
6
|
+
attribute :interaction, ContentPackaging::ChoiceInteraction
|
7
|
+
attribute :response, Types::Strict::Array.member(String) | Types::Strict::String
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
module Qti
|
2
|
+
module ContentPackaging
|
3
|
+
class AssessmentTest < Dry::Struct
|
4
|
+
attribute :title, Types::Strict::String
|
5
|
+
attribute :items, Types::Strict::Array.member(ContentPackaging::AssessmentItem)
|
6
|
+
attribute :outcome_declarations, Types::Strict::Array.member(ContentPackaging::OutcomeDeclaration)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Qti
|
2
|
+
module ContentPackaging
|
3
|
+
class ChoiceInteraction < Dry::Struct
|
4
|
+
constructor_type :schema
|
5
|
+
|
6
|
+
attribute :prompt, Types::Strict::String
|
7
|
+
attribute :shuffle, Types::Strict::Bool.default(false)
|
8
|
+
attribute :maxChoices, Types::Coercible::Int
|
9
|
+
attribute :choices, Types::Strict::Array.member(ContentPackaging::SimpleChoice)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
module Qti
|
2
|
+
module ContentPackaging
|
3
|
+
class OutcomeDeclaration < Dry::Struct
|
4
|
+
attribute :identifier, Types::Strict::String
|
5
|
+
attribute :baseType, Types::Strict::String
|
6
|
+
attribute :cardinality, Types::Strict::String
|
7
|
+
attribute :defaultValue, Types::Strict::String | Types::Coercible::Int | Types::Coercible::Float
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module Qti
|
2
|
+
module ContentPackaging
|
3
|
+
class SimpleChoice < Dry::Struct
|
4
|
+
constructor_type :schema
|
5
|
+
|
6
|
+
attribute :body, Types::Strict::String
|
7
|
+
attribute :identifier, Types::Strict::String
|
8
|
+
attribute :fixed, Types::Strict::Bool.default(true)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
data/lib/qti/exporter.rb
ADDED
@@ -0,0 +1,168 @@
|
|
1
|
+
module Qti
|
2
|
+
class Exporter
|
3
|
+
attr_reader :assessment_test, :package_root_path, :exported_file_path, :logger
|
4
|
+
|
5
|
+
def initialize(assessment_test, args = {})
|
6
|
+
@logger = args[:logger] || NullLogger.new
|
7
|
+
@assessment_test = assessment_test
|
8
|
+
@package_root_path = args[:package_root_path] || '.'
|
9
|
+
@exported_file_path =
|
10
|
+
File.join(File.expand_path('..', package_root_path), File.basename(export_file_name)) + '.zip'
|
11
|
+
end
|
12
|
+
|
13
|
+
def export
|
14
|
+
Dir.mkdir(package_root_path) unless File.exist?(package_root_path)
|
15
|
+
create_assessment_xml
|
16
|
+
create_imsmanifest_xml
|
17
|
+
export_items
|
18
|
+
compress_package
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def export_file_name
|
24
|
+
@export_file_name ||= "#{assessment_test.title.camelcase.gsub(/\s+/, '')}#{file_timestamp}"
|
25
|
+
end
|
26
|
+
|
27
|
+
def file_timestamp
|
28
|
+
Time.now.utc.strftime('%Y%m%d%H%M%S')
|
29
|
+
end
|
30
|
+
|
31
|
+
def create_assessment_xml
|
32
|
+
builder = Nokogiri::XML::Builder.new(encoding: 'UTF-8') do |xml|
|
33
|
+
xml.assessmentTest(assesment_test_attributes(title: assessment_test.title)) do
|
34
|
+
outcome_declarations(xml, assessment_test)
|
35
|
+
xml.testPart do
|
36
|
+
xml_assessment_section(xml)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
File.open(File.join(package_root_path, 'assessment.xml'), 'wb') do |f|
|
42
|
+
f.write builder.to_xml
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def outcome_declarations(xml, assessment_test)
|
47
|
+
assessment_test.outcome_declarations.each do |outcome_declaration|
|
48
|
+
xml.outcomeDeclaration('baseType' => outcome_declaration.baseType,
|
49
|
+
'cardinality' => outcome_declaration.cardinality,
|
50
|
+
'identifier' => outcome_declaration.identifier) do
|
51
|
+
xml.defaultValue do
|
52
|
+
xml.value outcome_declaration.defaultValue
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def xml_assessment_section(xml)
|
59
|
+
xml.assessmentSection('identifier' => 'S1', 'visible' => 'true', 'title' => 'Section 1') do
|
60
|
+
assessment_test.items.each_with_index do |item, index|
|
61
|
+
xml.assessmentItemRef('identifier' => item.identifier, 'href' => "item-#{index + 1}.xml")
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def create_imsmanifest_xml
|
67
|
+
builder = Nokogiri::XML::Builder.new(encoding: 'UTF-8') do |xml|
|
68
|
+
xml.manifest(imsmanifest_attributes) do
|
69
|
+
manifest_metadata(xml)
|
70
|
+
manifest_resources(xml)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
File.open(File.join(package_root_path, 'imsmanifest.xml'), 'wb') do |f|
|
75
|
+
f.write builder.to_xml
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def manifest_metadata(xml)
|
80
|
+
xml.metadata do
|
81
|
+
xml.schema 'QTIv2.2 Package'
|
82
|
+
xml.schemaversion '1.0.0'
|
83
|
+
learning_object_metadata(xml)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def learning_object_metadata(xml)
|
88
|
+
imsmd_ns = xml['imsmd']
|
89
|
+
|
90
|
+
imsmd_ns.lom do
|
91
|
+
imsmd_ns.general do
|
92
|
+
imsmd_ns.identifier do
|
93
|
+
imsmd_ns.entry 'FB-02'
|
94
|
+
end
|
95
|
+
imsmd_ns.title do
|
96
|
+
imsmd_ns.string(assessment_test.title, 'language' => 'en')
|
97
|
+
end
|
98
|
+
imsmd_ns.language 'en'
|
99
|
+
imsmd_ns.description do
|
100
|
+
imsmd_ns.string('Instructure QTI package.' \
|
101
|
+
'Feedback XML used as an example of unprocessable entity', 'language' => 'en')
|
102
|
+
end
|
103
|
+
end
|
104
|
+
keywords(xml)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def keywords(xml)
|
109
|
+
keywords = %w(feedback modal test inline block)
|
110
|
+
keywords.each do |keyword|
|
111
|
+
xml['imsmd'].keyword do
|
112
|
+
xml['imsmd'].string(keyword, 'language' => 'en')
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def manifest_resources(xml)
|
118
|
+
xml.resources do
|
119
|
+
xml.resource('href' => 'assessment.xml', 'type' => 'imsqti_test_xmlv2p2', 'identifier' => 'TEST') do
|
120
|
+
xml.file('href' => 'assessment.xml')
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def export_items
|
126
|
+
assessment_test.items.each_with_index do |assessment_item, index|
|
127
|
+
Qti::AssessmentItemExporter.new(index, assessment_item, package_root_path: package_root_path).export
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def assesment_test_attributes(args = {})
|
132
|
+
{ 'xmlns' => 'http://www.imsglobal.org/xsd/imsqti_v2p2', 'xmlns:xi' => 'http://www.w3.org/2001/XInclude',
|
133
|
+
'xmlns:m' => 'http://www.w3.org/1998/Math/MathML', 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
|
134
|
+
'xsi:schemaLocation' => 'http://www.imsglobal.org/xsd/imsqti_v2p2' \
|
135
|
+
'http://www.imsglobal.org/xsd/qti/qtiv2p2/imsqti_v2p2.xsd' }.merge(args)
|
136
|
+
end
|
137
|
+
|
138
|
+
def imsmanifest_attributes
|
139
|
+
{ 'xmlns' => 'http://www.imsglobal.org/xsd/imscp_v1p1', 'xmlns:imsmd' => 'http://ltsc.ieee.org/xsd/LOM',
|
140
|
+
'xmlns:imsqti' => 'http://www.imsglobal.org/xsd/imsqti_v2p2', 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
|
141
|
+
'xsi:schemaLocation' => 'http://www.imsglobal.org/xsd/imscp_v1p1 ' \
|
142
|
+
'http://www.imsglobal.org/xsd/qti/qtiv2p2/qtiv2p2_imscpv1p2_v1p0.xsd' \
|
143
|
+
'http://ltsc.ieee.org/xsd/LOM http://www.imsglobal.org/xsd/imsmd_loose_v1p3p2.xsd' \
|
144
|
+
'http://www.imsglobal.org/xsd/imsqti_metadata_v2p2' \
|
145
|
+
'http://www.imsglobal.org/xsd/qti/qtiv2p2/imsqti_metadata_v2p2.xsd' }
|
146
|
+
end
|
147
|
+
|
148
|
+
def compress_package
|
149
|
+
Zip::File.open(exported_file_path, 'w') do |zipfile|
|
150
|
+
add_all_files(zipfile, package_root_path)
|
151
|
+
end
|
152
|
+
|
153
|
+
FileUtils.rm_rf(package_root_path)
|
154
|
+
exported_file_path
|
155
|
+
end
|
156
|
+
|
157
|
+
def add_all_files(zipfile, package_root_path)
|
158
|
+
Dir["#{package_root_path}/**/**"].each do |file|
|
159
|
+
begin
|
160
|
+
entry = file.sub(package_root_path + '/', '')
|
161
|
+
zipfile.add(entry, file)
|
162
|
+
rescue Zip::EntryExistsError
|
163
|
+
logger.info("#{file} already exists")
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Qti
|
2
|
+
class ItemExporterFactory
|
3
|
+
EXPORTER_CLASS = { 'TrueFalse' => TrueFalseItemExporter }.freeze
|
4
|
+
|
5
|
+
def self.create(item, args = {})
|
6
|
+
exporter_class = EXPORTER_CLASS[item.interaction_type] || NullExporter
|
7
|
+
exporter_class.new(item, args)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class NullExporter < ItemExporter
|
12
|
+
def export
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Qti::Exporter do
|
4
|
+
let(:assessment_test) do
|
5
|
+
Qti::ContentPackaging::AssessmentTest.new(
|
6
|
+
title: 'Example test',
|
7
|
+
items: [
|
8
|
+
Qti::ContentPackaging::AssessmentItem.new(
|
9
|
+
identifier: '1', title: 'Question 1', response: 'true',
|
10
|
+
interaction: Qti::ContentPackaging::ChoiceInteraction.new(
|
11
|
+
prompt: 'Is 1+1 equals 2?', maxChoices: 1,
|
12
|
+
choices: [
|
13
|
+
Qti::ContentPackaging::SimpleChoice.new(
|
14
|
+
identifier: 'true', body: 'True'
|
15
|
+
),
|
16
|
+
Qti::ContentPackaging::SimpleChoice.new(
|
17
|
+
identifier: 'false', body: 'False'
|
18
|
+
)
|
19
|
+
]
|
20
|
+
)
|
21
|
+
)
|
22
|
+
],
|
23
|
+
outcome_declarations: [
|
24
|
+
Qti::ContentPackaging::OutcomeDeclaration.new(
|
25
|
+
identifier: 'TEST_total', baseType: 'float', cardinality: 'single', defaultValue: 0.0
|
26
|
+
),
|
27
|
+
Qti::ContentPackaging::OutcomeDeclaration.new(
|
28
|
+
identifier: 'S1', baseType: 'float', cardinality: 'single', defaultValue: 0.0
|
29
|
+
)
|
30
|
+
]
|
31
|
+
)
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'creates the zip file' do
|
35
|
+
dir = Dir.mktmpdir
|
36
|
+
|
37
|
+
exporter = Qti::Exporter.new(assessment_test, package_root_path: dir)
|
38
|
+
exporter.export
|
39
|
+
|
40
|
+
expect(File.exist?(exporter.exported_file_path)).to be_truthy
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'contains an imsnanifest.xml and an assessment.xml files' do
|
44
|
+
dir = Dir.mktmpdir
|
45
|
+
|
46
|
+
exporter = Qti::Exporter.new(assessment_test, package_root_path: dir)
|
47
|
+
exporter.export
|
48
|
+
|
49
|
+
Zip::File.open(exporter.exported_file_path, 'r') do |zip_file|
|
50
|
+
expect(zip_file.glob('imsmanifest.xml').first).to be_present
|
51
|
+
expect(zip_file.glob('assessment.xml').first).to be_present
|
52
|
+
expect(zip_file.glob('item-1.xml').first).to be_present
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,15 +1,58 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: qti
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Hannah Bottalla
|
8
|
+
- Robinson Rodríguez
|
8
9
|
autorequire:
|
9
10
|
bindir: bin
|
10
11
|
cert_chain: []
|
11
|
-
date: 2017-
|
12
|
+
date: 2017-03-06 00:00:00.000000000 Z
|
12
13
|
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: activesupport
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - "~>"
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: 4.2.6
|
21
|
+
type: :runtime
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - "~>"
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: 4.2.6
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: dry-struct
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - "~>"
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: 0.2.1
|
35
|
+
type: :runtime
|
36
|
+
prerelease: false
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - "~>"
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: 0.2.1
|
42
|
+
- !ruby/object:Gem::Dependency
|
43
|
+
name: rubyzip
|
44
|
+
requirement: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - "~>"
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: 1.2.0
|
49
|
+
type: :runtime
|
50
|
+
prerelease: false
|
51
|
+
version_requirements: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - "~>"
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: 1.2.0
|
13
56
|
- !ruby/object:Gem::Dependency
|
14
57
|
name: bundler
|
15
58
|
requirement: !ruby/object:Gem::Requirement
|
@@ -24,6 +67,20 @@ dependencies:
|
|
24
67
|
- - "~>"
|
25
68
|
- !ruby/object:Gem::Version
|
26
69
|
version: '1.11'
|
70
|
+
- !ruby/object:Gem::Dependency
|
71
|
+
name: byebug
|
72
|
+
requirement: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - "~>"
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: 9.0.5
|
77
|
+
type: :development
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - "~>"
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: 9.0.5
|
27
84
|
- !ruby/object:Gem::Dependency
|
28
85
|
name: rake
|
29
86
|
requirement: !ruby/object:Gem::Requirement
|
@@ -111,16 +168,28 @@ dependencies:
|
|
111
168
|
description:
|
112
169
|
email:
|
113
170
|
- hannah@instructure.com
|
114
|
-
-
|
171
|
+
- rrodriguez-bd@instructure.com
|
172
|
+
- quizzes@instructure.com
|
115
173
|
executables: []
|
116
174
|
extensions: []
|
117
175
|
extra_rdoc_files: []
|
118
176
|
files:
|
119
177
|
- README.md
|
120
178
|
- Rakefile
|
179
|
+
- lib/null_logger.rb
|
121
180
|
- lib/qti.rb
|
181
|
+
- lib/qti/assessment_item_exporter.rb
|
182
|
+
- lib/qti/content_packaging.rb
|
183
|
+
- lib/qti/content_packaging/assessment_item.rb
|
184
|
+
- lib/qti/content_packaging/assessment_test.rb
|
185
|
+
- lib/qti/content_packaging/choice_interaction.rb
|
186
|
+
- lib/qti/content_packaging/outcome_declaration.rb
|
187
|
+
- lib/qti/content_packaging/simple_choice.rb
|
188
|
+
- lib/qti/exporter.rb
|
189
|
+
- lib/qti/item_exporter_factory.rb
|
122
190
|
- lib/qti/models/base.rb
|
123
191
|
- lib/qti/models/manifest.rb
|
192
|
+
- lib/qti/true_false_item_exporter.rb
|
124
193
|
- lib/qti/v1/models/assessment.rb
|
125
194
|
- lib/qti/v1/models/assessment_item.rb
|
126
195
|
- lib/qti/v1/models/base.rb
|
@@ -297,6 +366,7 @@ files:
|
|
297
366
|
- spec/fixtures/tests/tests/rtest25.xml
|
298
367
|
- spec/fixtures/tests/tests/rtest26.xml
|
299
368
|
- spec/fixtures/tests/tests/rtest27.xml
|
369
|
+
- spec/qti/exporter_spec.rb
|
300
370
|
- spec/qti/models/base_spec.rb
|
301
371
|
- spec/qti/models/manifest_spec.rb
|
302
372
|
- spec/qti/v1/models/assessment_item_spec.rb
|
@@ -496,6 +566,7 @@ test_files:
|
|
496
566
|
- spec/fixtures/tests/tests/rtest25.xml
|
497
567
|
- spec/fixtures/tests/tests/rtest26.xml
|
498
568
|
- spec/fixtures/tests/tests/rtest27.xml
|
569
|
+
- spec/qti/exporter_spec.rb
|
499
570
|
- spec/qti/models/base_spec.rb
|
500
571
|
- spec/qti/models/manifest_spec.rb
|
501
572
|
- spec/qti/v1/models/assessment_item_spec.rb
|