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.
Files changed (130) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +18 -19
  3. data/bin/asker +2 -1
  4. data/lib/asker/ai/ai.rb +10 -3
  5. data/lib/asker/ai/ai_calculate.rb +20 -6
  6. data/lib/asker/ai/code/base_code_ai.rb +104 -0
  7. data/lib/asker/{code/ai → ai/code}/code_ai_factory.rb +11 -1
  8. data/lib/asker/{code/ai → ai/code}/javascript_code_ai.rb +2 -5
  9. data/lib/asker/ai/code/problem_code_ai.rb +176 -0
  10. data/lib/asker/{code/ai → ai/code}/python_code_ai.rb +2 -5
  11. data/lib/asker/{code/ai → ai/code}/ruby_code_ai.rb +14 -7
  12. data/lib/asker/{code/ai → ai/code}/sql_code_ai.rb +2 -5
  13. data/lib/asker/ai/concept_ai.rb +12 -2
  14. data/lib/asker/ai/question.rb +28 -6
  15. data/lib/asker/ai/stages/base_stage.rb +45 -6
  16. data/lib/asker/ai/stages/stage_b.rb +100 -50
  17. data/lib/asker/ai/stages/stage_d.rb +75 -90
  18. data/lib/asker/ai/stages/stage_f.rb +64 -36
  19. data/lib/asker/ai/stages/stage_i.rb +79 -92
  20. data/lib/asker/ai/stages/stage_s.rb +41 -36
  21. data/lib/asker/ai/stages/stage_t.rb +149 -108
  22. data/lib/asker/application.rb +24 -7
  23. data/lib/asker/checker.rb +149 -52
  24. data/lib/asker/cli.rb +37 -32
  25. data/lib/asker/data/code.rb +76 -0
  26. data/lib/asker/data/column.rb +31 -21
  27. data/lib/asker/data/concept.rb +108 -65
  28. data/lib/asker/data/data_field.rb +14 -0
  29. data/lib/asker/data/row.rb +75 -52
  30. data/lib/asker/data/table.rb +91 -42
  31. data/lib/asker/data/template.rb +3 -1
  32. data/lib/asker/data/world.rb +61 -32
  33. data/lib/asker/{exporter/code_screen_exporter.rb → displayer/code_displayer.rb} +13 -6
  34. data/lib/asker/displayer/concept_ai_displayer.erb +10 -0
  35. data/lib/asker/displayer/concept_ai_displayer.rb +133 -0
  36. data/lib/asker/displayer/concept_displayer.rb +34 -0
  37. data/lib/asker/displayer/stats_displayer.rb +22 -0
  38. data/lib/asker/exporter/code_gift_exporter.rb +10 -11
  39. data/lib/asker/exporter/concept_ai_gift_exporter.rb +21 -13
  40. data/lib/asker/exporter/concept_ai_moodle_exporter.rb +44 -0
  41. data/lib/asker/exporter/concept_ai_yaml_exporter.rb +14 -9
  42. data/lib/asker/exporter/concept_doc_exporter.rb +21 -14
  43. data/lib/asker/exporter/data_gift_exporter.rb +29 -0
  44. data/lib/asker/exporter/output_file_exporter.rb +21 -0
  45. data/lib/asker/files/{config.ini → asker.ini} +48 -1
  46. data/lib/asker/files/example-concept.haml +24 -8
  47. data/lib/asker/files/language/du/connectors.yaml +81 -0
  48. data/lib/asker/files/language/du/mistakes.yaml +82 -0
  49. data/lib/asker/files/language/du/templates.yaml +29 -0
  50. data/lib/asker/files/language/en/connectors.yaml +44 -0
  51. data/lib/asker/files/language/en/mistakes.yaml +37 -0
  52. data/lib/asker/files/language/en/templates.yaml +29 -0
  53. data/lib/asker/files/language/es/connectors.yaml +92 -0
  54. data/lib/asker/files/language/es/mistakes.yaml +84 -0
  55. data/lib/asker/files/language/es/templates.yaml +29 -0
  56. data/lib/asker/files/language/fr/connectors.yaml +76 -0
  57. data/lib/asker/files/language/fr/mistakes.yaml +82 -0
  58. data/lib/asker/files/language/fr/templates.yaml +29 -0
  59. data/lib/asker/files/language/javascript/connectors.yaml +11 -0
  60. data/lib/asker/files/language/javascript/mistakes.yaml +30 -0
  61. data/lib/asker/files/language/javascript/templates.yaml +3 -0
  62. data/lib/asker/files/language/math/connectors.yaml +2 -0
  63. data/lib/asker/files/language/math/mistakes.yaml +2 -0
  64. data/lib/asker/files/language/math/templates.yaml +1 -0
  65. data/lib/asker/files/language/python/connectors.yaml +11 -0
  66. data/lib/asker/files/language/python/mistakes.yaml +26 -0
  67. data/lib/asker/files/language/python/templates.yaml +3 -0
  68. data/lib/asker/files/language/ruby/connectors.yaml +11 -0
  69. data/lib/asker/files/language/ruby/mistakes.yaml +33 -0
  70. data/lib/asker/files/language/ruby/templates.yaml +3 -0
  71. data/lib/asker/files/language/sql/connectors.yaml +6 -0
  72. data/lib/asker/files/language/sql/mistakes.yaml +11 -0
  73. data/lib/asker/files/language/sql/templates.yaml +2 -0
  74. data/lib/asker/formatter/concept_string_formatter.rb +13 -9
  75. data/lib/asker/formatter/moodle/matching.erb +38 -0
  76. data/lib/asker/formatter/moodle/multichoice.erb +49 -0
  77. data/lib/asker/formatter/moodle/shortanswer.erb +30 -0
  78. data/lib/asker/formatter/moodle/truefalse.erb +47 -0
  79. data/lib/asker/formatter/question_gift_formatter.rb +30 -20
  80. data/lib/asker/formatter/question_moodle_formatter.rb +27 -0
  81. data/lib/asker/lang/lang.rb +18 -12
  82. data/lib/asker/lang/lang_factory.rb +32 -5
  83. data/lib/asker/lang/text_actions.rb +87 -69
  84. data/lib/asker/loader/code_loader.rb +4 -4
  85. data/lib/asker/loader/content_loader.rb +16 -12
  86. data/lib/asker/loader/directory_loader.rb +3 -3
  87. data/lib/asker/loader/embedded_file.rb +42 -0
  88. data/lib/asker/loader/file_loader.rb +3 -12
  89. data/lib/asker/loader/haml_loader.rb +15 -0
  90. data/lib/asker/loader/image_url_loader.rb +9 -11
  91. data/lib/asker/loader/input_loader.rb +24 -8
  92. data/lib/asker/loader/project_loader.rb +42 -30
  93. data/lib/asker/logger.rb +30 -6
  94. data/lib/asker/project.rb +28 -117
  95. data/lib/asker/skeleton.rb +40 -29
  96. data/lib/asker.rb +68 -79
  97. metadata +57 -74
  98. data/docs/changelog/v2.1.md +0 -99
  99. data/docs/commands.md +0 -12
  100. data/docs/contributions.md +0 -18
  101. data/docs/history.md +0 -40
  102. data/docs/idea.md +0 -44
  103. data/docs/inputs/README.md +0 -39
  104. data/docs/inputs/code.md +0 -69
  105. data/docs/inputs/concepts.md +0 -142
  106. data/docs/inputs/jedi.md +0 -68
  107. data/docs/inputs/tables.md +0 -112
  108. data/docs/inputs/templates.md +0 -87
  109. data/docs/install/README.md +0 -38
  110. data/docs/install/manual.md +0 -26
  111. data/docs/install/scripts.md +0 -38
  112. data/docs/revise/asker-file.md +0 -41
  113. data/docs/revise/buenas-practicas/01-convocatoria.md +0 -30
  114. data/docs/revise/buenas-practicas/02-formulario.md +0 -35
  115. data/docs/revise/buenas-practicas/03-descripcion.md +0 -63
  116. data/docs/revise/buenas-practicas/04-resultados.md +0 -17
  117. data/docs/revise/buenas-practicas/05-reproducir.md +0 -10
  118. data/docs/revise/ejemplos/01/README.md +0 -27
  119. data/docs/revise/ejemplos/02/README.md +0 -31
  120. data/docs/revise/ejemplos/03/README.md +0 -31
  121. data/docs/revise/ejemplos/04/README.md +0 -37
  122. data/docs/revise/ejemplos/05/README.md +0 -25
  123. data/docs/revise/ejemplos/06/README.md +0 -43
  124. data/docs/revise/ejemplos/README.md +0 -11
  125. data/docs/revise/projects.md +0 -74
  126. data/lib/asker/code/ai/base_code_ai.rb +0 -48
  127. data/lib/asker/code/code.rb +0 -53
  128. data/lib/asker/exporter/concept_ai_screen_exporter.rb +0 -115
  129. data/lib/asker/exporter/concept_screen_exporter.rb +0 -25
  130. data/lib/asker/exporter/main.rb +0 -9
@@ -3,20 +3,37 @@
3
3
  require 'rainbow'
4
4
  require 'rexml/document'
5
5
 
6
- require_relative '../project'
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, :lang, :context
14
- attr_reader :names, :type, :filename
15
- attr_reader :data
16
- attr_accessor :process
17
-
18
- @@id = 0
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] = [] # TODO: By now, We'll treat images separated from texts
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
- read_data_from_xml(xml_data)
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
- weights = Project.instance.formula_weights
96
+ a = Application.instance.config['ai']['formula_weights']
97
+ weights = a.split(',').map(&:to_f)
76
98
 
77
- li_max1 = @context.count
78
- li_max2 = @data[:tags].count
79
- li_max3 = @data[:tables].count
99
+ max1 = @context.count
100
+ max2 = @data[:tags].count
101
+ max3 = @data[:tables].count
80
102
 
81
- lf_alike1 = lf_alike2 = lf_alike3 = 0.0
103
+ alike1 = alike2 = alike3 = 0.0
82
104
 
83
105
  # 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? }
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
- 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)
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 { |i| reference_to += 1 unless other.names.index(i.downcase).nil? }
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
- if reference_to.positive?
103
- @data[:reference_to] << other.name
104
- other.data[:referenced_by] << name
105
- end
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 method_missing(method)
109
- @data[method]
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] <#{i.name}> unkown XML attribute for concept #{name}"
134
- msg = Rainbow(text).color(:red)
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
- raise '[Error] tags label empty!' if value.text.nil? || value.text.size.zero?
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
- 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
-
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 'textfile_path'
178
- @data[:textfile_paths] << value.text.strip
179
- else
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
@@ -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
- def initialize( table, index, xml_data )
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 + "." + @index.to_s
20
+ @id = "#{@table.id}.#{@index}"
13
21
  @langs = @table.langs
14
22
  @types = @table.types
15
23
  @raws = []
16
24
  @columns = []
17
- @simple = { :lang => true, :type => true }
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(pXMLdata)
29
- if pXMLdata.elements.count==0 then
30
- build_row_with_1_column(pXMLdata)
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
- build_row_with_N_columns(pXMLdata)
40
+ build_row_with_n_columns(xml_data)
33
41
  end
34
42
 
35
- raise "[ERROR] Row: #{pXMLdata}" if @columns.size!=@table.fields.size
43
+ raise "[ERROR] Row: #{xml_data}" unless @columns.size == @table.fields.size
36
44
  end
37
45
 
38
- def build_row_with_1_column(pXMLdata)
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 = [ Column.new( self, @raws.size, pXMLdata) ]
42
- @raws = [ pXMLdata.text.strip.to_s ]
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
- if pXMLdata.attributes['type'] then
55
- type = pXMLdata.attributes['type'].strip
56
- if type != @types[0] then
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 build_row_with_N_columns(pXMLdata)
65
- pXMLdata.elements.each do |i|
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
- j = i.text.split(",")
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
- j = i.text.split(",")
79
- if j.join(",")!=@types.join(",") then
80
- @types = []
81
- j.each { |k| @types << k.strip.to_s }
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
@@ -1,4 +1,4 @@
1
- # encoding: utf-8
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, :langs, :types, :sequence
10
- attr_reader :datarows, :rows
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
- # read attributes from XML data
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
- @name = ''
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 { |r| r.raws }
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 > 0
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
- j = i.text.split(',')
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
- j = i.text.split(',')
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
@@ -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