asciidoctor-moodle 1.0.0.dev

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 7cda5ba859d51bb5e75a9e32456dbeb68f0bc692981cd87ceffa38a2e1416592
4
+ data.tar.gz: 99805f9c1e42aabf270a9259b0b82956cf90688065980f0b1173c81f7a769db8
5
+ SHA512:
6
+ metadata.gz: ceb40738246d082023478f9c41a679a71d7443a24e1b0bb9ab298eb3fb2b2657d253b7eae3817dcc73bea1afd66735d7065827793a3f1ae2df202fe934d8a3f9
7
+ data.tar.gz: 70a2864be96d9f85f8ea51ee0b03899a7860f3c92e237a9a83b2a6458b5867a975efdbe5e83dacf9d95a6344288162ab74bb73fe6030db9634f9ecbc5f237748
data/README.adoc ADDED
@@ -0,0 +1,412 @@
1
+ [source,asciidoc]
2
+
3
+ = Asciidoctor Moodle-Question
4
+ ifndef::imagesdir[:imagesdir: images]
5
+
6
+ :description: README for the Asciidoctor Moodle-Question extension for Asciidoctor, based on Asciidoctor-Question.
7
+ :version: 0.0.1
8
+
9
+ image:https://img.shields.io/badge/license-MIT-blue.svg[MIT License, link=#copyright]
10
+
11
+ Asciidoctor Moodle-Question is a set of Asciidoctor extensions that allows you to add questions as multiple choice and gap text and convert them to Moodle XML format. The questions are defined using plain text in your AsciiDoc document.
12
+
13
+ == Creating a Question
14
+
15
+ A question is written inside a literal block, which needs at least two attributes.
16
+
17
+ .Anatomy of a question
18
+ ----
19
+ [question, question-type] // <1> <2>
20
+ .... // <3>
21
+ Question in appropriate syntax
22
+ ....
23
+ ----
24
+ <1> The first positional attribute in the attribute list specifies that this block is a question.
25
+ <2> The second positional attribute defines the type of this question (mc or gap)
26
+ <3> Place the attribute list directly on top of the delimited literal block (+....+). You can also use an example (+====+) or open block (`--`) as an alternative.
27
+
28
+ The following question types are available:
29
+
30
+ I used HTML <p> to format the output in Moodle to fit the tabular's case.
31
+
32
+ .Resume
33
+ [cols="2,3a,3a",options="header"]
34
+ |===
35
+ |Question type |Input |Output
36
+
37
+ |mc
38
+ |[source]
39
+ ----
40
+ [question, mc]
41
+ ....
42
+ Which of these are capitals ?
43
+
44
+ - [X] Romes
45
+ - [ ] Sydney
46
+ - [X] Paris
47
+ ....
48
+ ----
49
+ |image::mc.png[]
50
+
51
+ |gap
52
+ |[source]
53
+ ----
54
+ [question, gap]
55
+ ....
56
+ <p> If debugging is the process of removing </p>
57
+ <p> software bugs, then programming must be </p>
58
+ <p> the process of __putting them in__. </p>
59
+ - Edsger Dijkstra
60
+ ....
61
+ ----
62
+ |image::gap.png[]
63
+
64
+
65
+ |tf
66
+ |[source]
67
+ ----
68
+ [question, TF, True]
69
+ ....
70
+ <p> Donald Knuth said : </p>
71
+ <p> "Premature optimization is the
72
+ root of all evil." </p>
73
+ ....
74
+ ----
75
+ |image::tf.png[]
76
+
77
+ |matching
78
+ |[source]
79
+ ----
80
+ [question, matching,
81
+ wrote the first computer programme in the world,
82
+ decrypted Enigma machine's messages,
83
+ invented the merge sort algorithm]
84
+ ....
85
+ Match each author with his contribution ?
86
+
87
+ - Ada Lovelace :
88
+
89
+ - Alan Turing :
90
+ ....
91
+ ----
92
+ |image::match.png[]
93
+
94
+ |cmc
95
+ |[source]
96
+ ----
97
+ [question, CMC, Merge sort algorithm, Bombe]
98
+ ====
99
+ John von Neumann's invented
100
+
101
+ * Merge sort algorithm
102
+ * Quicksort algorithm
103
+ * ShellSort algorithm
104
+
105
+ <p>
106
+ Enigma's message machine was decrypted by
107
+ </p>
108
+
109
+ - Bombe
110
+ - Decryptma
111
+ - Decrypte's machine
112
+ ====
113
+ ----
114
+ |image::cmc.png[]
115
+
116
+ |ordering
117
+ |[source]
118
+ ----
119
+ [question, ordering]
120
+ ....
121
+ Arrange the layers with the deepest at the bottom:
122
+
123
+ * VM
124
+ * OS
125
+ * Material
126
+ ....
127
+ ----
128
+ |image::order.png[]
129
+
130
+ |ddt
131
+ |[source]
132
+ ----
133
+ [question, ddt]
134
+ ....
135
+ “Computers are good at *following instructions*,
136
+ but not at *reading your mind*.”
137
+ – Donald Knuth,
138
+ the “father of analysis of algorithms”
139
+ ....
140
+ ----
141
+ |image::ddt.png[]
142
+
143
+ |short
144
+ |[source]
145
+ ----
146
+ [question, short, Paris, case=case]
147
+ ....
148
+ What city is the capital of France ?
149
+ ....
150
+ ----
151
+ |image::short.png[]
152
+
153
+
154
+
155
+ |num
156
+ |[source]
157
+ ----
158
+ [question, num, unit="cm=1,dm=0.1",tolerance=1, ans=4]
159
+ ====
160
+ 2cm + 2cm =
161
+ ====
162
+ ----
163
+ |image::numerical.png[]
164
+
165
+ |mw
166
+ |[source]
167
+ ----
168
+ [question, mw]
169
+ ....
170
+ “Computers are good at *following instructions*, but not at *reading your mind*.”
171
+ – Donald Knuth, the “father of analysis of algorithms”
172
+ ....
173
+ ----
174
+ |image::mw.png[]
175
+
176
+
177
+
178
+
179
+ |===
180
+
181
+ === Generating a Question Document from a Terminal
182
+
183
+ You can load Asciidoctor question in a terminal using the -r (require) and -b (backend) flags.
184
+ [source]
185
+ ----
186
+ asciidoctor -r asciidoctor-moodle -b moodle sample.adoc
187
+
188
+ ----
189
+
190
+
191
+ === Details format
192
+
193
+ ==== +++<u> MC (multiple choice question) : </u>+++
194
+ [source]
195
+ ----
196
+ [question, mc|MC, shuffle=shuffle] //Used of the named attributes.
197
+ ----
198
+ [source]
199
+ ----
200
+ [question, mc|MC, shuffle] //Or just set the third attribute.
201
+ ----
202
+ If you want the answers to be shuffle for each try. You can either use 'MC' or 'mc'.
203
+
204
+ [source]
205
+ ----
206
+ - [X] correct1
207
+ - [*] correct2
208
+ - [ ] false
209
+ ----
210
+
211
+ You can either tick the correct(s) answer(s) with X or *.
212
+
213
+ The question is on 1 point, the point you receive for a good answer is 1/nbCorrectAnswersPossibles.
214
+
215
+ WARNING: You need space bewteen [ ] if it's false.
216
+
217
+ ==== +++<u>Gap (gap fill question) </u>+++
218
+
219
+ You gap your text with :
220
+ [source]
221
+ ----
222
+ The gap is __here__
223
+ ----
224
+
225
+ You gain 1 point for each gap correctly fill.
226
+
227
+ ==== +++<u>TF (true or false question) </u>+++
228
+
229
+ You can only write one question by question's block. One point for each question's block.
230
+
231
+ [cols="2a,2a",options="header"]
232
+ |===
233
+ |Good
234
+ |Bad
235
+ |
236
+ [source]
237
+ ----
238
+ [question, TF, true]
239
+ ....
240
+ Question to which correct answer is true
241
+ ....
242
+
243
+ [question, TF, false]
244
+ ....
245
+ Question to which correct answer is false
246
+ ....
247
+ ----
248
+ |
249
+ [source]
250
+ ----
251
+ [question, TF, true, false]
252
+ ....
253
+ Question to which correct answer is true
254
+
255
+ Question to which correct answer is false
256
+ ....
257
+ ----
258
+ |===
259
+
260
+
261
+ ==== +++<u>Matching (matching question)</u>+++
262
+
263
+ The matching question is based on a pool of questions/text and a pool of answers.
264
+
265
+ The pool of answers is shared by all the questions/text.
266
+
267
+ Each questions is linked to a correct answer.
268
+
269
+ It's represented as a dropdown menu in-line in the text.
270
+
271
+ [source]
272
+ ----
273
+ [question, matching, Answer1, Answer2, Answer3]
274
+ ....
275
+ General text need.
276
+
277
+ - Sentence1 :
278
+
279
+ - Sentence2 :
280
+ ....
281
+ ----
282
+ In this exemple the first sentence (Sentence1) match the first argument (Answer1) after 'matching'.
283
+
284
+ The second second sentence (Sentence2) match the second argument (Answer2) after 'matching'.
285
+
286
+ Answer3 isn't linked to any sentence but it will still be part of the pool of possible answers.
287
+
288
+ TIP: You can use either * or - for listing the sentences.
289
+
290
+ WARNING: Depending on your Moodle's version you will need at least 2 questions and 3 answers or one answer for each question if there is more than 2 questions, to be imported correctly.
291
+
292
+
293
+
294
+ ==== +++<u>CMC (cloze mutliple choice)</u>+++
295
+ Unlike matching questions, each CMC question has it own pool of answers.
296
+
297
+ Each questions is linked to a correct answer.
298
+
299
+ It's represented as a dropdown menu in-line in the text.
300
+
301
+ You can use either a delimiter or a block list format to write the possible answers.
302
+
303
+ [cols="2a,2a",options="header"]
304
+ |===
305
+ |List
306
+ |Delimiter
307
+ |
308
+ [source]
309
+ ----
310
+
311
+ [question, CMC, Correct1, Correct2]
312
+ ====
313
+
314
+ Question 1
315
+
316
+ * False1
317
+ * AlsoFalse1
318
+ * Correct1
319
+
320
+ Question 2
321
+
322
+ - Correct2
323
+ - False2
324
+ - AlsoFalse2
325
+
326
+ ====
327
+ ----
328
+ |
329
+ [source]
330
+ --
331
+ [question, CMC, Correct1, Correct2]
332
+ ====
333
+
334
+ Question 1
335
+
336
+ ----
337
+ * False1
338
+ * AlsoFalse1
339
+ * Correct1
340
+ ----
341
+ Question 2
342
+
343
+ ----
344
+ - Correct2
345
+ - False2
346
+ - AlsoFalse2
347
+ ----
348
+ ====
349
+ --
350
+ |===
351
+
352
+ TIP: You can use either * or - to enumerate the answers, whether you are using a List or a delimiter.
353
+
354
+ WARNING: For delimiter of a list you can only use ---- or ====, -- won't work.
355
+
356
+ WARNING: If you don't have a correct answer for each question, Moodle won't accept your file.
357
+
358
+
359
+ ==== +++<u>Ordering</u>+++
360
+
361
+ You need to list the items in the same order as the correct answer. Moodle will shuffle them.
362
+
363
+ TIP: You can use either * or - for listing the sentences.
364
+
365
+ WARNING: Depending on your version of Moodle, you will need at least 2 or 3 items in the list for it to be imported correctly.
366
+
367
+ ==== +++<u>DDT (drag and drop into text) and MW (missing Words)</u>+++
368
+
369
+ Simply enclose the portion of the text you with to label with asterisks (*).
370
+
371
+ You can't have more draggable texts (possible answers) than gaps.
372
+
373
+ WARNING: The text you enclose needs to be on the same line to be imported correctly.
374
+
375
+ [cols="2a,2a",options="header"]
376
+ |===
377
+ |Good
378
+ |Bad
379
+ |
380
+ [source]
381
+ ----
382
+ [question, ddt]
383
+ ....
384
+ “Computers are good at *following instructions*,
385
+ but not at *reading your mind*.”
386
+ – Donald Knuth, the “father of analysis of algorithms”
387
+ ....
388
+ ----
389
+ |
390
+ [source]
391
+ --
392
+ [question, ddt]
393
+ ....
394
+ “Computers are good at *following
395
+ instructions,* but not at*reading *your* mind.”
396
+ – Donald Knuth, the “father of analysis of algorithms”
397
+ ....
398
+ --
399
+ |===
400
+
401
+ ==== +++<u>Short (answer)</u>+++
402
+ You can either tag with "Short" or "short".
403
+
404
+ ==== +++<u>Num (Numerical)</u>+++
405
+ You can either tag with "num" or "Num".
406
+
407
+ If the tolerance is 1 and the answer is 4, then [3, 5] is an interval for a possible answer.
408
+
409
+ If a student writes the correct answer without the correct unit, they will lose half of the marks.
410
+
411
+ WARNING: Use coma (,) to separate units, and the dot (.) for decimal.
412
+
@@ -0,0 +1,36 @@
1
+ begin
2
+ require_relative 'lib/asciidoctor-moodle/version'
3
+ rescue LoadError
4
+ require 'asciidoctor-moodle/version'
5
+ end
6
+
7
+ Gem::Specification.new do |s|
8
+ s.name = 'asciidoctor-moodle'
9
+ s.version = Asciidoctor::Moodle::VERSION
10
+ s.summary = 'Converts AsciiDoc documents to Moodle XML'
11
+ s.description = 'An Asciidoctor converter that converts AsciiDoc to Moodle XML documents'
12
+ s.authors = ['Gerson Sunyé', 'Robin Gloaguen']
13
+ s.email = ['gerson.sunye@gmail.com','robin.gloaguen@hotmail.fr']
14
+ s.homepage = 'https://github.com/'
15
+ s.license = 'MIT'
16
+ s.required_ruby_version = '>= 3.0.0'
17
+ s.metadata = {
18
+ 'bug_tracker_uri' => 'https://github.com/asciidoctor/asciidoctor-docbook45/issues',
19
+ 'changelog_uri' => 'https://github.com/asciidoctor/asciidoctor-docbook45/blob/master/CHANGELOG.adoc',
20
+ 'mailing_list_uri' => 'http://discuss.asciidoctor.org',
21
+ 'source_code_uri' => 'https://github.com/asciidoctor/asciidoctor-docbook45'
22
+ }
23
+
24
+ # NOTE the logic to build the list of files is designed to produce a usable package even when the git command is not available
25
+ begin
26
+ files = (result = `git ls-files -z`.split ?\0).empty? ? Dir['**/*'] : result
27
+ rescue
28
+ files = Dir['**/*']
29
+ end
30
+ s.files = files.grep %r/^(?:lib\/.+|LICENSE|(?:CHANGELOG|README)\.adoc|\.yardopts|#{s.name}\.gemspec)$/
31
+ s.require_paths = ['lib']
32
+
33
+ s.add_runtime_dependency 'asciidoctor', '>= 2.0.0'
34
+ s.add_development_dependency 'rake', '~> 12.3.0'
35
+ s.add_development_dependency 'rspec', '~> 3.8.0'
36
+ end
@@ -0,0 +1,134 @@
1
+ require_relative '../extensions'
2
+
3
+
4
+ module Asciidoctor
5
+ module Question
6
+
7
+ class ClozeMCBlockProcessor < Extensions::BaseProcessor
8
+
9
+ def process(parent, source, tag)
10
+
11
+ docName = parent.attributes['docname']
12
+ id = tag[:id]
13
+ size = tag.size
14
+ answers = Array.new
15
+ stringSource= Array.new
16
+ question = Array.new
17
+ source.lines.each { |line| stringSource.push line}
18
+ tag.each { |key, val| answers.push val if key.class==Integer && key>2 && key< size-3} #Récupère les réponses en tag
19
+
20
+ new_parent = Asciidoctor::Block.new parent, :open, {:attributes => {'id' => "#{docName}_question_mc_#{id}"}}
21
+ blocks = Array.new
22
+ reader = Asciidoctor::Reader.new(stringSource)
23
+ answers_block = Asciidoctor::Parser.next_block reader, new_parent
24
+
25
+ #Get the answers from the reader to put them in the tabular 'blocks'
26
+ while answers_block != nil
27
+ blocks.push answers_block
28
+ answers_block = Asciidoctor::Parser.next_block reader, new_parent
29
+ end
30
+
31
+ for i in 0..(blocks.size-1)
32
+ if blocks[i].class==Asciidoctor::List #Using list bloc
33
+ ans=""
34
+ blocks[i].items.each do |item|
35
+ ans << item.text
36
+ ans << "\n"
37
+ end
38
+ reader = Asciidoctor::Reader.new(ans)
39
+ new_block = Asciidoctor::Parser.next_block reader, new_parent
40
+ new_block.lines = prepare_answer_lines(answers[(i/2)], new_block.content)
41
+ blocks[i] = new_block
42
+ else #Using delimitier
43
+ next if i % 2 == 0 #There is 1 question follow by 1 answer etc...
44
+ blocks[i].lines = prepare_answer_lines(answers[(i/2)], blocks[i].content)
45
+ end
46
+ end
47
+
48
+ blocks = prepare_question_lines(blocks,docName,id)
49
+ new_parent = Asciidoctor::Block.new parent, :open, {:attributes => {'id' => "#{docName}_question_#{id}_mc"}}
50
+
51
+
52
+
53
+ finalstring = ""
54
+ blocks.each do |bloc|
55
+ finalstring << bloc.lines.join("\n")
56
+ end
57
+
58
+ reader = Asciidoctor::Reader.new(finalstring)
59
+ loop do
60
+ block = Asciidoctor::Parser.next_block reader, new_parent
61
+ break if block.nil?
62
+ new_parent.blocks.push block
63
+ end
64
+
65
+ new_parent
66
+ end
67
+
68
+ def prepare_answer_lines(answer, answerBloc)
69
+ puts answer
70
+ end
71
+
72
+ end
73
+
74
+ class MOODLEClozeMCBlockProcessor < ClozeMCBlockProcessor
75
+
76
+ def prepare_answer_lines(answer, stringBlock)
77
+ answer = answer.chomp # erase ending \n
78
+ preAns = "+++ {1:MCS:"
79
+
80
+ postAns = "}+++"
81
+
82
+ stringBlock = stringBlock.each_line.map { |line| line.sub(/(^-|^\*) /, "") }.join
83
+
84
+ stringBlock = stringBlock.each_line.map do |line|
85
+
86
+ line = line.chomp
87
+ if line == answer
88
+ "~=#{line}"
89
+ else
90
+ "~#{line}"
91
+ end
92
+ end.join(" ")
93
+
94
+ stringBlock.slice!(0)
95
+ stringBlock = "#{preAns}#{stringBlock}#{postAns}"
96
+ [stringBlock]
97
+
98
+ end
99
+
100
+
101
+ def prepare_question_lines(blocks, docName,id)
102
+
103
+ preQuest = " <question type=\"cloze\">
104
+ <name>
105
+ <text> #{docName}_question_#{id}_clozemc </text>
106
+ </name>
107
+ <questiontext format=\"html\">
108
+ <text><![CDATA[<p>"
109
+ postQuest = " </p>]]></text>
110
+ </questiontext>
111
+ <generalfeedback format=\"html\">
112
+ <text></text>
113
+ </generalfeedback>
114
+ <penalty>0.3333333</penalty>
115
+ <hidden>0</hidden>
116
+ <idnumber></idnumber>
117
+ </question>"
118
+ size = (blocks.size) -1
119
+
120
+
121
+
122
+ blocks[0].lines.prepend("+++")
123
+ blocks[0].lines.prepend(preQuest)
124
+ blocks[0].lines.prepend("+++")
125
+
126
+ blocks[size].lines.push("+++")
127
+ blocks[size].lines.push(postQuest)
128
+ blocks[size].lines.push("+++")
129
+
130
+ blocks
131
+ end
132
+ end
133
+ end
134
+ end