asker-tool 2.7.1 → 2.8.0

Sign up to get free protection for your applications and to get access to all the features.
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