asker-tool 2.6.0 → 2.7.0
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/README.md +4 -4
- data/lib/asker/ai/ai.rb +6 -6
- data/lib/asker/ai/ai_calculate.rb +3 -3
- data/lib/asker/ai/code/base_code_ai.rb +5 -30
- data/lib/asker/ai/code/code_ai_factory.rb +6 -12
- data/lib/asker/ai/code/javascript_code_ai.rb +33 -34
- data/lib/asker/ai/code/python_code_ai.rb +35 -36
- data/lib/asker/ai/code/ruby_code_ai.rb +33 -33
- data/lib/asker/ai/code/sql_code_ai.rb +20 -21
- data/lib/asker/ai/concept_ai.rb +12 -22
- data/lib/asker/ai/problem/problem_ai.rb +226 -0
- data/lib/asker/ai/question.rb +34 -45
- data/lib/asker/ai/stages/base_stage.rb +7 -7
- data/lib/asker/ai/stages/stage_b.rb +62 -28
- data/lib/asker/ai/stages/stage_d.rb +10 -10
- data/lib/asker/ai/stages/stage_f.rb +17 -17
- data/lib/asker/ai/stages/stage_i.rb +8 -18
- data/lib/asker/ai/stages/stage_s.rb +28 -26
- data/lib/asker/ai/stages/stage_t.rb +40 -51
- data/lib/asker/application.rb +15 -14
- data/lib/asker/check_input/check_haml_data.rb +52 -51
- data/lib/asker/check_input/check_table.rb +17 -20
- data/lib/asker/check_input.rb +10 -23
- data/lib/asker/cli.rb +43 -24
- data/lib/asker/data/code.rb +10 -9
- data/lib/asker/data/column.rb +21 -17
- data/lib/asker/data/concept.rb +24 -37
- data/lib/asker/data/data_field.rb +2 -2
- data/lib/asker/data/problem.rb +112 -0
- data/lib/asker/data/project_data.rb +11 -15
- data/lib/asker/data/row.rb +25 -23
- data/lib/asker/data/table.rb +25 -46
- data/lib/asker/data/template.rb +7 -7
- data/lib/asker/data/world.rb +3 -3
- data/lib/asker/{formatter → deprecated}/question_moodlexml_formatter.rb +19 -21
- data/lib/asker/displayer/code_displayer.rb +10 -10
- data/lib/asker/displayer/concept_ai_displayer.erb +1 -1
- data/lib/asker/displayer/concept_ai_displayer.rb +16 -16
- data/lib/asker/displayer/concept_displayer.rb +4 -2
- data/lib/asker/displayer/problem_displayer.rb +45 -0
- data/lib/asker/displayer/stats_displayer.rb +7 -12
- data/lib/asker/exporter/code_gift_exporter.rb +2 -2
- data/lib/asker/exporter/concept_ai_gift_exporter.rb +4 -4
- data/lib/asker/exporter/concept_ai_yaml_exporter.rb +7 -7
- data/lib/asker/exporter/concept_doc_exporter.rb +5 -5
- data/lib/asker/exporter/data_gift_exporter.rb +14 -15
- data/lib/asker/exporter/data_moodle_exporter.rb +51 -20
- data/lib/asker/exporter/output_file_exporter.rb +9 -8
- data/lib/asker/exporter/problem_gift_exporter.rb +30 -0
- data/lib/asker/files/language/ca/templates.yaml +6 -0
- data/lib/asker/files/language/du/templates.yaml +6 -0
- data/lib/asker/files/language/en/templates.yaml +7 -1
- data/lib/asker/files/language/es/templates.yaml +6 -0
- data/lib/asker/files/language/fr/templates.yaml +6 -0
- data/lib/asker/formatter/code_string_formatter.rb +5 -5
- data/lib/asker/formatter/concept_doc_formatter.rb +3 -3
- data/lib/asker/formatter/concept_string_formatter.rb +6 -6
- data/lib/asker/formatter/moodle/ddmatch.erb +40 -0
- data/lib/asker/formatter/moodle/gapfill.erb +57 -0
- data/lib/asker/formatter/moodle/ordering.erb +41 -0
- data/lib/asker/formatter/question_gift_formatter.rb +41 -14
- data/lib/asker/formatter/question_hash_formatter.rb +5 -6
- data/lib/asker/formatter/question_moodle_formatter.rb +14 -7
- data/lib/asker/formatter/rb2haml_formatter.rb +8 -7
- data/lib/asker/lang/lang.rb +16 -16
- data/lib/asker/lang/lang_factory.rb +13 -16
- data/lib/asker/lang/text_actions.rb +20 -18
- data/lib/asker/loader/code_loader.rb +10 -22
- data/lib/asker/loader/content_loader.rb +42 -49
- data/lib/asker/loader/directory_loader.rb +13 -16
- data/lib/asker/loader/embedded_file.rb +14 -14
- data/lib/asker/loader/file_loader.rb +5 -4
- data/lib/asker/loader/haml_loader.rb +4 -3
- data/lib/asker/loader/image_url_loader.rb +6 -5
- data/lib/asker/loader/input_loader.rb +24 -10
- data/lib/asker/loader/problem_loader.rb +88 -0
- data/lib/asker/loader/project_loader.rb +5 -12
- data/lib/asker/logger.rb +19 -10
- data/lib/asker/skeleton.rb +19 -35
- data/lib/asker/start.rb +44 -0
- data/lib/asker/version.rb +1 -1
- data/lib/asker.rb +7 -52
- metadata +12 -6
- data/lib/asker/ai/code/problem_code_ai.rb +0 -176
- data/lib/asker/exporter/code_moodle_exporter.rb +0 -15
- data/lib/asker/exporter/concept_ai_moodle_exporter.rb +0 -15
@@ -1,31 +1,62 @@
|
|
1
|
+
require_relative "../application"
|
2
|
+
require_relative "../version"
|
3
|
+
require_relative "../formatter/question_moodle_formatter"
|
1
4
|
|
2
|
-
require_relative '../version'
|
3
|
-
require_relative 'concept_ai_moodle_exporter'
|
4
|
-
require_relative 'code_moodle_exporter'
|
5
|
-
|
6
|
-
# Export data to MoodleXML file
|
7
5
|
module DataMoodleExporter
|
6
|
+
def self.call(data, project)
|
7
|
+
file = File.open(project.get(:moodlepath), "w")
|
8
|
+
add_header(file, project)
|
9
|
+
|
10
|
+
export_concepts(concepts: data[:concepts_ai], file: file)
|
11
|
+
export_codes(codes: data[:codes_ai], file: file)
|
12
|
+
export_problems(problems: data[:problems], file: file)
|
13
|
+
|
14
|
+
close(file)
|
15
|
+
end
|
8
16
|
|
9
|
-
def self.
|
10
|
-
file = File.open(project.get(:moodlepath), 'w')
|
17
|
+
def self.add_header(file, project)
|
11
18
|
file.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
|
12
19
|
file.write("<quiz>\n")
|
13
|
-
file.write("<!--\n#{
|
14
|
-
file.write("
|
15
|
-
file.write("
|
16
|
-
file.write("
|
17
|
-
file.write("
|
18
|
-
file
|
19
|
-
|
20
|
-
|
21
|
-
|
20
|
+
file.write("<!--\n#{"=" * 50}\n")
|
21
|
+
file.write(" #{Asker::NAME} : version #{Asker::VERSION}\n")
|
22
|
+
file.write(" Filename : #{project.get(:moodlename)}\n")
|
23
|
+
file.write(" Datetime : #{Time.new}\n")
|
24
|
+
file.write("#{"=" * 50}\n-->\n\n")
|
25
|
+
file
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.close(file)
|
29
|
+
file.write("</quiz>\n")
|
30
|
+
file.close
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.export_concepts(concepts:, file:)
|
34
|
+
concepts.each do |concept_ai|
|
35
|
+
next unless concept_ai.concept.process?
|
36
|
+
|
37
|
+
Application.instance.config["questions"]["stages"].each do |stage|
|
38
|
+
concept_ai.questions[stage].each do |question|
|
39
|
+
file.write(QuestionMoodleFormatter.to_s(question))
|
40
|
+
end
|
41
|
+
end
|
22
42
|
end
|
43
|
+
end
|
23
44
|
|
24
|
-
|
25
|
-
|
45
|
+
def self.export_codes(codes:, file:)
|
46
|
+
codes.each do |code|
|
47
|
+
next unless code.process?
|
48
|
+
code.questions.each do |question|
|
49
|
+
file.write QuestionMoodleFormatter.to_s(question)
|
50
|
+
end
|
26
51
|
end
|
52
|
+
end
|
27
53
|
|
28
|
-
|
29
|
-
|
54
|
+
def self.export_problems(problems:, file:)
|
55
|
+
problems.each do |problem|
|
56
|
+
next unless problem.process?
|
57
|
+
problem.questions.each do |question|
|
58
|
+
file.write QuestionMoodleFormatter.to_s(question)
|
59
|
+
end
|
60
|
+
end
|
30
61
|
end
|
31
62
|
end
|
@@ -1,7 +1,7 @@
|
|
1
|
-
require_relative
|
2
|
-
require_relative
|
3
|
-
require_relative
|
4
|
-
require_relative
|
1
|
+
require_relative "concept_ai_yaml_exporter"
|
2
|
+
require_relative "concept_doc_exporter"
|
3
|
+
require_relative "data_gift_exporter"
|
4
|
+
require_relative "data_moodle_exporter"
|
5
5
|
|
6
6
|
##
|
7
7
|
# Export Output data files
|
@@ -9,9 +9,10 @@ require_relative 'data_moodle_exporter'
|
|
9
9
|
module OutputFileExporter
|
10
10
|
def self.export(data, project)
|
11
11
|
config = Application.instance.config
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
12
|
+
|
13
|
+
ConceptAIYAMLExporter.export_all(data[:concepts_ai], project) if config["output"]["yaml"] == "yes"
|
14
|
+
ConceptDocExporter.export_all(data[:concepts], project) if config["output"]["doc"] == "yes"
|
15
|
+
DataGiftExporter.export_all(data, project) if config["output"]["gift"] == "yes"
|
16
|
+
DataMoodleExporter.call(data, project) if config["output"]["moodle"] == "yes"
|
16
17
|
end
|
17
18
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require_relative "../formatter/question_gift_formatter"
|
2
|
+
|
3
|
+
class ProblemGiftExporter
|
4
|
+
##
|
5
|
+
# Export an Array of problems to gift format file
|
6
|
+
# @param problems (Array)
|
7
|
+
def call(problems, file)
|
8
|
+
problems.each { |problem| export_one(problem, file) }
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def export_one(problem, file)
|
14
|
+
return false unless problem.process?
|
15
|
+
|
16
|
+
file.write head(problem)
|
17
|
+
problem.questions.each do |question|
|
18
|
+
file.write QuestionGiftFormatter.to_s(question)
|
19
|
+
end
|
20
|
+
true
|
21
|
+
end
|
22
|
+
|
23
|
+
def head(problem)
|
24
|
+
s = "\n"
|
25
|
+
s += "// " + "=" * 50 + "\n"
|
26
|
+
s += "// Problem: #{problem.name} (#{problem.questions.size} questions)\n"
|
27
|
+
s += "// " + "=" * 50 + "\n"
|
28
|
+
s
|
29
|
+
end
|
30
|
+
end
|
@@ -27,3 +27,9 @@
|
|
27
27
|
:t8table: 'Concepte <b><%=text1%></b><br/>Completa la següent associació:<br/><ul><li><%=text2%>: "<%=text3%>"</li><li><%=text4%>: [*]</li></ul>Escriu una paraula.<br/>'
|
28
28
|
:t9table: 'Concepte <b><%=text1%></b><br/>Completa la següent associació:<br/><ul><li><%=text2%>: "<%=text3%>"</li><li><%=text4%>: <%=text5%></li></ul>Escriu <%=text6%> paraules.<br/>'
|
29
29
|
:code1: '<pre><%=text1%></pre><br/><p>Escriu el número de línia hi ha el primer error. Escriu 0 si no hi ha cap error.</p>'
|
30
|
+
:pa1: '<p><%=text1%></p><p><b>Pregunta:</b> <%=text2%></p><p><b>Resposta:</b > <%=text3%></p>'
|
31
|
+
:pa2: '<p><%=text1%></p><p><b>Pregunta:</b> <%=text2%></p>'
|
32
|
+
:ps3: '<p><%=text1%></p><p><b>Pregunta:</b> <%=text2%></p><p><b>Resposta:</b ></p><pre><%=text3%></pre><br/><i>(Escriure el número de línia on hi ha el primer error. Escriure 0 si no hi ha cap error)</i>'
|
33
|
+
:ps4: 'Canvia el pas <%=text1%> pel pas <%=text2%>'
|
34
|
+
:ps5: '<p><%=text1%></p><p><b>Pregunta:</b> <%=text2%></p><p><b>Resposta:</b ></p><pre><%=text3%></pre><br/><i>(Col·loca cada pas en la seva posició correcta dins de la seqüència)</i>'
|
35
|
+
:ps6: '<p><%=text1%></p><p><b>Pregunta:</b> <%=text2%></p><br/><i>(Posa cada pas en la posició correcta dins de la seqüència)</i>'
|
@@ -27,3 +27,9 @@
|
|
27
27
|
:t8table: 'Begriff <b><%=text1%></b><br/>Vervollständigen Sie / Schreiben Sie einen Begriff:<br/><ul><li><%=text2%>: "<%=text3%>"</li><li><%=text4%>: [*]</li></ul>Escribir una palabra.<br/>'
|
28
28
|
:t9table: 'Begriff <b><%=text1%></b><br/>Verbinden Sie / Schreiben Sie fogende Begriffe:<br/><ul><li><%=text2%>: "<%=text3%>"</li><li><%=text4%>: <%=text5%></li></ul>Escribir <%=text6%> palabras.<br/>'
|
29
29
|
:code1: '<pre><%=text1%></pre><br/><p>Nennen Sie die Nummer der Zeile, in der sich der erste Fehler befindet / Wenn es keinen Fehler gibt, setzen Sie 0 ein.</p>'
|
30
|
+
:pa1: '<p><%=text1%></p><p><b>Frage:</b> <%=text2%></p><p><b>Antwort:</b > <%=text3%></p>'
|
31
|
+
:pa2: '<p><%=text1%></p><p><b>Frage:</b> <%=text2%></p>'
|
32
|
+
:ps3: '<p><%=text1%></p><p><b>Frage:</b> <%=text2%></p><p><b>Antwort:</b ></p><pre><%=text3%></pre><br/><i>(Schreiben Sie die Zeilennummer, in der sich der erste Fehler befindet. Schreiben Sie 0, wenn kein Fehler vorliegt)</i>'
|
33
|
+
:ps4: 'Ändere Schritt <%=text1%> in Schritt <%=text2%>'
|
34
|
+
:ps5: '<p><%=text1%></p><p><b>Frage:</b> <%=text2%></p><p><b>Antwort:</b ></p><pre><%=text3%></pre><br/><i>(Platzieren Sie jeden Schritt an der richtigen Position innerhalb der Sequenz)</i>'
|
35
|
+
:ps6: '<p><%=text1%></p><p><b>Frage:</b> <%=text2%></p><br/><i>(Platzieren Sie jeden Schritt an der richtigen Position innerhalb der Sequenz)</i>'
|
@@ -1,5 +1,5 @@
|
|
1
1
|
---
|
2
|
-
:none: '
|
2
|
+
:none: 'None correct'
|
3
3
|
:error: 'Error'
|
4
4
|
:misspelling: 'Misspelling'
|
5
5
|
:true: 'True'
|
@@ -27,3 +27,9 @@
|
|
27
27
|
:t8table: '<b>Concept <%=text1%></b><br/>Complete the next association:<br/><ul><li><%=text2%>: "<%=text3%>"</li><li><%=text4%>: [*]</li></ul>Write only one word.<br/>'
|
28
28
|
:t9table: '<b>Concept <%=text1%></b><br/>Complete the next association:<br/><ul><li><%=text2%>: "<%=text3%>"</li><li><%=text4%>: <%=text5%></li></ul>Write <%=text6%> words.<br/>'
|
29
29
|
:code1: '<pre><%=text1%></pre><br/><p>Write the number of the first wrong line. Write 0 if there is no fail.</p>'
|
30
|
+
:pa1: '<p><%=text1%></p><p><b>Question:</b> <%=text2%></p><p><b>Answer:</b> <%=text3%></p>'
|
31
|
+
:pa2: '<p><%=text1%></p><p><b>Question:</b> <%=text2%></p>'
|
32
|
+
:ps3: '<p><%=text1%></p><p><b>Question:</b> <%=text2%></p><p><b>Answer:</b></p><pre><%=text3%></pre><br/><i>(Write the number of the first wrong line. Write 0 if there is no fail)</i>'
|
33
|
+
:ps4: 'Change step <%=text1%> by step <%=text2%>'
|
34
|
+
:ps5: '<p><%=text1%></p><p><b>Question:</b> <%=text2%></p><p><b>Answer:</b></p><pre><%=text3%></pre><br/><i>(Place each step in its correct position within the sequence)</i>'
|
35
|
+
:ps6: '<p><%=text1%></p><p><b>Question:</b> <%=text2%></p><br/><i>(Place each step in its correct position within the sequence)</i>'
|
@@ -27,3 +27,9 @@
|
|
27
27
|
:t8table: 'Concepto <b><%=text1%></b><br/>Completa la siguiente asociación:<br/><ul><li><%=text2%>: "<%=text3%>"</li><li><%=text4%>: [*]</li></ul>Escribir una palabra.<br/>'
|
28
28
|
:t9table: 'Concepto <b><%=text1%></b><br/>Completa la siguiente asociación:<br/><ul><li><%=text2%>: "<%=text3%>"</li><li><%=text4%>: <%=text5%></li></ul>Escribir <%=text6%> palabras.<br/>'
|
29
29
|
:code1: '<pre><%=text1%></pre><br/><p>Escribir el número de línea donde está el primer error. Escribir 0 si no hay ningún error.</p>'
|
30
|
+
:pa1: '<p><%=text1%></p><p><b>Pregunta:</b> <%=text2%></p><p><b>Respuesta:</b> <%=text3%></p>'
|
31
|
+
:pa2: '<p><%=text1%></p><p><b>Pregunta:</b> <%=text2%></p>'
|
32
|
+
:ps3: '<p><%=text1%></p><p><b>Pregunta:</b> <%=text2%></p><p><b>Respuesta:</b></p><pre><%=text3%></pre><br/><i>(Escribir el número de línea donde está el primer error. Escribir 0 si no hay ningún error)</i>'
|
33
|
+
:ps4: 'Cambia el paso <%=text1%> por el paso <%=text2%>'
|
34
|
+
:ps5: '<p><%=text1%></p><p><b>Pregunta:</b> <%=text2%></p><p><b>Respuesta:</b></p><pre><%=text3%></pre><br/><i>(Coloca cada paso en su posición correcta dentro de la secuencia)</i>'
|
35
|
+
:ps6: '<p><%=text1%></p><p><b>Pregunta:</b> <%=text2%></p><br/><i>(Coloca cada paso en su posición correcta dentro de la secuencia)</i>'
|
@@ -27,3 +27,9 @@
|
|
27
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
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
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>"
|
30
|
+
:pa1 : "<p><%=text1%></p><p><b>Question :</b> <%=text2%></p><p><b>Réponse :</b > <%=text3%></p>"
|
31
|
+
:pa2 : "<p><%=text1%></p><p><b>Question :</b> <%=text2%></p>"
|
32
|
+
:ps3 : "<p><%=text1%></p><p><b>Question :</b> <%=text2%></p><p><b>Réponse :</b ></p><pre><%=text3%></pre><br/><i>(Écrivez le numéro de ligne où se trouve la première erreur. Écrivez 0 s'il n'y a pas d'erreur)</i>"
|
33
|
+
:ps4: "Changer l'étape <%=text1%> en étape <%=text2%>"
|
34
|
+
:ps5 : "<p><%=text1%></p><p><b>Question :</b> <%=text2%></p><p><b>Réponse :</b ></p><pre><%=text3%></pre><br/><i>(Placez chaque étape dans sa position correcte dans la séquence)</i>"
|
35
|
+
:ps6 : "<p><%=text1%></p><p><b>Question :</b> <%=text2%></p><br/><i>(Placez chaque étape dans sa position correcte dans la séquence)</i>"
|
@@ -1,16 +1,16 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require "rainbow"
|
4
|
+
require "terminal-table"
|
5
5
|
|
6
6
|
# Define methods to trasnforme Code object into String
|
7
7
|
module CodeStringFormatter
|
8
8
|
def self.to_s(code)
|
9
9
|
t = Terminal::Table.new
|
10
10
|
msg = Rainbow(code.filename).white.bg(:blue).bright
|
11
|
-
t.add_row [Rainbow(
|
12
|
-
t.add_row [Rainbow(
|
13
|
-
t.add_row [Rainbow(
|
11
|
+
t.add_row [Rainbow("Code").bright, msg]
|
12
|
+
t.add_row [Rainbow("Type").blue, code.type.to_s]
|
13
|
+
t.add_row [Rainbow("Lines").blue, code.lines_to_s(code.lines)]
|
14
14
|
"#{t}\n"
|
15
15
|
end
|
16
16
|
end
|
@@ -1,14 +1,14 @@
|
|
1
1
|
# frozen_string_literal: false
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require "rainbow"
|
4
|
+
require "terminal-table"
|
5
5
|
|
6
6
|
module ConceptDocFormatter
|
7
7
|
##
|
8
8
|
# Formatter Concept into Doc
|
9
9
|
# @param concept (Concept)
|
10
10
|
def self.to_s(concept)
|
11
|
-
out =
|
11
|
+
out = ""
|
12
12
|
out << "\n#{Rainbow(concept.name).bg(:blue).bright}\n\n"
|
13
13
|
concept.texts.each { |i| out << "* #{i}\n" }
|
14
14
|
out << "\n"
|
@@ -18,18 +18,18 @@ module ConceptStringFormatter
|
|
18
18
|
private_class_method def self.get_tt_rows(concept)
|
19
19
|
rows = []
|
20
20
|
rows << [Rainbow(concept.id.to_s).bright,
|
21
|
-
|
22
|
-
|
21
|
+
Rainbow(concept.name(:screen)).green.bright]
|
22
|
+
# + " (lang=#{concept.lang.lang}) "]
|
23
23
|
# rows << [Rainbow("Filename").white, concept.filename]
|
24
24
|
# rows << [Rainbow("Context").white, concept.context.join(', ').to_s]
|
25
|
-
rows << [Rainbow("Tags").white, concept.tags.join(
|
25
|
+
rows << [Rainbow("Tags").white, concept.tags.join(", ").to_s]
|
26
26
|
unless concept.reference_to.size.zero?
|
27
27
|
rows << [Rainbow("Reference to").white,
|
28
|
-
|
28
|
+
concept.reference_to.join(", ")[0...70].to_s]
|
29
29
|
end
|
30
30
|
unless concept.referenced_by.size.zero?
|
31
31
|
rows << [Rainbow("Referenced by").white,
|
32
|
-
|
32
|
+
concept.referenced_by.join(", ")[0...70].to_s]
|
33
33
|
end
|
34
34
|
rows << format_texts(concept)
|
35
35
|
unless concept.images.size.zero?
|
@@ -50,7 +50,7 @@ module ConceptStringFormatter
|
|
50
50
|
list << i.to_s
|
51
51
|
next
|
52
52
|
end
|
53
|
-
list << i[0...70].to_s +
|
53
|
+
list << i[0...70].to_s + "..."
|
54
54
|
end
|
55
55
|
# [Rainbow("def").white, list.join("\n")]
|
56
56
|
[Rainbow("def").white, list.size.to_s]
|
@@ -0,0 +1,40 @@
|
|
1
|
+
<% unless question.comment.nil? || question.comment.empty? %>
|
2
|
+
<!-- question: <%= question.comment %> -->
|
3
|
+
<% end %>
|
4
|
+
<question type="ddmatch">
|
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></text>
|
16
|
+
</generalfeedback>
|
17
|
+
<defaultgrade>1.0000000</defaultgrade>
|
18
|
+
<penalty>0.3333333</penalty>
|
19
|
+
<hidden>0</hidden>
|
20
|
+
<idnumber></idnumber>
|
21
|
+
<shuffleanswers>true</shuffleanswers>
|
22
|
+
<correctfeedback format="html">
|
23
|
+
<text></text>
|
24
|
+
</correctfeedback>
|
25
|
+
<partiallycorrectfeedback format="html">
|
26
|
+
<text></text>
|
27
|
+
</partiallycorrectfeedback>
|
28
|
+
<incorrectfeedback format="html">
|
29
|
+
<text></text>
|
30
|
+
</incorrectfeedback>
|
31
|
+
<shownumcorrect/>
|
32
|
+
<% question.matching.each do |i, j| %>
|
33
|
+
<subquestion format="html">
|
34
|
+
<text><![CDATA[<%= i %>]]></text>
|
35
|
+
<answer format="html">
|
36
|
+
<text><![CDATA[<%= j %>]]></text>
|
37
|
+
</answer>
|
38
|
+
</subquestion>
|
39
|
+
<% end %>
|
40
|
+
</question>
|
@@ -0,0 +1,57 @@
|
|
1
|
+
<% unless question.comment.nil? || question.comment.empty? %>
|
2
|
+
<!-- question: <%= question.comment %> -->
|
3
|
+
<% end %>
|
4
|
+
<question type="gapfill">
|
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></text>
|
16
|
+
</generalfeedback>
|
17
|
+
<defaultgrade>2.0000000</defaultgrade>
|
18
|
+
<penalty>0.3333333</penalty>
|
19
|
+
<hidden>0</hidden>
|
20
|
+
<idnumber></idnumber>
|
21
|
+
<answerdisplay>dragdrop</answerdisplay>
|
22
|
+
<delimitchars>[]</delimitchars>
|
23
|
+
<casesensitive>0</casesensitive>
|
24
|
+
<noduplicates>0</noduplicates>
|
25
|
+
<disableregex>0</disableregex>
|
26
|
+
<fixedgapsize>0</fixedgapsize>
|
27
|
+
<optionsaftertext>0</optionsaftertext>
|
28
|
+
<letterhints>0</letterhints>
|
29
|
+
<singleuse>0</singleuse>
|
30
|
+
<% question.shorts.uniq! %>
|
31
|
+
<% question.shorts.each do |i| %>
|
32
|
+
<answer fraction="100" format="moodle_auto_format">
|
33
|
+
<text><![CDATA[<%= i %>]]></text>
|
34
|
+
<feedback format="html">
|
35
|
+
<text></text>
|
36
|
+
</feedback>
|
37
|
+
</answer>
|
38
|
+
<% end %>
|
39
|
+
<delimitchars>[]</delimitchars>
|
40
|
+
<answerdisplay>dragdrop</answerdisplay>
|
41
|
+
<casesensitive>0</casesensitive>
|
42
|
+
<noduplicates>0</noduplicates>
|
43
|
+
<disableregex>0</disableregex>
|
44
|
+
<fixedgapsize>0</fixedgapsize>
|
45
|
+
<optionsaftertext>0</optionsaftertext>
|
46
|
+
<letterhints>0</letterhints>
|
47
|
+
<!-- Gapfill release:2.133 version:2022032500 Moodle version:2020061514.02 release:3.9.14+ (Build: 20220603) -->
|
48
|
+
<correctfeedback format="html">
|
49
|
+
<text></text>
|
50
|
+
</correctfeedback>
|
51
|
+
<partiallycorrectfeedback format="html">
|
52
|
+
<text></text>
|
53
|
+
</partiallycorrectfeedback>
|
54
|
+
<incorrectfeedback format="html">
|
55
|
+
<text></text>
|
56
|
+
</incorrectfeedback>
|
57
|
+
</question>
|
@@ -0,0 +1,41 @@
|
|
1
|
+
<% unless question.comment.nil? || question.comment.empty? %>
|
2
|
+
<!-- question: <%= question.comment %> -->
|
3
|
+
<% end %>
|
4
|
+
<question type="ordering">
|
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
|
+
<idnumber></idnumber>
|
21
|
+
<layouttype>VERTICAL</layouttype>
|
22
|
+
<selecttype>ALL</selecttype>
|
23
|
+
<selectcount>0</selectcount>
|
24
|
+
<gradingtype>ABSOLUTE_POSITION</gradingtype>
|
25
|
+
<showgrading>SHOW</showgrading>
|
26
|
+
<numberingstyle>none</numberingstyle>
|
27
|
+
<correctfeedback format="html">
|
28
|
+
<text>Respuesta correcta</text>
|
29
|
+
</correctfeedback>
|
30
|
+
<partiallycorrectfeedback format="html">
|
31
|
+
<text>Respuesta parcialmente correcta.</text>
|
32
|
+
</partiallycorrectfeedback>
|
33
|
+
<incorrectfeedback format="html">
|
34
|
+
<text>Respuesta incorrecta.</text>
|
35
|
+
</incorrectfeedback>
|
36
|
+
<% question.ordering.each_with_index do |step, index| %>
|
37
|
+
<answer fraction="<%= index + 1 %>" format="moodle_auto_format">
|
38
|
+
<text><%= step %></text>
|
39
|
+
</answer>
|
40
|
+
<% end %>
|
41
|
+
</question>
|
@@ -7,7 +7,7 @@ module QuestionGiftFormatter
|
|
7
7
|
# @param question (Question)
|
8
8
|
# @return String
|
9
9
|
def self.to_s(question)
|
10
|
-
s =
|
10
|
+
s = ""
|
11
11
|
return s unless question.encode == :none
|
12
12
|
|
13
13
|
# Return question using gift format
|
@@ -16,40 +16,48 @@ module QuestionGiftFormatter
|
|
16
16
|
s << "::#{question.name}::[html]#{sanitize(question.text)}\n"
|
17
17
|
|
18
18
|
case question.type
|
19
|
+
when :boolean
|
20
|
+
s << "{#{question.good}#####{sanitize(question.feedback.to_s)}}\n\n"
|
19
21
|
when :choice
|
20
22
|
s += "{\n"
|
21
23
|
a = [" =#{sanitize(question.good)}\n"]
|
22
|
-
penalties = [
|
24
|
+
penalties = ["", "%-50%", "%-33.33333%", "%-25%", "%-20%"]
|
23
25
|
penalty = penalties[question.bads.size]
|
24
26
|
|
25
27
|
question.bads.each { |i| a << (" ~#{penalty}" + sanitize(i) + "\n") }
|
26
28
|
a.shuffle! if question.shuffle?
|
27
29
|
a.each do |i|
|
28
30
|
text = i
|
29
|
-
text = i[0, 220] +
|
31
|
+
text = i[0, 220] + "...(ERROR: text too long)" if text.size > 255
|
30
32
|
s << text
|
31
33
|
end
|
32
34
|
s += " #####{sanitize(question.feedback.to_s)}\n" if question.feedback
|
33
35
|
s += "}\n\n"
|
34
|
-
when :
|
35
|
-
s << "
|
36
|
+
when :ddmatch
|
37
|
+
s << "// WARNING: can't export ddmatch questions to this format"
|
38
|
+
when :gapfill
|
39
|
+
s << "// WARNING: can't export gapfill questions to this format"
|
36
40
|
when :match
|
37
41
|
s << "{\n"
|
38
42
|
a = []
|
39
43
|
question.matching.each do |i, j|
|
40
|
-
i = i[0, 220] +
|
41
|
-
j = j[0, 220] +
|
44
|
+
i = i[0, 220] + "...(ERROR: text too long)" if i.size > 255
|
45
|
+
j = j[0, 220] + "...(ERROR: text too long)" if j.size > 255
|
42
46
|
a << " =#{sanitize(i)} -> #{sanitize(j)}\n"
|
43
47
|
end
|
44
48
|
a.shuffle! if question.shuffle?
|
45
49
|
a.each { |i| s << i }
|
46
50
|
s << "}\n\n"
|
51
|
+
when :ordering
|
52
|
+
s << "{>0 ALL VERTICAL ABSOLUTE_POSITION SHOW none\n"
|
53
|
+
question.ordering.each { |i| s << "#{i}\n" }
|
54
|
+
s << "}\n\n"
|
47
55
|
when :short
|
48
56
|
s << "{\n"
|
49
57
|
question.shorts.uniq!
|
50
58
|
question.shorts.each do |i|
|
51
59
|
text = i
|
52
|
-
text = i[0, 220] +
|
60
|
+
text = i[0, 220] + "...(ERROR: too long)" if text.size > 255
|
53
61
|
s << " =%100%#{text}#\n"
|
54
62
|
end
|
55
63
|
s << " #####{sanitize(question.feedback.to_s)}\n" if question.feedback
|
@@ -62,14 +70,33 @@ module QuestionGiftFormatter
|
|
62
70
|
# Sanitize gift text
|
63
71
|
# @param input (String)
|
64
72
|
# @return String
|
65
|
-
def self.sanitize(input =
|
73
|
+
def self.sanitize(input = "")
|
74
|
+
return sanitize_exclude_pre(input) if input.include? '<pre>'
|
75
|
+
|
66
76
|
output = input.dup
|
67
|
-
output.gsub!(
|
77
|
+
output.gsub!("#", '\#')
|
68
78
|
output.gsub!("\n", " ")
|
69
|
-
output.gsub!(
|
70
|
-
output.gsub!(
|
71
|
-
output.gsub!("
|
72
|
-
output.gsub!("
|
79
|
+
output.gsub!(":", '\:')
|
80
|
+
output.gsub!("=", '\=')
|
81
|
+
output.gsub!("{", "\\{")
|
82
|
+
output.gsub!("}", "\\}")
|
83
|
+
|
73
84
|
output
|
74
85
|
end
|
86
|
+
|
87
|
+
def self.sanitize_exclude_pre(input = "")
|
88
|
+
pres = input.split('<pre>')
|
89
|
+
|
90
|
+
pres = [pres[0]] + pres[1].split("</pre>")
|
91
|
+
[0, 2].each do |index|
|
92
|
+
pres[index].gsub!("#", '\#')
|
93
|
+
pres[index].gsub!("\n", " ")
|
94
|
+
pres[index].gsub!(":", '\:')
|
95
|
+
pres[index].gsub!("=", '\=')
|
96
|
+
pres[index].gsub!("{", "\\{")
|
97
|
+
pres[index].gsub!("}", "\\}")
|
98
|
+
end
|
99
|
+
|
100
|
+
pres.join("")
|
101
|
+
end
|
75
102
|
end
|
@@ -1,4 +1,3 @@
|
|
1
|
-
|
2
1
|
# Transform Questions into YAML format
|
3
2
|
module QuestionHashFormatter
|
4
3
|
def self.to_hash(question)
|
@@ -26,14 +25,14 @@ module QuestionHashFormatter
|
|
26
25
|
s
|
27
26
|
end
|
28
27
|
|
29
|
-
def self.sanitize(input =
|
28
|
+
def self.sanitize(input = "")
|
30
29
|
output = input.dup
|
31
30
|
output.gsub!("#", "\\#")
|
32
|
-
output.
|
33
|
-
#output.gsub!(":", "\\:")
|
31
|
+
output.tr!("\n", " ")
|
32
|
+
# output.gsub!(":", "\\:")
|
34
33
|
output.gsub!("=", "\\=")
|
35
|
-
output.gsub!("
|
36
|
-
output.gsub!("
|
34
|
+
output.gsub!("{", "\\{")
|
35
|
+
output.gsub!("}", "\\}")
|
37
36
|
output
|
38
37
|
end
|
39
38
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: false
|
2
2
|
|
3
|
-
require
|
4
|
-
require_relative
|
3
|
+
require "erb"
|
4
|
+
require_relative "../application"
|
5
5
|
|
6
6
|
# Transform Questions into Gift format
|
7
7
|
class QuestionMoodleFormatter
|
@@ -12,20 +12,27 @@ class QuestionMoodleFormatter
|
|
12
12
|
def self.to_s(question)
|
13
13
|
case question.type
|
14
14
|
when :choice
|
15
|
-
fractions = Application.instance.config[
|
15
|
+
fractions = Application.instance.config["questions"]["fractions"]
|
16
16
|
penalties = fractions
|
17
17
|
# penalties = ['', '-50', '-33.33333', '-25', '-20']
|
18
18
|
# puts "[DEBUG] fractions : #{fractions}"
|
19
19
|
# puts "[DEBUG] penalties : #{penalties}"
|
20
20
|
|
21
21
|
penalty = penalties[question.bads.size]
|
22
|
-
template = File.read(File.join(File.dirname(__FILE__),
|
22
|
+
template = File.read(File.join(File.dirname(__FILE__), "moodle", "multichoice.erb"))
|
23
23
|
when :boolean
|
24
|
-
template = File.read(File.join(File.dirname(__FILE__),
|
24
|
+
template = File.read(File.join(File.dirname(__FILE__), "moodle", "truefalse.erb"))
|
25
|
+
when :ddmatch
|
26
|
+
template = File.read(File.join(File.dirname(__FILE__), "moodle", "ddmatch.erb"))
|
25
27
|
when :match
|
26
|
-
template = File.read(File.join(File.dirname(__FILE__),
|
28
|
+
template = File.read(File.join(File.dirname(__FILE__), "moodle", "matching.erb"))
|
29
|
+
when :ordering
|
30
|
+
template = File.read(File.join(File.dirname(__FILE__), "moodle", "ordering.erb"))
|
27
31
|
when :short
|
28
|
-
template = File.read(File.join(File.dirname(__FILE__),
|
32
|
+
template = File.read(File.join(File.dirname(__FILE__), "moodle", "shortanswer.erb"))
|
33
|
+
else
|
34
|
+
warn "[ERROR] QuestionMoodleFormatter: Unkown type (#{question.type})"
|
35
|
+
exit 1
|
29
36
|
end
|
30
37
|
renderer = ERB.new(template)
|
31
38
|
renderer.result(binding)
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# UNDER DEVELOPMENT!!
|
2
2
|
|
3
|
+
require_relative "../logger"
|
4
|
+
|
3
5
|
module Rb2HamlExporter
|
4
6
|
def self.export(filename)
|
5
7
|
check_file filename
|
@@ -8,19 +10,18 @@ module Rb2HamlExporter
|
|
8
10
|
end
|
9
11
|
|
10
12
|
def self.check_file(filename)
|
11
|
-
unless File.extname(filename).casecmp(
|
12
|
-
|
13
|
-
|
13
|
+
unless File.extname(filename).casecmp(".rb").zero?
|
14
|
+
Logger.error "Rb2HamlExporter: File name error #{filename}"
|
15
|
+
exit 1
|
14
16
|
end
|
15
17
|
unless File.exist? filename
|
16
|
-
|
17
|
-
|
18
|
+
Logger.error "Rb2HamlExporter: File #{filename} not found!"
|
19
|
+
exit 1
|
18
20
|
end
|
19
21
|
end
|
20
22
|
|
21
23
|
class Map
|
22
24
|
end
|
23
|
-
|
24
25
|
end
|
25
26
|
|
26
|
-
Rb2HamlExporter.export(
|
27
|
+
Rb2HamlExporter.export("docs/examples/home/rb/furniture.rb")
|