asker-tool 2.5.9 → 2.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +10 -7
  3. data/lib/asker/ai/ai.rb +17 -22
  4. data/lib/asker/ai/ai_calculate.rb +10 -17
  5. data/lib/asker/ai/code/base_code_ai.rb +5 -30
  6. data/lib/asker/ai/code/code_ai_factory.rb +6 -12
  7. data/lib/asker/ai/code/javascript_code_ai.rb +33 -34
  8. data/lib/asker/ai/code/python_code_ai.rb +35 -36
  9. data/lib/asker/ai/code/ruby_code_ai.rb +33 -33
  10. data/lib/asker/ai/code/sql_code_ai.rb +20 -21
  11. data/lib/asker/ai/concept_ai.rb +12 -22
  12. data/lib/asker/ai/problem/problem_ai.rb +226 -0
  13. data/lib/asker/ai/question.rb +34 -45
  14. data/lib/asker/ai/stages/base_stage.rb +7 -7
  15. data/lib/asker/ai/stages/main.rb +6 -7
  16. data/lib/asker/ai/stages/stage_b.rb +62 -28
  17. data/lib/asker/ai/stages/stage_d.rb +10 -10
  18. data/lib/asker/ai/stages/stage_f.rb +17 -17
  19. data/lib/asker/ai/stages/stage_i.rb +8 -18
  20. data/lib/asker/ai/stages/stage_s.rb +28 -26
  21. data/lib/asker/ai/stages/stage_t.rb +54 -76
  22. data/lib/asker/application.rb +15 -14
  23. data/lib/asker/check_input/check_haml_data.rb +57 -51
  24. data/lib/asker/check_input/check_table.rb +26 -19
  25. data/lib/asker/check_input.rb +10 -22
  26. data/lib/asker/cli.rb +43 -24
  27. data/lib/asker/data/code.rb +10 -9
  28. data/lib/asker/data/column.rb +21 -17
  29. data/lib/asker/data/concept.rb +24 -37
  30. data/lib/asker/data/data_field.rb +2 -2
  31. data/lib/asker/data/problem.rb +112 -0
  32. data/lib/asker/data/project_data.rb +11 -15
  33. data/lib/asker/data/row.rb +25 -23
  34. data/lib/asker/data/table.rb +25 -46
  35. data/lib/asker/data/template.rb +7 -7
  36. data/lib/asker/data/world.rb +3 -3
  37. data/lib/asker/{formatter → deprecated}/question_moodlexml_formatter.rb +19 -21
  38. data/lib/asker/displayer/code_displayer.rb +10 -10
  39. data/lib/asker/displayer/concept_ai_displayer.erb +1 -1
  40. data/lib/asker/displayer/concept_ai_displayer.rb +22 -34
  41. data/lib/asker/displayer/concept_displayer.rb +9 -11
  42. data/lib/asker/displayer/problem_displayer.rb +45 -0
  43. data/lib/asker/displayer/stats_displayer.rb +7 -12
  44. data/lib/asker/exporter/code_gift_exporter.rb +2 -2
  45. data/lib/asker/exporter/concept_ai_gift_exporter.rb +4 -4
  46. data/lib/asker/exporter/concept_ai_yaml_exporter.rb +7 -7
  47. data/lib/asker/exporter/concept_doc_exporter.rb +5 -5
  48. data/lib/asker/exporter/data_gift_exporter.rb +14 -15
  49. data/lib/asker/exporter/data_moodle_exporter.rb +51 -20
  50. data/lib/asker/exporter/output_file_exporter.rb +9 -8
  51. data/lib/asker/exporter/problem_gift_exporter.rb +30 -0
  52. data/lib/asker/files/language/ca/templates.yaml +6 -0
  53. data/lib/asker/files/language/du/templates.yaml +6 -0
  54. data/lib/asker/files/language/en/templates.yaml +7 -1
  55. data/lib/asker/files/language/es/templates.yaml +6 -0
  56. data/lib/asker/files/language/fr/templates.yaml +6 -0
  57. data/lib/asker/formatter/code_string_formatter.rb +5 -5
  58. data/lib/asker/formatter/concept_doc_formatter.rb +3 -3
  59. data/lib/asker/formatter/concept_string_formatter.rb +27 -24
  60. data/lib/asker/formatter/moodle/ddmatch.erb +40 -0
  61. data/lib/asker/formatter/moodle/gapfill.erb +57 -0
  62. data/lib/asker/formatter/moodle/ordering.erb +41 -0
  63. data/lib/asker/formatter/question_gift_formatter.rb +41 -14
  64. data/lib/asker/formatter/question_hash_formatter.rb +5 -6
  65. data/lib/asker/formatter/question_moodle_formatter.rb +14 -7
  66. data/lib/asker/formatter/rb2haml_formatter.rb +8 -7
  67. data/lib/asker/lang/lang.rb +16 -16
  68. data/lib/asker/lang/lang_factory.rb +13 -16
  69. data/lib/asker/lang/text_actions.rb +20 -18
  70. data/lib/asker/loader/code_loader.rb +10 -22
  71. data/lib/asker/loader/content_loader.rb +42 -49
  72. data/lib/asker/loader/directory_loader.rb +13 -16
  73. data/lib/asker/loader/embedded_file.rb +29 -24
  74. data/lib/asker/loader/file_loader.rb +7 -6
  75. data/lib/asker/loader/haml_loader.rb +6 -5
  76. data/lib/asker/loader/image_url_loader.rb +21 -18
  77. data/lib/asker/loader/input_loader.rb +27 -14
  78. data/lib/asker/loader/problem_loader.rb +88 -0
  79. data/lib/asker/loader/project_loader.rb +11 -28
  80. data/lib/asker/logger.rb +22 -13
  81. data/lib/asker/skeleton.rb +27 -43
  82. data/lib/asker/start.rb +44 -0
  83. data/lib/asker/version.rb +1 -1
  84. data/lib/asker.rb +7 -53
  85. metadata +12 -20
  86. data/lib/asker/ai/code/problem_code_ai.rb +0 -176
  87. data/lib/asker/exporter/code_moodle_exporter.rb +0 -15
  88. data/lib/asker/exporter/concept_ai_moodle_exporter.rb +0 -15
@@ -1,51 +1,39 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'rainbow'
4
- require 'rexml/document'
5
- require_relative '../logger'
6
- require_relative '../data/code'
3
+ require "rexml/document"
4
+ require_relative "../logger"
5
+ require_relative "../data/code"
7
6
 
8
- # Read XML info about Code input data
9
7
  module CodeLoader
10
8
  ##
11
9
  # Load XML data about Code object
12
10
  # @param xmldata (XML Object)
13
11
  # @param filepath (String)
14
12
  # @return Code object
15
- def self.load(xmldata, filepath)
13
+ def self.call(xmldata, filepath)
16
14
  data = read_codedata_from_xml(xmldata, File.basename(filepath))
17
15
  code = Code.new(File.dirname(filepath), data[:path], data[:type])
18
16
  code.features << data[:features]
19
17
  code
20
18
  end
21
19
 
22
- ##
23
- # Read Code data from XML content
24
- # @param xmldata (XML Object)
25
- # @param filename (String) File name that contains data
26
- # @return Code object
27
20
  private_class_method def self.read_codedata_from_xml(xmldata, filename)
28
- data = { path: '?', type: '?', features: [] }
21
+ data = {path: "?", type: "?", features: []}
29
22
  xmldata.elements.each do |i|
30
- data[:path] = i.text if i.name == 'path'
31
- data[:type] = i.text.to_sym if i.name == 'type'
32
- data[:features] << read_features(i, filename) if i.name == 'features'
23
+ data[:path] = i.text if i.name == "path"
24
+ data[:type] = i.text.to_sym if i.name == "type"
25
+ data[:features] << read_features(i, filename) if i.name == "features"
33
26
  end
34
27
  data
35
28
  end
36
29
 
37
- ##
38
- # Read features data from XML input
39
- # @param xmldata (XML object)
40
- # @return Array with features (Strings)
41
30
  private_class_method def self.read_features(xmldata, filename)
42
31
  features = []
43
32
  xmldata.elements.each do |i|
44
- if i.name == 'row'
33
+ if i.name == "row"
45
34
  features << i.text
46
35
  else
47
- msg = Rainbow("[ERROR] features/#{i.name} from #{filename}").color(:red)
48
- Logger.verboseln msg
36
+ Logger.error "CodeLoader: features/#{i.name} from #{filename}"
49
37
  end
50
38
  end
51
39
  features
@@ -1,100 +1,93 @@
1
- require "rainbow"
2
1
  require "rexml/document"
3
2
  require_relative "code_loader"
3
+ require_relative "problem_loader"
4
4
  require_relative "../data/concept"
5
5
  require_relative "../data/project_data"
6
+ require_relative "../lang/lang_factory"
7
+ require_relative "../logger"
6
8
 
7
- # Define methods that load data from XML contents
8
9
  module ContentLoader
9
10
  ##
10
11
  # Load XML content into Asker data objects
11
12
  # @param filepath (String) File path
12
13
  # @param content (String) XML plane text content
13
- def self.load(filepath, content)
14
- concepts = []
15
- codes = []
14
+ def self.call(filepath, content)
16
15
  begin
17
16
  xmlcontent = REXML::Document.new(content)
18
17
  rescue REXML::ParseException
19
18
  raise_error_with(filepath, content)
20
19
  end
20
+ codes = []
21
+ concepts = []
22
+ problems = []
21
23
  lang = read_lang_attribute(xmlcontent)
22
24
  context = read_context_attribute(xmlcontent)
23
25
 
24
26
  xmlcontent.root.elements.each do |xmldata|
25
27
  case xmldata.name
26
- when "concept"
27
- concepts << read_concept(xmldata, filepath, lang, context)
28
28
  when "code"
29
29
  codes << read_code(xmldata, filepath)
30
+ when "concept"
31
+ concepts << read_concept(xmldata, filepath, lang, context)
32
+ when "problem"
33
+ problems << read_problem(xmldata, filepath, lang, context)
30
34
  else
31
- puts Rainbow("[ERROR] Unkown tag: #{xmldata.name}").red
32
- puts Rainbow("[INFO ] Only 'concept' and 'code' are available at this level").red
35
+ Logger.warn "ContentLoader: Unkown tag (#{xmldata.name}) Use concept, code or problem."
33
36
  end
34
37
  end
35
38
 
36
- { concepts: concepts, codes: codes }
39
+ {concepts: concepts, codes: codes, problems: problems}
37
40
  end
38
41
 
39
- ##
40
- # Read lang attr from input XML data
41
- # @param xmldata (XML Object)
42
42
  private_class_method def self.read_lang_attribute(xmldata)
43
43
  begin
44
- lang = xmldata.root.attributes["lang"]
45
- rescue StandardError
46
- lang = ProjectData.instance.lang
47
- puts Rainbow("[WARN ] Default lang: #{lang}").yellow
44
+ lang_code = xmldata.root.attributes["lang"]
45
+ rescue itself
46
+ lang_code = ProjectData.instance.lang
47
+ Logger.warn "ContentLoader: Applying default lang (#{lang_code})"
48
48
  end
49
- lang
49
+ LangFactory.instance.get(lang_code)
50
50
  end
51
51
 
52
- ##
53
- # Read context attr from input XML data
54
- # @param xmldata (XML Object)
55
52
  private_class_method def self.read_context_attribute(xmldata)
56
53
  begin
57
- context = xmldata.root.attributes["context"]
58
- rescue StandardError
59
- context = "unknown"
60
- puts Rainbow("[WARN ] Default context: #{context}").yellow
54
+ context = xmldata.root.attributes["context"].split(",")
55
+ context.collect!(&:strip)
56
+ rescue itself
57
+ context = ["unknown"]
58
+ Logger.warn "ContentLoader: Context is empty!"
61
59
  end
62
60
  context
63
61
  end
64
62
 
65
- ##
66
- # Read concept from input XML data
67
- # @param xmldata (XML Object)
68
- # @param filepath (String)
69
- # @param lang
70
- # @param context
71
63
  private_class_method def self.read_concept(xmldata, filepath, lang, context)
72
64
  project = ProjectData.instance
73
- c = Concept.new(xmldata, filepath, lang, context)
74
- c.process = true if [File.basename(filepath), :default].include? project.get(:process_file)
75
- c
65
+ concept = Concept.new(xmldata, filepath, lang, context)
66
+ cond = [File.basename(filepath), :default].include? project.get(:process_file)
67
+ concept.process = true if cond
68
+ concept
76
69
  end
77
70
 
78
- ##
79
- # Read code from input XML data
80
- # @param xmldata (XML Object)
81
- # @param filepath (String)
82
71
  private_class_method def self.read_code(xmldata, filepath)
83
72
  project = ProjectData.instance
84
- c = CodeLoader.load(xmldata, filepath)
85
- c.process = true if [File.basename(filepath), :default].include? project.get(:process_file)
86
- c
73
+ code = CodeLoader.call(xmldata, filepath)
74
+ cond = [File.basename(filepath), :default].include? project.get(:process_file)
75
+ code.process = true if cond
76
+ code
77
+ end
78
+
79
+ private_class_method def self.read_problem(xmldata, filepath, lang, context)
80
+ project = ProjectData.instance
81
+ problem = ProblemLoader.new(lang, context).call(xmldata, filepath)
82
+ cond = [File.basename(filepath), :default].include? project.get(:process_file)
83
+ problem.process = true if cond
84
+ problem
87
85
  end
88
86
 
89
- ##
90
- # Raise error and save content into error.file
91
- # @param filepath (String)
92
- # @param content (String)
93
87
  private_class_method def self.raise_error_with(filepath, content)
94
- msg = "[ERROR] ContentLoader: Format error in #{filepath}\n"
95
- msg += " Take a look at ouput/error.xml"
96
- puts Rainbow(msg).red.bright
97
- f = File.open('output/error.xml', 'w')
88
+ Logger.error "ContentLoader: Format error (#{filepath})"
89
+ Logger.error " : Revise output file (ouput/error.xml)"
90
+ f = File.open("output/error.xml", "w")
98
91
  f.write(content)
99
92
  f.close
100
93
  raise msg
@@ -1,29 +1,25 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'file_loader'
3
+ require_relative "file_loader"
4
+ require_relative "../logger"
4
5
 
5
- # Load input data from one directory
6
6
  module DirectoryLoader
7
7
  ##
8
- # Load input data from directory
8
+ # Load input data from one directory
9
9
  # @param dirname (String) Directory name
10
- def self.load(dirname)
10
+ def self.call(dirname)
11
11
  DirectoryLoader.check_dir(dirname)
12
- files = (Dir.new(dirname).entries - ['.', '..']).sort
12
+ files = (Dir.new(dirname).entries - [".", ".."]).sort
13
13
  # Accept only HAML or XML files
14
14
  accepted = files.select { |f| %w[.xml .haml].include? File.extname(f) }
15
15
  DirectoryLoader.load_files(accepted, dirname)
16
16
  end
17
17
 
18
- ##
19
- # Check directory
20
- # @param dirname (String) Directory name
21
18
  def self.check_dir(dirname)
22
19
  return if Dir.exist? dirname
23
20
 
24
- msg = Rainbow("[ERROR] #{dirname} directory dosn't exist!").color(:red)
25
- puts msg
26
- raise msg
21
+ Logger.error "DirectoryLoader: #{dirname} directory dosn't exist!"
22
+ exit 1
27
23
  end
28
24
 
29
25
  ##
@@ -31,13 +27,14 @@ module DirectoryLoader
31
27
  # @param filenames (Array) File name list
32
28
  # @param dirname (String) Base directory
33
29
  def self.load_files(filenames, dirname)
34
- output = { concepts: [], codes: [] }
30
+ data = {concepts: [], codes: [], problems: []}
35
31
  filenames.each do |filename|
36
32
  filepath = File.join(dirname, filename)
37
- data = FileLoader.load(filepath)
38
- output[:concepts] += data[:concepts]
39
- output[:codes] += data[:codes]
33
+ loaded = FileLoader.call(filepath)
34
+ data[:concepts] += loaded[:concepts]
35
+ data[:codes] += loaded[:codes]
36
+ data[:problems] += loaded[:problems]
40
37
  end
41
- output
38
+ data
42
39
  end
43
40
  end
@@ -1,4 +1,5 @@
1
- require 'base64'
1
+ require "base64"
2
+ require_relative "../logger"
2
3
 
3
4
  # Methods to load embedded files defined into asker input data file
4
5
  # Example:
@@ -15,46 +16,46 @@ module EmbeddedFile
15
16
  return load_video(value, localdir) if is_video? value
16
17
 
17
18
  if is_url? value
18
- Logger.verbose Rainbow("[ERROR] EmbebbedFile. Unkown URL: #{value}").red.bright
19
+ Logger.error "EmbebbedFile: Unkown URL (#{value})"
19
20
  exit 1
20
21
  end
21
22
 
22
23
  filepath = File.join(localdir, value)
23
24
  unless File.exist?(filepath)
24
- Logger.verbose Rainbow("[ERROR] EmbeddedFile. File does not exist!: #{filepath}").red.bright
25
- # return { text: "URI error", file: :none, type: :unkown }
25
+ Logger.error "EmbeddedFile: File does not exist (#{filepath})"
26
26
  exit 1
27
27
  end
28
28
 
29
29
  # Suposse that filename is TEXT file
30
- return { text: "<pre>#{File.read(filepath)}</pre>", file: :none, type: :text }
30
+ {text: "<pre>#{File.read(filepath)}</pre>", file: :none, type: :text}
31
31
  end
32
32
 
33
33
  def self.is_audio?(filename)
34
- extens = ['.mp3', '.ogg', '.wav']
35
- extens.each {|ext| return true if filename.downcase.end_with?(ext) }
34
+ extens = [".mp3", ".ogg", ".wav"]
35
+ extens.each { |ext| return true if filename.downcase.end_with?(ext) }
36
36
  false
37
37
  end
38
38
 
39
39
  def self.is_image?(filename)
40
- extens = ['.jpg', '.jpeg', '.png']
41
- extens.each {|ext| return true if filename.downcase.end_with?(ext) }
40
+ extens = [".jpg", ".jpeg", ".png"]
41
+ extens.each { |ext| return true if filename.downcase.end_with?(ext) }
42
42
  false
43
43
  end
44
44
 
45
45
  def self.is_video?(filename)
46
- extens = ['.mp4', '.ogv']
47
- extens.each {|ext| return true if filename.downcase.end_with?(ext) }
46
+ extens = [".mp4", ".ogv"]
47
+ extens.each { |ext| return true if filename.downcase.end_with?(ext) }
48
48
  false
49
49
  end
50
50
 
51
51
  def self.is_url?(value)
52
- return true if value.start_with?('https://') || value.start_with?('http://')
52
+ return true if value.start_with?("https://", "http://")
53
+
53
54
  false
54
55
  end
55
56
 
56
57
  def self.load_audio(value, localdir)
57
- output = { text: :error, file: :none, type: :audio}
58
+ output = {text: :error, file: :none, type: :audio}
58
59
 
59
60
  if is_url? value
60
61
  output[:text] = "<audio src=\"#{value}\" controls></audio>"
@@ -65,20 +66,21 @@ module EmbeddedFile
65
66
 
66
67
  filepath = File.join(localdir, value)
67
68
  unless File.exist?(filepath)
68
- Logger.verbose Rainbow("[ERROR] Audio file no exists!: #{filepath}").red.bright
69
+ Logger.error "EmbebbedFile: Audio file no exists (#{filepath})"
69
70
  exit 1
70
71
  end
71
72
  output[:text] = '<audio controls><source src="@@PLUGINFILE@@/' + File.basename(filepath) \
72
73
  + '">Your browser does not support the audio tag.</audio>'
73
74
  output[:file] = '<file name="' + File.basename(filepath) \
74
75
  + '" path="/" encoding="base64">' \
75
- + Base64.strict_encode64(File.open(filepath, 'rb').read) + '</file>'
76
+ + Base64.strict_encode64(File.open(filepath, "rb").read) \
77
+ + "</file>"
76
78
  output[:type] = :audio
77
79
  output
78
80
  end
79
81
 
80
82
  def self.load_image(value, localdir)
81
- output = { text: :error, file: :none, type: :image}
83
+ output = {text: :error, file: :none, type: :image}
82
84
 
83
85
  if is_url? value
84
86
  output[:text] = "<img src=\"#{value}\" alt=\"image\" width=\"400\" height=\"300\">"
@@ -89,21 +91,21 @@ module EmbeddedFile
89
91
 
90
92
  filepath = File.join(localdir, value)
91
93
  unless File.exist?(filepath)
92
- Logger.verbose Rainbow("[ERROR] Unknown file! #{filepath}").red.bright
94
+ Logger.error "EmbeddedFile: Unknown file (#{filepath})"
93
95
  exit 1
94
96
  end
95
97
  output[:text] = '<img src="@@PLUGINFILE@@/' + File.basename(filepath) \
96
98
  + '" alt="imagen" class="img-responsive atto_image_button_text-bottom">'
97
99
  output[:file] = '<file name="' + File.basename(filepath) \
98
100
  + '" path="/" encoding="base64">' \
99
- + Base64.strict_encode64(File.open(filepath, 'rb').read) + '</file>'
101
+ + Base64.strict_encode64(File.open(filepath, "rb").read) \
102
+ + "</file>"
100
103
  output[:type] = :image
101
104
  output
102
105
  end
103
106
 
104
107
  def self.load_video(value, localdir)
105
- output = { text: :error, file: :none, type: :video}
106
-
108
+ output = {text: :error, file: :none, type: :video}
107
109
  if is_url? value
108
110
  output[:text] = "<video controls width=\"400\" height=\"300\">" \
109
111
  + "<source src=\"#{value}\"/></video>"
@@ -114,14 +116,17 @@ module EmbeddedFile
114
116
 
115
117
  filepath = File.join(localdir, value)
116
118
  unless File.exist?(filepath)
117
- Logger.verbose Rainbow("[ERROR] Unknown file! #{filepath}").red.bright
119
+ Logger.error "Unknown file (#{filepath})"
118
120
  exit 1
119
121
  end
120
- output[:text] = '<video controls><source src="@@PLUGINFILE@@/' + File.basename(filepath) \
122
+ output[:text] = '<video controls><source src="@@PLUGINFILE@@/' \
123
+ + File.basename(filepath) \
121
124
  + '"/>Your browser does not support the video tag.</video>'
122
- output[:file] = '<file name="' + File.basename(filepath) \
125
+ output[:file] = '<file name="' \
126
+ + File.basename(filepath) \
123
127
  + '" path="/" encoding="base64">' \
124
- + Base64.strict_encode64(File.open(filepath, 'rb').read) + '</file>'
128
+ + Base64.strict_encode64(File.open(filepath, "rb").read) \
129
+ + "</file>"
125
130
  output[:type] = :video
126
131
  output
127
132
  end
@@ -1,19 +1,20 @@
1
1
  require_relative "content_loader"
2
2
  require_relative "haml_loader"
3
+ require_relative "../logger"
3
4
 
4
5
  ##
5
6
  # Load a filename and return a Hash with concepts list and code list
6
7
  # return { concepts: [], codes: [] }
7
8
  module FileLoader
8
- def self.load(filename)
9
- if File.extname(filename).casecmp('.haml').zero?
9
+ def self.call(filename)
10
+ if File.extname(filename).casecmp(".haml").zero?
10
11
  file_content = HamlLoader.load filename
11
- elsif File.extname(filename).casecmp('.xml').zero?
12
+ elsif File.extname(filename).casecmp(".xml").zero?
12
13
  file_content = File.read(filename)
13
14
  else
14
- puts "[ERROR] FileLoader: Format error #{filename}"
15
- raise msg
15
+ Logger.error "FileLoader: HAML or XML required (#{filename})"
16
+ exit 1
16
17
  end
17
- ContentLoader.load(filename, file_content)
18
+ ContentLoader.call(filename, file_content)
18
19
  end
19
20
  end
@@ -1,4 +1,5 @@
1
1
  require "haml"
2
+ require_relative "../logger"
2
3
 
3
4
  module HamlLoader
4
5
  def self.load(filename)
@@ -6,13 +7,13 @@ module HamlLoader
6
7
  begin
7
8
  # INFO <haml 5.1> 20221223
8
9
  haml_engine = Haml::Engine.new(template)
9
- return haml_engine.render
10
10
  # INFO <haml 6.1> 20221226
11
11
  # return Haml::Template.new { template }.render
12
- rescue StandardError => e
13
- puts "[ERROR] HamlLoader: Can't load <#{filename}> file!"
14
- puts " => #{e}"
15
- exit 0
12
+ rescue => e
13
+ Logger.error "HamlLoader: Can't load file (#{filename})"
14
+ Logger.error " : #{e}"
15
+ exit 1
16
16
  end
17
+ haml_engine.render
17
18
  end
18
19
  end
@@ -1,6 +1,6 @@
1
-
2
- require 'net/http'
3
- require 'uri'
1
+ require "net/http"
2
+ require "uri"
3
+ require_relative "../logger"
4
4
 
5
5
  # Search URL images on Internet
6
6
  # Methods:
@@ -11,44 +11,47 @@ module ImageUrlLoader
11
11
  # Search "input" images on Google and return URL
12
12
  def self.load(input = [])
13
13
  filters = []
14
- if input.class == String
14
+ if input.instance_of? String
15
15
  filters += sanitize_string(input.clone)
16
- elsif input.class == Array
16
+ elsif input.instance_of? Array
17
17
  filters = sanitize_array(input.clone)
18
18
  else
19
- raise "[ERROR] ImageUrlLoader: Unkown type #{input.class}"
19
+ Logger.error "ImageUrlLoader: Unkown type (#{input.class})"
20
+ exit 1
20
21
  end
21
22
  # Search Image URLs from Google site, selected by <filters>
22
- search_url = 'https://www.google.es/search?q='
23
- search_url << filters.flatten.join('+').to_s
24
- search_url << '&source=lnms&tbm=isch&sa=X&ved=2ahUKEwj_g8Wfst7nAhWpzoUKHf_wDbsQ_AUoAnoECBMQBA&biw=1280&bih=591'
23
+ search_url = "https://www.google.es/search?q="
24
+ search_url << filters.flatten.join("+").to_s
25
+ search_url << "&source=lnms&tbm=isch&sa=X&ved=2ahUKEwj_g8Wfst7nAhWpzoUKHf_wDbsQ_AUoAnoECBMQBA&biw=1280&bih=591"
25
26
  image_urls = []
26
27
  begin
27
28
  uri = URI.parse(search_url)
28
29
  response = Net::HTTP.get_response(uri)
29
30
 
30
- r = response.body.split(' ')
31
+ r = response.body.split(" ")
31
32
  r.each do |line|
32
33
  if line.include? 'src="https'
33
34
  image_urls << line.delete('"')[4, line.size]
34
35
  end
35
36
  end
36
37
  rescue
37
- puts '[ERROR] ImageUrlLoader'
38
- puts " => #{search_url}"
39
- puts ' => Check Internet connections'
40
- puts ' => Ensure URL is well formed'
38
+ Logger.warn "ImageUrlLoader: Problems with URL (#{search_url})"
39
+ Logger.warn " (a) Check Internet connections"
40
+ Logger.warn " (b) Ensure URL is well formed"
41
41
  end
42
42
  image_urls
43
43
  end
44
44
 
45
45
  def self.sanitize_string(input)
46
46
  text = input.dup
47
- r = [ ['á', 'a'], ['é', 'e'], ['í', 'i'], ['ó', 'o'], ['ú', 'u'], ['ñ', 'n'], ['Á', 'A'], ['É', 'E'], ['Í', 'I'], ['Ó', 'O'], ['Ú', 'U'], ['Ñ', 'N']]
47
+ r = [
48
+ %w[á a], %w[é e], %w[í i], %w[ó o], %w[ú u], %w[ñ n],
49
+ %w[Á A], %w[É E], %w[Í I], %w[Ó O], %w[Ú U], %w[Ñ N]
50
+ ]
48
51
  r.each { |item| text.gsub!(item[0], item[1]) }
49
- r = ['-', '_', ',', '"']
50
- r.each { |item| text.gsub!(item, ' ') }
51
- text.split(' ')
52
+ r = %w[- _ , "]
53
+ r.each { |item| text.gsub!(item, " ") }
54
+ text.split(" ")
52
55
  end
53
56
 
54
57
  def self.sanitize_array(input)
@@ -1,35 +1,48 @@
1
- require_relative 'directory_loader'
2
- require_relative '../ai/concept_ai'
3
- require_relative '../data/world'
1
+ require_relative "directory_loader"
2
+ require_relative "../ai/concept_ai"
3
+ require_relative "../ai/code/code_ai_factory"
4
+ require_relative "../ai/problem/problem_ai"
5
+ require_relative "../data/world"
4
6
 
5
- module InputLoader
7
+ class InputLoader
6
8
  ##
7
9
  # Load input data from every input directory
8
10
  # @param inputdirs (Array)
9
- def self.load(inputdirs, internet = true)
10
- data = { concepts: [], codes: [], world: nil,
11
- concepts_ai: [], codes_ai: [] }
11
+ def call(inputdirs, internet = true)
12
+ data = {
13
+ world: nil,
14
+ concepts: [], codes: [], problems: [],
15
+ concepts_ai: [], codes_ai: []
16
+ }
12
17
  inputdirs.each do |dirname|
13
- temp = DirectoryLoader.load(dirname)
14
- data[:concepts] += temp[:concepts]
15
- data[:codes] += temp[:codes]
18
+ loaded = DirectoryLoader.call(dirname)
19
+ data[:concepts] += loaded[:concepts]
20
+ data[:codes] += loaded[:codes]
21
+ data[:problems] += loaded[:problems]
16
22
  end
17
23
  create_questions(data, internet)
18
24
  end
19
25
 
20
- private_class_method def self.create_questions(data, internet)
21
- # Create World data
22
- # * Calculate concept neighbours
23
- # * TO-DO: Calculate code neighbours
26
+ private
27
+
28
+ def create_questions(data, internet)
29
+ # Create World data. Calculate concept neighbours
30
+ # TODO: Calculate code and problem neighbours
24
31
  data[:world] = World.new(data[:concepts], internet)
32
+
25
33
  # Create ConceptAI data (ConceptAI = concept + questions)
26
34
  data[:concepts].each do |concept|
27
35
  data[:concepts_ai] << ConceptAI.new(concept, data[:world])
28
36
  end
37
+
29
38
  # Create CodeAI data (CodeAI = code + questions)
30
39
  data[:codes].each do |code|
31
40
  data[:codes_ai] << CodeAIFactory.get(code)
32
41
  end
42
+
43
+ # Fill problem with questions
44
+ data[:problems].each { |problem| ProblemAI.new.call(problem) }
45
+
33
46
  data
34
47
  end
35
48
  end