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,69 @@
1
+
2
+ require_relative '../../lang/lang_factory'
3
+ require_relative '../../ai/question'
4
+ require_relative 'base_code_ai'
5
+
6
+ class SQLCodeAI < BaseCodeAI
7
+ def initialize(data_object)
8
+ @data_object = data_object
9
+ @lines = data_object.lines
10
+ @lang = LangFactory.instance.get('sql')
11
+ @num = 0
12
+ @questions = []
13
+ end
14
+
15
+ def make_comment_error
16
+ error_lines = []
17
+ questions = []
18
+ @lines.each_with_index do |line,index|
19
+ if line.include?('//')
20
+ lines = clone_array @lines
21
+ lines[index].sub!('//','').strip!
22
+
23
+ q = Question.new(:short)
24
+ q.name = "#{name}-#{num}-code1uncomment"
25
+ q.text = @lang.text_for(:code1,lines_to_html(lines))
26
+ q.shorts << (index+1)
27
+ q.feedback = 'Comment symbol removed'
28
+ questions << q
29
+ elsif line.strip.size>0
30
+ lines = clone_array @lines
31
+ lines[index]='// ' + lines[index]
32
+
33
+ q = Question.new(:short)
34
+ q.name = "#{name}-#{num}-code1comment"
35
+ q.text = @lang.text_for(:code1,lines_to_html(lines))
36
+ q.shorts << (index+1)
37
+ q.feedback = 'Comment symbol added'
38
+ questions << q
39
+ end
40
+ end
41
+ questions
42
+ end
43
+
44
+ def make_keyword_error
45
+ error_lines = []
46
+ questions = []
47
+
48
+ @lang.mistakes.each_pair do |key,values|
49
+ v = values.split(',')
50
+ v.each do |value|
51
+ @lines.each_with_index do |line,index|
52
+ error_lines << index if line.include?(key.to_s)
53
+ end
54
+
55
+ error_lines.each do |index|
56
+ lines = clone_array @lines
57
+ lines[index].sub!(key.to_s, value)
58
+ q = Question.new(:short)
59
+ q.name = "#{name}-#{num}-code1keyword"
60
+ q.text = @lang.text_for(:code1,lines_to_html(lines))
61
+ q.shorts << (index+1)
62
+ q.feedback = "Keyword error: '#{value}' must be '#{key}'"
63
+ questions << q
64
+ end
65
+ end
66
+ end
67
+ questions
68
+ end
69
+ end
@@ -0,0 +1,53 @@
1
+ require_relative 'ai/code_ai_factory'
2
+ require_relative '../project'
3
+ require_relative '../formatter/code_string_formatter'
4
+
5
+ # Contains code data input
6
+ class Code
7
+ attr_reader :dirname, :filename, :type
8
+ attr_accessor :process, :features
9
+ attr_reader :lines, :questions
10
+
11
+ def initialize(dirname, filename, type)
12
+ @dirname = dirname
13
+ @filename = filename
14
+ @type = type
15
+ @filepath = File.join(@dirname, @filename)
16
+ @process = false
17
+ @features = []
18
+ @lines = load(@filepath)
19
+ @questions = []
20
+ @code_ai = CodeAIFactory.get(self)
21
+ end
22
+
23
+ def process?
24
+ @process
25
+ end
26
+
27
+ def make_questions
28
+ return unless process?
29
+ @questions += @code_ai.make_questions
30
+ end
31
+
32
+ def lines_to_s(lines)
33
+ out = ''
34
+ lines.each_with_index do |line, index|
35
+ out << format("%2d| #{line}\n", (index + 1))
36
+ end
37
+ out
38
+ end
39
+
40
+ def debug
41
+ out = CodeStringFormatter.to_s(self)
42
+ p = Project.instance
43
+ p.verbose out
44
+ end
45
+
46
+ private
47
+
48
+ def load(filepath)
49
+ return if filepath.nil?
50
+ content = File.read(filepath)
51
+ content.split("\n")
52
+ end
53
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+ # encoding: utf-8
3
+
4
+ # Contain data information for every column
5
+ # Params:
6
+ # * +pRow+ - Parent row for this column
7
+ # * +index+ - Sequence order (Integer)
8
+ # * +xml_data+ - XML input data
9
+ class Column
10
+ attr_reader :row, :index, :id, :raw, :lang, :type, :simple
11
+
12
+ def initialize(row, index, xml_data)
13
+ @row = row
14
+ @index = index
15
+ @id = @row.id + '.' + @index.to_s
16
+ @raw = ''
17
+ @lang = @row.langs[@index]
18
+ @type = @row.types[@index]
19
+ @simple = { lang: true, type: true }
20
+ read_data_from_xml(xml_data)
21
+ end
22
+
23
+ def to_html
24
+ case @type
25
+ when 'text'
26
+ return @raw
27
+ when 'image_url'
28
+ return "<img src=\"#{raw}\" alt\=\"image\">"
29
+ when 'textfile_path'
30
+ return "<pre>#{raw}</pre>"
31
+ else
32
+ return "ERROR type #{@type}"
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ def read_data_from_xml(xml_data)
39
+ raise '[ERROR] Column XML data with elements!' if xml_data.elements.count.positive?
40
+
41
+ @raw = xml_data.text.strip.to_s
42
+
43
+ # read attributes from XML input data
44
+ if xml_data.attributes['lang']
45
+ code = xml_data.attributes['lang'].strip
46
+ if code != @lang.code
47
+ @lang = LangFactory.instance.get(code)
48
+ @simple[:lang] = false
49
+ @row.simple_off(:lang)
50
+ end
51
+ end
52
+
53
+ if xml_data.attributes['type']
54
+ type = xml_data.attributes['type'].strip
55
+ if type != @type.to_s
56
+ @type = type
57
+ @simple[:type] = false
58
+ @row.simple_off(:type)
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,183 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rainbow'
4
+ require 'rexml/document'
5
+
6
+ require_relative '../project'
7
+ require_relative '../lang/lang_factory'
8
+ require_relative 'table'
9
+ require_relative 'data_field'
10
+
11
+ # Store Concept information
12
+ class Concept
13
+ attr_reader :id, :lang, :context
14
+ attr_reader :names, :type, :filename
15
+ attr_reader :data
16
+ attr_accessor :process
17
+
18
+ @@id = 0
19
+
20
+ def initialize(xml_data, filename, lang_code = 'en', context = [])
21
+ @@id += 1
22
+ @id = @@id
23
+
24
+ @filename = filename
25
+ @process = false
26
+ @lang = LangFactory.instance.get(lang_code)
27
+
28
+ if context.class == Array
29
+ @context = context
30
+ elsif context.nil?
31
+ @context = []
32
+ else
33
+ @context = context.split(',')
34
+ @context.collect!(&:strip)
35
+ end
36
+ @names = ['concept.' + @id.to_s]
37
+ @type = 'text'
38
+
39
+ @data = {}
40
+ @data[:tags] = []
41
+ @data[:texts] = []
42
+ @data[:images] = [] # TODO: By now, We'll treat images separated from texts
43
+ @data[:textfile_paths] = [] # TODO: By now, We'll treat this separated from texts
44
+ @data[:tables] = []
45
+ @data[:neighbors] = []
46
+ @data[:reference_to] = []
47
+ @data[:referenced_by] = []
48
+
49
+ read_data_from_xml(xml_data)
50
+ end
51
+
52
+ def name(option = :raw)
53
+ DataField.new(@names[0], @id, @type).get(option)
54
+ end
55
+
56
+ def text
57
+ @data[:texts][0] || '...'
58
+ end
59
+
60
+ def process?
61
+ @process
62
+ end
63
+
64
+ def try_adding_neighbor(other)
65
+ p = calculate_nearness_to_concept(other)
66
+ return if p.zero?
67
+
68
+ @data[:neighbors] << { concept: other, value: p }
69
+ # Sort neighbors list
70
+ @data[:neighbors].sort! { |a, b| a[:value] <=> b[:value] }
71
+ @data[:neighbors].reverse!
72
+ end
73
+
74
+ def calculate_nearness_to_concept(other)
75
+ weights = Project.instance.formula_weights
76
+
77
+ li_max1 = @context.count
78
+ li_max2 = @data[:tags].count
79
+ li_max3 = @data[:tables].count
80
+
81
+ lf_alike1 = lf_alike2 = lf_alike3 = 0.0
82
+
83
+ # check if exists this items from concept1 into concept2
84
+ @context.each { |i| lf_alike1 += 1.0 unless other.context.index(i).nil? }
85
+ @data[:tags].each { |i| lf_alike2 += 1.0 unless other.tags.index(i).nil? }
86
+ @data[:tables].each { |i| lf_alike3 += 1.0 unless other.tables.index(i).nil? }
87
+
88
+ lf_alike = (lf_alike1 * weights[0] + lf_alike2 * weights[1] + lf_alike3 * weights[2])
89
+ li_max = (li_max1 * weights[0] + li_max2 * weights[1] + li_max3 * weights[2])
90
+ (lf_alike * 100.0 / li_max)
91
+ end
92
+
93
+ def try_adding_references(other)
94
+ reference_to = 0
95
+ @data[:tags].each { |i| reference_to += 1 unless other.names.index(i.downcase).nil? }
96
+ @data[:texts].each do |t|
97
+ text = t.clone
98
+ text.split(' ').each do |word|
99
+ reference_to += 1 unless other.names.index(word.downcase).nil?
100
+ end
101
+ end
102
+ if reference_to.positive?
103
+ @data[:reference_to] << other.name
104
+ other.data[:referenced_by] << name
105
+ end
106
+ end
107
+
108
+ def method_missing(method)
109
+ @data[method]
110
+ end
111
+
112
+ private
113
+
114
+ def read_data_from_xml(xml_data)
115
+ xml_data.elements.each do |i|
116
+ case i.name
117
+ when 'names'
118
+ process_names(i)
119
+ when 'tags'
120
+ process_tags(i)
121
+ when 'context'
122
+ # DEPRECATED: Don't use xml tag <context>
123
+ # instead define it as attibute of root xml tag
124
+ process_context(i)
125
+ when 'text'
126
+ # DEPRECATED: Use xml tag <def> instead of <text>
127
+ process_text(i)
128
+ when 'def'
129
+ process_def(i)
130
+ when 'table'
131
+ @data[:tables] << Table.new(self, i)
132
+ else
133
+ text = " [ERROR] <#{i.name}> unkown XML attribute for concept #{name}"
134
+ msg = Rainbow(text).color(:red)
135
+ Project.instance.verbose msg
136
+ end
137
+ end
138
+ end
139
+
140
+ def process_names(value)
141
+ @names = []
142
+ j = value.text.split(',')
143
+ j.each { |k| @names << k.strip }
144
+ @type = value.attributes['type'].strip if value.attributes['type']
145
+ end
146
+
147
+ def process_tags(value)
148
+ raise '[Error] tags label empty!' if value.text.nil? || value.text.size.zero?
149
+ @data[:tags] = value.text.split(',')
150
+ @data[:tags].collect!(&:strip)
151
+ end
152
+
153
+ def process_context(value)
154
+ msg = ' │  ' + Rainbow(' [DEPRECATED] Concept ').yellow
155
+ msg += Rainbow(name).yellow.bright
156
+ msg += Rainbow(' move <context> tag info to <map>.').yellow
157
+ Project.instance.verbose msg
158
+ @context = value.text.split(',')
159
+ @context.collect!(&:strip)
160
+ end
161
+
162
+ def process_text(value)
163
+ msg = ' │  ' + Rainbow(' [DEPRECATED] Concept ').yellow
164
+ msg += Rainbow(name).yellow.bright
165
+ msg += Rainbow(' replace <text> tag by <def>.').yellow
166
+ Project.instance.verbose msg
167
+ @data[:texts] << value.text.strip
168
+ end
169
+
170
+ def process_def(value)
171
+ case value.attributes['type']
172
+ when 'image'
173
+ msg = "[DEBUG] Concept#read_xml: image #{Rainbow(value.text).bright}"
174
+ Project.instance.verbose Rainbow(msg).yellow
175
+ when 'image_url'
176
+ @data[:images] << value.text.strip
177
+ when 'textfile_path'
178
+ @data[:textfile_paths] << value.text.strip
179
+ else
180
+ @data[:texts] << value.text.strip
181
+ end
182
+ end
183
+ end
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Contain data information for every field
4
+ # Params:
5
+ # * +data+ - Data (Text). This is the field content
6
+ # * +id+ - Identifier (Integer)
7
+ # * +type+ - May be "text", "textfile_path", "textfile_url" or "image_url"
8
+ class DataField
9
+ attr_reader :id, :type
10
+
11
+ def initialize(data, id, type)
12
+ @data = data
13
+ @id = id.to_i # TODO: revise where it comes from? Is it unique value?
14
+ @type = type.to_sym
15
+ end
16
+
17
+ def get(option = :raw)
18
+ case @type
19
+ when :text
20
+ return get_text(option)
21
+ when :textfile_path
22
+ return get_textfile_path(option)
23
+ when :textfile_url
24
+ return get_textfile_url(option)
25
+ when :image_url
26
+ return get_image_url(option)
27
+ end
28
+ raise ".get: data=#{@data}, type=#{@type}, option=#{option}"
29
+ end
30
+
31
+ private
32
+
33
+ def get_text(option)
34
+ return to_screen(@data) if option == :screen
35
+
36
+ @data
37
+ end
38
+
39
+ def get_textfile_path(option)
40
+ case option
41
+ when :raw
42
+ return @data
43
+ when :id
44
+ return "textfile_path.#{@id}"
45
+ when :decorated
46
+ content = File.new(@data).read
47
+ return "<pre>\n#{content}</pre>"
48
+ when :screen
49
+ return to_screen(@data)
50
+ end
51
+ raise ".get_textfile_path: data=#{@data}, type=#{@type}, option=#{option}"
52
+ end
53
+
54
+ def get_textfile_url(option)
55
+ case option
56
+ when :raw
57
+ return @data
58
+ when :id
59
+ return "textfile_url.#{@id}"
60
+ when :decorated
61
+ return "<a href=\"#{@data}\">Textfile URL</a>"
62
+ when :screen
63
+ return to_screen(@data)
64
+ end
65
+ raise ".get_textfile_url: data=#{@data}, type=#{@type}, option=#{option}"
66
+ end
67
+
68
+ def get_image_url(option)
69
+ case option
70
+ when :raw
71
+ return @data
72
+ when :id
73
+ return "image_url.#{@id}"
74
+ when :decorated
75
+ return "<img src=\"#{@data}\" alt=\"image\">"
76
+ when :screen
77
+ return to_screen(@data)
78
+ end
79
+ raise ".get_image_url: data=#{@data}, type=#{@type}, option=#{option}"
80
+ end
81
+
82
+ def to_screen(text)
83
+ return text[0, 7] + '...' + text[-15, 15] if text.size > 25
84
+
85
+ text
86
+ end
87
+ end