asker-tool 2.1.2

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 (91) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +674 -0
  3. data/README.md +53 -0
  4. data/bin/asker +4 -0
  5. data/docs/changelog/v2.1.md +99 -0
  6. data/docs/commands.md +15 -0
  7. data/docs/contributions.md +18 -0
  8. data/docs/history.md +40 -0
  9. data/docs/idea.md +44 -0
  10. data/docs/inputs/README.md +39 -0
  11. data/docs/inputs/code.md +69 -0
  12. data/docs/inputs/concepts.md +142 -0
  13. data/docs/inputs/jedi.md +68 -0
  14. data/docs/inputs/tables.md +112 -0
  15. data/docs/inputs/templates.md +87 -0
  16. data/docs/install/README.md +38 -0
  17. data/docs/install/manual.md +26 -0
  18. data/docs/install/scripts.md +26 -0
  19. data/docs/revise/asker-file.md +41 -0
  20. data/docs/revise/buenas-practicas/01-convocatoria.md +30 -0
  21. data/docs/revise/buenas-practicas/02-formulario.md +35 -0
  22. data/docs/revise/buenas-practicas/03-descripcion.md +63 -0
  23. data/docs/revise/buenas-practicas/04-resultados.md +17 -0
  24. data/docs/revise/buenas-practicas/05-reproducir.md +10 -0
  25. data/docs/revise/ejemplos/01/README.md +27 -0
  26. data/docs/revise/ejemplos/02/README.md +31 -0
  27. data/docs/revise/ejemplos/03/README.md +31 -0
  28. data/docs/revise/ejemplos/04/README.md +37 -0
  29. data/docs/revise/ejemplos/05/README.md +25 -0
  30. data/docs/revise/ejemplos/06/README.md +43 -0
  31. data/docs/revise/ejemplos/README.md +11 -0
  32. data/docs/revise/projects.md +74 -0
  33. data/lib/asker.rb +103 -0
  34. data/lib/asker/ai/ai.rb +70 -0
  35. data/lib/asker/ai/ai_calculate.rb +55 -0
  36. data/lib/asker/ai/concept_ai.rb +49 -0
  37. data/lib/asker/ai/question.rb +58 -0
  38. data/lib/asker/ai/stages/base_stage.rb +16 -0
  39. data/lib/asker/ai/stages/main.rb +8 -0
  40. data/lib/asker/ai/stages/stage_b.rb +87 -0
  41. data/lib/asker/ai/stages/stage_d.rb +160 -0
  42. data/lib/asker/ai/stages/stage_f.rb +156 -0
  43. data/lib/asker/ai/stages/stage_i.rb +140 -0
  44. data/lib/asker/ai/stages/stage_s.rb +52 -0
  45. data/lib/asker/ai/stages/stage_t.rb +170 -0
  46. data/lib/asker/application.rb +30 -0
  47. data/lib/asker/checker.rb +356 -0
  48. data/lib/asker/cli.rb +85 -0
  49. data/lib/asker/code/ai/base_code_ai.rb +48 -0
  50. data/lib/asker/code/ai/code_ai_factory.rb +26 -0
  51. data/lib/asker/code/ai/javascript_code_ai.rb +167 -0
  52. data/lib/asker/code/ai/python_code_ai.rb +167 -0
  53. data/lib/asker/code/ai/ruby_code_ai.rb +169 -0
  54. data/lib/asker/code/ai/sql_code_ai.rb +69 -0
  55. data/lib/asker/code/code.rb +53 -0
  56. data/lib/asker/data/column.rb +62 -0
  57. data/lib/asker/data/concept.rb +183 -0
  58. data/lib/asker/data/data_field.rb +87 -0
  59. data/lib/asker/data/row.rb +93 -0
  60. data/lib/asker/data/table.rb +96 -0
  61. data/lib/asker/data/template.rb +65 -0
  62. data/lib/asker/data/world.rb +53 -0
  63. data/lib/asker/exporter/code_gift_exporter.rb +35 -0
  64. data/lib/asker/exporter/code_screen_exporter.rb +45 -0
  65. data/lib/asker/exporter/concept_ai_gift_exporter.rb +33 -0
  66. data/lib/asker/exporter/concept_ai_screen_exporter.rb +115 -0
  67. data/lib/asker/exporter/concept_ai_yaml_exporter.rb +33 -0
  68. data/lib/asker/exporter/concept_doc_exporter.rb +21 -0
  69. data/lib/asker/exporter/concept_screen_exporter.rb +25 -0
  70. data/lib/asker/exporter/main.rb +9 -0
  71. data/lib/asker/files/config.ini +40 -0
  72. data/lib/asker/formatter/code_string_formatter.rb +16 -0
  73. data/lib/asker/formatter/concept_doc_formatter.rb +37 -0
  74. data/lib/asker/formatter/concept_string_formatter.rb +66 -0
  75. data/lib/asker/formatter/question_gift_formatter.rb +65 -0
  76. data/lib/asker/formatter/question_hash_formatter.rb +40 -0
  77. data/lib/asker/formatter/question_moodlexml_formatter.rb +71 -0
  78. data/lib/asker/formatter/rb2haml_formatter.rb +26 -0
  79. data/lib/asker/lang/lang.rb +42 -0
  80. data/lib/asker/lang/lang_factory.rb +19 -0
  81. data/lib/asker/lang/text_actions.rb +150 -0
  82. data/lib/asker/loader/code_loader.rb +53 -0
  83. data/lib/asker/loader/content_loader.rb +101 -0
  84. data/lib/asker/loader/directory_loader.rb +58 -0
  85. data/lib/asker/loader/file_loader.rb +33 -0
  86. data/lib/asker/loader/image_url_loader.rb +61 -0
  87. data/lib/asker/loader/input_loader.rb +24 -0
  88. data/lib/asker/loader/project_loader.rb +71 -0
  89. data/lib/asker/logger.rb +21 -0
  90. data/lib/asker/project.rb +170 -0
  91. metadata +261 -0
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'erb'
4
+ require 'yaml'
5
+ require_relative 'text_actions'
6
+
7
+ # Lang#lang
8
+ class Lang
9
+ include TextActions
10
+
11
+ attr_reader :code, :mistakes
12
+
13
+ def initialize(code = 'en')
14
+ @code = code.to_s
15
+ load_files
16
+ end
17
+
18
+ def lang
19
+ @code
20
+ end
21
+
22
+ private
23
+
24
+ def load_files
25
+ dirbase = File.dirname(__FILE__)
26
+ filename = File.join(dirbase, 'locales', @code, 'templates.yaml')
27
+ begin
28
+ @templates = YAML.load(File.new(filename))
29
+ rescue StandardError => e
30
+ p = Project.instance
31
+ p.vervose "[ERROR] lang.initialize(): Reading YAML file <#{filename}>"
32
+ p.vervose "[ADVISE] Revise apostrophe into string without \\ char\n"
33
+ raise e
34
+ end
35
+ filename = File.join(dirbase, 'locales', @code, 'connectors.yaml')
36
+ @connectors = YAML.load(File.new(filename))
37
+
38
+ filename = File.join(dirbase, 'locales', @code, 'mistakes.yaml')
39
+ @mistakes = YAML.load(File.new(filename))
40
+ end
41
+
42
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'singleton'
4
+ require_relative 'lang'
5
+ require_relative '../project'
6
+
7
+ # LangFactory#get
8
+ class LangFactory
9
+ include Singleton
10
+
11
+ def initialize
12
+ @langs = {}
13
+ Project.instance.locales.each { |i| @langs[i] = Lang.new(i) }
14
+ end
15
+
16
+ def get(locale)
17
+ @langs[locale]
18
+ end
19
+ end
@@ -0,0 +1,150 @@
1
+ # encoding: utf-8
2
+
3
+ module TextActions
4
+
5
+ def text_for(pOption, pText1="",pText2="",pText3="",pText4="",pText5="",pText6="",pText7="")
6
+ text1=pText1
7
+ text2=pText2
8
+ text3=pText3
9
+ text4=pText4
10
+ text5=pText5
11
+ text6=pText6
12
+ text7=pText7
13
+
14
+ # TODO: check if exists pOption before use it
15
+ renderer = ERB.new(@templates[pOption])
16
+ output = renderer.result(binding)
17
+ return output
18
+ end
19
+
20
+ def text_filter_connectors(pText, pFilter)
21
+ input_lines = pText.split(".")
22
+ output_lines = []
23
+ output_words = []
24
+ input_lines.each_with_index do |line, rowindex|
25
+ row=[]
26
+ line.split(' ').each_with_index do |word, colindex|
27
+ flag = @connectors.include? word.downcase
28
+
29
+ # if <word> is a conector and <pFilter>==true Then Choose this <word>
30
+ # if <word> isn't a conector and <pFilter>==true and <word>.length>1 Then Choose this <word>
31
+ if (flag and pFilter) || (!flag and !pFilter and word.length>1)
32
+ output_words << {:word => word,
33
+ :row => rowindex,
34
+ :col => colindex }
35
+ row << (output_words.size-1)
36
+ else
37
+ row << word
38
+ end
39
+ end
40
+ row << '.'
41
+ output_lines << row
42
+ end
43
+
44
+ indexes = []
45
+ exclude = ['[', ']', '(', ')', "\"" ]
46
+ output_words.each_with_index do |item, index|
47
+ flag = true
48
+ exclude.each { |e| flag = false if (item[:word].include?(e)) }
49
+ indexes << index if flag
50
+ end
51
+
52
+ result={ :lines => output_lines, :words => output_words, :indexes => indexes }
53
+ return result
54
+ end
55
+
56
+ def text_with_connectors(text)
57
+ text_filter_connectors(text, false)
58
+ end
59
+
60
+ def text_without_connectors(text)
61
+ text_filter_connectors(text, true)
62
+ end
63
+
64
+ def build_text_from_filtered(pStruct, pIndexes)
65
+ lines = pStruct[:lines]
66
+ lIndexes = pIndexes.sort
67
+ counter = 1
68
+ lText = ''
69
+
70
+ lines.each do |line|
71
+ line.each do |value|
72
+ if value.class == String
73
+ lText += (' ' + value)
74
+ elsif value == value.to_i
75
+ # INFO: ruby 2.4 unifies Fixnum and Bignum into Integer
76
+ # Avoid using deprecated classes.
77
+ if lIndexes.include? value
78
+ lText += " [#{counter.to_s}]"
79
+ counter += 1
80
+ else
81
+ lword = pStruct[:words][value][:word]
82
+ lText += (' ' + lword)
83
+ end
84
+ end
85
+ end
86
+ end
87
+ lText.gsub!(' .', '.')
88
+ lText.gsub!(' ,', ',')
89
+ lText = lText[1, lText.size] if lText[0] == ' '
90
+ lText
91
+ end
92
+
93
+ def count_words(pInputText)
94
+ return 0 if pInputText.nil?
95
+
96
+ t = pInputText.clone
97
+ t.gsub!("\n"," ")
98
+ t.gsub!("/"," ")
99
+ #t.gsub!("-"," ")
100
+ t.gsub!("."," ")
101
+ t.gsub!(","," ")
102
+ t.gsub!(" "," ")
103
+ t.gsub!(" "," ")
104
+ t.split(" ").count
105
+ end
106
+
107
+ def do_mistake_to(pText = '')
108
+ lText = pText.dup
109
+ keys = @mistakes.keys
110
+
111
+ # Try to do mistake with one item from the key list
112
+ keys.shuffle!
113
+ keys.each do |key|
114
+ if lText.include? key.to_s
115
+ values = @mistakes[key].split(',')
116
+ values.shuffle!
117
+ lText = lText.sub(key.to_s,values[0].to_s)
118
+ return lText
119
+ end
120
+ end
121
+
122
+ # Force mistake by swapping letters
123
+ if lText.size > 1
124
+ i = rand(lText.size - 2)
125
+ aux = lText[i]
126
+ lText[i] = lText[i + 1]
127
+ lText[i + 1] = aux
128
+ end
129
+ return lText if lText != pText
130
+
131
+ lText + 's'
132
+ end
133
+
134
+ def hide_text(input_text)
135
+ input = input_text.clone
136
+ if count_words(input) < 2 && input.size < 10
137
+ output = '[*]'
138
+ else
139
+ output = ''
140
+ input.each_char do |char|
141
+ if ' !|"@#$%&/()=?¿¡+*(){}[],.-_<>'.include? char
142
+ output += char
143
+ else
144
+ output += '?'
145
+ end
146
+ end
147
+ end
148
+ output
149
+ end
150
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rainbow'
4
+ require 'rexml/document'
5
+ require_relative '../logger'
6
+ require_relative '../code/code'
7
+
8
+ # Read XML info about Code input data
9
+ module CodeLoader
10
+ ##
11
+ # Load XML data about Code object
12
+ # @param xmldata (XML Object)
13
+ # @param filepath (String)
14
+ # @return Code object
15
+ def self.load(xmldata, filepath)
16
+ data = read_codedata_from_xml(xmldata, File.basename(filepath))
17
+ code = Code.new(File.dirname(filepath), data[:path], data[:type])
18
+ code.features << data[:features]
19
+ code
20
+ end
21
+
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
+ def self.read_codedata_from_xml(xmldata, filename)
28
+ data = { path: '?', type: '?', features: [] }
29
+ 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'
33
+ end
34
+ data
35
+ end
36
+
37
+ ##
38
+ # Read features data from XML input
39
+ # @param xmldata (XML object)
40
+ # @return Array with features (Strings)
41
+ def self.read_features(xmldata, filename)
42
+ features = []
43
+ xmldata.elements.each do |i|
44
+ if i.name == 'row'
45
+ features << i.text
46
+ else
47
+ msg = Rainbow("[ERROR] features/#{i.name} from #{filename}").color(:red)
48
+ Logger.verbose msg
49
+ end
50
+ end
51
+ features
52
+ end
53
+ end
@@ -0,0 +1,101 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rainbow'
4
+ require 'rexml/document'
5
+ require_relative '../data/concept'
6
+ require_relative 'code_loader'
7
+ require_relative '../logger'
8
+ require_relative '../project'
9
+
10
+ # Define methods that load data from XML contents
11
+ module ContentLoader
12
+ ##
13
+ # Load XML content into Asker data objects
14
+ # @param filepath (String) File path
15
+ # @param content (String) XML plane text content
16
+ def self.load(filepath, content)
17
+ concepts = []
18
+ codes = []
19
+ begin
20
+ xmlcontent = REXML::Document.new(content)
21
+ rescue REXML::ParseException
22
+ raise_error_with(filepath, content)
23
+ end
24
+ lang = read_lang_attribute(xmlcontent)
25
+ context = read_context_attribute(xmlcontent)
26
+
27
+ xmlcontent.root.elements.each do |xmldata|
28
+ case xmldata.name
29
+ when 'concept'
30
+ concepts << read_concept(xmldata, filepath, lang, context)
31
+ when 'code'
32
+ codes << read_code(xmldata, filepath)
33
+ else
34
+ Logger.verboseln Rainbow("[ERROR] Unkown tag <#{xmldata.name}>").red
35
+ end
36
+ end
37
+
38
+ { concepts: concepts, codes: codes }
39
+ end
40
+
41
+ ##
42
+ # Read lang attr from input XML data
43
+ # @param xmldata (XML Object)
44
+ def self.read_lang_attribute(xmldata)
45
+ begin
46
+ lang = xmldata.root.attributes['lang']
47
+ rescue StandardError
48
+ lang = Project.instance.lang
49
+ end
50
+ lang
51
+ end
52
+
53
+ ##
54
+ # Read context attr from input XML data
55
+ # @param xmldata (XML Object)
56
+ def self.read_context_attribute(xmldata)
57
+ begin
58
+ context = xmldata.root.attributes['context']
59
+ rescue StandardError
60
+ context = 'unknown'
61
+ end
62
+ context
63
+ end
64
+
65
+ ##
66
+ # Read concept from input XML data
67
+ # @param xmldata (XML Object)
68
+ # @param filepath (String)
69
+ # @param lang
70
+ # @param context
71
+ def self.read_concept(xmldata, filepath, lang, context)
72
+ project = Project.instance
73
+ c = Concept.new(xmldata, filepath, lang, context)
74
+ if [ File.basename(filepath), :default ].include? project.process_file
75
+ c.process = true
76
+ end
77
+ c
78
+ end
79
+
80
+ ##
81
+ # Read code from input XML data
82
+ # @param xmldata (XML Object)
83
+ # @param filepath (String)
84
+ def self.read_code(xmldata, filepath)
85
+ project = Project.instance
86
+ c = CodeLoader.load(xmldata, filepath)
87
+ if [ File.basename(filepath), :default ].include? project.process_file
88
+ c.process = true
89
+ end
90
+ c
91
+ end
92
+
93
+ def self.raise_error_with(filepath, content)
94
+ msg = Rainbow("[ERROR] ContentLoader: Format error in #{filepath}").red.bright
95
+ Logger.verbose msg
96
+ f = File.open('output/error.xml', 'w')
97
+ f.write(content)
98
+ f.close
99
+ raise msg
100
+ end
101
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'file_loader'
4
+ require_relative '../logger'
5
+
6
+ # Load input data from one directory
7
+ module DirectoryLoader
8
+ ##
9
+ # Load input data from directory
10
+ # @param dirname (String) Directory name
11
+ def self.load(dirname)
12
+ DirectoryLoader.check_dir(dirname)
13
+ files = (Dir.new(dirname).entries - ['.', '..']).sort
14
+ # Accept only HAML or XML files
15
+ accepted = files.select { |f| %w[.xml .haml].include? File.extname(f) }
16
+ Logger.verbose " * Input directory = #{Rainbow(dirname).bright}"
17
+ DirectoryLoader.load_files(accepted, dirname)
18
+ end
19
+
20
+ ##
21
+ # Check directory
22
+ # @param dirname (String) Directory name
23
+ def self.check_dir(dirname)
24
+ return if Dir.exist? dirname
25
+
26
+ msg = Rainbow("[ERROR] #{dirname} directory dosn't exist!").color(:red)
27
+ Logger.verboseln msg
28
+ raise msg
29
+ end
30
+
31
+ ##
32
+ # Load accepted files from dirname directory
33
+ # @param filenames (Array) File name list
34
+ # @param dirname (String) Base directory
35
+ def self.load_files(filenames, dirname)
36
+ output = { concepts: [], codes: [] }
37
+ filenames.each do |filename|
38
+ filepath = File.join(dirname, filename)
39
+ data = DirectoryLoader.load_file(filepath, filename == filenames.last)
40
+ output[:concepts] += data[:concepts]
41
+ output[:codes] += data[:codes]
42
+ end
43
+ output
44
+ end
45
+
46
+ ##
47
+ # Load one input file
48
+ # @param filepath (String) Path to input file
49
+ # @param last (Boolean) True if it is the last filename
50
+ def self.load_file(filepath, last = false)
51
+ if last
52
+ Logger.verbose " └── Input file = #{Rainbow(filepath).bright}"
53
+ else
54
+ Logger.verbose " ├── Input file = #{Rainbow(filepath).bright}"
55
+ end
56
+ FileLoader.load(filepath)
57
+ end
58
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'haml'
4
+ require_relative 'content_loader'
5
+ require_relative '../logger'
6
+
7
+ # Methods that load a filename and return list of concepts
8
+ module FileLoader
9
+ ##
10
+ # Load asker data from file
11
+ # @param filename (String) File name to be load
12
+ def self.load(filename)
13
+ if File.extname(filename).casecmp('.haml').zero?
14
+ file_content = load_haml filename
15
+ elsif File.extname(filename).casecmp('.xml').zero?
16
+ file_content = File.read(filename)
17
+ else
18
+ msg = "[ERROR] FileLoader: Format error #{filename}"
19
+ Logger.verbose msg
20
+ raise msg
21
+ end
22
+ ContentLoader.load(filename, file_content)
23
+ end
24
+
25
+ ##
26
+ # Load HAML file name
27
+ # @param filename (String) HAML file name
28
+ def self.load_haml(filename)
29
+ template = File.read(filename)
30
+ haml_engine = Haml::Engine.new(template)
31
+ haml_engine.render
32
+ end
33
+ end