asker-tool 2.1.7 → 2.2.3
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/{LICENSE.txt → LICENSE} +0 -0
- data/README.md +14 -15
- data/bin/asker +1 -1
- data/lib/asker/ai/ai.rb +6 -3
- data/lib/asker/ai/ai_calculate.rb +20 -6
- data/lib/asker/ai/concept_ai.rb +12 -3
- data/lib/asker/ai/question.rb +28 -6
- data/lib/asker/ai/stages/base_stage.rb +45 -6
- data/lib/asker/ai/stages/stage_b.rb +90 -49
- data/lib/asker/ai/stages/stage_d.rb +69 -90
- data/lib/asker/ai/stages/stage_f.rb +47 -38
- data/lib/asker/ai/stages/stage_i.rb +79 -92
- data/lib/asker/ai/stages/stage_s.rb +41 -36
- data/lib/asker/ai/stages/stage_t.rb +114 -73
- data/lib/asker/application.rb +7 -16
- data/lib/asker/check_input/check_haml_data.rb +264 -0
- data/lib/asker/check_input/check_table.rb +104 -0
- data/lib/asker/check_input.rb +51 -0
- data/lib/asker/cli.rb +47 -44
- data/lib/asker/data/code.rb +5 -16
- data/lib/asker/data/concept.rb +71 -24
- data/lib/asker/data/project_data.rb +63 -0
- data/lib/asker/data/table.rb +2 -0
- data/lib/asker/data/template.rb +3 -1
- data/lib/asker/data/world.rb +8 -16
- data/lib/asker/displayer/code_displayer.rb +7 -0
- data/lib/asker/displayer/concept_ai_displayer.erb +10 -0
- data/lib/asker/displayer/concept_ai_displayer.rb +24 -22
- data/lib/asker/displayer/concept_displayer.rb +9 -4
- data/lib/asker/displayer/stats_displayer.rb +8 -0
- data/lib/asker/exporter/concept_ai_gift_exporter.rb +7 -11
- data/lib/asker/exporter/concept_ai_moodle_exporter.rb +45 -0
- data/lib/asker/exporter/concept_ai_yaml_exporter.rb +6 -3
- data/lib/asker/exporter/concept_doc_exporter.rb +12 -2
- data/lib/asker/exporter/data_gift_exporter.rb +31 -0
- data/lib/asker/exporter/output_file_exporter.rb +9 -6
- data/lib/asker/files/{config.ini → asker.ini} +14 -4
- data/lib/asker/files/language/du/connectors.yaml +81 -0
- data/lib/asker/files/language/du/mistakes.yaml +82 -0
- data/lib/asker/files/language/du/templates.yaml +28 -49
- data/lib/asker/files/language/en/templates.yaml +19 -19
- data/lib/asker/files/language/es/mistakes.yaml +9 -7
- data/lib/asker/files/language/es/templates.yaml +19 -19
- data/lib/asker/files/language/fr/connectors.yaml +68 -84
- data/lib/asker/files/language/fr/templates.yaml +22 -22
- data/lib/asker/formatter/concept_doc_formatter.rb +0 -4
- data/lib/asker/formatter/concept_string_formatter.rb +7 -4
- data/lib/asker/formatter/moodle/matching.erb +38 -0
- data/lib/asker/formatter/moodle/multichoice.erb +49 -0
- data/lib/asker/formatter/moodle/shortanswer.erb +30 -0
- data/lib/asker/formatter/moodle/truefalse.erb +47 -0
- data/lib/asker/formatter/question_gift_formatter.rb +21 -19
- data/lib/asker/formatter/question_moodle_formatter.rb +27 -0
- data/lib/asker/lang/lang_factory.rb +7 -1
- data/lib/asker/loader/code_loader.rb +1 -1
- data/lib/asker/loader/content_loader.rb +12 -14
- data/lib/asker/loader/directory_loader.rb +1 -8
- data/lib/asker/loader/embedded_file.rb +42 -0
- data/lib/asker/loader/file_loader.rb +1 -6
- data/lib/asker/loader/haml_loader.rb +9 -5
- data/lib/asker/loader/image_url_loader.rb +8 -9
- data/lib/asker/loader/input_loader.rb +5 -6
- data/lib/asker/loader/project_loader.rb +18 -10
- data/lib/asker/logger.rb +36 -9
- data/lib/asker/skeleton.rb +3 -2
- data/lib/asker/version.rb +9 -0
- data/lib/asker.rb +72 -43
- metadata +60 -18
- data/lib/asker/checker.rb +0 -455
- data/lib/asker/project.rb +0 -146
@@ -1,92 +1,76 @@
|
|
1
1
|
---
|
2
2
|
- '[*]'
|
3
|
-
-
|
4
|
-
-
|
5
|
-
-
|
6
|
-
-
|
7
|
-
-
|
8
|
-
-
|
9
|
-
-
|
10
|
-
-
|
11
|
-
-
|
12
|
-
-
|
13
|
-
-
|
14
|
-
-
|
3
|
+
- à
|
4
|
+
- au
|
5
|
+
- suède
|
6
|
+
- bas
|
7
|
+
- chaque
|
8
|
+
- comme
|
9
|
+
- comment
|
10
|
+
- avec
|
11
|
+
- contre
|
12
|
+
- quand
|
13
|
+
- combien
|
14
|
+
- qui
|
15
15
|
- de
|
16
|
-
-
|
17
|
-
-
|
16
|
+
- du
|
17
|
+
- depuis
|
18
18
|
- e
|
19
|
-
-
|
19
|
+
- dans
|
20
20
|
- entre
|
21
|
-
-
|
22
|
-
-
|
23
|
-
-
|
24
|
-
-
|
25
|
-
-
|
26
|
-
-
|
27
|
-
-
|
28
|
-
-
|
29
|
-
-
|
30
|
-
-
|
31
|
-
-
|
32
|
-
-
|
33
|
-
-
|
34
|
-
- estos
|
35
|
-
- estas
|
36
|
-
- hacia
|
37
|
-
- hasta
|
21
|
+
- il
|
22
|
+
- il
|
23
|
+
- elle
|
24
|
+
- ils
|
25
|
+
- "c'est"
|
26
|
+
- cette
|
27
|
+
- ceux
|
28
|
+
- est
|
29
|
+
- ce
|
30
|
+
- est
|
31
|
+
- celles-ci
|
32
|
+
- celles-ci
|
33
|
+
- vers
|
38
34
|
- la
|
39
|
-
- las
|
40
|
-
- lo
|
41
|
-
- los
|
42
|
-
- le
|
43
35
|
- les
|
44
|
-
-
|
45
|
-
-
|
46
|
-
-
|
47
|
-
-
|
48
|
-
-
|
49
|
-
-
|
50
|
-
-
|
51
|
-
-
|
52
|
-
-
|
53
|
-
-
|
54
|
-
-
|
55
|
-
-
|
56
|
-
-
|
57
|
-
-
|
58
|
-
-
|
59
|
-
-
|
36
|
+
- quelle
|
37
|
+
- lui
|
38
|
+
- leur
|
39
|
+
- plus
|
40
|
+
- moi
|
41
|
+
- JE
|
42
|
+
- très
|
43
|
+
- beaucoup
|
44
|
+
- non
|
45
|
+
- nous
|
46
|
+
- États-Unis
|
47
|
+
- ou
|
48
|
+
- pour
|
49
|
+
- mais
|
50
|
+
- pour
|
51
|
+
- parce
|
60
52
|
- que
|
61
|
-
-
|
62
|
-
-
|
63
|
-
-
|
64
|
-
-
|
65
|
-
-
|
66
|
-
-
|
67
|
-
-
|
68
|
-
-
|
69
|
-
-
|
70
|
-
-
|
71
|
-
-
|
72
|
-
-
|
73
|
-
-
|
74
|
-
-
|
75
|
-
-
|
76
|
-
-
|
77
|
-
-
|
78
|
-
-
|
79
|
-
-
|
80
|
-
-
|
81
|
-
-
|
82
|
-
-
|
83
|
-
-
|
84
|
-
-
|
85
|
-
- unas
|
86
|
-
- vosotros
|
87
|
-
- vuestro
|
88
|
-
- vuestros
|
89
|
-
- nuestro
|
90
|
-
- nuestros
|
91
|
-
- y
|
92
|
-
- yo
|
53
|
+
- quoi
|
54
|
+
- qui
|
55
|
+
- oui
|
56
|
+
- sur
|
57
|
+
- tout
|
58
|
+
- toutes
|
59
|
+
- après
|
60
|
+
- toi
|
61
|
+
- toi
|
62
|
+
- sa
|
63
|
+
- leur
|
64
|
+
- posséder
|
65
|
+
- mien
|
66
|
+
- ou
|
67
|
+
- une
|
68
|
+
- une
|
69
|
+
- certains
|
70
|
+
- ongle
|
71
|
+
- clou
|
72
|
+
- toi
|
73
|
+
- le
|
74
|
+
- notre
|
75
|
+
- et
|
76
|
+
- je
|
@@ -4,26 +4,26 @@
|
|
4
4
|
:misspelling: 'Erreur ortographique'
|
5
5
|
:true: 'Vrai'
|
6
6
|
:false: 'Faux'
|
7
|
-
:d1: "Définition
|
8
|
-
:d2: 'Définition de <b><%=text1%></b
|
9
|
-
:d3: 'Définition de <b><%=text1%></b
|
10
|
-
:d4: 'Définition de <b><%=text1%></b
|
7
|
+
:d1: "Définition: <i><%=text1%></i><br/>Choisissez l'option qui correspond le mieux à la définition précédente.<br/>"
|
8
|
+
:d2: 'Définition de <b><%=text1%></b>:<br/> <i><%=text2%></i><br/>'
|
9
|
+
:d3: 'Définition de <b><%=text1%></b>:<br/> <i><%=text2%></i><br/></br><p>Note: Chaque symbole ? représente une lettre, et * un ou plusieurs mots.</p>'
|
10
|
+
:d4: 'Définition de <b><%=text1%></b>:<br/> <i><%=text2%></i><br/><br/>(Mettez chaque mot à la bonne position dans le texte)'
|
11
11
|
:b1: 'Par rapport au concept <b><%=text1%></b>, associez chaque "<%=text2%>" avec son,sa "<%=text3%>".<br/>'
|
12
|
-
:f1: 'Les éléments suivants sont "<%=text2%>" du concept <b><%=text1%></b
|
13
|
-
:f2: "Les éléments suivants sont \"<%=text2%>\".<br/>Sélectionnez l'
|
14
|
-
:f3: 'Les éléments suivants sont "<%=text2%>" du concept <b><%=text1%></b
|
15
|
-
:i1: "
|
16
|
-
:i2: "
|
17
|
-
:i3: "
|
18
|
-
:i4: '
|
19
|
-
:s1:
|
20
|
-
:t1table:
|
21
|
-
:t2table:
|
22
|
-
:t3table:
|
23
|
-
:t4table:
|
24
|
-
:t5table:
|
25
|
-
:t6table:
|
26
|
-
:t7table:
|
27
|
-
:t8table:
|
28
|
-
:t9table:
|
29
|
-
:code1:
|
12
|
+
:f1: 'Les éléments suivants sont "<%=text2%>" du concept <b><%=text1%></b>:<ul><li><%=text3%></li></ul>'
|
13
|
+
:f2: "Les éléments suivants sont \"<%=text2%>\".<br/>Sélectionnez l'option qui n'appartient pas au concept <b><%=text1%></b>."
|
14
|
+
:f3: 'Les éléments suivants sont "<%=text2%>" du concept <b><%=text1%></b>:<br><p><%=text3%></p>(Mettez chaque mot à la bonne position dans le texte)'
|
15
|
+
:i1: "<%=text1%><br/>Choisissez l'option qui correspond le mieux à l'image précédente.<br/>"
|
16
|
+
:i2: "<%=text1%><br/>L'image précédente correspond à <b><%=text2%></b>."
|
17
|
+
:i3: "<%=text1%><br/>Écrivez l'option <%=text2%>, qui correspond le mieux à l'image précédente.<br/>"
|
18
|
+
:i4: '<%=text1%><br/>Définition: <i><%=text2%></i><br/><br/>(Mettez chaque mot à la bonne position dans le texte)'
|
19
|
+
:s1: "Par rapport au concept <b><%=text1%></b>, mettez dans l'ordre chaque \"<%=text2%>\" afin que le critère soit rempli \"<%=text3%>\".<br/>"
|
20
|
+
:t1table: "Concept <b><%=text1%></b><br/><%=text2%>: [*]<br/><%=text3%>: \"<%=text4%>\"<br/>Choisissez l'option correcte.<br/>"
|
21
|
+
:t2table: "Concept <b><%=text1%></b><br/><%=text2%>: [*]<br/><%=text3%>: \"<%=text4%>\"<br/>Choisissez l'option correcte.<br/>"
|
22
|
+
:t3table: "Concept <b><%=text1%></b><br/><%=text2%>: \"<%=text3%>\"<br/><%=text4%>: [*]<br/>Choisissez l'option correcte.<br/>"
|
23
|
+
:t4table: "Concept <b><%=text1%></b><br/><%=text2%>: \"<%=text3%>\"<br/><%=text4%>: [*]<br/>Choisissez l'option correcte.<br/>"
|
24
|
+
:t5table: "Concept <b><%=text1%></b><br/>L'association suivante est correcte:<br/><ul><li><%=text2%>: \"<%=text3%>\"</li><li><%=text4%>: \"<%=text5%>\"</li></ul>"
|
25
|
+
:t6table: "Concept <b><%=text1%></b><br/>L'association suivante est correcte:<br/><ul><li><%=text2%>: \"<%=text3%>\"</li><li><%=text4%>: \"<%=text5%>\"</li></ul>"
|
26
|
+
:t7table: "Concept <b><%=text1%></b><br/>L'association suivante est correcte:<br/><ul><li><%=text2%>: \"<%=text3%>\"</li><li><%=text4%>: \"<%=text5%>\"</li></ul>"
|
27
|
+
:t8table: "Concept <b><%=text1%></b><br/>Complétez l'association suivante:<br/><ul><li><%=text2%>: \"<%=text3%>\"</li><li><%=text4%>: [*]</li></ul>Écrire un mot.<br/>"
|
28
|
+
:t9table: "Concept <b><%=text1%></b><br/>Complétez l'association suivante:<br/><ul><li><%=text2%>: \"<%=text3%>\"</li><li><%=text4%>: <%=text5%></li></ul>Écrire<%=text6%> mots.<br/>"
|
29
|
+
:code1: "<pre><%=text1%></pre><br/><p>Écrire le numéro de ligne où se trouve la première erreur. Écrire 0 s'il n'y a aucune erreur.</p>"
|
@@ -12,12 +12,11 @@ module ConceptStringFormatter
|
|
12
12
|
def self.to_s(concept)
|
13
13
|
tt = Terminal::Table.new
|
14
14
|
get_tt_rows(concept).each { |row| tt.add_row row }
|
15
|
-
|
15
|
+
tt.to_s
|
16
16
|
end
|
17
17
|
|
18
18
|
# rubocop:disable Metrics/AbcSize
|
19
19
|
# rubocop:disable Metrics/MethodLength
|
20
|
-
# rubocop:disable Layout/LineLength
|
21
20
|
private_class_method def self.get_tt_rows(concept)
|
22
21
|
rows = []
|
23
22
|
rows << [Rainbow(concept.id.to_s).bright,
|
@@ -31,13 +30,17 @@ module ConceptStringFormatter
|
|
31
30
|
rows << [Rainbow('Referenced by').blue,
|
32
31
|
concept.referenced_by.join(', ')[0...70].to_s]
|
33
32
|
rows << format_texts(concept)
|
34
|
-
|
33
|
+
unless concept.images.size.zero?
|
34
|
+
counter1 = 0
|
35
|
+
concept.images.each { |image| counter1 += 1 if image[:file] == :none }
|
36
|
+
counter2 = concept.images.size - counter1
|
37
|
+
rows << [Rainbow('.def(images)').blue, "#{counter1} text / #{counter2} file"]
|
38
|
+
end
|
35
39
|
rows << format_tables(concept) unless concept.tables.count.zero?
|
36
40
|
rows << format_neighbors(concept)
|
37
41
|
end
|
38
42
|
# rubocop:enable Metrics/AbcSize
|
39
43
|
# rubocop:enable Metrics/MethodLength
|
40
|
-
# rubocop:enable Layout/LineLength
|
41
44
|
|
42
45
|
private_class_method def self.format_texts(concept)
|
43
46
|
list = []
|
@@ -0,0 +1,38 @@
|
|
1
|
+
<% unless question.comment.nil? || question.comment.empty? %>
|
2
|
+
<!-- question: <%= question.comment %> -->
|
3
|
+
<% end %>
|
4
|
+
<question type="matching">
|
5
|
+
<name>
|
6
|
+
<text><%= question.name %></text>
|
7
|
+
</name>
|
8
|
+
<questiontext format="html">
|
9
|
+
<text><![CDATA[<%= question.text %>]]></text>
|
10
|
+
<% unless question.encode == :none %>
|
11
|
+
<%= question.encode %>
|
12
|
+
<% end %>
|
13
|
+
</questiontext>
|
14
|
+
<generalfeedback format="html">
|
15
|
+
<text><![CDATA[<%= question.feedback.to_s %>]]></text>
|
16
|
+
</generalfeedback>
|
17
|
+
<defaultgrade>1.0000000</defaultgrade>
|
18
|
+
<penalty>0.3333333</penalty>
|
19
|
+
<hidden>0</hidden>
|
20
|
+
<shuffleanswers>true</shuffleanswers>
|
21
|
+
<correctfeedback format="html">
|
22
|
+
<text></text>
|
23
|
+
</correctfeedback>
|
24
|
+
<partiallycorrectfeedback format="html">
|
25
|
+
<text></text>
|
26
|
+
</partiallycorrectfeedback>
|
27
|
+
<incorrectfeedback format="html">
|
28
|
+
<text></text>
|
29
|
+
</incorrectfeedback>
|
30
|
+
<% question.matching.each do |i, j| %>
|
31
|
+
<subquestion format="html">
|
32
|
+
<text><![CDATA[<%= i %>]]></text>
|
33
|
+
<answer>
|
34
|
+
<text><![CDATA[<%= j %>]]></text>
|
35
|
+
</answer>
|
36
|
+
</subquestion>
|
37
|
+
<% end %>
|
38
|
+
</question>
|
@@ -0,0 +1,49 @@
|
|
1
|
+
<% unless question.comment.nil? || question.comment.empty? %>
|
2
|
+
<!-- question: <%= question.comment %> -->
|
3
|
+
<% end %>
|
4
|
+
<question type="multichoice">
|
5
|
+
<name>
|
6
|
+
<text><%= question.name %></text>
|
7
|
+
</name>
|
8
|
+
<questiontext format="html">
|
9
|
+
<text><![CDATA[<%= question.text %>]]></text>
|
10
|
+
<% unless question.encode == :none %>
|
11
|
+
<%= question.encode %>
|
12
|
+
<% end %>
|
13
|
+
</questiontext>
|
14
|
+
<generalfeedback format="html">
|
15
|
+
<text><![CDATA[<%= question.feedback.to_s %>]]></text>
|
16
|
+
</generalfeedback>
|
17
|
+
<defaultgrade>1.0000000</defaultgrade>
|
18
|
+
<penalty>0.3333333</penalty>
|
19
|
+
<hidden>0</hidden>
|
20
|
+
<single>true</single>
|
21
|
+
<shuffleanswers>true</shuffleanswers>
|
22
|
+
<answernumbering>abc</answernumbering>
|
23
|
+
<correctfeedback format="html">
|
24
|
+
<text></text>
|
25
|
+
</correctfeedback>
|
26
|
+
<partiallycorrectfeedback format="html">
|
27
|
+
<text></text>
|
28
|
+
</partiallycorrectfeedback>
|
29
|
+
<incorrectfeedback format="html">
|
30
|
+
<text></text>
|
31
|
+
</incorrectfeedback>
|
32
|
+
<answer fraction="100" format="html">
|
33
|
+
<text><%= question.good %></text>
|
34
|
+
<feedback format="html">
|
35
|
+
<text></text>
|
36
|
+
</feedback>
|
37
|
+
</answer>
|
38
|
+
<%
|
39
|
+
question.bads.shuffle! if question.shuffle?
|
40
|
+
question.bads.each do |i|
|
41
|
+
%>
|
42
|
+
<answer fraction="<%= penalty %>" format="html">
|
43
|
+
<text><![CDATA[<%= i %>]]></text>
|
44
|
+
<feedback format="html">
|
45
|
+
<text></text>
|
46
|
+
</feedback>
|
47
|
+
</answer>
|
48
|
+
<% end %>
|
49
|
+
</question>
|
@@ -0,0 +1,30 @@
|
|
1
|
+
<% unless question.comment.nil? || question.comment.empty? %>
|
2
|
+
<!-- question: <%= question.comment %> -->
|
3
|
+
<% end %>
|
4
|
+
<question type="shortanswer">
|
5
|
+
<name>
|
6
|
+
<text><%= question.name %></text>
|
7
|
+
</name>
|
8
|
+
<questiontext format="html">
|
9
|
+
<text><![CDATA[<%= question.text %>]]></text>
|
10
|
+
<% unless question.encode == :none %>
|
11
|
+
<%= question.encode %>
|
12
|
+
<% end %>
|
13
|
+
</questiontext>
|
14
|
+
<generalfeedback format="html">
|
15
|
+
<text><![CDATA[<%= question.feedback.to_s %>]]></text>
|
16
|
+
</generalfeedback>
|
17
|
+
<defaultgrade>1.0000000</defaultgrade>
|
18
|
+
<penalty>0.3333333</penalty>
|
19
|
+
<hidden>0</hidden>
|
20
|
+
<usecase>0</usecase>
|
21
|
+
<% question.shorts.uniq! %>
|
22
|
+
<% question.shorts.each do |i| %>
|
23
|
+
<answer fraction="100" format="moodle_auto_format">
|
24
|
+
<text><![CDATA[<%= i %>]]></text>
|
25
|
+
<feedback format="html">
|
26
|
+
<text></text>
|
27
|
+
</feedback>
|
28
|
+
</answer>
|
29
|
+
<% end %>
|
30
|
+
</question>
|
@@ -0,0 +1,47 @@
|
|
1
|
+
<% unless question.comment.nil? || question.comment.empty? %>
|
2
|
+
<!-- question: <%= question.comment %> -->
|
3
|
+
<% end %>
|
4
|
+
<question type="truefalse">
|
5
|
+
<name>
|
6
|
+
<text><%= question.name %></text>
|
7
|
+
</name>
|
8
|
+
<questiontext format="html">
|
9
|
+
<text><![CDATA[<%= question.text %>]]></text>
|
10
|
+
<% unless question.encode == :none %>
|
11
|
+
<%= question.encode %>
|
12
|
+
<% end %>
|
13
|
+
</questiontext>
|
14
|
+
<generalfeedback format="html">
|
15
|
+
<text><![CDATA[<%= question.feedback.to_s %>]]></text>
|
16
|
+
</generalfeedback>
|
17
|
+
<defaultgrade>1.0000000</defaultgrade>
|
18
|
+
<penalty>1.0000000</penalty>
|
19
|
+
<hidden>0</hidden>
|
20
|
+
<% if question.good == 'TRUE' %>
|
21
|
+
<answer fraction="100" format="moodle_auto_format">
|
22
|
+
<text>true</text>
|
23
|
+
<feedback format="html">
|
24
|
+
<text></text>
|
25
|
+
</feedback>
|
26
|
+
</answer>
|
27
|
+
<answer fraction="0" format="moodle_auto_format">
|
28
|
+
<text>false</text>
|
29
|
+
<feedback format="html">
|
30
|
+
<text></text>
|
31
|
+
</feedback>
|
32
|
+
</answer>
|
33
|
+
<% else %>
|
34
|
+
<answer fraction="0" format="moodle_auto_format">
|
35
|
+
<text>true</text>
|
36
|
+
<feedback format="html">
|
37
|
+
<text></text>
|
38
|
+
</feedback>
|
39
|
+
</answer>
|
40
|
+
<answer fraction="100" format="moodle_auto_format">
|
41
|
+
<text>false</text>
|
42
|
+
<feedback format="html">
|
43
|
+
<text></text>
|
44
|
+
</feedback>
|
45
|
+
</answer>
|
46
|
+
<% end %>
|
47
|
+
</question>
|
@@ -7,50 +7,52 @@ module QuestionGiftFormatter
|
|
7
7
|
# @param question (Question)
|
8
8
|
# @return String
|
9
9
|
def self.to_s(question)
|
10
|
-
|
10
|
+
s = ''
|
11
|
+
return s unless question.encode == :none
|
12
|
+
|
11
13
|
# Return question using gift format
|
12
|
-
cond =
|
13
|
-
s = "// #{
|
14
|
-
s << "::#{
|
14
|
+
cond = question.comment.nil? || question.comment.empty?
|
15
|
+
s = "// #{question.comment}\n" unless cond
|
16
|
+
s << "::#{question.name}::[html]#{sanitize(question.text)}\n"
|
15
17
|
|
16
|
-
case
|
18
|
+
case question.type
|
17
19
|
when :choice
|
18
20
|
s += "{\n"
|
19
|
-
a = [" =#{sanitize(
|
21
|
+
a = [" =#{sanitize(question.good)}\n"]
|
20
22
|
penalties = ['', '%-50%', '%-33.33333%', '%-25%', '%-20%']
|
21
|
-
penalty = penalties[
|
23
|
+
penalty = penalties[question.bads.size]
|
22
24
|
|
23
|
-
|
24
|
-
a.shuffle! if
|
25
|
+
question.bads.each { |i| a << (" ~#{penalty}" + sanitize(i) + "\n") }
|
26
|
+
a.shuffle! if question.shuffle?
|
25
27
|
a.each do |i|
|
26
28
|
text = i
|
27
29
|
text = i[0, 220] + '...(ERROR: text too long)' if text.size > 255
|
28
30
|
s << text
|
29
31
|
end
|
30
|
-
s += " #####{sanitize(
|
32
|
+
s += " #####{sanitize(question.feedback.to_s)}\n" if question.feedback
|
31
33
|
s += "}\n\n"
|
32
34
|
when :boolean
|
33
|
-
s << "{#{
|
35
|
+
s << "{#{question.good}#####{sanitize(question.feedback.to_s)}}\n\n"
|
34
36
|
when :match
|
35
37
|
s << "{\n"
|
36
38
|
a = []
|
37
|
-
|
39
|
+
question.matching.each do |i, j|
|
38
40
|
i = i[0, 220] + '...(ERROR: text too long)' if i.size > 255
|
39
41
|
j = j[0, 220] + '...(ERROR: text too long)' if j.size > 255
|
40
42
|
a << " =#{sanitize(i)} -> #{sanitize(j)}\n"
|
41
43
|
end
|
42
|
-
a.shuffle! if
|
44
|
+
a.shuffle! if question.shuffle?
|
43
45
|
a.each { |i| s << i }
|
44
46
|
s << "}\n\n"
|
45
47
|
when :short
|
46
48
|
s << "{\n"
|
47
|
-
|
48
|
-
|
49
|
+
question.shorts.uniq!
|
50
|
+
question.shorts.each do |i|
|
49
51
|
text = i
|
50
52
|
text = i[0, 220] + '...(ERROR: too long)' if text.size > 255
|
51
53
|
s << " =%100%#{text}#\n"
|
52
54
|
end
|
53
|
-
s << " #####{sanitize(
|
55
|
+
s << " #####{sanitize(question.feedback.to_s)}\n" if question.feedback
|
54
56
|
s << "}\n\n"
|
55
57
|
end
|
56
58
|
s
|
@@ -62,10 +64,10 @@ module QuestionGiftFormatter
|
|
62
64
|
# @return String
|
63
65
|
def self.sanitize(input = '')
|
64
66
|
output = input.dup
|
65
|
-
output.gsub!(
|
67
|
+
output.gsub!('#', '\#')
|
66
68
|
output.gsub!("\n", " ")
|
67
|
-
|
68
|
-
output.gsub!(
|
69
|
+
output.gsub!(':', '\:')
|
70
|
+
output.gsub!('=', '\=')
|
69
71
|
output.gsub!("\{", "\\{")
|
70
72
|
output.gsub!("\}", "\\}")
|
71
73
|
output
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: false
|
2
|
+
|
3
|
+
require 'erb'
|
4
|
+
|
5
|
+
# Transform Questions into Gift format
|
6
|
+
module QuestionMoodleFormatter
|
7
|
+
##
|
8
|
+
# Convert question object into gift formatted string
|
9
|
+
# @param question (Question)
|
10
|
+
# @return String
|
11
|
+
def self.to_s(question)
|
12
|
+
case question.type
|
13
|
+
when :choice
|
14
|
+
penalties = ['', '-50', '-33.33333', '-25', '-20']
|
15
|
+
penalty = penalties[question.bads.size]
|
16
|
+
template = File.read(File.join(File.dirname(__FILE__), 'moodle', 'multichoice.erb'))
|
17
|
+
when :boolean
|
18
|
+
template = File.read(File.join(File.dirname(__FILE__), 'moodle', 'truefalse.erb'))
|
19
|
+
when :match
|
20
|
+
template = File.read(File.join(File.dirname(__FILE__), 'moodle', 'matching.erb'))
|
21
|
+
when :short
|
22
|
+
template = File.read(File.join(File.dirname(__FILE__), 'moodle', 'shortanswer.erb'))
|
23
|
+
end
|
24
|
+
renderer = ERB.new(template)
|
25
|
+
renderer.result(binding)
|
26
|
+
end
|
27
|
+
end
|
@@ -29,7 +29,13 @@ class LangFactory
|
|
29
29
|
# Return Lang object associated to code
|
30
30
|
# @param code (String)
|
31
31
|
def get(code)
|
32
|
-
@langs[code]
|
32
|
+
return @langs[code] unless @langs[code].nil?
|
33
|
+
|
34
|
+
puts Rainbow("[ERROR] Unkown Lang code: #{code}").bright
|
35
|
+
puts Rainbow(' => Change input file code lang').bright
|
36
|
+
puts Rainbow(' => Revise configuration from config.ini').bright
|
37
|
+
puts Rainbow(' => Revise template files').bright
|
38
|
+
exit 1
|
33
39
|
end
|
34
40
|
|
35
41
|
##
|
@@ -4,8 +4,7 @@ require 'rainbow'
|
|
4
4
|
require 'rexml/document'
|
5
5
|
require_relative '../data/concept'
|
6
6
|
require_relative 'code_loader'
|
7
|
-
require_relative '../
|
8
|
-
require_relative '../project'
|
7
|
+
require_relative '../data/project_data'
|
9
8
|
|
10
9
|
# Define methods that load data from XML contents
|
11
10
|
module ContentLoader
|
@@ -31,12 +30,14 @@ module ContentLoader
|
|
31
30
|
when 'code'
|
32
31
|
codes << read_code(xmldata, filepath)
|
33
32
|
else
|
34
|
-
|
33
|
+
puts Rainbow("[ERROR] Unkown tag <#{xmldata.name}>").red
|
35
34
|
end
|
36
35
|
end
|
37
36
|
|
38
37
|
{ concepts: concepts, codes: codes }
|
39
38
|
end
|
39
|
+
# rubocop:enable Metrics/MethodLength
|
40
|
+
# rubocop:enable Metrics/AbcSize
|
40
41
|
|
41
42
|
##
|
42
43
|
# Read lang attr from input XML data
|
@@ -45,7 +46,7 @@ module ContentLoader
|
|
45
46
|
begin
|
46
47
|
lang = xmldata.root.attributes['lang']
|
47
48
|
rescue StandardError
|
48
|
-
lang =
|
49
|
+
lang = ProjectData.instance.lang
|
49
50
|
end
|
50
51
|
lang
|
51
52
|
end
|
@@ -69,11 +70,9 @@ module ContentLoader
|
|
69
70
|
# @param lang
|
70
71
|
# @param context
|
71
72
|
private_class_method def self.read_concept(xmldata, filepath, lang, context)
|
72
|
-
project =
|
73
|
+
project = ProjectData.instance
|
73
74
|
c = Concept.new(xmldata, filepath, lang, context)
|
74
|
-
if [
|
75
|
-
c.process = true
|
76
|
-
end
|
75
|
+
c.process = true if [File.basename(filepath), :default].include? project.get(:process_file)
|
77
76
|
c
|
78
77
|
end
|
79
78
|
|
@@ -82,11 +81,9 @@ module ContentLoader
|
|
82
81
|
# @param xmldata (XML Object)
|
83
82
|
# @param filepath (String)
|
84
83
|
private_class_method def self.read_code(xmldata, filepath)
|
85
|
-
project =
|
84
|
+
project = ProjectData.instance
|
86
85
|
c = CodeLoader.load(xmldata, filepath)
|
87
|
-
if [
|
88
|
-
c.process = true
|
89
|
-
end
|
86
|
+
c.process = true if [File.basename(filepath), :default].include? project.get(:process_file)
|
90
87
|
c
|
91
88
|
end
|
92
89
|
|
@@ -95,8 +92,9 @@ module ContentLoader
|
|
95
92
|
# @param filepath (String)
|
96
93
|
# @param content (String)
|
97
94
|
private_class_method def self.raise_error_with(filepath, content)
|
98
|
-
msg =
|
99
|
-
|
95
|
+
msg = "[ERROR] ContentLoader: Format error in #{filepath}\n"
|
96
|
+
msg += " Take a look at ouput/error.xml"
|
97
|
+
puts Rainbow(msg).red.bright
|
100
98
|
f = File.open('output/error.xml', 'w')
|
101
99
|
f.write(content)
|
102
100
|
f.close
|