asker-tool 2.1.5 → 2.2.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.
Files changed (105) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +13 -17
  3. data/bin/asker +2 -1
  4. data/lib/asker/ai/ai.rb +10 -3
  5. data/lib/asker/ai/ai_calculate.rb +20 -6
  6. data/lib/asker/ai/code/base_code_ai.rb +104 -0
  7. data/lib/asker/{code/ai → ai/code}/code_ai_factory.rb +11 -1
  8. data/lib/asker/{code/ai → ai/code}/javascript_code_ai.rb +2 -5
  9. data/lib/asker/ai/code/problem_code_ai.rb +176 -0
  10. data/lib/asker/{code/ai → ai/code}/python_code_ai.rb +2 -5
  11. data/lib/asker/{code/ai → ai/code}/ruby_code_ai.rb +14 -7
  12. data/lib/asker/{code/ai → ai/code}/sql_code_ai.rb +2 -5
  13. data/lib/asker/ai/concept_ai.rb +13 -3
  14. data/lib/asker/ai/question.rb +28 -6
  15. data/lib/asker/ai/stages/base_stage.rb +45 -6
  16. data/lib/asker/ai/stages/stage_b.rb +100 -50
  17. data/lib/asker/ai/stages/stage_d.rb +75 -90
  18. data/lib/asker/ai/stages/stage_f.rb +64 -36
  19. data/lib/asker/ai/stages/stage_i.rb +79 -92
  20. data/lib/asker/ai/stages/stage_s.rb +41 -36
  21. data/lib/asker/ai/stages/stage_t.rb +149 -108
  22. data/lib/asker/application.rb +19 -11
  23. data/lib/asker/cli.rb +31 -44
  24. data/lib/asker/data/code.rb +62 -0
  25. data/lib/asker/data/column.rb +31 -21
  26. data/lib/asker/data/concept.rb +109 -65
  27. data/lib/asker/data/data_field.rb +14 -0
  28. data/lib/asker/data/project_data.rb +63 -0
  29. data/lib/asker/data/row.rb +75 -52
  30. data/lib/asker/data/table.rb +91 -42
  31. data/lib/asker/data/template.rb +3 -1
  32. data/lib/asker/data/world.rb +51 -35
  33. data/lib/asker/displayer/code_displayer.rb +7 -0
  34. data/lib/asker/displayer/concept_ai_displayer.erb +10 -0
  35. data/lib/asker/displayer/concept_ai_displayer.rb +74 -53
  36. data/lib/asker/displayer/concept_displayer.rb +16 -9
  37. data/lib/asker/displayer/stats_displayer.rb +12 -3
  38. data/lib/asker/exporter/concept_ai_gift_exporter.rb +19 -11
  39. data/lib/asker/exporter/concept_ai_moodle_exporter.rb +44 -0
  40. data/lib/asker/exporter/concept_ai_yaml_exporter.rb +13 -6
  41. data/lib/asker/exporter/concept_doc_exporter.rb +14 -1
  42. data/lib/asker/exporter/data_gift_exporter.rb +29 -0
  43. data/lib/asker/exporter/output_file_exporter.rb +9 -6
  44. data/lib/asker/files/{config.ini → asker.ini} +48 -1
  45. data/lib/asker/files/example-concept.haml +0 -1
  46. data/lib/asker/files/language/du/connectors.yaml +81 -0
  47. data/lib/asker/{lang/locales/fr → files/language/du}/mistakes.yaml +1 -1
  48. data/lib/asker/files/language/du/templates.yaml +29 -0
  49. data/lib/asker/{lang/locales → files/language}/en/connectors.yaml +0 -0
  50. data/lib/asker/{lang/locales → files/language}/en/mistakes.yaml +0 -0
  51. data/lib/asker/files/language/en/templates.yaml +29 -0
  52. data/lib/asker/{lang/locales → files/language}/es/connectors.yaml +0 -0
  53. data/lib/asker/files/language/es/mistakes.yaml +84 -0
  54. data/lib/asker/files/language/es/templates.yaml +29 -0
  55. data/lib/asker/files/language/fr/connectors.yaml +76 -0
  56. data/lib/asker/{lang/locales/es → files/language/fr}/mistakes.yaml +0 -0
  57. data/lib/asker/files/language/fr/templates.yaml +29 -0
  58. data/lib/asker/{lang/locales → files/language}/javascript/connectors.yaml +0 -0
  59. data/lib/asker/{lang/locales → files/language}/javascript/mistakes.yaml +0 -0
  60. data/lib/asker/{lang/locales → files/language}/javascript/templates.yaml +0 -0
  61. data/lib/asker/{lang/locales → files/language}/math/connectors.yaml +0 -0
  62. data/lib/asker/{lang/locales → files/language}/math/mistakes.yaml +0 -0
  63. data/lib/asker/{lang/locales → files/language}/math/templates.yaml +0 -0
  64. data/lib/asker/{lang/locales → files/language}/python/connectors.yaml +0 -0
  65. data/lib/asker/{lang/locales → files/language}/python/mistakes.yaml +0 -0
  66. data/lib/asker/{lang/locales → files/language}/python/templates.yaml +0 -0
  67. data/lib/asker/{lang/locales → files/language}/ruby/connectors.yaml +0 -0
  68. data/lib/asker/{lang/locales → files/language}/ruby/mistakes.yaml +0 -0
  69. data/lib/asker/{lang/locales → files/language}/ruby/templates.yaml +0 -0
  70. data/lib/asker/{lang/locales → files/language}/sql/connectors.yaml +0 -0
  71. data/lib/asker/{lang/locales → files/language}/sql/mistakes.yaml +0 -0
  72. data/lib/asker/{lang/locales → files/language}/sql/templates.yaml +0 -0
  73. data/lib/asker/formatter/concept_doc_formatter.rb +0 -4
  74. data/lib/asker/formatter/concept_string_formatter.rb +7 -4
  75. data/lib/asker/formatter/moodle/matching.erb +38 -0
  76. data/lib/asker/formatter/moodle/multichoice.erb +49 -0
  77. data/lib/asker/formatter/moodle/shortanswer.erb +30 -0
  78. data/lib/asker/formatter/moodle/truefalse.erb +47 -0
  79. data/lib/asker/formatter/question_gift_formatter.rb +30 -20
  80. data/lib/asker/formatter/question_moodle_formatter.rb +27 -0
  81. data/lib/asker/{checker.rb → input_checker.rb} +126 -49
  82. data/lib/asker/lang/lang.rb +17 -10
  83. data/lib/asker/lang/lang_factory.rb +32 -5
  84. data/lib/asker/lang/text_actions.rb +87 -69
  85. data/lib/asker/loader/code_loader.rb +4 -4
  86. data/lib/asker/loader/content_loader.rb +21 -19
  87. data/lib/asker/loader/directory_loader.rb +1 -8
  88. data/lib/asker/loader/embedded_file.rb +42 -0
  89. data/lib/asker/loader/file_loader.rb +3 -14
  90. data/lib/asker/loader/haml_loader.rb +15 -0
  91. data/lib/asker/loader/image_url_loader.rb +8 -12
  92. data/lib/asker/loader/input_loader.rb +13 -15
  93. data/lib/asker/loader/project_loader.rb +25 -15
  94. data/lib/asker/logger.rb +36 -9
  95. data/lib/asker/skeleton.rb +23 -13
  96. data/lib/asker.rb +76 -42
  97. metadata +53 -54
  98. data/lib/asker/code/ai/base_code_ai.rb +0 -48
  99. data/lib/asker/code/code.rb +0 -53
  100. data/lib/asker/lang/locales/du/templates.yaml +0 -50
  101. data/lib/asker/lang/locales/en/templates.yaml +0 -29
  102. data/lib/asker/lang/locales/es/templates.yaml +0 -29
  103. data/lib/asker/lang/locales/fr/connectors.yaml +0 -92
  104. data/lib/asker/lang/locales/fr/templates.yaml +0 -29
  105. data/lib/asker/project.rb +0 -172
@@ -3,10 +3,6 @@
3
3
  require 'rainbow'
4
4
  require 'terminal-table'
5
5
 
6
- require_relative '../project'
7
-
8
- ##
9
- # Formatter Concept to Doc
10
6
  module ConceptDocFormatter
11
7
  ##
12
8
  # Formatter Concept into Doc
@@ -12,12 +12,11 @@ module ConceptStringFormatter
12
12
  def self.to_s(concept)
13
13
  tt = Terminal::Table.new
14
14
  get_tt_rows(concept).each { |row| tt.add_row row }
15
- "#{tt}\n"
15
+ tt.to_s
16
16
  end
17
17
 
18
18
  # rubocop:disable Metrics/AbcSize
19
19
  # rubocop:disable Metrics/MethodLength
20
- # rubocop:disable Layout/LineLength
21
20
  private_class_method def self.get_tt_rows(concept)
22
21
  rows = []
23
22
  rows << [Rainbow(concept.id.to_s).bright,
@@ -31,13 +30,17 @@ module ConceptStringFormatter
31
30
  rows << [Rainbow('Referenced by').blue,
32
31
  concept.referenced_by.join(', ')[0...70].to_s]
33
32
  rows << format_texts(concept)
34
- rows << [Rainbow('.def(images)').blue, concept.images.size.to_s] unless concept.images.size.zero?
33
+ unless concept.images.size.zero?
34
+ counter1 = 0
35
+ concept.images.each { |image| counter1 += 1 if image[:file] == :none }
36
+ counter2 = concept.images.size - counter1
37
+ rows << [Rainbow('.def(images)').blue, "#{counter1} text / #{counter2} file"]
38
+ end
35
39
  rows << format_tables(concept) unless concept.tables.count.zero?
36
40
  rows << format_neighbors(concept)
37
41
  end
38
42
  # rubocop:enable Metrics/AbcSize
39
43
  # rubocop:enable Metrics/MethodLength
40
- # rubocop:enable Layout/LineLength
41
44
 
42
45
  private_class_method def self.format_texts(concept)
43
46
  list = []
@@ -0,0 +1,38 @@
1
+ <% unless question.comment.nil? || question.comment.empty? %>
2
+ <!-- question: <%= question.comment %> -->
3
+ <% end %>
4
+ <question type="matching">
5
+ <name>
6
+ <text><%= question.name %></text>
7
+ </name>
8
+ <questiontext format="html">
9
+ <text><![CDATA[<%= question.text %>]]></text>
10
+ <% unless question.encode == :none %>
11
+ <%= question.encode %>
12
+ <% end %>
13
+ </questiontext>
14
+ <generalfeedback format="html">
15
+ <text><![CDATA[<%= question.feedback.to_s %>]]></text>
16
+ </generalfeedback>
17
+ <defaultgrade>1.0000000</defaultgrade>
18
+ <penalty>0.3333333</penalty>
19
+ <hidden>0</hidden>
20
+ <shuffleanswers>true</shuffleanswers>
21
+ <correctfeedback format="html">
22
+ <text></text>
23
+ </correctfeedback>
24
+ <partiallycorrectfeedback format="html">
25
+ <text></text>
26
+ </partiallycorrectfeedback>
27
+ <incorrectfeedback format="html">
28
+ <text></text>
29
+ </incorrectfeedback>
30
+ <% question.matching.each do |i, j| %>
31
+ <subquestion format="html">
32
+ <text><![CDATA[<%= i %>]]></text>
33
+ <answer>
34
+ <text><![CDATA[<%= j %>]]></text>
35
+ </answer>
36
+ </subquestion>
37
+ <% end %>
38
+ </question>
@@ -0,0 +1,49 @@
1
+ <% unless question.comment.nil? || question.comment.empty? %>
2
+ <!-- question: <%= question.comment %> -->
3
+ <% end %>
4
+ <question type="multichoice">
5
+ <name>
6
+ <text><%= question.name %></text>
7
+ </name>
8
+ <questiontext format="html">
9
+ <text><![CDATA[<%= question.text %>]]></text>
10
+ <% unless question.encode == :none %>
11
+ <%= question.encode %>
12
+ <% end %>
13
+ </questiontext>
14
+ <generalfeedback format="html">
15
+ <text><![CDATA[<%= question.feedback.to_s %>]]></text>
16
+ </generalfeedback>
17
+ <defaultgrade>1.0000000</defaultgrade>
18
+ <penalty>0.3333333</penalty>
19
+ <hidden>0</hidden>
20
+ <single>true</single>
21
+ <shuffleanswers>true</shuffleanswers>
22
+ <answernumbering>abc</answernumbering>
23
+ <correctfeedback format="html">
24
+ <text></text>
25
+ </correctfeedback>
26
+ <partiallycorrectfeedback format="html">
27
+ <text></text>
28
+ </partiallycorrectfeedback>
29
+ <incorrectfeedback format="html">
30
+ <text></text>
31
+ </incorrectfeedback>
32
+ <answer fraction="100" format="html">
33
+ <text><%= question.good %></text>
34
+ <feedback format="html">
35
+ <text></text>
36
+ </feedback>
37
+ </answer>
38
+ <%
39
+ question.bads.shuffle! if question.shuffle?
40
+ question.bads.each do |i|
41
+ %>
42
+ <answer fraction="<%= penalty %>" format="html">
43
+ <text><![CDATA[<%= i %>]]></text>
44
+ <feedback format="html">
45
+ <text></text>
46
+ </feedback>
47
+ </answer>
48
+ <% end %>
49
+ </question>
@@ -0,0 +1,30 @@
1
+ <% unless question.comment.nil? || question.comment.empty? %>
2
+ <!-- question: <%= question.comment %> -->
3
+ <% end %>
4
+ <question type="shortanswer">
5
+ <name>
6
+ <text><%= question.name %></text>
7
+ </name>
8
+ <questiontext format="html">
9
+ <text><![CDATA[<%= question.text %>]]></text>
10
+ <% unless question.encode == :none %>
11
+ <%= question.encode %>
12
+ <% end %>
13
+ </questiontext>
14
+ <generalfeedback format="html">
15
+ <text><![CDATA[<%= question.feedback.to_s %>]]></text>
16
+ </generalfeedback>
17
+ <defaultgrade>1.0000000</defaultgrade>
18
+ <penalty>0.3333333</penalty>
19
+ <hidden>0</hidden>
20
+ <usecase>0</usecase>
21
+ <% question.shorts.uniq! %>
22
+ <% question.shorts.each do |i| %>
23
+ <answer fraction="100" format="moodle_auto_format">
24
+ <text><![CDATA[<%= i %>]]></text>
25
+ <feedback format="html">
26
+ <text></text>
27
+ </feedback>
28
+ </answer>
29
+ <% end %>
30
+ </question>
@@ -0,0 +1,47 @@
1
+ <% unless question.comment.nil? || question.comment.empty? %>
2
+ <!-- question: <%= question.comment %> -->
3
+ <% end %>
4
+ <question type="truefalse">
5
+ <name>
6
+ <text><%= question.name %></text>
7
+ </name>
8
+ <questiontext format="html">
9
+ <text><![CDATA[<%= question.text %>]]></text>
10
+ <% unless question.encode == :none %>
11
+ <%= question.encode %>
12
+ <% end %>
13
+ </questiontext>
14
+ <generalfeedback format="html">
15
+ <text><![CDATA[<%= question.feedback.to_s %>]]></text>
16
+ </generalfeedback>
17
+ <defaultgrade>1.0000000</defaultgrade>
18
+ <penalty>1.0000000</penalty>
19
+ <hidden>0</hidden>
20
+ <% if question.good == 'TRUE' %>
21
+ <answer fraction="100" format="moodle_auto_format">
22
+ <text>true</text>
23
+ <feedback format="html">
24
+ <text></text>
25
+ </feedback>
26
+ </answer>
27
+ <answer fraction="0" format="moodle_auto_format">
28
+ <text>false</text>
29
+ <feedback format="html">
30
+ <text></text>
31
+ </feedback>
32
+ </answer>
33
+ <% else %>
34
+ <answer fraction="0" format="moodle_auto_format">
35
+ <text>true</text>
36
+ <feedback format="html">
37
+ <text></text>
38
+ </feedback>
39
+ </answer>
40
+ <answer fraction="100" format="moodle_auto_format">
41
+ <text>false</text>
42
+ <feedback format="html">
43
+ <text></text>
44
+ </feedback>
45
+ </answer>
46
+ <% end %>
47
+ </question>
@@ -1,63 +1,73 @@
1
- # encoding: utf-8
1
+ # frozen_string_literal: false
2
2
 
3
3
  # Transform Questions into Gift format
4
4
  module QuestionGiftFormatter
5
+ ##
6
+ # Convert question object into gift formatted string
7
+ # @param question (Question)
8
+ # @return String
5
9
  def self.to_s(question)
6
- @question = question
10
+ s = ''
11
+ return s unless question.encode == :none
12
+
7
13
  # Return question using gift format
8
- cond = @question.comment.nil? && @question.comment.empty?
9
- s = "// #{@question.comment}\n" unless cond
10
- s << "::#{@question.name}::[html]#{sanitize(@question.text)}\n"
14
+ cond = question.comment.nil? || question.comment.empty?
15
+ s = "// #{question.comment}\n" unless cond
16
+ s << "::#{question.name}::[html]#{sanitize(question.text)}\n"
11
17
 
12
- case @question.type
18
+ case question.type
13
19
  when :choice
14
20
  s += "{\n"
15
- a = [" =#{sanitize(@question.good)}\n"]
21
+ a = [" =#{sanitize(question.good)}\n"]
16
22
  penalties = ['', '%-50%', '%-33.33333%', '%-25%', '%-20%']
17
- penalty = penalties[@question.bads.size]
23
+ penalty = penalties[question.bads.size]
18
24
 
19
- @question.bads.each { |i| a << (" ~#{penalty}" + sanitize(i) + "\n") }
20
- a.shuffle! if @question.shuffle?
25
+ question.bads.each { |i| a << (" ~#{penalty}" + sanitize(i) + "\n") }
26
+ a.shuffle! if question.shuffle?
21
27
  a.each do |i|
22
28
  text = i
23
29
  text = i[0, 220] + '...(ERROR: text too long)' if text.size > 255
24
30
  s << text
25
31
  end
26
- s += " #####{sanitize(@question.feedback.to_s)}\n" if @question.feedback
32
+ s += " #####{sanitize(question.feedback.to_s)}\n" if question.feedback
27
33
  s += "}\n\n"
28
34
  when :boolean
29
- s << "{#{@question.good}#####{sanitize(@question.feedback.to_s)}}\n\n"
35
+ s << "{#{question.good}#####{sanitize(question.feedback.to_s)}}\n\n"
30
36
  when :match
31
37
  s << "{\n"
32
38
  a = []
33
- @question.matching.each do |i, j|
39
+ question.matching.each do |i, j|
34
40
  i = i[0, 220] + '...(ERROR: text too long)' if i.size > 255
35
41
  j = j[0, 220] + '...(ERROR: text too long)' if j.size > 255
36
42
  a << " =#{sanitize(i)} -> #{sanitize(j)}\n"
37
43
  end
38
- a.shuffle! if @question.shuffle?
44
+ a.shuffle! if question.shuffle?
39
45
  a.each { |i| s << i }
40
46
  s << "}\n\n"
41
47
  when :short
42
48
  s << "{\n"
43
- @question.shorts.uniq!
44
- @question.shorts.each do |i|
49
+ question.shorts.uniq!
50
+ question.shorts.each do |i|
45
51
  text = i
46
52
  text = i[0, 220] + '...(ERROR: too long)' if text.size > 255
47
53
  s << " =%100%#{text}#\n"
48
54
  end
49
- s << " #####{sanitize(@question.feedback.to_s)}\n" if @question.feedback
55
+ s << " #####{sanitize(question.feedback.to_s)}\n" if question.feedback
50
56
  s << "}\n\n"
51
57
  end
52
58
  s
53
59
  end
54
60
 
61
+ ##
62
+ # Sanitize gift text
63
+ # @param input (String)
64
+ # @return String
55
65
  def self.sanitize(input = '')
56
66
  output = input.dup
57
- output.gsub!("#", "\\#")
67
+ output.gsub!('#', '\#')
58
68
  output.gsub!("\n", " ")
59
- #output.gsub!(":", "\\:")
60
- output.gsub!("=", "\\=")
69
+ output.gsub!(':', '\:')
70
+ output.gsub!('=', '\=')
61
71
  output.gsub!("\{", "\\{")
62
72
  output.gsub!("\}", "\\}")
63
73
  output
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: false
2
+
3
+ require 'erb'
4
+
5
+ # Transform Questions into Gift format
6
+ module QuestionMoodleFormatter
7
+ ##
8
+ # Convert question object into gift formatted string
9
+ # @param question (Question)
10
+ # @return String
11
+ def self.to_s(question)
12
+ case question.type
13
+ when :choice
14
+ penalties = ['', '-50', '-33.33333', '-25', '-20']
15
+ penalty = penalties[question.bads.size]
16
+ template = File.read(File.join(File.dirname(__FILE__), 'moodle', 'multichoice.erb'))
17
+ when :boolean
18
+ template = File.read(File.join(File.dirname(__FILE__), 'moodle', 'truefalse.erb'))
19
+ when :match
20
+ template = File.read(File.join(File.dirname(__FILE__), 'moodle', 'matching.erb'))
21
+ when :short
22
+ template = File.read(File.join(File.dirname(__FILE__), 'moodle', 'shortanswer.erb'))
23
+ end
24
+ renderer = ERB.new(template)
25
+ renderer.result(binding)
26
+ end
27
+ end