asker-tool 2.6.0 → 2.7.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/README.md +5 -5
- 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 +17 -17
- 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,30 +1,29 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 | 
            -
            require_relative  | 
| 4 | 
            -
            require_relative  | 
| 5 | 
            -
            require_relative  | 
| 6 | 
            -
            require_relative  | 
| 3 | 
            +
            require_relative "concept_ai_gift_exporter"
         | 
| 4 | 
            +
            require_relative "code_gift_exporter"
         | 
| 5 | 
            +
            require_relative "problem_gift_exporter"
         | 
| 6 | 
            +
            require_relative "../application"
         | 
| 7 | 
            +
            require_relative "../version"
         | 
| 7 8 |  | 
| 8 | 
            -
            # Export Data (ConceptIA and Code) to gift to outputfile
         | 
| 9 9 | 
             
            module DataGiftExporter
         | 
| 10 10 | 
             
              ##
         | 
| 11 | 
            -
              # Export an array of Data ( | 
| 11 | 
            +
              # Export an array of Data (ConceptAIs, Codes and Problems objects) into GIFT file
         | 
| 12 12 | 
             
              # @param data (Hash)
         | 
| 13 13 | 
             
              # @param project (Project)
         | 
| 14 14 | 
             
              def self.export_all(data, project)
         | 
| 15 | 
            -
                file = File.open(project.get(:outputpath),  | 
| 16 | 
            -
                file.write( | 
| 17 | 
            -
                file.write("//  | 
| 18 | 
            -
                file.write("  | 
| 19 | 
            -
                file.write("//  | 
| 20 | 
            -
                file.write("//  | 
| 21 | 
            -
                 | 
| 22 | 
            -
                category = Application.instance.config['questions']['category']
         | 
| 15 | 
            +
                file = File.open(project.get(:outputpath), "w")
         | 
| 16 | 
            +
                file.write("// " + ("=" * 50) + "\n")
         | 
| 17 | 
            +
                file.write("// #{Asker::NAME}    : version #{Asker::VERSION}\n")
         | 
| 18 | 
            +
                file.write("// Filename : #{project.get(:outputname)}\n")
         | 
| 19 | 
            +
                file.write("// Datetime : #{Time.new}\n")
         | 
| 20 | 
            +
                file.write("// " + ("=" * 50) + "\n\n")
         | 
| 21 | 
            +
                category = Application.instance.config["questions"]["category"]
         | 
| 23 22 | 
             
                file.write("$CATEGORY: $course$/#{category}\n") unless category.nil?
         | 
| 24 23 |  | 
| 25 24 | 
             
                ConceptAIGiftExporter.export_all(data[:concepts_ai], file)
         | 
| 26 25 | 
             
                CodeGiftExporter.export_all(data[:codes_ai], file)
         | 
| 27 | 
            -
             | 
| 26 | 
            +
                ProblemGiftExporter.new.call(data[:problems], file)
         | 
| 28 27 | 
             
                file.close
         | 
| 29 28 | 
             
              end
         | 
| 30 29 | 
             
            end
         | 
| @@ -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
         |