asker-tool 2.7.1 → 2.8.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 (34) hide show
  1. checksums.yaml +4 -4
  2. data/lib/asker/ai/problem/customizer.rb +36 -0
  3. data/lib/asker/ai/problem/problem_ai.rb +9 -213
  4. data/lib/asker/ai/problem/stage_answers.rb +104 -0
  5. data/lib/asker/ai/problem/stage_base.rb +34 -0
  6. data/lib/asker/ai/problem/stage_steps.rb +121 -0
  7. data/lib/asker/application.rb +1 -0
  8. data/lib/asker/check_input/check_haml_data.rb +136 -0
  9. data/lib/asker/check_input.rb +15 -10
  10. data/lib/asker/cli.rb +2 -0
  11. data/lib/asker/data/concept.rb +3 -3
  12. data/lib/asker/data/problem.rb +10 -2
  13. data/lib/asker/data/project_data.rb +2 -1
  14. data/lib/asker/displayer/code_displayer.rb +2 -2
  15. data/lib/asker/displayer/concept_ai_displayer.rb +5 -3
  16. data/lib/asker/displayer/concept_displayer.rb +2 -2
  17. data/lib/asker/displayer/problem_displayer.rb +14 -7
  18. data/lib/asker/displayer/stats_displayer.rb +3 -3
  19. data/lib/asker/files/language/ca/templates.yaml +1 -0
  20. data/lib/asker/files/language/du/templates.yaml +1 -0
  21. data/lib/asker/files/language/en/templates.yaml +1 -0
  22. data/lib/asker/files/language/es/templates.yaml +1 -0
  23. data/lib/asker/files/language/fr/templates.yaml +1 -0
  24. data/lib/asker/formatter/concept_string_formatter.rb +0 -1
  25. data/lib/asker/loader/content_loader.rb +10 -8
  26. data/lib/asker/loader/embedded_file/loader.rb +103 -0
  27. data/lib/asker/loader/embedded_file/type.rb +51 -0
  28. data/lib/asker/loader/file_loader.rb +2 -1
  29. data/lib/asker/loader/problem_loader.rb +2 -0
  30. data/lib/asker/logger.rb +7 -3
  31. data/lib/asker/start.rb +2 -2
  32. data/lib/asker/version.rb +1 -1
  33. metadata +8 -3
  34. data/lib/asker/loader/embedded_file.rb +0 -133
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0e5cbcd35b27392a56444a2bdae4036445ac8b7b8404c6601e006764fbe0dae8
4
- data.tar.gz: 04de6c0757edfba5abf31744d53844fd51f766c5287413d387c309fa3c95131e
3
+ metadata.gz: a70a91ae23f461cc6740e7938555a205ca50fa9f7b910a6af4e4d6b873ff3ba1
4
+ data.tar.gz: 79a7f6dccf7faea3bc97b7e21b2bc5680d52b887b0aaa3eef52a6c0302f9d5ed
5
5
  SHA512:
6
- metadata.gz: b0305dfd9e98c0f92cf05cf567f1ab71b2522db32f930865e623dadc84fa9601623269a095fe590e4d7be9cc77c842590fd03848ad961c9047be786bfae6c7d6
7
- data.tar.gz: 833a34e6159b81f68919944a9fbc412c6870634d3d5eb6614e23c470c9d1bea5d4bf4a2c57bc70c836b06a75ad914f411710200cc2bde8070e5c8d32f04cb745
6
+ metadata.gz: d87d28ecb0899a1f37fe791e0a08057e4b5dbba966202dc2111b339d34e4cc063a000b87436fa5e864320d366c245216123bffed9b9b7848c838a95fb3b9f845
7
+ data.tar.gz: 9fe5684a838726523be099358f604e5ed5838c083a1043577cb9e445cba32e733f89e0dc98c4fa2408f37bab1909f523211a20d5820dd9743565f0435a11df87
@@ -0,0 +1,36 @@
1
+ require_relative "../../logger"
2
+
3
+ class Customizer
4
+ def initialize(problem)
5
+ @problem = problem
6
+ end
7
+
8
+ def call(text:, custom:, type: nil)
9
+ output = text.clone
10
+ custom.each_pair { |oldvalue, newvalue| output.gsub!(oldvalue, newvalue) }
11
+
12
+ if type.nil?
13
+ return output
14
+ elsif type == "formula"
15
+ begin
16
+ return eval(output).to_s
17
+ rescue SyntaxError => e
18
+ Logger.error "Problem.name = #{@problem.name}"
19
+ Logger.error "Customizer: Wrong formula '#{text}' or wrong values '#{output}'"
20
+ Logger.error e.to_s
21
+ exit 1
22
+ end
23
+ else
24
+ Logger.error "Customizer: Wrong answer type (#{type})"
25
+ exit 1
26
+ end
27
+ end
28
+
29
+ def min(*args)
30
+ args.min
31
+ end
32
+
33
+ def max(*args)
34
+ args.max
35
+ end
36
+ end
@@ -1,226 +1,22 @@
1
1
  require_relative "../../lang/lang_factory"
2
2
  require_relative "../question"
3
+ require_relative "stage_answers"
4
+ require_relative "stage_steps"
3
5
 
4
6
  class ProblemAI
5
7
  attr_accessor :problem
6
8
 
7
9
  def call(problem)
8
10
  @problem = problem
9
- make_questions
10
- @problem
11
- end
12
-
13
- def make_questions
14
- @counter = 0
15
- @questions = []
16
- @customs = get_customs(@problem)
17
- make_questions_with_aswers
18
- make_questions_with_steps
19
- @problem.questions = @questions
20
- end
21
-
22
- private
23
-
24
- def counter
25
- @counter += 1
26
- end
27
-
28
- def customize(text:, custom:)
29
- output = text.clone
30
- custom.each_pair { |oldvalue, newvalue| output.gsub!(oldvalue, newvalue) }
31
- output
32
- end
33
-
34
- def get_customs(problem)
35
- customs = []
36
- vars = problem.varnames
37
- problem.cases.each do |acase|
38
- custom = {}
39
- vars.each_with_index { |varname, index| custom[varname] = acase[index] }
40
- customs << custom
41
- end
42
- customs
43
- end
44
-
45
- def lines_to_s(lines)
46
- output = ""
47
- lines.each_with_index do |line, index|
48
- output << "%2d: #{line}\n" % (index + 1)
49
- end
50
- output
51
- end
52
-
53
- def make_questions_with_aswers
54
- name = @problem.name
55
- lang = @problem.lang
56
-
57
- @customs.each do |custom|
58
- desc = customize(text: @problem.desc, custom: custom)
59
-
60
- @problem.asks.each do |ask|
61
- next if ask[:text].nil?
62
- asktext = customize(text: ask[:text], custom: custom)
63
- next if ask[:answer].nil?
64
- correct_answer = customize(text: ask[:answer], custom: custom)
65
11
 
66
- # Question boolean => true
67
- q = Question.new(:boolean)
68
- q.name = "#{name}-#{counter}-pa1true1"
69
- q.text = lang.text_for(:pa1, desc, asktext, correct_answer)
70
- q.good = "TRUE"
71
- @questions << q
12
+ questions = StageAnswers.new(@problem).make_questions
13
+ @problem.stats[:answer] = questions.size
14
+ @problem.questions = questions
72
15
 
73
- # Locate incorrect answers
74
- incorrect_answers = []
75
- @customs.each do |aux|
76
- next if aux == custom
77
- incorrect = customize(text: ask[:answer], custom: aux)
78
- incorrect_answers << incorrect if incorrect != correct_answer
79
- end
16
+ questions = StageSteps.new(@problem).make_questions
17
+ @problem.stats[:steps] = questions.size
18
+ @problem.questions += questions
80
19
 
81
- # Question boolean => true
82
- if incorrect_answers.size > 0
83
- q = Question.new(:boolean)
84
- q.name = "#{name}-#{counter}-pa2false2"
85
- q.text = lang.text_for(:pa1, desc, asktext, incorrect_answers.first)
86
- q.good = "FALSE"
87
- @questions << q
88
- end
89
-
90
- # Question choice NONE
91
- if incorrect_answers.size > 2
92
- q = Question.new(:choice)
93
- q.name = "#{name}-#{counter}-pa2-choice-none3"
94
- q.text = lang.text_for(:pa2, desc, asktext)
95
- q.good = lang.text_for(:none)
96
- incorrect_answers.shuffle!
97
- q.bads << incorrect_answers[0]
98
- q.bads << incorrect_answers[1]
99
- q.bads << incorrect_answers[2]
100
- q.feedback = "Correct answer is #{correct_answer}."
101
- @questions << q
102
- end
103
-
104
- # Question choice OK
105
- if incorrect_answers.size > 2
106
- q = Question.new(:choice)
107
- q.name = "#{name}-#{counter}-pa2choice4"
108
- q.text = lang.text_for(:pa2, desc, asktext)
109
- q.good = correct_answer
110
- incorrect_answers.shuffle!
111
- q.bads << incorrect_answers[0]
112
- q.bads << incorrect_answers[1]
113
- q.bads << incorrect_answers[2]
114
- q.feedback = "Correct answer is #{correct_answer}."
115
- @questions << q
116
- end
117
-
118
- if incorrect_answers.size > 1
119
- q = Question.new(:choice)
120
- q.name = "#{name}-#{counter}-pa2choice5"
121
- q.text = lang.text_for(:pa2, desc, asktext)
122
- q.good = correct_answer
123
- incorrect_answers.shuffle!
124
- q.bads << incorrect_answers[0]
125
- q.bads << incorrect_answers[1]
126
- q.bads << lang.text_for(:none)
127
- q.feedback = "Correct answer is #{correct_answer}."
128
- @questions << q
129
- end
130
-
131
- # Question short
132
- q = Question.new(:short)
133
- q.name = "#{name}-#{counter}-pa2short6"
134
- q.text = lang.text_for(:pa2, desc, asktext)
135
- q.shorts << correct_answer
136
- q.feedback = "Correct answer is #{correct_answer}."
137
- @questions << q
138
- end
139
- end
140
-
141
- def make_questions_with_steps
142
- name = @problem.name
143
- lang = @problem.lang
144
-
145
- @customs.each do |custom|
146
- desc = customize(text: @problem.desc, custom: custom)
147
-
148
- @problem.asks.each do |ask|
149
- next if ask[:text].nil?
150
- asktext = customize(text: ask[:text], custom: custom)
151
- next if ask[:steps].nil? || ask[:steps].empty?
152
- steps = ask[:steps].map { |step| customize(text: step, custom: custom) }
153
-
154
- # Question steps ok
155
- q = Question.new(:short)
156
- q.name = "#{name}-#{counter}-ps3short7"
157
- q.text = lang.text_for(:ps3, desc, asktext, lines_to_s(steps))
158
- q.shorts << 0
159
- @questions << q
160
-
161
- if steps.size > 3
162
- q = Question.new(:ordering)
163
- q.name = "#{name}-#{counter}-ps6ordering8"
164
- q.text = lang.text_for(:ps6, desc, asktext, lines_to_s(steps))
165
- steps.each { |step| q.ordering << step }
166
- @questions << q
167
- end
168
-
169
- # Using diferents wrong steps sequences
170
- max = steps.size - 1
171
- (0..max).each do |index|
172
- change = rand(max + 1)
173
- bads = steps.clone
174
-
175
- minor = index
176
- major = change
177
- if minor > major
178
- minor, major = major, minor
179
- elsif minor == major
180
- next
181
- end
182
- bads[minor], bads[major] = bads[major], bads[minor]
183
-
184
- # Question steps error
185
- q = Question.new(:short)
186
- q.name = "#{name}-#{counter}-ps3short-error9"
187
- q.text = lang.text_for(:ps3, desc, asktext, lines_to_s(bads))
188
- q.shorts << minor + 1
189
- q.feedback = lang.text_for(:ps4, minor + 1, major + 1)
190
- @questions << q
191
- end
192
-
193
- # Match questions
194
- indexes = (0..(steps.size - 1)).to_a.shuffle
195
- (0..(steps.size - 4)).each do |first|
196
- incomplete_steps = steps.clone
197
- incomplete_steps[indexes[first]] = "?"
198
- incomplete_steps[indexes[first + 1]] = "?"
199
- incomplete_steps[indexes[first + 2]] = "?"
200
- incomplete_steps[indexes[first + 3]] = "?"
201
-
202
- q = Question.new(:match)
203
- q.name = "#{name}-#{counter}-ps5match10"
204
- q.text = lang.text_for(:ps5, desc, asktext, lines_to_s(incomplete_steps))
205
- q.matching << [steps[indexes[first]], (indexes[first] + 1).to_s]
206
- q.matching << [steps[indexes[first + 1]], (indexes[first + 1] + 1).to_s]
207
- q.matching << [steps[indexes[first + 2]], (indexes[first + 2] + 1).to_s]
208
- q.matching << [steps[indexes[first + 3]], (indexes[first + 3] + 1).to_s]
209
- q.matching << ["", lang.text_for(:error)]
210
- @questions << q
211
-
212
- q = Question.new(:ddmatch)
213
- q.name = "#{name}-#{counter}-ps5ddmatch11"
214
- q.text = lang.text_for(:ps5, desc, asktext, lines_to_s(incomplete_steps))
215
- q.matching << [(indexes[first] + 1).to_s, steps[indexes[first]]]
216
- q.matching << [(indexes[first + 1] + 1).to_s, steps[indexes[first + 1]]]
217
- q.matching << [(indexes[first + 2] + 1).to_s, steps[indexes[first + 2]]]
218
- q.matching << [(indexes[first + 3] + 1).to_s, steps[indexes[first + 3]]]
219
- q.matching << ["", lang.text_for(:error)]
220
- @questions << q
221
- end
222
- end
223
- end
224
- end
20
+ @problem
225
21
  end
226
22
  end
@@ -0,0 +1,104 @@
1
+ require_relative "../question"
2
+ require_relative "stage_base"
3
+
4
+ class StageAnswers < StageBase
5
+ def make_questions
6
+ name = @problem.name
7
+ lang = @problem.lang
8
+ questions = []
9
+
10
+ @customs.each do |custom|
11
+ desc = customize(text: @problem.desc, custom: custom)
12
+
13
+ @problem.asks.each do |ask|
14
+ next if ask[:text].nil?
15
+ asktext = customize(text: ask[:text], custom: custom)
16
+ next if ask[:answer].nil?
17
+
18
+ correct_answer = customize(
19
+ text: ask[:answer],
20
+ custom: custom,
21
+ type: ask[:answer_type]
22
+ )
23
+
24
+ # Question boolean => true
25
+ q = Question.new(:boolean)
26
+ q.name = "#{name}-#{counter}-01pa1true"
27
+ q.text = lang.text_for(:pa1, desc, asktext, correct_answer)
28
+ q.good = "TRUE"
29
+ questions << q
30
+
31
+ # Locate incorrect answers
32
+ incorrect_answers = []
33
+ @customs.each do |aux|
34
+ next if aux == custom
35
+ incorrect = customize(
36
+ text: ask[:answer],
37
+ custom: aux,
38
+ type: ask[:answer_type]
39
+ )
40
+ incorrect_answers << incorrect if incorrect != correct_answer
41
+ end
42
+
43
+ # Question boolean => true
44
+ if incorrect_answers.size > 0
45
+ q = Question.new(:boolean)
46
+ q.name = "#{name}-#{counter}-02pa1false"
47
+ q.text = lang.text_for(:pa1, desc, asktext, incorrect_answers.first)
48
+ q.good = "FALSE"
49
+ questions << q
50
+ end
51
+
52
+ # Question choice NONE
53
+ if incorrect_answers.size > 2
54
+ q = Question.new(:choice)
55
+ q.name = "#{name}-#{counter}-03pa2-choice-none"
56
+ q.text = lang.text_for(:pa2, desc, asktext)
57
+ q.good = lang.text_for(:none)
58
+ incorrect_answers.shuffle!
59
+ q.bads << incorrect_answers[0]
60
+ q.bads << incorrect_answers[1]
61
+ q.bads << incorrect_answers[2]
62
+ q.feedback = "Correct answer is #{correct_answer}."
63
+ questions << q
64
+ end
65
+
66
+ # Question choice OK
67
+ if incorrect_answers.size > 2
68
+ q = Question.new(:choice)
69
+ q.name = "#{name}-#{counter}-04pa2choice"
70
+ q.text = lang.text_for(:pa2, desc, asktext)
71
+ q.good = correct_answer
72
+ incorrect_answers.shuffle!
73
+ q.bads << incorrect_answers[0]
74
+ q.bads << incorrect_answers[1]
75
+ q.bads << incorrect_answers[2]
76
+ q.feedback = "Correct answer is #{correct_answer}."
77
+ questions << q
78
+ end
79
+
80
+ if incorrect_answers.size > 1
81
+ q = Question.new(:choice)
82
+ q.name = "#{name}-#{counter}-05pa2choice"
83
+ q.text = lang.text_for(:pa2, desc, asktext)
84
+ q.good = correct_answer
85
+ incorrect_answers.shuffle!
86
+ q.bads << incorrect_answers[0]
87
+ q.bads << incorrect_answers[1]
88
+ q.bads << lang.text_for(:none)
89
+ q.feedback = "Correct answer is #{correct_answer}."
90
+ questions << q
91
+ end
92
+
93
+ # Question short
94
+ q = Question.new(:short)
95
+ q.name = "#{name}-#{counter}-06pa2short"
96
+ q.text = lang.text_for(:pa2, desc, asktext)
97
+ q.shorts << correct_answer
98
+ q.feedback = "Correct answer is #{correct_answer}."
99
+ questions << q
100
+ end
101
+ end
102
+ questions
103
+ end
104
+ end
@@ -0,0 +1,34 @@
1
+ require_relative "../../logger"
2
+ require_relative "customizer"
3
+
4
+ class StageBase
5
+ def initialize(problem)
6
+ @problem = problem
7
+ @customs = get_customs(@problem)
8
+ @customizer = Customizer.new(@problem)
9
+ @counter = @problem.questions.size
10
+ end
11
+
12
+ def counter
13
+ @counter += 1
14
+ end
15
+
16
+ def customize(...)
17
+ @customizer.call(...)
18
+ end
19
+
20
+ private
21
+
22
+ def get_customs(problem)
23
+ return [] if problem.cases.nil?
24
+
25
+ customs = []
26
+ vars = problem.varnames
27
+ problem.cases.each do |acase|
28
+ custom = {}
29
+ vars.each_with_index { |varname, index| custom[varname] = acase[index] }
30
+ customs << custom
31
+ end
32
+ customs
33
+ end
34
+ end
@@ -0,0 +1,121 @@
1
+ require_relative "../question"
2
+ require_relative "stage_base"
3
+
4
+ class StageSteps < StageBase
5
+ def make_questions
6
+ name = @problem.name
7
+ lang = @problem.lang
8
+ questions = []
9
+
10
+ @customs.each do |custom|
11
+ desc = customize(text: @problem.desc, custom: custom)
12
+
13
+ @problem.asks.each do |ask|
14
+ next if ask[:text].nil?
15
+ asktext = customize(text: ask[:text], custom: custom)
16
+ next if ask[:steps].nil? || ask[:steps].empty?
17
+ steps = ask[:steps].map { |step| customize(text: step, custom: custom) }
18
+
19
+ # Question steps ok
20
+ q = Question.new(:short)
21
+ q.name = "#{name}-#{counter}-07ps3short-ok"
22
+ q.text = lang.text_for(:ps3, desc, asktext, lines_to_s(steps))
23
+ q.shorts << 0
24
+ questions << q
25
+
26
+ # Question steps ordering
27
+ if steps.size > 3
28
+ q = Question.new(:ordering)
29
+ q.name = "#{name}-#{counter}-08ps6ordering"
30
+ q.text = lang.text_for(:ps6, desc, asktext, lines_to_s(steps))
31
+ steps.each { |step| q.ordering << step }
32
+ questions << q
33
+ end
34
+
35
+ # Question steps hide
36
+ if steps.size > 3
37
+ (0...(steps.size)).each do |index|
38
+ q = Question.new(:short)
39
+ q.name = "#{name}-#{counter}-09ps7short-hide"
40
+ hide_steps = steps.clone
41
+ hide_steps[index] = hide(steps[index])
42
+ q.text = lang.text_for(:ps7, desc, asktext, lines_to_s(hide_steps))
43
+ q.shorts << steps[index]
44
+ questions << q
45
+ end
46
+ end
47
+
48
+ # Using diferents wrong steps sequences
49
+ indexes = (0...(steps.size)).to_a
50
+ combinations = indexes.combination(2).to_a
51
+
52
+ combinations.each do |minor, major|
53
+ bads = steps.clone
54
+ bads[minor], bads[major] = bads[major], bads[minor]
55
+
56
+ # Question steps error
57
+ q = Question.new(:short)
58
+ q.name = "#{name}-#{counter}-10ps3short-error"
59
+ q.text = lang.text_for(:ps3, desc, asktext, lines_to_s(bads))
60
+ q.shorts << minor + 1
61
+ q.feedback = lang.text_for(:ps4, minor + 1, major + 1)
62
+ questions << q
63
+ end
64
+
65
+ # Match questions
66
+ indexes = (0..(steps.size - 1)).to_a.shuffle
67
+ (0..(steps.size - 4)).each do |first|
68
+ incomplete_steps = steps.clone
69
+ incomplete_steps[indexes[first]] = "?"
70
+ incomplete_steps[indexes[first + 1]] = "?"
71
+ incomplete_steps[indexes[first + 2]] = "?"
72
+ incomplete_steps[indexes[first + 3]] = "?"
73
+
74
+ q = Question.new(:match)
75
+ q.name = "#{name}-#{counter}-11ps5match"
76
+ q.text = lang.text_for(:ps5, desc, asktext, lines_to_s(incomplete_steps))
77
+ q.matching << [steps[indexes[first]], (indexes[first] + 1).to_s]
78
+ q.matching << [steps[indexes[first + 1]], (indexes[first + 1] + 1).to_s]
79
+ q.matching << [steps[indexes[first + 2]], (indexes[first + 2] + 1).to_s]
80
+ q.matching << [steps[indexes[first + 3]], (indexes[first + 3] + 1).to_s]
81
+ q.matching << ["", lang.text_for(:error)]
82
+ questions << q
83
+
84
+ q = Question.new(:ddmatch)
85
+ q.name = "#{name}-#{counter}-12ps5ddmatch"
86
+ q.text = lang.text_for(:ps5, desc, asktext, lines_to_s(incomplete_steps))
87
+ q.matching << [(indexes[first] + 1).to_s, steps[indexes[first]]]
88
+ q.matching << [(indexes[first + 1] + 1).to_s, steps[indexes[first + 1]]]
89
+ q.matching << [(indexes[first + 2] + 1).to_s, steps[indexes[first + 2]]]
90
+ q.matching << [(indexes[first + 3] + 1).to_s, steps[indexes[first + 3]]]
91
+ q.matching << ["", lang.text_for(:error)]
92
+ questions << q
93
+ end
94
+ end
95
+ end
96
+ questions
97
+ end
98
+
99
+ private
100
+
101
+ def hide(text)
102
+ output = []
103
+ text.chars do |c|
104
+ output << if c == " "
105
+ c
106
+ else
107
+ "?"
108
+ end
109
+ end
110
+ output.join
111
+ end
112
+
113
+ def lines_to_s(lines)
114
+ output = ""
115
+ lines.each_with_index do |line, index|
116
+ output << "%2d: #{line}\n" % (index + 1)
117
+ end
118
+ output
119
+ end
120
+
121
+ end
@@ -1,5 +1,6 @@
1
1
  require "singleton"
2
2
  require "inifile"
3
+ require "rainbow"
3
4
  require_relative "logger"
4
5
  require_relative "version"
5
6
 
@@ -73,6 +73,14 @@ class CheckHamlData
73
73
  check_type(line, index)
74
74
  check_path(line, index)
75
75
  check_features(line, index)
76
+ check_problem(line, index)
77
+ check_cases(line, index)
78
+ check_case(line, index)
79
+ check_desc(line, index)
80
+ check_ask(line, index)
81
+ check_text(line, index)
82
+ check_answer(line, index)
83
+ check_step(line, index)
76
84
  check_unknown(line, index)
77
85
  @ok = false unless @outputs[index][:state] == :ok
78
86
  @ok = false if @outputs[index][:type] == :unkown
@@ -245,6 +253,134 @@ class CheckHamlData
245
253
  end
246
254
  end
247
255
 
256
+ def check_problem(line, index)
257
+ return unless @outputs[index][:state] == :none
258
+ return unless line.include? "%problem"
259
+
260
+ @outputs[index][:type] = :problem
261
+ @outputs[index][:level] = 1
262
+ @outputs[index][:state] = :ok
263
+ if find_parent(index) != :map
264
+ @outputs[index][:state] = :err
265
+ @outputs[index][:msg] = "Parent(map) not found!"
266
+ elsif !line.match(/^\s\s%problem\s*$/)
267
+ @outputs[index][:state] = :err
268
+ @outputs[index][:msg] = "Write 2 spaces before %problem, and no text after"
269
+ end
270
+ end
271
+
272
+ def check_cases(line, index)
273
+ return unless @outputs[index][:state] == :none
274
+ return unless line.include? "%cases"
275
+
276
+ @outputs[index][:type] = :cases
277
+ @outputs[index][:level] = 2
278
+ @outputs[index][:state] = :ok
279
+ if find_parent(index) != :problem
280
+ @outputs[index][:state] = :err
281
+ @outputs[index][:msg] = "Parent(problem) not found!"
282
+ elsif !line.match(/^\s\s\s\s%cases{\s/)
283
+ @outputs[index][:state] = :err
284
+ @outputs[index][:msg] = "Write 4 spaces before %cases"
285
+ end
286
+ end
287
+
288
+ def check_case(line, index)
289
+ return unless @outputs[index][:state] == :none
290
+ return unless line.include? "%case "
291
+
292
+ @outputs[index][:type] = :case
293
+ @outputs[index][:level] = 3
294
+ @outputs[index][:state] = :ok
295
+ if find_parent(index) != :cases
296
+ @outputs[index][:state] = :err
297
+ @outputs[index][:msg] = "Parent(cases) not found!"
298
+ elsif !line.match(/^\s\s\s\s\s\s%case\s/)
299
+ @outputs[index][:state] = :err
300
+ @outputs[index][:msg] = "Write 6 spaces before %case"
301
+ end
302
+ end
303
+
304
+ def check_desc(line, index)
305
+ return unless @outputs[index][:state] == :none
306
+ return unless line.include? "%desc"
307
+
308
+ @outputs[index][:type] = :desc
309
+ @outputs[index][:level] = 2
310
+ @outputs[index][:state] = :ok
311
+ if find_parent(index) != :problem
312
+ @outputs[index][:state] = :err
313
+ @outputs[index][:msg] = "Parent(problem) not found!"
314
+ elsif !line.match(/^\s\s\s\s%desc\s/)
315
+ @outputs[index][:state] = :err
316
+ @outputs[index][:msg] = "Write 4 spaces before %desc"
317
+ end
318
+ end
319
+
320
+ def check_ask(line, index)
321
+ return unless @outputs[index][:state] == :none
322
+ return unless line.include? "%ask"
323
+
324
+ @outputs[index][:type] = :ask
325
+ @outputs[index][:level] = 2
326
+ @outputs[index][:state] = :ok
327
+ if find_parent(index) != :problem
328
+ @outputs[index][:state] = :err
329
+ @outputs[index][:msg] = "Parent(problem) not found!"
330
+ elsif !line.match(/^\s\s\s\s%ask/)
331
+ @outputs[index][:state] = :err
332
+ @outputs[index][:msg] = "Write 4 spaces before %ask"
333
+ end
334
+ end
335
+
336
+ def check_text(line, index)
337
+ return unless @outputs[index][:state] == :none
338
+ return unless line.include? "%text"
339
+
340
+ @outputs[index][:type] = :text
341
+ @outputs[index][:level] = 3
342
+ @outputs[index][:state] = :ok
343
+ if find_parent(index) != :ask
344
+ @outputs[index][:state] = :err
345
+ @outputs[index][:msg] = "Parent(ask) not found!"
346
+ elsif !line.match(/^\s\s\s\s\s\s%text\s/)
347
+ @outputs[index][:state] = :err
348
+ @outputs[index][:msg] = "Write 6 spaces before %text"
349
+ end
350
+ end
351
+
352
+ def check_answer(line, index)
353
+ return unless @outputs[index][:state] == :none
354
+ return unless line.include? "%answer"
355
+
356
+ @outputs[index][:type] = :answer
357
+ @outputs[index][:level] = 3
358
+ @outputs[index][:state] = :ok
359
+ if find_parent(index) != :ask
360
+ @outputs[index][:state] = :err
361
+ @outputs[index][:msg] = "Parent(ask) not found!"
362
+ elsif !line.match(/^\s\s\s\s\s\s%answer[\s|\{type:]/)
363
+ @outputs[index][:state] = :err
364
+ @outputs[index][:msg] = "Write 6 spaces before %answer, then space or {type:"
365
+ end
366
+ end
367
+
368
+ def check_step(line, index)
369
+ return unless @outputs[index][:state] == :none
370
+ return unless line.include? "%step"
371
+
372
+ @outputs[index][:type] = :step
373
+ @outputs[index][:level] = 3
374
+ @outputs[index][:state] = :ok
375
+ if find_parent(index) != :ask
376
+ @outputs[index][:state] = :err
377
+ @outputs[index][:msg] = "Parent(ask) not found!"
378
+ elsif !line.match(/^\s\s\s\s\s\s%step\s/)
379
+ @outputs[index][:state] = :err
380
+ @outputs[index][:msg] = "Write 6 spaces before %step"
381
+ end
382
+ end
383
+
248
384
  def check_unknown(line, index)
249
385
  return unless @outputs[index][:state] == :none
250
386