ruql-canvas 1.0.0 → 1.0.1
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/ruql/canvas/canvas.rb +50 -17
- data/lib/ruql/canvas/version.rb +1 -1
- data/templates/quiz.yml +9 -3
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fdc05b1cc995933e8a0b76fa2b29c0f351ce002605e25c21ae1f1f411d1841bd
|
4
|
+
data.tar.gz: bf751328a381352dc45a221f87ffaffe086c65087f2c65b826c68415781648a7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1a68292bf05596303e9cd7ab6d377e06ae92999fb119ff095882115b84c53f69de9deeb6db1f7f9f454f97a8f8c22cec1e1ed7e9da93a0506b6bd5ef824b425d
|
7
|
+
data.tar.gz: 16da6cf1a5e248652b26e35fca2ea008c33c2c94b7d48302f5e89386d82eaf7f03f94cd9287bf9bd4320fe7ac0454df67255ed92d40fac07c19a4a7b6af2746c
|
data/lib/ruql/canvas/canvas.rb
CHANGED
@@ -24,9 +24,11 @@ module Ruql
|
|
24
24
|
yaml = YAML.load_file(yaml_options)
|
25
25
|
logger.warn "Doing dry run without making any changes" if
|
26
26
|
(@dry_run = yaml['dry_run'] || options['--canvas-dry-run'])
|
27
|
-
|
27
|
+
@canvas_options = yaml['canvas']
|
28
|
+
set_canvas_options(@canvas_options)
|
28
29
|
|
29
30
|
@quiz_options = YAML.load_file(@default_quiz_options_file)['quiz'].merge(yaml['quiz'] || {})
|
31
|
+
@quiz_id = @quiz_options['quiz_id'] # may be nil if new quiz is to be created.
|
30
32
|
logger.info "Using quiz options:\n#{@quiz_options.inspect}"
|
31
33
|
|
32
34
|
verify_valid_quiz!
|
@@ -48,16 +50,20 @@ module Ruql
|
|
48
50
|
help = <<eos
|
49
51
|
The Canvas renderer adds the given file as a quiz in Canvas, with these options:
|
50
52
|
--canvas-dry-run - don't actually change anything, but do all non-state-changing API calls.
|
51
|
-
You can also set dry_run: true in the YAML file instead.
|
53
|
+
You can also set dry_run: true in the YAML file instead. The presence of either
|
54
|
+
mechanism will turn this into a dry run.
|
52
55
|
--canvas-config=file.yml - A Yaml file that must contain at least the following:
|
53
56
|
dry_run: true # don't actually change anything, but check API connection and parsability
|
54
57
|
canvas:
|
55
58
|
api_base: https://bcourses.berkeley.edu/api/v1 # base URL for Canvas LMS API
|
56
59
|
auth_token: 012345 # Bearer auth token for Canvas API
|
57
60
|
course_id: 99999 # Course ID in Canvas to which a NEW quiz should be added
|
58
|
-
# If
|
59
|
-
|
60
|
-
|
61
|
+
# If quiz_id given, replace that quiz's questions and time limit; if not, create new
|
62
|
+
quiz_id: 99999
|
63
|
+
# How quiz time limit is set, eg 20-point quiz = 40 minutes. Default is 1
|
64
|
+
minutes_per_point: 2
|
65
|
+
# Fixed extra time in addition to minutes/point. Default 5. Total time rounded up to multiple of 5.
|
66
|
+
extra_minutes: 5
|
61
67
|
quiz:
|
62
68
|
# various options that control quiz; defaults are in #{@default_quiz_options_file}
|
63
69
|
eos
|
@@ -86,10 +92,32 @@ eos
|
|
86
92
|
create_quiz!
|
87
93
|
@output = "New quiz #{@quiz_id}"
|
88
94
|
end
|
89
|
-
|
90
|
-
|
91
|
-
|
95
|
+
emit_ungrouped_questions
|
96
|
+
emit_grouped_questions
|
97
|
+
@output << " now has #{@qcount} questions in #{@group_count} pool(s)"
|
98
|
+
end
|
99
|
+
#####
|
100
|
+
|
101
|
+
|
102
|
+
private
|
103
|
+
|
104
|
+
# all "ungrouped" questions go into a single big group that can be shuffled.
|
105
|
+
# Caveat 1: where groups are typically "pick 1 of the following N", this big group has to be "pick N of the
|
106
|
+
# following N" so that all questions are presented, just in a shuffled order.
|
107
|
+
# Caveat 2: all questions in a group must be worth same # points, so we actually have to subdivide
|
108
|
+
# ungrouped questions into subgroups by point value.
|
109
|
+
def emit_ungrouped_questions
|
110
|
+
ungrouped_question_sets = quiz.ungrouped_questions.group_by(&:points)
|
111
|
+
ungrouped_question_sets.each_pair do |points,questions|
|
112
|
+
start_new_group(:name => "Group:unpooled:#{points}", :pick_count => questions.length, :question_points => points)
|
113
|
+
questions.each do |q|
|
114
|
+
canvas_question = render_multiple_choice(q)
|
115
|
+
add_question_to_current_group(canvas_question)
|
116
|
+
end
|
92
117
|
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def emit_grouped_questions
|
93
121
|
current_group = nil
|
94
122
|
quiz.grouped_questions.each do |q|
|
95
123
|
if q.question_group != current_group
|
@@ -99,12 +127,8 @@ eos
|
|
99
127
|
canvas_question = render_multiple_choice(q)
|
100
128
|
add_question_to_current_group(canvas_question)
|
101
129
|
end
|
102
|
-
@output << " now has #{@qcount} questions in #{@group_count} pool(s)"
|
103
130
|
end
|
104
|
-
|
105
|
-
|
106
|
-
private
|
107
|
-
|
131
|
+
|
108
132
|
def set_canvas_options(canvas)
|
109
133
|
@course_id = canvas['course_id'] || raise(Ruql::OptionsError.new("course_id missing from config file"))
|
110
134
|
@quiz_id = canvas['quiz_id'] # may be nil => create new quiz
|
@@ -137,8 +161,12 @@ eos
|
|
137
161
|
def time_limit_for_quiz
|
138
162
|
# intent is 1 point per minute, add 5 minutes for slop, round total up to nearest 5 minutes
|
139
163
|
# but # questions is really # unique groups.
|
140
|
-
|
141
|
-
|
164
|
+
minutes_per_point = (@canvas_options['minutes_per_point'] || 1).to_i
|
165
|
+
slop = (@canvas_options['extra_minutes'] || 5).to_i
|
166
|
+
limit = quiz.points.to_i * minutes_per_point + slop
|
167
|
+
# round up to 5 minutes
|
168
|
+
limit += 5 - (limit % 5)
|
169
|
+
logger.info "Time limit #{limit} based on #{quiz.points} points"
|
142
170
|
limit
|
143
171
|
end
|
144
172
|
|
@@ -157,14 +185,19 @@ eos
|
|
157
185
|
group_ids.each do |gid|
|
158
186
|
canvas("Delete group #{gid}", :delete, path + "/groups/#{gid}")
|
159
187
|
end
|
188
|
+
# modify time limit to reflect the questions we're about to replace them with
|
189
|
+
# and update quiz title
|
190
|
+
update_quiz = {'quiz' => {
|
191
|
+
'title' => quiz.title,
|
192
|
+
'time_limit' => time_limit_for_quiz
|
193
|
+
}}.to_json
|
194
|
+
canvas("Update quiz title and time limit", :put, path, data: update_quiz)
|
160
195
|
end
|
161
196
|
|
162
197
|
def create_quiz!
|
163
198
|
quiz_opts = @quiz_options.merge({
|
164
199
|
'title' => quiz.title,
|
165
200
|
'time_limit' => time_limit_for_quiz,
|
166
|
-
'due_at' => "2020-08-01T23:00Z",
|
167
|
-
'unlock_at' => "2020-05-21T00:00Z"
|
168
201
|
})
|
169
202
|
quiz_object = {:quiz => quiz_opts}.to_json
|
170
203
|
path = "courses/#{@course_id}/quizzes"
|
data/lib/ruql/canvas/version.rb
CHANGED
data/templates/quiz.yml
CHANGED
@@ -1,10 +1,16 @@
|
|
1
|
+
# See canvas.instructure.com/doc/api/quizzes.html for valid values
|
1
2
|
quiz:
|
2
3
|
title: "Will be overridden by argument of 'quiz' in RuQL file"
|
3
4
|
description: "Short description seen when quiz is started"
|
4
5
|
quiz_type: assignment
|
5
6
|
show_correct_answers: false
|
6
7
|
shuffle_answers: true
|
7
|
-
|
8
|
-
|
9
|
-
|
8
|
+
due_at: "2030-01-01T00:00Z"
|
9
|
+
unlock_at: "2030-01-01T00:00Z"
|
10
|
+
lock_at: "2030-01-01T00:00Z"
|
10
11
|
published: false
|
12
|
+
# when can student see correct answer and results? (see Canvas docs)
|
13
|
+
hide_results: always
|
14
|
+
one_question_at_a_time: false
|
15
|
+
# to put it into an assignment group:
|
16
|
+
# assignment_group_id: 9999
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruql-canvas
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Armando Fox
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-06-
|
11
|
+
date: 2020-06-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: faraday
|