canvas_qti_to_learnosity_converter 2.2.0 → 2.4.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: 2e102ffcbd4d59f3fb3e466bdfada0f614ed1ae8438e2e63322454d1585203f7
4
- data.tar.gz: 8f52c78fc0e604827e947095e4ca12ed2a1da248a2d97fa9ca18721da255e0c7
3
+ metadata.gz: a2f612956cbc00ab89e47a628c2c7d9007053f1533f5ec5cf5d6f6066b5d0b95
4
+ data.tar.gz: 196ec2ae80fee84fd92812a7d720218efc9219c7f97fb11c04b79681b093657f
5
5
  SHA512:
6
- metadata.gz: 96621e2221a06448c6a351cee7f460ef5067c470cc84102b9b2e37bab8d8d6e77c9ee81ca006d7336cffb42ac4d1972b3a957eb2e31f8f7f8fd2b3125ffc8d70
7
- data.tar.gz: e184a67f1c709ed6189bb2d7fe8aee3484d03a2f0a8ee25747fed902c3fbe78f62634f4f2aa878976624e70c5f97eef551e49dc7300981f4ba19a4b7b982ec69
6
+ metadata.gz: 8289a948c65d4506923e9097c1bfbef83cd1e7b89f2a2d80ce6bd86eb86b416948883ef81a693a574b09a4187d37c7a6fb73259e838c5a7296c917d952f78c65
7
+ data.tar.gz: 2a4a8d92ec9a9739cb4048c7698e61af46c0ad9691a4d154f49573c1ce6e38c3d0c3b12e25db1cea931c017303f58bd6b04afac42c58a34e1bfffcf235cbc208
data/.gitignore CHANGED
@@ -6,6 +6,7 @@
6
6
  /pkg/
7
7
  /spec/reports/
8
8
  /tmp/
9
+ /vendor/
9
10
 
10
11
  .byebug_history
11
12
 
@@ -18,7 +18,7 @@ Gem::Specification.new do |spec|
18
18
  end
19
19
  spec.require_paths = ["lib"]
20
20
 
21
- spec.add_development_dependency "bundler", "~> 1.16"
21
+ spec.add_development_dependency "bundler", "~> 2.3"
22
22
  spec.add_development_dependency "byebug"
23
23
  spec.add_development_dependency "rake", "~> 10.0"
24
24
  spec.add_development_dependency "rspec", "~> 3.0"
@@ -45,6 +45,11 @@ module CanvasQtiToLearnosityConverter
45
45
  }
46
46
 
47
47
  class CanvasQuestionTypeNotSupportedError < RuntimeError
48
+ attr_reader :question_type
49
+ def initialize(question_type)
50
+ @question_type = question_type.to_s
51
+ super("Unsupported question type #{@question_type}")
52
+ end
48
53
  end
49
54
 
50
55
  class CanvasQtiQuiz
@@ -78,8 +83,8 @@ module CanvasQtiToLearnosityConverter
78
83
  end
79
84
 
80
85
  def self.add_files_to_assets(assets, path, text)
81
- text.scan(/%24IMS-CC-FILEBASE%24\/([^"]+)/).flatten.each do |asset_path|
82
- decoded_path = URI.unescape(asset_path)
86
+ text.scan(/(%24|\$)IMS-CC-FILEBASE\1\/([^"]+)/) do |_delimiter, asset_path|
87
+ decoded_path = CGI.unescape(asset_path)
83
88
  assets[decoded_path] ||= []
84
89
  assets[decoded_path].push(path)
85
90
  end
@@ -106,7 +111,7 @@ module CanvasQtiToLearnosityConverter
106
111
  if question_class
107
112
  question = question_class.new(xml)
108
113
  else
109
- raise CanvasQuestionTypeNotSupportedError
114
+ raise CanvasQuestionTypeNotSupportedError.new(type)
110
115
  end
111
116
 
112
117
  [learnosity_type, question]
@@ -116,19 +121,22 @@ module CanvasQtiToLearnosityConverter
116
121
  title.gsub(/["']/, "")
117
122
  end
118
123
 
119
- def self.convert(qti, assets)
124
+ def self.convert(qti, assets, errors)
120
125
  quiz = CanvasQtiQuiz.new(qti_string: qti)
121
126
  assessment = quiz.css("assessment")
122
127
  ident = assessment.attribute("ident").value
123
128
  assets[ident] = {}
129
+ errors[ident] = []
124
130
 
125
131
  items = []
126
132
 
127
133
  quiz.css("item").each.with_index do |item, index|
128
134
  begin
135
+ item_title = item.attribute("title").value
129
136
  learnosity_type, quiz_item = convert_item(qti_string: item.to_html)
130
137
 
131
138
  item = {
139
+ title: item_title,
132
140
  type: learnosity_type,
133
141
  data: quiz_item.to_learnosity,
134
142
  dynamic_content_data: quiz_item.dynamic_content_data()
@@ -138,8 +146,19 @@ module CanvasQtiToLearnosityConverter
138
146
  path = [items.count - 1, :data]
139
147
 
140
148
  quiz_item.add_learnosity_assets(assets[ident], path)
141
- rescue CanvasQuestionTypeNotSupportedError
142
- nil
149
+ rescue CanvasQuestionTypeNotSupportedError => e
150
+ errors[ident].push({
151
+ index: index,
152
+ error_type: "unsupported_question",
153
+ question_type: e.question_type.to_s,
154
+ message: e.message,
155
+ })
156
+ rescue StandardError => e
157
+ errors[ident].push({
158
+ index: index,
159
+ error_type: e.class.to_s,
160
+ message: e.message,
161
+ })
143
162
  end
144
163
  end
145
164
 
@@ -172,14 +191,16 @@ module CanvasQtiToLearnosityConverter
172
191
  paths = imscc_quiz_paths(parsed_manifest)
173
192
 
174
193
  assets = {}
194
+ errors = {}
175
195
  converted_assesments = paths.map do |qti_path|
176
196
  qti = zip_file.find_entry(qti_path).get_input_stream.read
177
- convert(qti, assets)
197
+ convert(qti, assets, errors)
178
198
  end
179
199
 
180
200
  {
181
201
  assessments: converted_assesments,
182
202
  assets: assets,
203
+ errors: errors,
183
204
  }
184
205
  end
185
206
  end
@@ -28,6 +28,7 @@ module CanvasQtiToLearnosityConverter
28
28
  {
29
29
  "scoring_type" => "exactMatch",
30
30
  "valid_response" => {
31
+ "score" => extract_points_possible,
31
32
  "value" => [[{
32
33
  "method" => "equivValue",
33
34
  "value" => "{{var:answer}}\\pm#{pm}"
@@ -6,6 +6,9 @@ module CanvasQtiToLearnosityConverter
6
6
  {
7
7
  type: "longtextV2",
8
8
  stimulus: extract_stimulus(),
9
+ validation: {
10
+ max_score: extract_points_possible,
11
+ },
9
12
  }
10
13
  end
11
14
 
@@ -6,6 +6,9 @@ module CanvasQtiToLearnosityConverter
6
6
  {
7
7
  type: "fileupload",
8
8
  stimulus: extract_stimulus(),
9
+ validation: {
10
+ max_score: extract_points_possible,
11
+ },
9
12
  allow_pdf: true,
10
13
  allow_jpg: true,
11
14
  allow_gif: true,
@@ -42,7 +42,8 @@ module CanvasQtiToLearnosityConverter
42
42
  create_responses(responses, 0, all_responses, [])
43
43
 
44
44
  {
45
- "scoring_type" => "partialMatch",
45
+ "scoring_type" => "partialMatchV2",
46
+ "rounding" => "none",
46
47
  "valid_response" => all_responses.shift,
47
48
  "alt_responses" => all_responses
48
49
  }
@@ -50,7 +51,7 @@ module CanvasQtiToLearnosityConverter
50
51
 
51
52
  def create_responses(blank_responses, depth, result, current_response)
52
53
  if depth == blank_responses.count
53
- result.push({ "value" => current_response })
54
+ result.push({ "score" => extract_points_possible, "value" => current_response })
54
55
  return
55
56
  end
56
57
 
@@ -4,19 +4,20 @@ module CanvasQtiToLearnosityConverter
4
4
  class MatchingQuestion < QuizQuestion
5
5
  def to_learnosity
6
6
  {
7
- type: "association",
7
+ type: "clozedropdown",
8
8
  stimulus: extract_stimulus(),
9
- stimulus_list: extract_stimulus_list(),
9
+ template: extract_template(),
10
10
  validation: extract_validation(),
11
11
  possible_responses: extract_responses(),
12
12
  duplicate_responses: true,
13
+ shuffle_options: true,
13
14
  }
14
15
  end
15
16
 
16
- def extract_stimulus_list()
17
+ def extract_template()
17
18
  @xml.css("item > presentation > response_lid > material > mattext").map do |node|
18
- extract_mattext(node)
19
- end
19
+ "<p>#{extract_mattext(node)} {{response}}</p>"
20
+ end.join("\n")
20
21
  end
21
22
 
22
23
  def extract_response_idents()
@@ -48,18 +49,20 @@ module CanvasQtiToLearnosityConverter
48
49
  end.flatten
49
50
 
50
51
  {
51
- "scoring_type" => "partialMatch",
52
+ "scoring_type" => "partialMatchV2",
53
+ "rounding" => "none",
52
54
  "valid_response" => {
53
- "value" => valid_responses
55
+ "value" => valid_responses,
56
+ "score" => extract_points_possible,
54
57
  }
55
58
  }
56
59
  end
57
60
 
58
61
  def extract_responses()
59
- response_node = @xml.css("item > presentation > response_lid").first
60
-
61
- response_node.css("response_label mattext").map do |node|
62
- extract_mattext(node)
62
+ @xml.css("item > presentation > response_lid").map do |response|
63
+ response.css("response_label mattext").map do |node|
64
+ extract_mattext(node)
65
+ end
63
66
  end
64
67
  end
65
68
 
@@ -30,6 +30,7 @@ module CanvasQtiToLearnosityConverter
30
30
  "scoring_type" => "exactMatch",
31
31
  "valid_response" => {
32
32
  "value" => [correct_value],
33
+ "score" => extract_points_possible,
33
34
  },
34
35
  }
35
36
  end
@@ -81,8 +82,13 @@ module CanvasQtiToLearnosityConverter
81
82
  and > varequal')
82
83
  alt_responses = correct_condition.map(&:text)
83
84
  {
84
- "scoring_type" => "partialMatch",
85
- "alt_responses" => alt_responses,
85
+ "scoring_type" => "partialMatchV2",
86
+ "rounding" => "none",
87
+ "penalty" => extract_points_possible,
88
+ "valid_response" => {
89
+ "score" => extract_points_possible,
90
+ "value" => alt_responses,
91
+ },
86
92
  }
87
93
  end
88
94
  end
@@ -28,9 +28,11 @@ module CanvasQtiToLearnosityConverter
28
28
  end.flatten
29
29
 
30
30
  {
31
- "scoring_type" => "partialMatch",
31
+ "scoring_type" => "partialMatchV2",
32
+ "rounding" => "none",
32
33
  "valid_response" => {
33
34
  "value" => valid_responses,
35
+ "score" => extract_points_possible,
34
36
  }
35
37
  }
36
38
  end
@@ -41,6 +41,7 @@ module CanvasQtiToLearnosityConverter
41
41
  "value" => [{
42
42
  "method" => "equivValue",
43
43
  "value" => "#{bounds[:center]}\\pm#{bounds[:pm]}",
44
+ "score" => extract_points_possible,
44
45
  }]
45
46
  }
46
47
  end
@@ -14,6 +14,12 @@ module CanvasQtiToLearnosityConverter
14
14
  extract_mattext(mattext)
15
15
  end
16
16
 
17
+ def extract_points_possible
18
+ @xml.css(%{ item > itemmetadata > qtimetadata >
19
+ qtimetadatafield > fieldlabel:contains("points_possible")})
20
+ &.first&.next&.text&.to_f || 1.0
21
+ end
22
+
17
23
  def extract_mattext(mattext_node)
18
24
  mattext_node.content
19
25
  end
@@ -20,11 +20,11 @@ module CanvasQtiToLearnosityConverter
20
20
  def extract_validation()
21
21
  correct_responses = @xml.css('item > resprocessing >
22
22
  respcondition[continue="No"] > conditionvar > varequal')
23
- correct_response = { "value" => correct_responses.shift.text }
23
+ correct_response = { "value" => correct_responses.shift.text, "score" => extract_points_possible}
24
24
  {
25
25
  "scoring_type" => "exactMatch",
26
26
  "valid_response" => correct_response,
27
- "alt_responses" => correct_responses.map { |res| { "value" => res.text } }
27
+ "alt_responses" => correct_responses.map { |res| { "value" => res.text, "score" => extract_points_possible } }
28
28
  }
29
29
  end
30
30
 
@@ -1,3 +1,3 @@
1
1
  module CanvasQtiToLearnosityConverter
2
- VERSION = "2.2.0"
2
+ VERSION = "2.4.0"
3
3
  end
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: canvas_qti_to_learnosity_converter
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.0
4
+ version: 2.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Atomic Jolt
8
8
  - Nick Benoit
9
- autorequire:
9
+ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2018-08-13 00:00:00.000000000 Z
12
+ date: 2022-10-31 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -17,14 +17,14 @@ dependencies:
17
17
  requirements:
18
18
  - - "~>"
19
19
  - !ruby/object:Gem::Version
20
- version: '1.16'
20
+ version: '2.3'
21
21
  type: :development
22
22
  prerelease: false
23
23
  version_requirements: !ruby/object:Gem::Requirement
24
24
  requirements:
25
25
  - - "~>"
26
26
  - !ruby/object:Gem::Version
27
- version: '1.16'
27
+ version: '2.3'
28
28
  - !ruby/object:Gem::Dependency
29
29
  name: byebug
30
30
  requirement: !ruby/object:Gem::Requirement
@@ -95,7 +95,7 @@ dependencies:
95
95
  - - ">="
96
96
  - !ruby/object:Gem::Version
97
97
  version: '0'
98
- description:
98
+ description:
99
99
  email:
100
100
  - support@atomicjolt.com
101
101
  executables: []
@@ -132,7 +132,7 @@ homepage: https://github.com/atomicjolt/qti_to_learnosity_converter
132
132
  licenses:
133
133
  - MIT
134
134
  metadata: {}
135
- post_install_message:
135
+ post_install_message:
136
136
  rdoc_options: []
137
137
  require_paths:
138
138
  - lib
@@ -147,9 +147,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
147
147
  - !ruby/object:Gem::Version
148
148
  version: '0'
149
149
  requirements: []
150
- rubyforge_project:
151
- rubygems_version: 2.7.6
152
- signing_key:
150
+ rubygems_version: 3.3.15
151
+ signing_key:
153
152
  specification_version: 4
154
153
  summary: Converts canvas qti to learnosity JSON
155
154
  test_files: []