asker-tool 2.1.3 → 2.2.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.
- checksums.yaml +4 -4
- data/README.md +18 -19
- data/bin/asker +2 -1
- data/lib/asker/ai/ai.rb +10 -3
- data/lib/asker/ai/ai_calculate.rb +20 -6
- data/lib/asker/ai/code/base_code_ai.rb +104 -0
- data/lib/asker/{code/ai → ai/code}/code_ai_factory.rb +11 -1
- data/lib/asker/{code/ai → ai/code}/javascript_code_ai.rb +2 -5
- data/lib/asker/ai/code/problem_code_ai.rb +176 -0
- data/lib/asker/{code/ai → ai/code}/python_code_ai.rb +2 -5
- data/lib/asker/{code/ai → ai/code}/ruby_code_ai.rb +14 -7
- data/lib/asker/{code/ai → ai/code}/sql_code_ai.rb +2 -5
- data/lib/asker/ai/concept_ai.rb +12 -2
- data/lib/asker/ai/question.rb +28 -6
- data/lib/asker/ai/stages/base_stage.rb +45 -6
- data/lib/asker/ai/stages/stage_b.rb +100 -50
- data/lib/asker/ai/stages/stage_d.rb +75 -90
- data/lib/asker/ai/stages/stage_f.rb +64 -36
- data/lib/asker/ai/stages/stage_i.rb +79 -92
- data/lib/asker/ai/stages/stage_s.rb +41 -36
- data/lib/asker/ai/stages/stage_t.rb +149 -108
- data/lib/asker/application.rb +24 -7
- data/lib/asker/checker.rb +149 -52
- data/lib/asker/cli.rb +37 -32
- data/lib/asker/data/code.rb +76 -0
- data/lib/asker/data/column.rb +31 -21
- data/lib/asker/data/concept.rb +108 -65
- data/lib/asker/data/data_field.rb +14 -0
- data/lib/asker/data/row.rb +75 -52
- data/lib/asker/data/table.rb +91 -42
- data/lib/asker/data/template.rb +3 -1
- data/lib/asker/data/world.rb +61 -32
- data/lib/asker/{exporter/code_screen_exporter.rb → displayer/code_displayer.rb} +13 -6
- data/lib/asker/displayer/concept_ai_displayer.erb +10 -0
- data/lib/asker/displayer/concept_ai_displayer.rb +133 -0
- data/lib/asker/displayer/concept_displayer.rb +34 -0
- data/lib/asker/displayer/stats_displayer.rb +22 -0
- data/lib/asker/exporter/code_gift_exporter.rb +10 -11
- data/lib/asker/exporter/concept_ai_gift_exporter.rb +21 -13
- data/lib/asker/exporter/concept_ai_moodle_exporter.rb +44 -0
- data/lib/asker/exporter/concept_ai_yaml_exporter.rb +14 -9
- data/lib/asker/exporter/concept_doc_exporter.rb +21 -14
- data/lib/asker/exporter/data_gift_exporter.rb +29 -0
- data/lib/asker/exporter/output_file_exporter.rb +21 -0
- data/lib/asker/files/{config.ini → asker.ini} +48 -1
- data/lib/asker/files/example-concept.haml +24 -8
- data/lib/asker/files/language/du/connectors.yaml +81 -0
- data/lib/asker/files/language/du/mistakes.yaml +82 -0
- data/lib/asker/files/language/du/templates.yaml +29 -0
- data/lib/asker/files/language/en/connectors.yaml +44 -0
- data/lib/asker/files/language/en/mistakes.yaml +37 -0
- data/lib/asker/files/language/en/templates.yaml +29 -0
- data/lib/asker/files/language/es/connectors.yaml +92 -0
- data/lib/asker/files/language/es/mistakes.yaml +84 -0
- data/lib/asker/files/language/es/templates.yaml +29 -0
- data/lib/asker/files/language/fr/connectors.yaml +76 -0
- data/lib/asker/files/language/fr/mistakes.yaml +82 -0
- data/lib/asker/files/language/fr/templates.yaml +29 -0
- data/lib/asker/files/language/javascript/connectors.yaml +11 -0
- data/lib/asker/files/language/javascript/mistakes.yaml +30 -0
- data/lib/asker/files/language/javascript/templates.yaml +3 -0
- data/lib/asker/files/language/math/connectors.yaml +2 -0
- data/lib/asker/files/language/math/mistakes.yaml +2 -0
- data/lib/asker/files/language/math/templates.yaml +1 -0
- data/lib/asker/files/language/python/connectors.yaml +11 -0
- data/lib/asker/files/language/python/mistakes.yaml +26 -0
- data/lib/asker/files/language/python/templates.yaml +3 -0
- data/lib/asker/files/language/ruby/connectors.yaml +11 -0
- data/lib/asker/files/language/ruby/mistakes.yaml +33 -0
- data/lib/asker/files/language/ruby/templates.yaml +3 -0
- data/lib/asker/files/language/sql/connectors.yaml +6 -0
- data/lib/asker/files/language/sql/mistakes.yaml +11 -0
- data/lib/asker/files/language/sql/templates.yaml +2 -0
- data/lib/asker/formatter/concept_string_formatter.rb +13 -9
- data/lib/asker/formatter/moodle/matching.erb +38 -0
- data/lib/asker/formatter/moodle/multichoice.erb +49 -0
- data/lib/asker/formatter/moodle/shortanswer.erb +30 -0
- data/lib/asker/formatter/moodle/truefalse.erb +47 -0
- data/lib/asker/formatter/question_gift_formatter.rb +30 -20
- data/lib/asker/formatter/question_moodle_formatter.rb +27 -0
- data/lib/asker/lang/lang.rb +18 -12
- data/lib/asker/lang/lang_factory.rb +32 -5
- data/lib/asker/lang/text_actions.rb +87 -69
- data/lib/asker/loader/code_loader.rb +4 -4
- data/lib/asker/loader/content_loader.rb +16 -12
- data/lib/asker/loader/directory_loader.rb +3 -3
- data/lib/asker/loader/embedded_file.rb +42 -0
- data/lib/asker/loader/file_loader.rb +3 -12
- data/lib/asker/loader/haml_loader.rb +15 -0
- data/lib/asker/loader/image_url_loader.rb +9 -11
- data/lib/asker/loader/input_loader.rb +24 -8
- data/lib/asker/loader/project_loader.rb +42 -30
- data/lib/asker/logger.rb +30 -6
- data/lib/asker/project.rb +28 -117
- data/lib/asker/skeleton.rb +40 -29
- data/lib/asker.rb +68 -79
- metadata +57 -74
- data/docs/changelog/v2.1.md +0 -99
- data/docs/commands.md +0 -12
- data/docs/contributions.md +0 -18
- data/docs/history.md +0 -40
- data/docs/idea.md +0 -44
- data/docs/inputs/README.md +0 -39
- data/docs/inputs/code.md +0 -69
- data/docs/inputs/concepts.md +0 -142
- data/docs/inputs/jedi.md +0 -68
- data/docs/inputs/tables.md +0 -112
- data/docs/inputs/templates.md +0 -87
- data/docs/install/README.md +0 -38
- data/docs/install/manual.md +0 -26
- data/docs/install/scripts.md +0 -38
- data/docs/revise/asker-file.md +0 -41
- data/docs/revise/buenas-practicas/01-convocatoria.md +0 -30
- data/docs/revise/buenas-practicas/02-formulario.md +0 -35
- data/docs/revise/buenas-practicas/03-descripcion.md +0 -63
- data/docs/revise/buenas-practicas/04-resultados.md +0 -17
- data/docs/revise/buenas-practicas/05-reproducir.md +0 -10
- data/docs/revise/ejemplos/01/README.md +0 -27
- data/docs/revise/ejemplos/02/README.md +0 -31
- data/docs/revise/ejemplos/03/README.md +0 -31
- data/docs/revise/ejemplos/04/README.md +0 -37
- data/docs/revise/ejemplos/05/README.md +0 -25
- data/docs/revise/ejemplos/06/README.md +0 -43
- data/docs/revise/ejemplos/README.md +0 -11
- data/docs/revise/projects.md +0 -74
- data/lib/asker/code/ai/base_code_ai.rb +0 -48
- data/lib/asker/code/code.rb +0 -53
- data/lib/asker/exporter/concept_ai_screen_exporter.rb +0 -115
- data/lib/asker/exporter/concept_screen_exporter.rb +0 -25
- data/lib/asker/exporter/main.rb +0 -9
data/lib/asker/data/concept.rb
CHANGED
|
@@ -3,20 +3,37 @@
|
|
|
3
3
|
require 'rainbow'
|
|
4
4
|
require 'rexml/document'
|
|
5
5
|
|
|
6
|
-
require_relative '../
|
|
6
|
+
require_relative '../application'
|
|
7
|
+
require_relative '../logger'
|
|
7
8
|
require_relative '../lang/lang_factory'
|
|
9
|
+
require_relative '../loader/embedded_file'
|
|
8
10
|
require_relative 'table'
|
|
9
11
|
require_relative 'data_field'
|
|
10
12
|
|
|
13
|
+
##
|
|
11
14
|
# Store Concept information
|
|
15
|
+
# rubocop:disable Metrics/ClassLength
|
|
16
|
+
# rubocop:disable Style/ClassVars
|
|
12
17
|
class Concept
|
|
13
|
-
attr_reader :id
|
|
14
|
-
attr_reader :
|
|
15
|
-
attr_reader :
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
attr_reader :id # Unique identifer (Integer)
|
|
19
|
+
attr_reader :lang # Lang code (By default is the same as map lang)
|
|
20
|
+
attr_reader :context # Context inherits from map
|
|
21
|
+
attr_reader :names # Names used to identify or name this concept
|
|
22
|
+
attr_reader :type # type = text -> Name values are only text
|
|
23
|
+
attr_reader :filename # Filename where this concept is defined
|
|
24
|
+
attr_reader :data # Data about this concept
|
|
25
|
+
attr_accessor :process # (Boolean) if it is necesary generate questions
|
|
26
|
+
|
|
27
|
+
@@id = 0 # Global Concept counter
|
|
28
|
+
|
|
29
|
+
##
|
|
30
|
+
# Initilize Concept
|
|
31
|
+
# @param xml_data (XML)
|
|
32
|
+
# @param filename (String)
|
|
33
|
+
# @param lang_code (String)
|
|
34
|
+
# @param context (Array)
|
|
35
|
+
# rubocop:disable Metrics/MethodLength
|
|
36
|
+
# rubocop:disable Metrics/AbcSize
|
|
20
37
|
def initialize(xml_data, filename, lang_code = 'en', context = [])
|
|
21
38
|
@@id += 1
|
|
22
39
|
@id = @@id
|
|
@@ -38,16 +55,17 @@ class Concept
|
|
|
38
55
|
|
|
39
56
|
@data = {}
|
|
40
57
|
@data[:tags] = []
|
|
41
|
-
@data[:texts] = []
|
|
42
|
-
@data[:images] = [] #
|
|
43
|
-
@data[:textfile_paths] = [] # TODO: By now, We'll treat this separated from texts
|
|
58
|
+
@data[:texts] = [] # Used by standard def inputs
|
|
59
|
+
@data[:images] = [] # Used by [type => file and type => image_url] def inputs
|
|
44
60
|
@data[:tables] = []
|
|
45
61
|
@data[:neighbors] = []
|
|
46
62
|
@data[:reference_to] = []
|
|
47
63
|
@data[:referenced_by] = []
|
|
48
64
|
|
|
49
|
-
|
|
65
|
+
read_data_from_xml(xml_data)
|
|
50
66
|
end
|
|
67
|
+
# rubocop:enable Metrics/MethodLength
|
|
68
|
+
# rubocop:enable Metrics/AbcSize
|
|
51
69
|
|
|
52
70
|
def name(option = :raw)
|
|
53
71
|
DataField.new(@names[0], @id, @type).get(option)
|
|
@@ -71,46 +89,84 @@ class Concept
|
|
|
71
89
|
@data[:neighbors].reverse!
|
|
72
90
|
end
|
|
73
91
|
|
|
92
|
+
# rubocop:disable Metrics/MethodLength
|
|
93
|
+
# rubocop:disable Metrics/AbcSize
|
|
94
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
|
74
95
|
def calculate_nearness_to_concept(other)
|
|
75
|
-
|
|
96
|
+
a = Application.instance.config['ai']['formula_weights']
|
|
97
|
+
weights = a.split(',').map(&:to_f)
|
|
76
98
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
99
|
+
max1 = @context.count
|
|
100
|
+
max2 = @data[:tags].count
|
|
101
|
+
max3 = @data[:tables].count
|
|
80
102
|
|
|
81
|
-
|
|
103
|
+
alike1 = alike2 = alike3 = 0.0
|
|
82
104
|
|
|
83
105
|
# check if exists this items from concept1 into concept2
|
|
84
|
-
@context.each { |i|
|
|
85
|
-
@data[:tags].each { |i|
|
|
86
|
-
@data[:tables].each { |i|
|
|
106
|
+
@context.each { |i| alike1 += 1.0 unless other.context.index(i).nil? }
|
|
107
|
+
@data[:tags].each { |i| alike2 += 1.0 unless other.tags.index(i).nil? }
|
|
108
|
+
@data[:tables].each { |i| alike3 += 1.0 unless other.tables.index(i).nil? }
|
|
87
109
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
(
|
|
110
|
+
alike = (alike1 * weights[0] + alike2 * weights[1] + alike3 * weights[2])
|
|
111
|
+
max = (max1 * weights[0] + max2 * weights[1] + max3 * weights[2])
|
|
112
|
+
(alike * 100.0 / max)
|
|
91
113
|
end
|
|
114
|
+
# rubocop:enable Metrics/MethodLength
|
|
115
|
+
# rubocop:enable Metrics/AbcSize
|
|
116
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
|
92
117
|
|
|
118
|
+
# rubocop:disable Metrics/MethodLength
|
|
119
|
+
# rubocop:disable Metrics/AbcSize
|
|
93
120
|
def try_adding_references(other)
|
|
94
121
|
reference_to = 0
|
|
95
|
-
@data[:tags].each
|
|
122
|
+
@data[:tags].each do |i|
|
|
123
|
+
reference_to += 1 unless other.names.index(i.downcase).nil?
|
|
124
|
+
end
|
|
96
125
|
@data[:texts].each do |t|
|
|
97
126
|
text = t.clone
|
|
98
127
|
text.split(' ').each do |word|
|
|
99
128
|
reference_to += 1 unless other.names.index(word.downcase).nil?
|
|
100
129
|
end
|
|
101
130
|
end
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
131
|
+
return unless reference_to.positive?
|
|
132
|
+
|
|
133
|
+
@data[:reference_to] << other.name
|
|
134
|
+
other.data[:referenced_by] << name
|
|
135
|
+
end
|
|
136
|
+
# rubocop:enable Metrics/MethodLength
|
|
137
|
+
# rubocop:enable Metrics/AbcSize
|
|
138
|
+
|
|
139
|
+
def tags
|
|
140
|
+
@data[:tags]
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def texts
|
|
144
|
+
@data[:texts]
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def images
|
|
148
|
+
@data[:images]
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def tables
|
|
152
|
+
@data[:tables]
|
|
106
153
|
end
|
|
107
154
|
|
|
108
|
-
def
|
|
109
|
-
@data[
|
|
155
|
+
def neighbors
|
|
156
|
+
@data[:neighbors]
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def reference_to
|
|
160
|
+
@data[:reference_to]
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def referenced_by
|
|
164
|
+
@data[:referenced_by]
|
|
110
165
|
end
|
|
111
166
|
|
|
112
167
|
private
|
|
113
168
|
|
|
169
|
+
# rubocop:disable Metrics/MethodLength
|
|
114
170
|
def read_data_from_xml(xml_data)
|
|
115
171
|
xml_data.elements.each do |i|
|
|
116
172
|
case i.name
|
|
@@ -118,24 +174,17 @@ class Concept
|
|
|
118
174
|
process_names(i)
|
|
119
175
|
when 'tags'
|
|
120
176
|
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
177
|
when 'def'
|
|
129
178
|
process_def(i)
|
|
130
179
|
when 'table'
|
|
131
180
|
@data[:tables] << Table.new(self, i)
|
|
132
181
|
else
|
|
133
|
-
text = " [ERROR]
|
|
134
|
-
|
|
135
|
-
Project.instance.verbose msg
|
|
182
|
+
text = " [ERROR] Concept #{name} with unkown attribute: #{i.name}"
|
|
183
|
+
Logger.verboseln Rainbow(text).color(:red)
|
|
136
184
|
end
|
|
137
185
|
end
|
|
138
186
|
end
|
|
187
|
+
# rubocop:enable Metrics/MethodLength
|
|
139
188
|
|
|
140
189
|
def process_names(value)
|
|
141
190
|
@names = []
|
|
@@ -145,39 +194,33 @@ class Concept
|
|
|
145
194
|
end
|
|
146
195
|
|
|
147
196
|
def process_tags(value)
|
|
148
|
-
|
|
197
|
+
if value.text.nil? || value.text.size.zero?
|
|
198
|
+
Logger.verboseln Rainbow("[ERROR] Concept #{name} has tags empty!").red.briht
|
|
199
|
+
exit 1
|
|
200
|
+
end
|
|
201
|
+
|
|
149
202
|
@data[:tags] = value.text.split(',')
|
|
150
203
|
@data[:tags].collect!(&:strip)
|
|
151
204
|
end
|
|
152
205
|
|
|
153
|
-
|
|
154
|
-
|
|
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
|
-
|
|
206
|
+
# rubocop:disable Metrics/AbcSize
|
|
207
|
+
# rubocop:disable Metrics/MethodLength
|
|
170
208
|
def process_def(value)
|
|
171
209
|
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
210
|
when 'image_url'
|
|
176
|
-
@data[:images] << value.text.strip
|
|
177
|
-
when '
|
|
178
|
-
@data[:
|
|
179
|
-
|
|
211
|
+
@data[:images] << EmbeddedFile.load(value.text.strip, File.dirname(@filename))
|
|
212
|
+
when 'file'
|
|
213
|
+
@data[:images] << EmbeddedFile.load(value.text.strip, File.dirname(@filename))
|
|
214
|
+
when nil
|
|
180
215
|
@data[:texts] << value.text.strip
|
|
216
|
+
else
|
|
217
|
+
msg = "[ERROR] Unknown type: #{value.attributes['type']}"
|
|
218
|
+
Logger.verboseln Rainbow(msg).red.bright
|
|
219
|
+
exit 1
|
|
181
220
|
end
|
|
182
221
|
end
|
|
222
|
+
# rubocop:enable Metrics/AbcSize
|
|
223
|
+
# rubocop:enable Metrics/MethodLength
|
|
183
224
|
end
|
|
225
|
+
# rubocop:enable Metrics/ClassLength
|
|
226
|
+
# rubocop:enable Style/ClassVars
|
|
@@ -8,12 +8,19 @@
|
|
|
8
8
|
class DataField
|
|
9
9
|
attr_reader :id, :type
|
|
10
10
|
|
|
11
|
+
##
|
|
12
|
+
# initialize DataField
|
|
11
13
|
def initialize(data, id, type)
|
|
12
14
|
@data = data
|
|
13
15
|
@id = id.to_i # TODO: revise where it comes from? Is it unique value?
|
|
14
16
|
@type = type.to_sym
|
|
15
17
|
end
|
|
16
18
|
|
|
19
|
+
##
|
|
20
|
+
# Return internal data
|
|
21
|
+
# @param option (Symbol)
|
|
22
|
+
# @return String
|
|
23
|
+
# rubocop:disable Metrics/MethodLength
|
|
17
24
|
def get(option = :raw)
|
|
18
25
|
case @type
|
|
19
26
|
when :text
|
|
@@ -27,6 +34,7 @@ class DataField
|
|
|
27
34
|
end
|
|
28
35
|
raise ".get: data=#{@data}, type=#{@type}, option=#{option}"
|
|
29
36
|
end
|
|
37
|
+
# rubocop:enable Metrics/MethodLength
|
|
30
38
|
|
|
31
39
|
private
|
|
32
40
|
|
|
@@ -36,6 +44,7 @@ class DataField
|
|
|
36
44
|
@data
|
|
37
45
|
end
|
|
38
46
|
|
|
47
|
+
# rubocop:disable Metrics/MethodLength
|
|
39
48
|
def get_textfile_path(option)
|
|
40
49
|
case option
|
|
41
50
|
when :raw
|
|
@@ -50,7 +59,9 @@ class DataField
|
|
|
50
59
|
end
|
|
51
60
|
raise ".get_textfile_path: data=#{@data}, type=#{@type}, option=#{option}"
|
|
52
61
|
end
|
|
62
|
+
# rubocop:enable Metrics/MethodLength
|
|
53
63
|
|
|
64
|
+
# rubocop:disable Metrics/MethodLength
|
|
54
65
|
def get_textfile_url(option)
|
|
55
66
|
case option
|
|
56
67
|
when :raw
|
|
@@ -64,7 +75,9 @@ class DataField
|
|
|
64
75
|
end
|
|
65
76
|
raise ".get_textfile_url: data=#{@data}, type=#{@type}, option=#{option}"
|
|
66
77
|
end
|
|
78
|
+
# rubocop:enable Metrics/MethodLength
|
|
67
79
|
|
|
80
|
+
# rubocop:disable Metrics/MethodLength
|
|
68
81
|
def get_image_url(option)
|
|
69
82
|
case option
|
|
70
83
|
when :raw
|
|
@@ -78,6 +91,7 @@ class DataField
|
|
|
78
91
|
end
|
|
79
92
|
raise ".get_image_url: data=#{@data}, type=#{@type}, option=#{option}"
|
|
80
93
|
end
|
|
94
|
+
# rubocop:enable Metrics/MethodLength
|
|
81
95
|
|
|
82
96
|
def to_screen(text)
|
|
83
97
|
return text[0, 7] + '...' + text[-15, 15] if text.size > 25
|
data/lib/asker/data/row.rb
CHANGED
|
@@ -1,93 +1,116 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
|
|
2
3
|
require_relative 'column'
|
|
3
4
|
|
|
5
|
+
##
|
|
6
|
+
# Row objects
|
|
4
7
|
class Row
|
|
5
8
|
attr_reader :table, :index, :id
|
|
6
9
|
attr_reader :langs, :types, :raws, :columns
|
|
7
10
|
attr_reader :simple
|
|
8
11
|
|
|
9
|
-
|
|
12
|
+
##
|
|
13
|
+
# Initialize Row Object
|
|
14
|
+
# @param table (Table)
|
|
15
|
+
# @param index (Integer)
|
|
16
|
+
# @param xml_data (XML)
|
|
17
|
+
def initialize(table, index, xml_data)
|
|
10
18
|
@table = table
|
|
11
19
|
@index = index
|
|
12
|
-
@id = @table.id
|
|
20
|
+
@id = "#{@table.id}.#{@index}"
|
|
13
21
|
@langs = @table.langs
|
|
14
22
|
@types = @table.types
|
|
15
23
|
@raws = []
|
|
16
24
|
@columns = []
|
|
17
|
-
@simple = { :
|
|
25
|
+
@simple = { lang: true, type: true }
|
|
18
26
|
read_data_from_xml(xml_data)
|
|
19
27
|
end
|
|
20
28
|
|
|
21
29
|
def simple_off(option)
|
|
22
|
-
@simple[option]=false
|
|
30
|
+
@simple[option] = false
|
|
23
31
|
@table.simple_off(option)
|
|
24
32
|
end
|
|
25
33
|
|
|
26
|
-
private
|
|
34
|
+
private
|
|
27
35
|
|
|
28
|
-
def read_data_from_xml(
|
|
29
|
-
if
|
|
30
|
-
build_row_with_1_column(
|
|
36
|
+
def read_data_from_xml(xml_data)
|
|
37
|
+
if xml_data.elements.count.zero?
|
|
38
|
+
build_row_with_1_column(xml_data)
|
|
31
39
|
else
|
|
32
|
-
|
|
40
|
+
build_row_with_n_columns(xml_data)
|
|
33
41
|
end
|
|
34
42
|
|
|
35
|
-
raise "[ERROR] Row: #{
|
|
43
|
+
raise "[ERROR] Row: #{xml_data}" unless @columns.size == @table.fields.size
|
|
36
44
|
end
|
|
37
45
|
|
|
38
|
-
def build_row_with_1_column(
|
|
46
|
+
def build_row_with_1_column(xml_data)
|
|
39
47
|
# When row tag only has text, we add this text as one value array
|
|
40
48
|
# This is usefull for tables with only one columns
|
|
41
|
-
@columns = [
|
|
42
|
-
@raws = [
|
|
43
|
-
|
|
44
|
-
#read attributes from XML data
|
|
45
|
-
if pXMLdata.attributes['lang'] then
|
|
46
|
-
code = pXMLdata.attributes['lang'].strip
|
|
47
|
-
if code != @langs[0].code then
|
|
48
|
-
@langs = [ LangFactory.instance.get(code) ]
|
|
49
|
-
@simple[:lang]= false
|
|
50
|
-
@table.simple_off(:lang)
|
|
51
|
-
end
|
|
52
|
-
end
|
|
49
|
+
@columns = [Column.new(self, @raws.size, xml_data)]
|
|
50
|
+
@raws = [xml_data.text.strip.to_s]
|
|
53
51
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
@types = [ type ]
|
|
58
|
-
@simple[:type]= false
|
|
59
|
-
@table.simple_off(:type)
|
|
60
|
-
end
|
|
61
|
-
end
|
|
52
|
+
# read attributes from XML data
|
|
53
|
+
read_lang_from_xml(xml_data)
|
|
54
|
+
read_type_from_xml(xml_data)
|
|
62
55
|
end
|
|
63
56
|
|
|
64
|
-
def
|
|
65
|
-
|
|
57
|
+
def read_lang_from_xml(xml_data)
|
|
58
|
+
return unless xml_data.attributes['lang']
|
|
59
|
+
|
|
60
|
+
code = xml_data.attributes['lang'].strip
|
|
61
|
+
return if code == @langs[0].code
|
|
62
|
+
|
|
63
|
+
@langs = [LangFactory.instance.get(code)]
|
|
64
|
+
@simple[:lang] = false
|
|
65
|
+
@table.simple_off(:lang)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def read_type_from_xml(xml_data)
|
|
69
|
+
return unless xml_data.attributes['type']
|
|
70
|
+
|
|
71
|
+
type = xml_data.attributes['type'].strip
|
|
72
|
+
return if type == @types[0]
|
|
73
|
+
|
|
74
|
+
@types = [type]
|
|
75
|
+
@simple[:type] = false
|
|
76
|
+
@table.simple_off(:type)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# rubocop:disable Metrics/MethodLength
|
|
80
|
+
def build_row_with_n_columns(xml_data)
|
|
81
|
+
xml_data.elements.each do |i|
|
|
66
82
|
case i.name
|
|
67
83
|
when 'lang'
|
|
68
|
-
|
|
69
|
-
codes = @langs.map {|i| i.code }
|
|
70
|
-
|
|
71
|
-
if j.join(",")!=codes.join(",")
|
|
72
|
-
@langs = []
|
|
73
|
-
j.each { |k| @langs << LangFactory.instance.get(k.strip.to_s) }
|
|
74
|
-
@simple[:lang]=false
|
|
75
|
-
@table.simple_off(:lang)
|
|
76
|
-
end
|
|
84
|
+
read_langs_from_xml(i)
|
|
77
85
|
when 'type'
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
@simple[:type]=false
|
|
83
|
-
@table.simple_off(:type)
|
|
84
|
-
end
|
|
85
|
-
when 'col' # When row tag has several columns, we add every value to the array
|
|
86
|
-
#Column Objects
|
|
87
|
-
@columns << Column.new( self, @raws.size, i)
|
|
86
|
+
read_types_from_xml(i)
|
|
87
|
+
when 'col'
|
|
88
|
+
# When row has several columns, we add every value to the array
|
|
89
|
+
@columns << Column.new(self, @raws.size, i) # Column Objects
|
|
88
90
|
@raws << i.text.to_s
|
|
89
91
|
end
|
|
90
92
|
end
|
|
91
93
|
end
|
|
94
|
+
# rubocop:enable Metrics/MethodLength
|
|
95
|
+
|
|
96
|
+
def read_langs_from_xml(xml_data)
|
|
97
|
+
j = xml_data.text.split(',')
|
|
98
|
+
codes = @langs.map(&:code)
|
|
99
|
+
return if j.join(',') == codes.join(',')
|
|
100
|
+
|
|
101
|
+
@langs = []
|
|
102
|
+
j.each { |k| @langs << LangFactory.instance.get(k.strip.to_s) }
|
|
103
|
+
@simple[:lang] = false
|
|
104
|
+
@table.simple_off(:lang)
|
|
105
|
+
end
|
|
92
106
|
|
|
107
|
+
def read_types_from_xml(xml_data)
|
|
108
|
+
j = xml_data.text.split(',')
|
|
109
|
+
return if j.join(',') == @types.join(',')
|
|
110
|
+
|
|
111
|
+
@types = []
|
|
112
|
+
j.each { |k| @types << k.strip.to_s }
|
|
113
|
+
@simple[:type] = false
|
|
114
|
+
@table.simple_off(:type)
|
|
115
|
+
end
|
|
93
116
|
end
|
data/lib/asker/data/table.rb
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#
|
|
1
|
+
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require_relative 'row'
|
|
4
4
|
require_relative 'template'
|
|
@@ -6,75 +6,96 @@ require_relative 'template'
|
|
|
6
6
|
# Contains data table information
|
|
7
7
|
class Table
|
|
8
8
|
attr_reader :name, :id
|
|
9
|
-
attr_reader :fields, :
|
|
10
|
-
attr_reader :
|
|
9
|
+
attr_reader :fields, :sequence
|
|
10
|
+
attr_reader :langs
|
|
11
|
+
attr_reader :datarows # DEV: experimental replace for Row objects
|
|
12
|
+
attr_reader :rows # Row objects are Datarows.raws values
|
|
13
|
+
# Table is simple when all their rows and col has the same lang and type value
|
|
11
14
|
attr_reader :simple
|
|
12
15
|
|
|
16
|
+
##
|
|
17
|
+
# initialize Table object
|
|
18
|
+
# @param concept (Concept)
|
|
19
|
+
# @param xml_data (XML)
|
|
13
20
|
def initialize(concept, xml_data)
|
|
14
21
|
@concept = concept
|
|
22
|
+
read_attributes_from_xml(xml_data)
|
|
15
23
|
|
|
16
|
-
|
|
17
|
-
t = xml_data.attributes['fields'].to_s.strip.split(',')
|
|
18
|
-
t.each { |i| i.strip! }
|
|
19
|
-
@fields = t || []
|
|
24
|
+
@simple = { lang: true, type: true }
|
|
20
25
|
@types = ['text'] * @fields.size
|
|
21
26
|
@langs = [@concept.lang] * @fields.size
|
|
22
27
|
|
|
23
|
-
@
|
|
24
|
-
@fields.each { |i| @name=@name + '$' + i.to_s.strip.downcase}
|
|
25
|
-
@id = @concept.name.to_s + '.' + @name
|
|
26
|
-
@simple = { lang: true, type: true }
|
|
27
|
-
|
|
28
|
-
@sequence = []
|
|
29
|
-
if xml_data.attributes['sequence']
|
|
30
|
-
t = xml_data.attributes['sequence'].to_s || ""
|
|
31
|
-
@sequence = t.split(",")
|
|
32
|
-
# puts "[DEPRECATED] sequence attr on table <#{@name}>"
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
@datarows = [] #DEV experiment replace row data with row objects
|
|
28
|
+
@datarows = [] # DEV experiment replace row data with row objects
|
|
36
29
|
read_data_from_xml(xml_data)
|
|
37
|
-
@rows = @datarows.map
|
|
30
|
+
@rows = @datarows.map(&:raws)
|
|
38
31
|
end
|
|
39
32
|
|
|
33
|
+
##
|
|
34
|
+
# Return table name
|
|
40
35
|
def to_s
|
|
41
36
|
@name.to_s
|
|
42
37
|
end
|
|
43
38
|
|
|
39
|
+
##
|
|
40
|
+
# Return true if table has a sequence defined
|
|
44
41
|
def sequence?
|
|
45
|
-
@sequence.size
|
|
42
|
+
@sequence.size.positive?
|
|
46
43
|
end
|
|
47
44
|
|
|
45
|
+
##
|
|
46
|
+
# Return fields type:
|
|
47
|
+
# * types(:all) => Return an Array with all field types
|
|
48
|
+
# * types(index) => Return type for fields[index]
|
|
49
|
+
# @param index (Integer)
|
|
48
50
|
def types(index = :all)
|
|
49
51
|
@types = (['text'] * @fields.size) if @types.nil?
|
|
50
52
|
return @types if index == :all
|
|
53
|
+
|
|
51
54
|
@types[index]
|
|
52
55
|
end
|
|
53
56
|
|
|
57
|
+
##
|
|
58
|
+
# Set table to simple off
|
|
59
|
+
# * simple_off(:lang) => Set table simple lang FALSE
|
|
60
|
+
# * simple_off(:type) => Set table simple type FALSE
|
|
61
|
+
# @param option (Symbol)
|
|
54
62
|
def simple_off(option)
|
|
55
63
|
@simple[option] = false
|
|
56
64
|
end
|
|
57
65
|
|
|
58
66
|
private
|
|
59
67
|
|
|
68
|
+
##
|
|
69
|
+
# Fill:fields, name and id from XML input
|
|
70
|
+
# @param xml_data (XML)
|
|
71
|
+
# rubocop:disable Metrics/AbcSize
|
|
72
|
+
def read_attributes_from_xml(xml_data)
|
|
73
|
+
# read attributes from XML data
|
|
74
|
+
t = xml_data.attributes['fields'].to_s.strip.split(',')
|
|
75
|
+
t.each(&:strip!)
|
|
76
|
+
@fields = t || []
|
|
77
|
+
|
|
78
|
+
@name = ''
|
|
79
|
+
@fields.each { |i| @name = "#{@name}$#{i.to_s.strip.downcase}" }
|
|
80
|
+
@id = "#{@concept.name}.#{@name}"
|
|
81
|
+
|
|
82
|
+
@sequence = []
|
|
83
|
+
return unless xml_data.attributes['sequence']
|
|
84
|
+
|
|
85
|
+
@sequence = xml_data.attributes['sequence'].to_s.split(',')
|
|
86
|
+
end
|
|
87
|
+
# rubocop:enable Metrics/AbcSize
|
|
88
|
+
|
|
89
|
+
##
|
|
90
|
+
# Build table data from xml input
|
|
91
|
+
# @param xml_data (XML)
|
|
92
|
+
# rubocop:disable Metrics/MethodLength
|
|
93
|
+
# rubocop:disable Metrics/AbcSize
|
|
60
94
|
def read_data_from_xml(xml_data)
|
|
61
95
|
xml_data.elements.each do |i|
|
|
62
96
|
case i.name
|
|
63
97
|
when 'lang'
|
|
64
|
-
|
|
65
|
-
codes = @langs.map(&:code)
|
|
66
|
-
|
|
67
|
-
if j.join(',') != codes.join(',')
|
|
68
|
-
simple_off(:lang)
|
|
69
|
-
@langs = []
|
|
70
|
-
j.each do |k|
|
|
71
|
-
if k.strip == '*' || k.strip == ''
|
|
72
|
-
@langs << @concept.lang
|
|
73
|
-
else
|
|
74
|
-
@langs << LangFactory.instance.get(k.strip.to_s)
|
|
75
|
-
end
|
|
76
|
-
end
|
|
77
|
-
end
|
|
98
|
+
read_lang_from_xml(i)
|
|
78
99
|
when 'row'
|
|
79
100
|
@datarows << Row.new(self, @datarows.size, i)
|
|
80
101
|
when 'sequence'
|
|
@@ -82,15 +103,43 @@ class Table
|
|
|
82
103
|
when 'template'
|
|
83
104
|
@datarows += Template.new(self, @datarows.size, i).datarows
|
|
84
105
|
when 'type'
|
|
85
|
-
|
|
86
|
-
if j.join(',') != @types.join(',')
|
|
87
|
-
simple_off(:type)
|
|
88
|
-
@types = []
|
|
89
|
-
j.each { |k| @types << k.strip.to_s }
|
|
90
|
-
end
|
|
106
|
+
read_type_from_xml(i)
|
|
91
107
|
else
|
|
92
108
|
puts Rainbow("[ERROR] concept/table#xml_data with #{i.name}").red.bright
|
|
93
109
|
end
|
|
94
110
|
end
|
|
95
111
|
end
|
|
112
|
+
# rubocop:enable Metrics/MethodLength
|
|
113
|
+
# rubocop:enable Metrics/AbcSize
|
|
114
|
+
|
|
115
|
+
# rubocop:disable Metrics/MethodLength
|
|
116
|
+
# rubocop:disable Metrics/AbcSize
|
|
117
|
+
# rubocop:disable Style/ConditionalAssignment
|
|
118
|
+
def read_lang_from_xml(xml_data)
|
|
119
|
+
j = xml_data.text.split(',')
|
|
120
|
+
codes = @langs.map(&:code)
|
|
121
|
+
return if j.join(',') == codes.join(',')
|
|
122
|
+
|
|
123
|
+
simple_off(:lang)
|
|
124
|
+
@langs = []
|
|
125
|
+
j.each do |k|
|
|
126
|
+
if ['*', ''].include? k.strip
|
|
127
|
+
@langs << @concept.lang
|
|
128
|
+
else
|
|
129
|
+
@langs << LangFactory.instance.get(k.strip.to_s)
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
# rubocop:enable Metrics/MethodLength
|
|
134
|
+
# rubocop:enable Metrics/AbcSize
|
|
135
|
+
# rubocop:enable Style/ConditionalAssignment
|
|
136
|
+
|
|
137
|
+
def read_type_from_xml(xml_data)
|
|
138
|
+
j = xml_data.text.split(',')
|
|
139
|
+
return if j.join(',') == @types.join(',')
|
|
140
|
+
|
|
141
|
+
simple_off(:type)
|
|
142
|
+
@types = []
|
|
143
|
+
j.each { |k| @types << k.strip.to_s }
|
|
144
|
+
end
|
|
96
145
|
end
|
data/lib/asker/data/template.rb
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# frozen_string_literal: false
|
|
1
2
|
|
|
2
3
|
require 'rexml/document'
|
|
3
4
|
require_relative 'row'
|
|
@@ -40,7 +41,8 @@ class Template
|
|
|
40
41
|
|
|
41
42
|
def apply_vars_to_template(vars, template)
|
|
42
43
|
output = ''
|
|
43
|
-
return if vars.size.zero?
|
|
44
|
+
return output if vars.size.zero?
|
|
45
|
+
|
|
44
46
|
max = vars.first[1].size
|
|
45
47
|
(1..max).each do |index|
|
|
46
48
|
t = template.dup
|