asker-tool 2.1.6 → 2.2.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. checksums.yaml +4 -4
  2. data/{LICENSE.txt → LICENSE} +0 -0
  3. data/README.md +14 -15
  4. data/bin/asker +1 -1
  5. data/lib/asker/ai/ai.rb +6 -3
  6. data/lib/asker/ai/ai_calculate.rb +20 -6
  7. data/lib/asker/ai/concept_ai.rb +12 -3
  8. data/lib/asker/ai/question.rb +28 -6
  9. data/lib/asker/ai/stages/base_stage.rb +45 -6
  10. data/lib/asker/ai/stages/stage_b.rb +90 -49
  11. data/lib/asker/ai/stages/stage_d.rb +69 -90
  12. data/lib/asker/ai/stages/stage_f.rb +47 -38
  13. data/lib/asker/ai/stages/stage_i.rb +79 -92
  14. data/lib/asker/ai/stages/stage_s.rb +41 -36
  15. data/lib/asker/ai/stages/stage_t.rb +114 -73
  16. data/lib/asker/application.rb +7 -15
  17. data/lib/asker/check_input/input_data.rb +358 -0
  18. data/lib/asker/check_input.rb +51 -0
  19. data/lib/asker/cli.rb +28 -28
  20. data/lib/asker/data/code.rb +5 -16
  21. data/lib/asker/data/concept.rb +71 -24
  22. data/lib/asker/data/project_data.rb +63 -0
  23. data/lib/asker/data/table.rb +2 -0
  24. data/lib/asker/data/template.rb +3 -1
  25. data/lib/asker/data/world.rb +8 -16
  26. data/lib/asker/displayer/code_displayer.rb +7 -0
  27. data/lib/asker/displayer/concept_ai_displayer.erb +10 -0
  28. data/lib/asker/displayer/concept_ai_displayer.rb +24 -22
  29. data/lib/asker/displayer/concept_displayer.rb +9 -4
  30. data/lib/asker/displayer/stats_displayer.rb +8 -0
  31. data/lib/asker/exporter/concept_ai_gift_exporter.rb +16 -10
  32. data/lib/asker/exporter/concept_ai_moodle_exporter.rb +44 -0
  33. data/lib/asker/exporter/concept_ai_yaml_exporter.rb +6 -3
  34. data/lib/asker/exporter/concept_doc_exporter.rb +14 -1
  35. data/lib/asker/exporter/data_gift_exporter.rb +29 -0
  36. data/lib/asker/exporter/output_file_exporter.rb +9 -6
  37. data/lib/asker/files/{config.ini → asker.ini} +14 -4
  38. data/lib/asker/files/language/du/connectors.yaml +81 -0
  39. data/lib/asker/files/language/du/mistakes.yaml +82 -0
  40. data/lib/asker/files/language/du/templates.yaml +28 -49
  41. data/lib/asker/files/language/en/templates.yaml +19 -19
  42. data/lib/asker/files/language/es/mistakes.yaml +9 -7
  43. data/lib/asker/files/language/es/templates.yaml +19 -19
  44. data/lib/asker/files/language/fr/connectors.yaml +68 -84
  45. data/lib/asker/files/language/fr/templates.yaml +22 -22
  46. data/lib/asker/formatter/concept_doc_formatter.rb +0 -4
  47. data/lib/asker/formatter/concept_string_formatter.rb +7 -4
  48. data/lib/asker/formatter/moodle/matching.erb +38 -0
  49. data/lib/asker/formatter/moodle/multichoice.erb +49 -0
  50. data/lib/asker/formatter/moodle/shortanswer.erb +30 -0
  51. data/lib/asker/formatter/moodle/truefalse.erb +47 -0
  52. data/lib/asker/formatter/question_gift_formatter.rb +30 -20
  53. data/lib/asker/formatter/question_moodle_formatter.rb +27 -0
  54. data/lib/asker/lang/lang_factory.rb +7 -1
  55. data/lib/asker/loader/code_loader.rb +1 -1
  56. data/lib/asker/loader/content_loader.rb +12 -14
  57. data/lib/asker/loader/directory_loader.rb +1 -8
  58. data/lib/asker/loader/embedded_file.rb +42 -0
  59. data/lib/asker/loader/file_loader.rb +1 -3
  60. data/lib/asker/loader/image_url_loader.rb +8 -9
  61. data/lib/asker/loader/input_loader.rb +5 -6
  62. data/lib/asker/loader/project_loader.rb +18 -10
  63. data/lib/asker/logger.rb +35 -8
  64. data/lib/asker/skeleton.rb +3 -2
  65. data/lib/asker.rb +72 -43
  66. metadata +43 -17
  67. data/lib/asker/checker.rb +0 -455
  68. data/lib/asker/project.rb +0 -146
@@ -0,0 +1,358 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rainbow'
4
+
5
+ class InputData
6
+ attr_reader :inputs, :outputs
7
+
8
+ def initialize(filepath)
9
+ @inputs = File.read(filepath).split("\n")
10
+ @outputs = []
11
+ @inputs.each_with_index do |line, index|
12
+ output = { id: index,
13
+ level: 0,
14
+ state: :none,
15
+ type: :none,
16
+ source: line,
17
+ msg: '' }
18
+ @outputs << output
19
+ end
20
+ @ok = false
21
+ end
22
+
23
+ def ok?
24
+ @ok
25
+ end
26
+
27
+ def show
28
+ @outputs.each do |i|
29
+ puts "#{i[:id]}: #{i[:state]} [#{i[:type]}] #{i[:msg]}"
30
+ end
31
+ end
32
+
33
+ def show_errors
34
+ errors = 0
35
+ # puts "Line : Error description"
36
+ @outputs.each do |i|
37
+ next if i[:state] == :ok
38
+
39
+ errors += 1
40
+ if errors < 11
41
+ data = { id: i[:id], msg: i[:msg], source: i[:source][0, 40] }
42
+ order = i[:id] + 1
43
+ data = { order: order, msg: i[:msg], source: i[:source][0, 40] }
44
+ puts format(' %<order>03d : %<msg>s. => %<source>s', data)
45
+ end
46
+ puts '...' if errors == 11
47
+ end
48
+
49
+ if errors.positive?
50
+ puts Rainbow("[ERROR] #{errors} errors " \
51
+ "from #{@inputs.size} lines!").red.bright
52
+ end
53
+ puts Rainbow('Syntax OK!').green if errors.zero?
54
+ end
55
+
56
+ def check
57
+ @ok = true
58
+ @inputs.each_with_index do |line, index|
59
+ check_empty_lines(line, index)
60
+ check_map(line, index)
61
+ check_concept(line, index)
62
+ check_names(line, index)
63
+ check_tags(line, index)
64
+ check_def(line, index)
65
+ check_table(line, index)
66
+ check_row(line, index)
67
+ check_col(line, index)
68
+ check_template(line, index)
69
+ check_code(line, index)
70
+ check_type(line, index)
71
+ check_path(line, index)
72
+ check_features(line, index)
73
+ check_unknown(line, index)
74
+ @ok = false unless @outputs[index][:state] == :ok
75
+ @ok = false if @outputs[index][:type] == :unkown
76
+ end
77
+ @ok
78
+ end
79
+
80
+ private
81
+
82
+ def check_empty_lines(line, index)
83
+ return unless line.strip.size.zero? || line.start_with?('#')
84
+
85
+ @outputs[index][:type] = :empty
86
+ @outputs[index][:level] = -1
87
+ @outputs[index][:state] = :ok
88
+ end
89
+
90
+ def check_map(line, index)
91
+ if index.zero?
92
+ @outputs[index][:type] = :map
93
+ if line.start_with?('%map{')
94
+ @outputs[index][:state] = :ok
95
+ else
96
+ @outputs[index][:state] = :err
97
+ @outputs[index][:msg] = 'Start with %map{'
98
+ end
99
+ elsif index.positive? && line.include?('%map{')
100
+ @outputs[index][:state] = :err
101
+ @outputs[index][:type] = :map
102
+ @outputs[index][:msg] = 'Write %map on line 0'
103
+ end
104
+ end
105
+
106
+ def check_concept(line, index)
107
+ return unless @outputs[index][:state] == :none
108
+ return unless line.include? '%concept'
109
+
110
+ @outputs[index][:type] = :concept
111
+ @outputs[index][:level] = 1
112
+ @outputs[index][:state] = :ok
113
+ if find_parent(index) != :map
114
+ @outputs[index][:state] = :err
115
+ @outputs[index][:msg] = 'Parent(map) not found!'
116
+ elsif line != ' %concept'
117
+ @outputs[index][:state] = :err
118
+ @outputs[index][:msg] = 'Write 2 spaces before %concept'
119
+ end
120
+ end
121
+
122
+ def check_names(line, index)
123
+ return unless @outputs[index][:state] == :none
124
+ return unless line.include? '%names'
125
+
126
+ @outputs[index][:type] = :names
127
+ @outputs[index][:level] = 2
128
+ @outputs[index][:state] = :ok
129
+ if find_parent(index) != :concept
130
+ @outputs[index][:state] = :err
131
+ @outputs[index][:msg] = 'Parent(concept) not found!'
132
+ elsif !line.start_with? ' %names'
133
+ @outputs[index][:state] = :err
134
+ @outputs[index][:msg] = 'Write 4 spaces before %names'
135
+ end
136
+ end
137
+
138
+ def check_tags(line, index)
139
+ return unless @outputs[index][:state] == :none
140
+ return unless line.include? '%tags'
141
+
142
+ @outputs[index][:type] = :tags
143
+ @outputs[index][:level] = 2
144
+ @outputs[index][:state] = :ok
145
+ if find_parent(index) != :concept
146
+ @outputs[index][:state] = :err
147
+ @outputs[index][:msg] = 'Parent(concept) not found!'
148
+ elsif !line.start_with? ' %tags'
149
+ @outputs[index][:state] = :err
150
+ @outputs[index][:msg] = 'Write 4 spaces before %tags'
151
+ end
152
+ end
153
+
154
+ def check_def(line, index)
155
+ return unless @outputs[index][:state] == :none
156
+ return unless line.include? '%def'
157
+
158
+ @outputs[index][:type] = :def
159
+ @outputs[index][:level] = 2
160
+ @outputs[index][:state] = :ok
161
+ if find_parent(index) != :concept
162
+ @outputs[index][:state] = :err
163
+ @outputs[index][:msg] = 'Parent(concept) not found!'
164
+ elsif !line.start_with? ' %def'
165
+ @outputs[index][:state] = :err
166
+ @outputs[index][:msg] = 'Write 4 spaces before %def'
167
+ end
168
+ end
169
+
170
+ def check_table(line, index)
171
+ return unless @outputs[index][:state] == :none
172
+ return unless line.include? '%table'
173
+
174
+ @outputs[index][:type] = :table
175
+ @outputs[index][:level] = 2
176
+ @outputs[index][:state] = :ok
177
+ if find_parent(index) != :concept
178
+ @outputs[index][:state] = :err
179
+ @outputs[index][:msg] = 'Parent(concept) not found!'
180
+ elsif !line.start_with? ' %table'
181
+ @outputs[index][:state] = :err
182
+ @outputs[index][:msg] = 'Write 4 spaces before %table'
183
+ end
184
+ end
185
+
186
+ def check_row(line, index)
187
+ return unless @outputs[index][:state] == :none
188
+ return unless line.include? '%row'
189
+
190
+ @outputs[index][:type] = :row
191
+ @outputs[index][:state] = :ok
192
+
193
+ case count_spaces(line)
194
+ when 6
195
+ @outputs[index][:level] = 3
196
+ parent = find_parent(index)
197
+ unless %i[table features].include? parent
198
+ @outputs[index][:state] = :err
199
+ @outputs[index][:msg] = 'Parent(table/features) not found!'
200
+ end
201
+ when 8
202
+ @outputs[index][:level] = 4
203
+ if find_parent(index) != :template
204
+ @outputs[index][:state] = :err
205
+ @outputs[index][:msg] = 'Parent(template) not found!'
206
+ end
207
+ else
208
+ @outputs[index][:state] = :err
209
+ @outputs[index][:msg] = 'Write 6 or 8 spaces before %row'
210
+ end
211
+ end
212
+
213
+ def check_col(line, index)
214
+ return unless @outputs[index][:state] == :none
215
+ return unless line.include? '%col'
216
+
217
+ @outputs[index][:type] = :col
218
+ @outputs[index][:state] = :ok
219
+ case count_spaces(line)
220
+ when 8
221
+ @outputs[index][:level] = 4
222
+ if find_parent(index) != :row
223
+ @outputs[index][:state] = :err
224
+ @outputs[index][:msg] = 'Parent(row) not found!'
225
+ end
226
+ when 10
227
+ @outputs[index][:level] = 5
228
+ if find_parent(index) != :row
229
+ @outputs[index][:state] = :err
230
+ @outputs[index][:msg] = 'Parent(row) not found!'
231
+ end
232
+ else
233
+ @outputs[index][:state] = :err
234
+ @outputs[index][:msg] = 'Write 8 or 10 spaces before %col'
235
+ end
236
+ check_text(line, index)
237
+ end
238
+
239
+ def check_text(line, index)
240
+ return unless @outputs[index][:state] == :ok
241
+
242
+ ok = ''
243
+ %w[< >].each do |char|
244
+ ok = char if line.include? char
245
+ end
246
+ return if ok == ''
247
+
248
+ @outputs[index][:state] = :err
249
+ @outputs[index][:msg] = "Char #{ok} not allow!"
250
+ end
251
+
252
+ def check_template(line, index)
253
+ return unless @outputs[index][:state] == :none
254
+ return unless line.include? '%template'
255
+
256
+ @outputs[index][:type] = :template
257
+ @outputs[index][:level] = 3
258
+ @outputs[index][:state] = :ok
259
+ if find_parent(index) != :table
260
+ @outputs[index][:state] = :err
261
+ @outputs[index][:msg] = 'Parent(concept) not found!'
262
+ elsif !line.start_with? ' %template'
263
+ @outputs[index][:state] = :err
264
+ @outputs[index][:msg] = 'Write 6 spaces before %template'
265
+ end
266
+ end
267
+
268
+ def check_code(line, index)
269
+ return unless @outputs[index][:state] == :none
270
+ return unless line.include? '%code'
271
+
272
+ @outputs[index][:type] = :code
273
+ @outputs[index][:level] = 1
274
+ @outputs[index][:state] = :ok
275
+ if find_parent(index) != :map
276
+ @outputs[index][:state] = :err
277
+ @outputs[index][:msg] = 'Parent(map) not found!'
278
+ elsif line != ' %code'
279
+ @outputs[index][:state] = :err
280
+ @outputs[index][:msg] = 'Write 2 spaces before %code'
281
+ end
282
+ end
283
+
284
+ def check_type(line, index)
285
+ return unless @outputs[index][:state] == :none
286
+ return unless line.include? '%type'
287
+
288
+ @outputs[index][:type] = :type
289
+ @outputs[index][:level] = 2
290
+ @outputs[index][:state] = :ok
291
+ if find_parent(index) != :code
292
+ @outputs[index][:state] = :err
293
+ @outputs[index][:msg] = 'Parent(code) not found!'
294
+ elsif !line.start_with? ' %type'
295
+ @outputs[index][:state] = :err
296
+ @outputs[index][:msg] = 'Write 4 spaces before %type'
297
+ end
298
+ end
299
+
300
+ def check_path(line, index)
301
+ return unless @outputs[index][:state] == :none
302
+ return unless line.include? '%path'
303
+
304
+ @outputs[index][:type] = :path
305
+ @outputs[index][:level] = 2
306
+ @outputs[index][:state] = :ok
307
+ if find_parent(index) != :code
308
+ @outputs[index][:state] = :err
309
+ @outputs[index][:msg] = 'Parent(code) not found!'
310
+ elsif !line.start_with? ' %path'
311
+ @outputs[index][:state] = :err
312
+ @outputs[index][:msg] = 'Write 4 spaces before %type'
313
+ end
314
+ end
315
+
316
+ def check_features(line, index)
317
+ return unless @outputs[index][:state] == :none
318
+ return unless line.include? '%features'
319
+
320
+ @outputs[index][:type] = :features
321
+ @outputs[index][:level] = 2
322
+ @outputs[index][:state] = :ok
323
+ if find_parent(index) != :code
324
+ @outputs[index][:state] = :err
325
+ @outputs[index][:msg] = 'Parent(code) not found!'
326
+ elsif !line.start_with? ' %features'
327
+ @outputs[index][:state] = :err
328
+ @outputs[index][:msg] = 'Write 4 spaces before %features'
329
+ end
330
+ end
331
+
332
+ def check_unknown(line, index)
333
+ return unless @outputs[index][:state] == :none
334
+
335
+ @outputs[index][:type] = :unknown
336
+ @outputs[index][:level] = count_spaces(line) / 2
337
+ @outputs[index][:state] = :err
338
+ @outputs[index][:msg] = "Unknown tag with parent(#{find_parent(index)})!"
339
+ end
340
+
341
+ def find_parent(index)
342
+ current_level = @outputs[index][:level]
343
+ return :noparent if current_level.zero?
344
+
345
+ i = index - 1
346
+ while i >= 0
347
+ return @outputs[i][:type] if @outputs[i][:level] == current_level - 1
348
+
349
+ i -= 1
350
+ end
351
+ :noparent
352
+ end
353
+
354
+ def count_spaces(line)
355
+ a = line.split('%')
356
+ a[0].count(' ')
357
+ end
358
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rainbow'
4
+ require_relative 'check_input/input_data'
5
+
6
+ class CheckInput
7
+ def initialize(verbose = true)
8
+ @verbose = verbose
9
+ end
10
+
11
+ def file(filepath)
12
+ @filepath = filepath
13
+ self
14
+ end
15
+
16
+ def verbose(verbose)
17
+ @verbose = verbose
18
+ self
19
+ end
20
+
21
+ def check
22
+ # Check HAML file syntax
23
+ exist = check_file_exist
24
+ return false unless exist
25
+ check_file_content
26
+ end
27
+
28
+ private
29
+
30
+ def check_file_exist
31
+ if @filepath.nil?
32
+ raise Rainbow("Can't check nil filename")
33
+ end
34
+ unless File.exist? @filepath
35
+ puts Rainbow('File not found!').red.bright if @verbose
36
+ return false
37
+ end
38
+ unless File.extname(@filepath) == '.haml'
39
+ puts Rainbow('Only check HAML files!').yellow.bright if @verbose
40
+ return false
41
+ end
42
+ true
43
+ end
44
+
45
+ def check_file_content
46
+ data = InputData.new(@filepath)
47
+ data.check
48
+ data.show_errors if @verbose
49
+ data.ok?
50
+ end
51
+ end
data/lib/asker/cli.rb CHANGED
@@ -8,46 +8,38 @@ require_relative '../asker'
8
8
  ##
9
9
  # Command Line User Interface
10
10
  class CLI < Thor
11
- map ['h', '-h', '--help'] => 'help'
11
+ map ['--help'] => 'help'
12
12
 
13
- map ['v', '-v', '--version'] => 'version'
13
+ map ['--version'] => 'version'
14
14
  desc 'version', 'Show the program version'
15
- ##
16
- # Show current version
17
15
  def version
18
- print Rainbow(Application::NAME).bright.blue
19
- puts " (version #{Rainbow(Application::VERSION).green})"
16
+ puts "#{Application::NAME} version #{Application::VERSION}"
20
17
  end
21
18
 
22
19
  map ['f', '-f', '--file'] => 'file'
23
- desc 'file NAME', 'Build output files, from HAML/XML input file.'
20
+ desc '[file] FILEPATH', 'Build output files, from HAML/XML input file.'
24
21
  long_desc <<-LONGDESC
25
- Create output files, from input file (HAML/XML format).
26
22
 
27
23
  Build questions about contents defined into input file specified.
28
24
 
25
+ Create output files, from input file (HAML/XML format).
26
+
29
27
  Examples:
30
28
 
31
- (1) #{Rainbow('asker input/foo/foo.haml').yellow}, Build questions from HAML file.
29
+ (1) #{Rainbow('asker input/foo/foo.haml').aqua}, Build questions from HAML file.
32
30
 
33
- (2) #{Rainbow('asker input/foo/foo.xml').yellow}, Build questions from XML file.
31
+ (2) #{Rainbow('asker input/foo/foo.xml').aqua}, Build questions from XML file.
34
32
 
35
- (3) #{Rainbow('asker projects/foo/foo.yaml').yellow}, Build questions from YAML project file.
33
+ (3) #{Rainbow('asker projects/foo/foo.yaml').aqua}, Build questions from YAML project file.
36
34
 
37
35
  LONGDESC
38
- ##
39
- # Create questions from input file
40
- # @param filename (String) Path to input file
41
36
  def file(filename)
42
37
  # Asker start processing input file
43
38
  Asker.start(filename)
44
39
  end
45
40
 
46
- map ['c', '-c', '--check'] => 'check'
47
- desc 'check', 'Check input HAML file syntax'
48
- ##
49
- # Check input file syntax
50
- # @param filename (String) Path to input file
41
+ map ['--check'] => 'check'
42
+ desc 'check FILEPATH', 'Check input HAML file syntax'
51
43
  def check(filename)
52
44
  # Enable/disable color output
53
45
  Rainbow.enabled = false if options['color'] == false
@@ -55,21 +47,19 @@ class CLI < Thor
55
47
  Asker.check(filename)
56
48
  end
57
49
 
58
- map ['i', '-i', '--init'] => 'init'
59
- desc 'init', 'Create default INI config fie'
60
- ##
61
- # Create default INI config file
50
+ map ['--init'] => 'init'
51
+ desc 'init', 'Create default INI config file'
62
52
  def init
63
- Asker.create_configuration
53
+ Asker.init
64
54
  end
65
55
 
66
- map ['n', '-b', '--new', 'new'] => 'create_input'
67
- desc 'new', 'Create Asker demo input files'
56
+ map ['new','--new'] => 'new_input'
57
+ desc 'new DIRPATH', 'Create Asker demo input files'
68
58
  ##
69
59
  # Create Asker demo input files
70
60
  # @param dirname (String) Path to folder
71
- def create_input(dirname)
72
- Asker.create_input(dirname)
61
+ def new_input(dirname)
62
+ Asker.new_input(dirname)
73
63
  end
74
64
 
75
65
  ##
@@ -79,4 +69,14 @@ class CLI < Thor
79
69
  def method_missing(method, *_args, &_block)
80
70
  file(method.to_s)
81
71
  end
72
+
73
+ def respond_to_missing?(_method_name)
74
+ true
75
+ end
76
+
77
+ ##
78
+ # Thor stop and show messages on screen on failure
79
+ def self.exit_on_failure?
80
+ true
81
+ end
82
82
  end
@@ -1,20 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative '../ai/code/code_ai_factory'
2
- require_relative '../project'
3
- require_relative '../logger'
4
- require_relative '../formatter/code_string_formatter'
5
4
 
6
- ##
7
- # Code data object
8
5
  class Code
9
6
  attr_reader :dirname, :filename, :type
10
7
  attr_accessor :process, :features
11
8
  attr_reader :lines, :questions
12
9
 
13
- ##
14
- # Initialize Code object
15
- # @param dirname (String)
16
- # @param filename (String)
17
- # @param type (String)
18
10
  def initialize(dirname, filename, type)
19
11
  @dirname = dirname
20
12
  @filename = filename
@@ -38,16 +30,13 @@ class Code
38
30
  out
39
31
  end
40
32
 
41
- def debug
42
- Logger.verbose CodeStringFormatter.to_s(self)
43
- end
44
-
45
33
  private
46
34
 
47
35
  def load(filepath)
48
36
  return if filepath.nil?
37
+
49
38
  unless File.exist? filepath
50
- Logger.verboseln Rainbow("[ERROR] Unkown file #{filepath}").red.bright
39
+ puts Rainbow("[ERROR] Unkown file #{filepath}").red.bright
51
40
  return
52
41
  end
53
42
  content = File.read(filepath)
@@ -56,7 +45,7 @@ class Code
56
45
 
57
46
  def encode_and_split(text, encoding = :default)
58
47
  # Convert text to UTF-8 deleting unknown chars
59
- text = text || '' # Ensure text is not nil
48
+ text ||= '' # Ensure text is not nil
60
49
  flag = [:default, 'UTF-8'].include? encoding
61
50
  return text.encode('UTF-8', invalid: :replace).split("\n") if flag
62
51