asker-tool 2.1.2

Sign up to get free protection for your applications and to get access to all the features.
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