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
    
        data/lib/asker/data/table.rb
    CHANGED
    
    | @@ -1,9 +1,9 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 | 
            -
            require_relative  | 
| 4 | 
            -
            require_relative  | 
| 3 | 
            +
            require_relative "row"
         | 
| 4 | 
            +
            require_relative "template"
         | 
| 5 | 
            +
            require_relative "../logger"
         | 
| 5 6 |  | 
| 6 | 
            -
            # Contains data table information
         | 
| 7 7 | 
             
            class Table
         | 
| 8 8 | 
             
              attr_reader :name, :id
         | 
| 9 9 | 
             
              attr_reader :fields, :sequence
         | 
| @@ -14,30 +14,25 @@ class Table | |
| 14 14 | 
             
              attr_reader :simple
         | 
| 15 15 |  | 
| 16 16 | 
             
              ##
         | 
| 17 | 
            -
              # initialize Table object
         | 
| 18 17 | 
             
              # @param concept (Concept)
         | 
| 19 18 | 
             
              # @param xml_data (XML)
         | 
| 20 19 | 
             
              def initialize(concept, xml_data)
         | 
| 21 20 | 
             
                @concept = concept
         | 
| 22 21 | 
             
                read_attributes_from_xml(xml_data)
         | 
| 23 22 |  | 
| 24 | 
            -
                @simple = { | 
| 25 | 
            -
                @types | 
| 26 | 
            -
                @langs | 
| 23 | 
            +
                @simple = {lang: true, type: true}
         | 
| 24 | 
            +
                @types = ["text"] * @fields.size
         | 
| 25 | 
            +
                @langs = [@concept.lang] * @fields.size
         | 
| 27 26 |  | 
| 28 27 | 
             
                @datarows = [] # DEV experiment replace row data with row objects
         | 
| 29 28 | 
             
                read_data_from_xml(xml_data)
         | 
| 30 29 | 
             
                @rows = @datarows.map(&:raws)
         | 
| 31 30 | 
             
              end
         | 
| 32 31 |  | 
| 33 | 
            -
              ##
         | 
| 34 | 
            -
              # Return table name
         | 
| 35 32 | 
             
              def to_s
         | 
| 36 33 | 
             
                @name.to_s
         | 
| 37 34 | 
             
              end
         | 
| 38 35 |  | 
| 39 | 
            -
              ##
         | 
| 40 | 
            -
              # Return true if table has a sequence defined
         | 
| 41 36 | 
             
              def sequence?
         | 
| 42 37 | 
             
                @sequence.size.positive?
         | 
| 43 38 | 
             
              end
         | 
| @@ -48,7 +43,7 @@ class Table | |
| 48 43 | 
             
              # * types(index) => Return type for fields[index]
         | 
| 49 44 | 
             
              # @param index (Integer)
         | 
| 50 45 | 
             
              def types(index = :all)
         | 
| 51 | 
            -
                @types = ([ | 
| 46 | 
            +
                @types = (["text"] * @fields.size) if @types.nil?
         | 
| 52 47 | 
             
                return @types if index == :all
         | 
| 53 48 |  | 
| 54 49 | 
             
                @types[index]
         | 
| @@ -68,75 +63,59 @@ class Table | |
| 68 63 | 
             
              ##
         | 
| 69 64 | 
             
              # Fill:fields, name and id from XML input
         | 
| 70 65 | 
             
              # @param xml_data (XML)
         | 
| 71 | 
            -
              # rubocop:disable Metrics/AbcSize
         | 
| 72 66 | 
             
              def read_attributes_from_xml(xml_data)
         | 
| 73 | 
            -
                 | 
| 74 | 
            -
                t = xml_data.attributes['fields'].to_s.strip.split(',')
         | 
| 67 | 
            +
                t = xml_data.attributes["fields"].to_s.strip.split(",")
         | 
| 75 68 | 
             
                t.each(&:strip!)
         | 
| 76 69 | 
             
                @fields = t || []
         | 
| 77 70 |  | 
| 78 | 
            -
                @name =  | 
| 71 | 
            +
                @name = ""
         | 
| 79 72 | 
             
                @fields.each { |i| @name = "#{@name}$#{i.to_s.strip.downcase}" }
         | 
| 80 73 | 
             
                @id = "#{@concept.name}.#{@name}"
         | 
| 81 74 |  | 
| 82 75 | 
             
                @sequence = []
         | 
| 83 | 
            -
                return unless xml_data.attributes[ | 
| 76 | 
            +
                return unless xml_data.attributes["sequence"]
         | 
| 84 77 |  | 
| 85 | 
            -
                @sequence = xml_data.attributes[ | 
| 78 | 
            +
                @sequence = xml_data.attributes["sequence"].to_s.split(",")
         | 
| 86 79 | 
             
              end
         | 
| 87 | 
            -
              # rubocop:enable Metrics/AbcSize
         | 
| 88 80 |  | 
| 89 | 
            -
              ##
         | 
| 90 | 
            -
              # Build table data from xml input
         | 
| 91 | 
            -
              # @param xml_data (XML)
         | 
| 92 | 
            -
              # rubocop:disable Metrics/MethodLength
         | 
| 93 | 
            -
              # rubocop:disable Metrics/AbcSize
         | 
| 94 81 | 
             
              def read_data_from_xml(xml_data)
         | 
| 95 82 | 
             
                xml_data.elements.each do |i|
         | 
| 96 83 | 
             
                  case i.name
         | 
| 97 | 
            -
                  when  | 
| 84 | 
            +
                  when "lang"
         | 
| 98 85 | 
             
                    read_lang_from_xml(i)
         | 
| 99 | 
            -
                  when  | 
| 86 | 
            +
                  when "row"
         | 
| 100 87 | 
             
                    @datarows << Row.new(self, @datarows.size, i)
         | 
| 101 | 
            -
                  when  | 
| 102 | 
            -
                    @sequence = i.text.split( | 
| 103 | 
            -
                  when  | 
| 88 | 
            +
                  when "sequence"
         | 
| 89 | 
            +
                    @sequence = i.text.split(",")
         | 
| 90 | 
            +
                  when "template"
         | 
| 104 91 | 
             
                    @datarows += Template.new(self, @datarows.size, i).datarows
         | 
| 105 | 
            -
                  when  | 
| 92 | 
            +
                  when "type"
         | 
| 106 93 | 
             
                    read_type_from_xml(i)
         | 
| 107 94 | 
             
                  else
         | 
| 108 | 
            -
                     | 
| 95 | 
            +
                    Logger.warn "Table: Tag unkown (concept/table/#{i.name})"
         | 
| 109 96 | 
             
                  end
         | 
| 110 97 | 
             
                end
         | 
| 111 98 | 
             
              end
         | 
| 112 | 
            -
              # rubocop:enable Metrics/MethodLength
         | 
| 113 | 
            -
              # rubocop:enable Metrics/AbcSize
         | 
| 114 99 |  | 
| 115 | 
            -
              # rubocop:disable Metrics/MethodLength
         | 
| 116 | 
            -
              # rubocop:disable Metrics/AbcSize
         | 
| 117 | 
            -
              # rubocop:disable Style/ConditionalAssignment
         | 
| 118 100 | 
             
              def read_lang_from_xml(xml_data)
         | 
| 119 | 
            -
                j = xml_data.text.split( | 
| 101 | 
            +
                j = xml_data.text.split(",")
         | 
| 120 102 | 
             
                codes = @langs.map(&:code)
         | 
| 121 | 
            -
                return if j.join( | 
| 103 | 
            +
                return if j.join(",") == codes.join(",")
         | 
| 122 104 |  | 
| 123 105 | 
             
                simple_off(:lang)
         | 
| 124 106 | 
             
                @langs = []
         | 
| 125 107 | 
             
                j.each do |k|
         | 
| 126 | 
            -
                  if [ | 
| 127 | 
            -
                    @ | 
| 108 | 
            +
                  @langs << if ["*", ""].include? k.strip
         | 
| 109 | 
            +
                    @concept.lang
         | 
| 128 110 | 
             
                  else
         | 
| 129 | 
            -
                     | 
| 111 | 
            +
                    LangFactory.instance.get(k.strip.to_s)
         | 
| 130 112 | 
             
                  end
         | 
| 131 113 | 
             
                end
         | 
| 132 114 | 
             
              end
         | 
| 133 | 
            -
              # rubocop:enable Metrics/MethodLength
         | 
| 134 | 
            -
              # rubocop:enable Metrics/AbcSize
         | 
| 135 | 
            -
              # rubocop:enable Style/ConditionalAssignment
         | 
| 136 115 |  | 
| 137 116 | 
             
              def read_type_from_xml(xml_data)
         | 
| 138 | 
            -
                j = xml_data.text.split( | 
| 139 | 
            -
                return if j.join( | 
| 117 | 
            +
                j = xml_data.text.split(",")
         | 
| 118 | 
            +
                return if j.join(",") == @types.join(",")
         | 
| 140 119 |  | 
| 141 120 | 
             
                simple_off(:type)
         | 
| 142 121 | 
             
                @types = []
         | 
    
        data/lib/asker/data/template.rb
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            # frozen_string_literal: false
         | 
| 2 2 |  | 
| 3 | 
            -
            require  | 
| 4 | 
            -
            require_relative  | 
| 3 | 
            +
            require "rexml/document"
         | 
| 4 | 
            +
            require_relative "row"
         | 
| 5 5 |  | 
| 6 6 | 
             
            # This class process "template" tag used by Tables
         | 
| 7 7 | 
             
            class Template
         | 
| @@ -19,10 +19,10 @@ class Template | |
| 19 19 | 
             
                vars = {}
         | 
| 20 20 | 
             
                v = xml.attributes
         | 
| 21 21 | 
             
                v.keys.each do |i|
         | 
| 22 | 
            -
                  if i ==  | 
| 22 | 
            +
                  if i == "mode"
         | 
| 23 23 | 
             
                    @mode = v[i].to_sym
         | 
| 24 24 | 
             
                  else
         | 
| 25 | 
            -
                    vars[i] = v[i].split( | 
| 25 | 
            +
                    vars[i] = v[i].split(",")
         | 
| 26 26 | 
             
                  end
         | 
| 27 27 | 
             
                end
         | 
| 28 28 | 
             
                # fill_vars_values(vars,mode)
         | 
| @@ -34,13 +34,13 @@ class Template | |
| 34 34 | 
             
              end
         | 
| 35 35 |  | 
| 36 36 | 
             
              def load_template_from(xml)
         | 
| 37 | 
            -
                template =  | 
| 37 | 
            +
                template = ""
         | 
| 38 38 | 
             
                xml.elements.each { |i| template << i.to_s + "\n" }
         | 
| 39 39 | 
             
                template
         | 
| 40 40 | 
             
              end
         | 
| 41 41 |  | 
| 42 42 | 
             
              def apply_vars_to_template(vars, template)
         | 
| 43 | 
            -
                output =  | 
| 43 | 
            +
                output = ""
         | 
| 44 44 | 
             
                return output if vars.size.zero?
         | 
| 45 45 |  | 
| 46 46 | 
             
                max = vars.first[1].size
         | 
| @@ -57,7 +57,7 @@ class Template | |
| 57 57 | 
             
                data = "<template>\n#{data_string}\n</template>"
         | 
| 58 58 | 
             
                xml = REXML::Document.new(data)
         | 
| 59 59 | 
             
                xml.root.elements.each do |i|
         | 
| 60 | 
            -
                  if i.name ==  | 
| 60 | 
            +
                  if i.name == "row"
         | 
| 61 61 | 
             
                    datarows << Row.new(table, index, i)
         | 
| 62 62 | 
             
                    index += 1
         | 
| 63 63 | 
             
                  end
         | 
    
        data/lib/asker/data/world.rb
    CHANGED
    
    | @@ -1,6 +1,6 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 | 
            -
            require_relative  | 
| 3 | 
            +
            require_relative "../loader/image_url_loader"
         | 
| 4 4 |  | 
| 5 5 | 
             
            class World
         | 
| 6 6 | 
             
              # TODO: change how World class works ?
         | 
| @@ -37,7 +37,7 @@ class World | |
| 37 37 |  | 
| 38 38 | 
             
                  concepts[c.name] = c
         | 
| 39 39 | 
             
                  filenames << c.filename
         | 
| 40 | 
            -
                  contexts | 
| 40 | 
            +
                  contexts << c.context
         | 
| 41 41 | 
             
                end
         | 
| 42 42 | 
             
                filenames.uniq!
         | 
| 43 43 | 
             
                contexts.uniq!
         | 
| @@ -52,7 +52,7 @@ class World | |
| 52 52 | 
             
                urls = {}
         | 
| 53 53 |  | 
| 54 54 | 
             
                @concepts&.each_key { |key| searchs << key }
         | 
| 55 | 
            -
                @contexts.each { |filter| searchs << filter.join( | 
| 55 | 
            +
                @contexts.each { |filter| searchs << filter.join(" ").to_s }
         | 
| 56 56 | 
             
                searchs.each do |search|
         | 
| 57 57 | 
             
                  threads << Thread.new { urls[search] = ImageUrlLoader.load(search) }
         | 
| 58 58 | 
             
                end
         | 
| @@ -1,5 +1,3 @@ | |
| 1 | 
            -
            # encoding: utf-8
         | 
| 2 | 
            -
             | 
| 3 1 | 
             
            # Transform Questions into Gift format
         | 
| 4 2 | 
             
            module QuestionMoodleXMLFormatter
         | 
| 5 3 | 
             
              def self.to_s(question)
         | 
| @@ -18,51 +16,51 @@ module QuestionMoodleXMLFormatter | |
| 18 16 | 
             
              def self.choice_to_s(question)
         | 
| 19 17 | 
             
                s = []
         | 
| 20 18 |  | 
| 21 | 
            -
                penalties = [ | 
| 19 | 
            +
                penalties = ["", "%-50%", "%-33.33333%", "%-25%", "%-20%"]
         | 
| 22 20 | 
             
                penalty = penalties[question.bads.size]
         | 
| 23 21 |  | 
| 24 22 | 
             
                s << "<!-- question: #{question.name}  -->"
         | 
| 25 23 | 
             
                s << '<question type="multichoice">'
         | 
| 26 | 
            -
                s <<  | 
| 24 | 
            +
                s << "  <name>"
         | 
| 27 25 | 
             
                s << "    <text>#{question.name}</text>"
         | 
| 28 | 
            -
                s <<  | 
| 26 | 
            +
                s << "  </name>"
         | 
| 29 27 | 
             
                s << '  <questiontext format="html">'
         | 
| 30 28 | 
             
                s << "    <text><![CDATA[#{question.text}]]></text>"
         | 
| 31 | 
            -
                s <<  | 
| 29 | 
            +
                s << "  </questiontext>"
         | 
| 32 30 | 
             
                s << '  <generalfeedback format="html">'
         | 
| 33 31 | 
             
                s << "    <text>#{question.feedback}</text>"
         | 
| 34 | 
            -
                s <<  | 
| 35 | 
            -
                s <<  | 
| 32 | 
            +
                s << "  </generalfeedback>"
         | 
| 33 | 
            +
                s << "  <defaultgrade>1.0000000</defaultgrade>"
         | 
| 36 34 | 
             
                s << "  <penalty>#{penalty}</penalty>"
         | 
| 37 | 
            -
                s <<  | 
| 38 | 
            -
                s <<  | 
| 35 | 
            +
                s << "  <hidden>0</hidden>"
         | 
| 36 | 
            +
                s << "  <single>true</single>"
         | 
| 39 37 | 
             
                s << "  <shuffleanswers>#{question.shuffle?}</shuffleanswers>"
         | 
| 40 | 
            -
                s <<  | 
| 38 | 
            +
                s << "  <answernumbering>abc</answernumbering>"
         | 
| 41 39 | 
             
                s << '  <incorrectfeedback format="html">'
         | 
| 42 40 | 
             
                s << "    <text>#{question.feedback}</text>"
         | 
| 43 | 
            -
                s <<  | 
| 41 | 
            +
                s << "  </incorrectfeedback>"
         | 
| 44 42 | 
             
                s << '  <answer fraction="100" format="html">'
         | 
| 45 43 | 
             
                s << "    <text>#{question.good}</text>"
         | 
| 46 | 
            -
                s <<  | 
| 44 | 
            +
                s << "  </answer>"
         | 
| 47 45 | 
             
                s << '  <answer fraction="-25" format="html">'
         | 
| 48 46 | 
             
                s << "    <text>#{question.bad[0]}</text>"
         | 
| 49 | 
            -
                s <<  | 
| 50 | 
            -
                s <<  | 
| 47 | 
            +
                s << "  </answer>"
         | 
| 48 | 
            +
                s << "  </question>"
         | 
| 51 49 | 
             
                s << '  <answer fraction="-25" format="html">'
         | 
| 52 50 | 
             
                s << "    <text>#{question.bad[1]}</text>"
         | 
| 53 | 
            -
                s <<  | 
| 54 | 
            -
                s <<  | 
| 51 | 
            +
                s << "  </answer>"
         | 
| 52 | 
            +
                s << "  </question>"
         | 
| 55 53 | 
             
                s << '  <answer fraction="-25" format="html">'
         | 
| 56 54 | 
             
                s << "    <text>#{question.bad[2]}</text>"
         | 
| 57 | 
            -
                s <<  | 
| 58 | 
            -
                s <<  | 
| 55 | 
            +
                s << "  </answer>"
         | 
| 56 | 
            +
                s << "  </question>"
         | 
| 59 57 | 
             
                s
         | 
| 60 58 | 
             
              end
         | 
| 61 59 |  | 
| 62 | 
            -
              def self.sanitize(input =  | 
| 60 | 
            +
              def self.sanitize(input = "")
         | 
| 63 61 | 
             
                output = input.dup
         | 
| 64 62 | 
             
                output.tr!("\n", " ")
         | 
| 65 | 
            -
                output.tr!(":", " | 
| 63 | 
            +
                output.tr!(":", ":")
         | 
| 66 64 | 
             
                output.tr!("=", "\\=")
         | 
| 67 65 | 
             
                # output.gsub!('{', "\\{")
         | 
| 68 66 | 
             
                # output.gsub!('}', "\\}")
         | 
| @@ -19,13 +19,13 @@ module CodeDisplayer | |
| 19 19 |  | 
| 20 20 | 
             
                  e = code.lines.size
         | 
| 21 21 | 
             
                  q = code.questions.size
         | 
| 22 | 
            -
                  factor =  | 
| 22 | 
            +
                  factor = "Unknown"
         | 
| 23 23 | 
             
                  factor = (q.to_f / e).round(2).to_s unless e.zero?
         | 
| 24 24 | 
             
                  my_screen_table.add_row [Rainbow(File.basename(code.filename)).green,
         | 
| 25 | 
            -
             | 
| 26 | 
            -
             | 
| 27 | 
            -
             | 
| 28 | 
            -
             | 
| 25 | 
            +
                    code.type,
         | 
| 26 | 
            +
                    q,
         | 
| 27 | 
            +
                    e,
         | 
| 28 | 
            +
                    factor]
         | 
| 29 29 | 
             
                  total_c += 1
         | 
| 30 30 | 
             
                  total_q += q
         | 
| 31 31 | 
             
                  total_e += e
         | 
| @@ -33,13 +33,13 @@ module CodeDisplayer | |
| 33 33 |  | 
| 34 34 | 
             
                my_screen_table.add_separator
         | 
| 35 35 | 
             
                my_screen_table.add_row [Rainbow("TOTAL = #{total_c}").bright,
         | 
| 36 | 
            -
             | 
| 37 | 
            -
             | 
| 38 | 
            -
             | 
| 39 | 
            -
             | 
| 36 | 
            +
                  " ",
         | 
| 37 | 
            +
                  Rainbow(total_q.to_s).bright,
         | 
| 38 | 
            +
                  Rainbow(total_e.to_s).bright,
         | 
| 39 | 
            +
                  Rainbow((total_q / total_e.to_f).round(2)).bright]
         | 
| 40 40 | 
             
                return unless total_c.positive?
         | 
| 41 41 |  | 
| 42 | 
            -
                Logger.verboseln "\n[INFO] Showing  | 
| 42 | 
            +
                Logger.verboseln "\n[INFO] Showing CODEs statistics"
         | 
| 43 43 | 
             
                Logger.verboseln my_screen_table.to_s
         | 
| 44 44 | 
             
              end
         | 
| 45 45 | 
             
            end
         | 
| @@ -1,11 +1,11 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 3 | 
             
            require "erb"
         | 
| 4 | 
            +
            require "rainbow"
         | 
| 4 5 | 
             
            require "terminal-table"
         | 
| 5 6 | 
             
            require_relative "../application"
         | 
| 6 7 | 
             
            require_relative "../logger"
         | 
| 7 8 |  | 
| 8 | 
            -
            # Display ConceptAI stat on screen
         | 
| 9 9 | 
             
            class ConceptAIDisplayer
         | 
| 10 10 | 
             
              ##
         | 
| 11 11 | 
             
              # Display ConceptAI stat on screen
         | 
| @@ -48,10 +48,10 @@ class ConceptAIDisplayer | |
| 48 48 | 
             
                  st = concept_ai.questions[:t].size if stages.include? :t
         | 
| 49 49 | 
             
                  t = sd + sb + sf + si + ss + st
         | 
| 50 50 |  | 
| 51 | 
            -
                  factor = " | 
| 51 | 
            +
                  factor = "Unknown"
         | 
| 52 52 | 
             
                  factor = (t.to_f / e).round(2).to_s unless e.zero?
         | 
| 53 53 | 
             
                  screen_table.add_row [Rainbow(concept_ai.concept.name(:screen)).green.bright,
         | 
| 54 | 
            -
             | 
| 54 | 
            +
                    t, e, factor, sd, sb, sf, si, ss, st]
         | 
| 55 55 |  | 
| 56 56 | 
             
                  total[:q] += t
         | 
| 57 57 | 
             
                  total[:e] += e
         | 
| @@ -71,13 +71,13 @@ class ConceptAIDisplayer | |
| 71 71 | 
             
                # Create table TAIL
         | 
| 72 72 | 
             
                screen_table.add_separator
         | 
| 73 73 | 
             
                screen_table.add_row [Rainbow("#{total[:c]} concept/s").bright,
         | 
| 74 | 
            -
             | 
| 75 | 
            -
             | 
| 76 | 
            -
             | 
| 77 | 
            -
             | 
| 78 | 
            -
             | 
| 74 | 
            +
                  Rainbow(total[:q].to_s).bright,
         | 
| 75 | 
            +
                  Rainbow(total[:e].to_s).bright,
         | 
| 76 | 
            +
                  Rainbow((total[:q].to_f / total[:e]).round(2)).bright,
         | 
| 77 | 
            +
                  total[:sd], total[:sb], total[:sf],
         | 
| 78 | 
            +
                  total[:si], total[:ss], total[:st]]
         | 
| 79 79 | 
             
                export_notes
         | 
| 80 | 
            -
                Logger. | 
| 80 | 
            +
                Logger.info "#{screen_table}\n"
         | 
| 81 81 | 
             
              end
         | 
| 82 82 |  | 
| 83 83 | 
             
              private_class_method def self.export_excluded_questions(screen_table, concepts_ai)
         | 
| @@ -107,16 +107,16 @@ class ConceptAIDisplayer | |
| 107 107 | 
             
                  total[:ss] += ss
         | 
| 108 108 | 
             
                  total[:st] += st
         | 
| 109 109 | 
             
                end
         | 
| 110 | 
            -
                screen_table.add_row [Rainbow( | 
| 111 | 
            -
             | 
| 112 | 
            -
             | 
| 113 | 
            -
             | 
| 114 | 
            -
             | 
| 110 | 
            +
                screen_table.add_row [Rainbow("Excluded questions").yellow.bright,
         | 
| 111 | 
            +
                  total[:q], "-", "-",
         | 
| 112 | 
            +
                  total[:sd], total[:sb],
         | 
| 113 | 
            +
                  total[:sf], total[:si],
         | 
| 114 | 
            +
                  total[:ss], total[:st]]
         | 
| 115 115 | 
             
              end
         | 
| 116 116 |  | 
| 117 117 | 
             
              private_class_method def self.export_notes
         | 
| 118 | 
            -
                exclude_questions = Application.instance.config[ | 
| 119 | 
            -
                renderer = ERB.new(File.read(File.join(File.dirname(__FILE__),  | 
| 120 | 
            -
                Logger. | 
| 118 | 
            +
                exclude_questions = Application.instance.config["questions"]["exclude"].to_s
         | 
| 119 | 
            +
                renderer = ERB.new(File.read(File.join(File.dirname(__FILE__), "concept_ai_displayer.erb")))
         | 
| 120 | 
            +
                Logger.info Rainbow(renderer.result(binding)).white
         | 
| 121 121 | 
             
              end
         | 
| 122 122 | 
             
            end
         | 
| @@ -7,6 +7,8 @@ module ConceptDisplayer | |
| 7 7 | 
             
              # Show concepts on screen
         | 
| 8 8 | 
             
              # @param concepts (Array) List of concept data
         | 
| 9 9 | 
             
              def self.show(concepts)
         | 
| 10 | 
            +
                return if concepts.nil? || concepts.size.zero?
         | 
| 11 | 
            +
             | 
| 10 12 | 
             
                show_mode = Application.instance.config["global"]["show_mode"]
         | 
| 11 13 | 
             
                return unless show_mode
         | 
| 12 14 |  | 
| @@ -14,8 +16,8 @@ module ConceptDisplayer | |
| 14 16 | 
             
                Logger.verboseln msg
         | 
| 15 17 | 
             
                case show_mode
         | 
| 16 18 | 
             
                when "resume"
         | 
| 17 | 
            -
                   | 
| 18 | 
            -
                   | 
| 19 | 
            +
                  names = concepts.map { |c| c.name }
         | 
| 20 | 
            +
                  s = " * Concepts (#{names.count}): #{names.join(",")}"
         | 
| 19 21 | 
             
                  Logger.verboseln s
         | 
| 20 22 | 
             
                when "default"
         | 
| 21 23 | 
             
                  # Only show Concepts with process attr true
         | 
| @@ -0,0 +1,45 @@ | |
| 1 | 
            +
            require "terminal-table"
         | 
| 2 | 
            +
            require_relative "../logger"
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            module ProblemDisplayer
         | 
| 5 | 
            +
              ##
         | 
| 6 | 
            +
              # Show all "problem" data on screen
         | 
| 7 | 
            +
              # @param problems (Array) List of "problems" data
         | 
| 8 | 
            +
              def self.show(problems)
         | 
| 9 | 
            +
                return if problems.nil? || problems.size.zero?
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                total_p = total_q = total_e = 0
         | 
| 12 | 
            +
                my_screen_table = Terminal::Table.new do |st|
         | 
| 13 | 
            +
                  st << %w[Problem Desc Questions Entries xFactor]
         | 
| 14 | 
            +
                  st << :separator
         | 
| 15 | 
            +
                end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                problems.each do |problem|
         | 
| 18 | 
            +
                  next unless problem.process?
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                  e = problem.cases.size
         | 
| 21 | 
            +
                  problem.asks.each do |ask|
         | 
| 22 | 
            +
                    e += ask[:steps].size
         | 
| 23 | 
            +
                    e += 1 if !ask[:answer].nil?
         | 
| 24 | 
            +
                  end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                  q = problem.questions.size
         | 
| 27 | 
            +
                  factor = "Unknown"
         | 
| 28 | 
            +
                  factor = (q.to_f / e).round(2).to_s unless e.zero?
         | 
| 29 | 
            +
                  desc = Rainbow(problem.desc[0, 24]).green
         | 
| 30 | 
            +
                  my_screen_table.add_row [problem.name, desc, q, e, factor]
         | 
| 31 | 
            +
                  total_p += 1
         | 
| 32 | 
            +
                  total_q += q
         | 
| 33 | 
            +
                  total_e += e
         | 
| 34 | 
            +
                end
         | 
| 35 | 
            +
                return unless total_p.positive?
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                my_screen_table.add_separator
         | 
| 38 | 
            +
                my_screen_table.add_row [Rainbow("TOTAL = #{total_p}").bright, "",
         | 
| 39 | 
            +
                  Rainbow(total_q.to_s).bright,
         | 
| 40 | 
            +
                  Rainbow(total_e.to_s).bright,
         | 
| 41 | 
            +
                  Rainbow((total_q / total_e.to_f).round(2)).bright]
         | 
| 42 | 
            +
                Logger.verboseln Rainbow("\n[INFO] Showing PROBLEMs statistics").white
         | 
| 43 | 
            +
                Logger.verboseln my_screen_table.to_s
         | 
| 44 | 
            +
              end
         | 
| 45 | 
            +
            end
         | 
| @@ -1,22 +1,17 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 | 
            -
            require_relative  | 
| 4 | 
            -
            require_relative  | 
| 5 | 
            -
            require_relative  | 
| 3 | 
            +
            require_relative "../application"
         | 
| 4 | 
            +
            require_relative "concept_ai_displayer"
         | 
| 5 | 
            +
            require_relative "code_displayer"
         | 
| 6 | 
            +
            require_relative "problem_displayer"
         | 
| 6 7 |  | 
| 7 | 
            -
            # Display Stats on screen.
         | 
| 8 | 
            -
            # * Display all "Concept AI"
         | 
| 9 | 
            -
            # * Display all "Code"
         | 
| 10 8 | 
             
            module StatsDisplayer
         | 
| 11 | 
            -
              #  | 
| 12 | 
            -
              # * Display all "Concept AI"
         | 
| 13 | 
            -
              # * Display all "Code"
         | 
| 14 | 
            -
              # @param data (Hash) With concept_ai list and code list
         | 
| 9 | 
            +
              # @param data (Hash) With concept_ai, code and problem list
         | 
| 15 10 | 
             
              def self.show(data)
         | 
| 16 | 
            -
                return unless Application.instance.config[ | 
| 11 | 
            +
                return unless Application.instance.config["global"]["show_mode"]
         | 
| 17 12 |  | 
| 18 | 
            -
                # show_final_results
         | 
| 19 13 | 
             
                ConceptAIDisplayer.show(data[:concepts_ai])
         | 
| 20 14 | 
             
                CodeDisplayer.show(data[:codes_ai])
         | 
| 15 | 
            +
                ProblemDisplayer.show(data[:problems])
         | 
| 21 16 | 
             
              end
         | 
| 22 17 | 
             
            end
         | 
| @@ -23,9 +23,9 @@ module CodeGiftExporter | |
| 23 23 |  | 
| 24 24 | 
             
              private_class_method def self.head(code)
         | 
| 25 25 | 
             
                s = "\n"
         | 
| 26 | 
            -
                s +=  | 
| 26 | 
            +
                s += "// " + "=" * 50 + "\n"
         | 
| 27 27 | 
             
                s += "// Code #{code.type}: #{code.filename} (#{code.questions.size})\n"
         | 
| 28 | 
            -
                s +=  | 
| 28 | 
            +
                s += "// " + "=" * 50 + "\n"
         | 
| 29 29 | 
             
                s
         | 
| 30 30 | 
             
              end
         | 
| 31 31 | 
             
            end
         | 
| @@ -1,6 +1,6 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 | 
            -
            require_relative  | 
| 3 | 
            +
            require_relative "../formatter/question_gift_formatter"
         | 
| 4 4 |  | 
| 5 5 | 
             
            # Export ConceptIA data to gift to outputfile
         | 
| 6 6 | 
             
            module ConceptAIGiftExporter
         | 
| @@ -20,7 +20,7 @@ module ConceptAIGiftExporter | |
| 20 20 | 
             
                return unless concept_ai.concept.process?
         | 
| 21 21 |  | 
| 22 22 | 
             
                file.write head(concept_ai.concept.name)
         | 
| 23 | 
            -
                Application.instance.config[ | 
| 23 | 
            +
                Application.instance.config["questions"]["stages"].each do |stage|
         | 
| 24 24 | 
             
                  concept_ai.questions[stage].each do |question|
         | 
| 25 25 | 
             
                    file.write(QuestionGiftFormatter.to_s(question))
         | 
| 26 26 | 
             
                  end
         | 
| @@ -33,9 +33,9 @@ module ConceptAIGiftExporter | |
| 33 33 | 
             
              # @return String
         | 
| 34 34 | 
             
              private_class_method def self.head(name)
         | 
| 35 35 | 
             
                s = "\n"
         | 
| 36 | 
            -
                s +=  | 
| 36 | 
            +
                s += "// " + "=" * 50 + "\n"
         | 
| 37 37 | 
             
                s += "// Concept name: #{name}\n"
         | 
| 38 | 
            -
                s +=  | 
| 38 | 
            +
                s += "// " + "=" * 50 + "\n"
         | 
| 39 39 | 
             
                s
         | 
| 40 40 | 
             
              end
         | 
| 41 41 | 
             
            end
         | 
| @@ -1,5 +1,5 @@ | |
| 1 | 
            -
            require  | 
| 2 | 
            -
            require_relative  | 
| 1 | 
            +
            require "yaml"
         | 
| 2 | 
            +
            require_relative "../formatter/question_hash_formatter"
         | 
| 3 3 |  | 
| 4 4 | 
             
            # Use to export data from ConceptIA to YAML format
         | 
| 5 5 | 
             
            module ConceptAIYAMLExporter
         | 
| @@ -12,11 +12,11 @@ module ConceptAIYAMLExporter | |
| 12 12 | 
             
                concepts_ai.each do |concept_ai|
         | 
| 13 13 | 
             
                  questions += get_questions_from concept_ai
         | 
| 14 14 | 
             
                end
         | 
| 15 | 
            -
                params = { | 
| 16 | 
            -
             | 
| 17 | 
            -
                output = { | 
| 15 | 
            +
                params = {lang: project.get(:lang),
         | 
| 16 | 
            +
                          projectname: project.get(:projectname)}
         | 
| 17 | 
            +
                output = {params: params, questions: questions}
         | 
| 18 18 |  | 
| 19 | 
            -
                yamlfile = File.open(project.get(:yamlpath),  | 
| 19 | 
            +
                yamlfile = File.open(project.get(:yamlpath), "w")
         | 
| 20 20 | 
             
                yamlfile.write(output.to_yaml)
         | 
| 21 21 | 
             
                yamlfile.close
         | 
| 22 22 | 
             
              end
         | 
| @@ -25,7 +25,7 @@ module ConceptAIYAMLExporter | |
| 25 25 | 
             
                data = []
         | 
| 26 26 | 
             
                return data unless concept_ai.concept.process?
         | 
| 27 27 |  | 
| 28 | 
            -
                Application.instance.config[ | 
| 28 | 
            +
                Application.instance.config["questions"]["stages"].each do |stage|
         | 
| 29 29 | 
             
                  concept_ai.questions[stage].each do |question|
         | 
| 30 30 | 
             
                    question.lang = concept_ai.concept.lang
         | 
| 31 31 | 
             
                    data << QuestionHashFormatter.to_hash(question)
         | 
| @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 | 
            -
            require_relative  | 
| 4 | 
            -
            require_relative  | 
| 3 | 
            +
            require_relative "../formatter/concept_doc_formatter"
         | 
| 4 | 
            +
            require_relative "../version"
         | 
| 5 5 |  | 
| 6 6 | 
             
            ##
         | 
| 7 7 | 
             
            # Export Concept to Doc file
         | 
| @@ -9,12 +9,12 @@ module ConceptDocExporter | |
| 9 9 | 
             
              ##
         | 
| 10 10 | 
             
              # Export array of concepts to doc
         | 
| 11 11 | 
             
              def self.export_all(concepts, project)
         | 
| 12 | 
            -
                file = File.new(project.get(:lessonpath),  | 
| 13 | 
            -
                file.write( | 
| 12 | 
            +
                file = File.new(project.get(:lessonpath), "w")
         | 
| 13 | 
            +
                file.write("=" * 50 + "\n")
         | 
| 14 14 | 
             
                file.write("Created by : #{Asker::NAME} (version #{Asker::VERSION})\n")
         | 
| 15 15 | 
             
                file.write("File       : #{project.get(:lessonname)}\n")
         | 
| 16 16 | 
             
                file.write("Time       : #{Time.new}\n")
         | 
| 17 | 
            -
                file.write( | 
| 17 | 
            +
                file.write("=" * 50 + "\n")
         | 
| 18 18 |  | 
| 19 19 | 
             
                concepts.each do |concept|
         | 
| 20 20 | 
             
                  file.write(ConceptDocFormatter.to_s(concept)) if concept.process
         |