asker-tool 2.5.9 → 2.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +10 -7
- data/lib/asker/ai/ai.rb +17 -22
- data/lib/asker/ai/ai_calculate.rb +10 -17
- data/lib/asker/ai/code/base_code_ai.rb +5 -30
- data/lib/asker/ai/code/code_ai_factory.rb +6 -12
- data/lib/asker/ai/code/javascript_code_ai.rb +33 -34
- data/lib/asker/ai/code/python_code_ai.rb +35 -36
- data/lib/asker/ai/code/ruby_code_ai.rb +33 -33
- data/lib/asker/ai/code/sql_code_ai.rb +20 -21
- data/lib/asker/ai/concept_ai.rb +12 -22
- data/lib/asker/ai/problem/problem_ai.rb +226 -0
- data/lib/asker/ai/question.rb +34 -45
- data/lib/asker/ai/stages/base_stage.rb +7 -7
- data/lib/asker/ai/stages/main.rb +6 -7
- data/lib/asker/ai/stages/stage_b.rb +62 -28
- data/lib/asker/ai/stages/stage_d.rb +10 -10
- data/lib/asker/ai/stages/stage_f.rb +17 -17
- data/lib/asker/ai/stages/stage_i.rb +8 -18
- data/lib/asker/ai/stages/stage_s.rb +28 -26
- data/lib/asker/ai/stages/stage_t.rb +54 -76
- data/lib/asker/application.rb +15 -14
- data/lib/asker/check_input/check_haml_data.rb +57 -51
- data/lib/asker/check_input/check_table.rb +26 -19
- data/lib/asker/check_input.rb +10 -22
- data/lib/asker/cli.rb +43 -24
- data/lib/asker/data/code.rb +10 -9
- data/lib/asker/data/column.rb +21 -17
- data/lib/asker/data/concept.rb +24 -37
- data/lib/asker/data/data_field.rb +2 -2
- data/lib/asker/data/problem.rb +112 -0
- data/lib/asker/data/project_data.rb +11 -15
- data/lib/asker/data/row.rb +25 -23
- data/lib/asker/data/table.rb +25 -46
- data/lib/asker/data/template.rb +7 -7
- data/lib/asker/data/world.rb +3 -3
- data/lib/asker/{formatter → deprecated}/question_moodlexml_formatter.rb +19 -21
- data/lib/asker/displayer/code_displayer.rb +10 -10
- data/lib/asker/displayer/concept_ai_displayer.erb +1 -1
- data/lib/asker/displayer/concept_ai_displayer.rb +22 -34
- data/lib/asker/displayer/concept_displayer.rb +9 -11
- data/lib/asker/displayer/problem_displayer.rb +45 -0
- data/lib/asker/displayer/stats_displayer.rb +7 -12
- data/lib/asker/exporter/code_gift_exporter.rb +2 -2
- data/lib/asker/exporter/concept_ai_gift_exporter.rb +4 -4
- data/lib/asker/exporter/concept_ai_yaml_exporter.rb +7 -7
- data/lib/asker/exporter/concept_doc_exporter.rb +5 -5
- data/lib/asker/exporter/data_gift_exporter.rb +14 -15
- data/lib/asker/exporter/data_moodle_exporter.rb +51 -20
- data/lib/asker/exporter/output_file_exporter.rb +9 -8
- data/lib/asker/exporter/problem_gift_exporter.rb +30 -0
- data/lib/asker/files/language/ca/templates.yaml +6 -0
- data/lib/asker/files/language/du/templates.yaml +6 -0
- data/lib/asker/files/language/en/templates.yaml +7 -1
- data/lib/asker/files/language/es/templates.yaml +6 -0
- data/lib/asker/files/language/fr/templates.yaml +6 -0
- data/lib/asker/formatter/code_string_formatter.rb +5 -5
- data/lib/asker/formatter/concept_doc_formatter.rb +3 -3
- data/lib/asker/formatter/concept_string_formatter.rb +27 -24
- data/lib/asker/formatter/moodle/ddmatch.erb +40 -0
- data/lib/asker/formatter/moodle/gapfill.erb +57 -0
- data/lib/asker/formatter/moodle/ordering.erb +41 -0
- data/lib/asker/formatter/question_gift_formatter.rb +41 -14
- data/lib/asker/formatter/question_hash_formatter.rb +5 -6
- data/lib/asker/formatter/question_moodle_formatter.rb +14 -7
- data/lib/asker/formatter/rb2haml_formatter.rb +8 -7
- data/lib/asker/lang/lang.rb +16 -16
- data/lib/asker/lang/lang_factory.rb +13 -16
- data/lib/asker/lang/text_actions.rb +20 -18
- data/lib/asker/loader/code_loader.rb +10 -22
- data/lib/asker/loader/content_loader.rb +42 -49
- data/lib/asker/loader/directory_loader.rb +13 -16
- data/lib/asker/loader/embedded_file.rb +29 -24
- data/lib/asker/loader/file_loader.rb +7 -6
- data/lib/asker/loader/haml_loader.rb +6 -5
- data/lib/asker/loader/image_url_loader.rb +21 -18
- data/lib/asker/loader/input_loader.rb +27 -14
- data/lib/asker/loader/problem_loader.rb +88 -0
- data/lib/asker/loader/project_loader.rb +11 -28
- data/lib/asker/logger.rb +22 -13
- data/lib/asker/skeleton.rb +27 -43
- data/lib/asker/start.rb +44 -0
- data/lib/asker/version.rb +1 -1
- data/lib/asker.rb +7 -53
- metadata +12 -20
- data/lib/asker/ai/code/problem_code_ai.rb +0 -176
- data/lib/asker/exporter/code_moodle_exporter.rb +0 -15
- data/lib/asker/exporter/concept_ai_moodle_exporter.rb +0 -15
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1baeb7aed03362eef9980d237bfa0fbd9b260c356fc11b96c88d870e970260ec
|
|
4
|
+
data.tar.gz: 67ed271bf5e6979643e7d63eed43fbb9659428b66a3f67522d8acc5bb4ea14ba
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9bf4fd2e2ca703548c1a5fdeca6d12bf05549e76423d5ce82f094ca5aaea455499632ae5926ae8ac2e9072ff748a1c74f68908fce8e8cca0ba51220802c97d30
|
|
7
|
+
data.tar.gz: bd150d797993fd3708c254f03fb227e04dc33789854f71b548d3cf27663288ea61c5b62be2a5242f43f8ac449a571675c889cb106e072e0709603642f3ed8d51
|
data/README.md
CHANGED
|
@@ -21,11 +21,10 @@ gem install asker-tool
|
|
|
21
21
|
|
|
22
22
|
# Usage
|
|
23
23
|
|
|
24
|
-
| Step | Action | Description |
|
|
25
|
-
| ---: | --------------------- | ----------- |
|
|
26
|
-
| 1 |
|
|
27
|
-
| 2 |
|
|
28
|
-
| 3 | Choose your **output files** | Output files saved into the `output` folder |
|
|
24
|
+
| Step | Action | Tool | Description |
|
|
25
|
+
| ---: | --------------------- | ---- | ----------- |
|
|
26
|
+
| 1 | Define your concepts | Text plain editor | Create input file with your contents (_conceptual map_). Here are some [examples](./docs/examples). And more examples at this [repository](https://github.com/dvarrui/asker-inputs).
|
|
27
|
+
| 2 | Generate questions | `asker PATH/TO/INPUT` | **Run `asker`** to process input file. Output files are saved into the `output` folder |
|
|
29
28
|
|
|
30
29
|
Let's see an example creating questions from ACDC input example file:
|
|
31
30
|
|
|
@@ -35,10 +34,10 @@ Let's see an example creating questions from ACDC input example file:
|
|
|
35
34
|
+--------------------+-----------+---------+---------+---+---+----+---+---+----+
|
|
36
35
|
| Concept | Questions | Entries | xFactor | d | b | f | i | s | t |
|
|
37
36
|
+--------------------+-----------+---------+---------+---+---+----+---+---+----+
|
|
38
|
-
| AC/DC |
|
|
37
|
+
| AC/DC | 46 | 18 | 2.5 | 7 | 0 | 15 | 0 | 4 | 20 |
|
|
39
38
|
| Excluded questions | 0 | - | - | 0 | 0 | 0 | 0 | 0 | 0 |
|
|
40
39
|
+--------------------+-----------+---------+---------+---+---+----+---+---+----+
|
|
41
|
-
| 1 concept/s |
|
|
40
|
+
| 1 concept/s | 46 | 18 | 2.5 | 7 | 0 | 15 | 0 | 4 | 20 |
|
|
42
41
|
+--------------------+-----------+---------+---------+---+---+----+---+---+----+
|
|
43
42
|
```
|
|
44
43
|
|
|
@@ -46,6 +45,10 @@ Let's see an example creating questions from ACDC input example file:
|
|
|
46
45
|
|
|
47
46
|
* [Free Software License](LICENSE).
|
|
48
47
|
* Multiplatform.
|
|
48
|
+
* Input files formats: XML, HAML.
|
|
49
|
+
* Output formats: GIFT, Moodle XML, YAML.
|
|
50
|
+
* Question types: true/false, multiple choice, short answer, matching and ordering.
|
|
51
|
+
* Embeded files: mp3, ogg, wav, jpg, jpeg, png, mp4, ogv and plain text files.
|
|
49
52
|
|
|
50
53
|
# Documentation
|
|
51
54
|
|
data/lib/asker/ai/ai.rb
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative
|
|
4
|
-
require_relative
|
|
3
|
+
require_relative "stages/main"
|
|
4
|
+
require_relative "ai_calculate"
|
|
5
5
|
|
|
6
6
|
# Description: Method to be included into every ConceptAI instance.
|
|
7
7
|
# * make_questions: use AI to fill @questions Array
|
|
@@ -13,13 +13,13 @@ module AI
|
|
|
13
13
|
|
|
14
14
|
make_questions_stages_di
|
|
15
15
|
# Process every table of this concept
|
|
16
|
-
concept.tables.each do |
|
|
17
|
-
list1, list2 = get_list1_and_list2_from(
|
|
18
|
-
make_questions_stages_bsf(
|
|
19
|
-
make_questions_stages_t(
|
|
16
|
+
concept.tables.each do |table|
|
|
17
|
+
list1, list2 = get_list1_and_list2_from(table)
|
|
18
|
+
make_questions_stages_bsf(table, list1, list2)
|
|
19
|
+
make_questions_stages_t(table, list1, list2)
|
|
20
20
|
end
|
|
21
21
|
# -------------------------------------------------------
|
|
22
|
-
# Exclude questions as is defined into
|
|
22
|
+
# Exclude questions as is defined into asker.ini params
|
|
23
23
|
exclude_questions
|
|
24
24
|
end
|
|
25
25
|
|
|
@@ -30,34 +30,31 @@ module AI
|
|
|
30
30
|
end
|
|
31
31
|
|
|
32
32
|
# Make questions for stages B, S and F
|
|
33
|
-
def make_questions_stages_bsf(
|
|
33
|
+
def make_questions_stages_bsf(table, list1, list2)
|
|
34
34
|
# Stage B: process table to make match questions
|
|
35
|
-
@questions[:b] += StageB.new(self).run(
|
|
35
|
+
@questions[:b] += StageB.new(self).run(table, list1, list2)
|
|
36
36
|
# Stage S: process tables with sequences
|
|
37
|
-
@questions[:s] += StageS.new(self).run(
|
|
37
|
+
@questions[:s] += StageS.new(self).run(table, list1, list2)
|
|
38
38
|
# Stage F: process tables with only 1 field
|
|
39
|
-
@questions[:f] += StageF.new(self).run(
|
|
39
|
+
@questions[:f] += StageF.new(self).run(table, list1, list2)
|
|
40
40
|
end
|
|
41
41
|
|
|
42
|
-
|
|
43
|
-
def make_questions_stages_t(tab, list1, list2)
|
|
42
|
+
def make_questions_stages_t(table, list1, list2)
|
|
44
43
|
# Stage T: process_tableXfields
|
|
45
44
|
list3 = list1 + list2
|
|
46
45
|
list1.each do |row|
|
|
47
46
|
reorder_list_with_row(list3, row)
|
|
48
|
-
@questions[:t] += StageT.new(self).run(
|
|
47
|
+
@questions[:t] += StageT.new(self).run(table, row, list3)
|
|
49
48
|
end
|
|
50
49
|
end
|
|
51
50
|
|
|
52
|
-
# rubocop:disable Metrics/AbcSize
|
|
53
|
-
# rubocop:disable Metrics/MethodLength
|
|
54
51
|
def exclude_questions
|
|
55
|
-
param = Application.instance.config[
|
|
52
|
+
param = Application.instance.config["questions"]["exclude"]
|
|
56
53
|
return if param.nil?
|
|
57
54
|
|
|
58
|
-
tags = param.split(
|
|
59
|
-
input = {
|
|
60
|
-
output = {
|
|
55
|
+
tags = param.split(",").each(&:strip!)
|
|
56
|
+
input = {d: [], b: [], f: [], i: [], s: [], t: []}
|
|
57
|
+
output = {d: [], b: [], f: [], i: [], s: [], t: []}
|
|
61
58
|
|
|
62
59
|
@questions.each_pair do |key, qlist|
|
|
63
60
|
output[key] = qlist.select { |q| string_has_this_tags?(q.name, tags) }
|
|
@@ -66,8 +63,6 @@ module AI
|
|
|
66
63
|
@questions = input
|
|
67
64
|
@excluded_questions = output
|
|
68
65
|
end
|
|
69
|
-
# rubocop:enable Metrics/AbcSize
|
|
70
|
-
# rubocop:enable Metrics/MethodLength
|
|
71
66
|
|
|
72
67
|
def string_has_this_tags?(input, tags)
|
|
73
68
|
flag = false
|
|
@@ -7,14 +7,12 @@ module AICalculate
|
|
|
7
7
|
# * return list1 (Array) List with all the rows from the table
|
|
8
8
|
# * return list2 (Array) List with similar rows (same table name) from the neighbours tables
|
|
9
9
|
# @param p_table (Table)
|
|
10
|
-
# rubocop:disable Metrics/MethodLength
|
|
11
|
-
# rubocop:disable Metrics/AbcSize
|
|
12
10
|
def get_list1_and_list2_from(p_table)
|
|
13
11
|
# create <list1> with all the rows from the table
|
|
14
12
|
list1 = []
|
|
15
13
|
count = 1
|
|
16
14
|
p_table.rows.each do |i|
|
|
17
|
-
list1 << {
|
|
15
|
+
list1 << {id: count, weight: 0, data: i}
|
|
18
16
|
count += 1
|
|
19
17
|
end
|
|
20
18
|
|
|
@@ -25,45 +23,40 @@ module AICalculate
|
|
|
25
23
|
next if t2.name != p_table.name
|
|
26
24
|
|
|
27
25
|
t2.rows.each do |i|
|
|
28
|
-
list2 << {
|
|
26
|
+
list2 << {id: count, weight: 0, data: i}
|
|
29
27
|
count += 1
|
|
30
28
|
end
|
|
31
29
|
end
|
|
32
30
|
end
|
|
33
31
|
[list1, list2]
|
|
34
32
|
end
|
|
35
|
-
# rubocop:enable Metrics/MethodLength
|
|
36
|
-
# rubocop:enable Metrics/AbcSize
|
|
37
33
|
|
|
38
34
|
def calculate_nearness_between_texts(text1, text2)
|
|
39
35
|
return 0.0 if text2.nil? || text2.empty?
|
|
40
36
|
|
|
41
|
-
words = text1.split(
|
|
37
|
+
words = text1.split(" ")
|
|
42
38
|
count = 0
|
|
43
39
|
words.each { |w| count += 1 if text2.include?(w) }
|
|
44
40
|
(count * 100 / words.count)
|
|
45
41
|
end
|
|
46
42
|
|
|
47
|
-
# rubocop:disable Metrics/MethodLength
|
|
48
|
-
# rubocop:disable Metrics/AbcSize
|
|
49
43
|
def reorder_list_with_row(list, row)
|
|
50
|
-
# evaluate every row of the
|
|
44
|
+
# evaluate every row of the list, and calculate weight
|
|
45
|
+
magic_number = -300
|
|
51
46
|
list.each do |r|
|
|
52
47
|
if r[:id] == row[:id]
|
|
53
|
-
r[:weight] =
|
|
48
|
+
r[:weight] = magic_number
|
|
54
49
|
else
|
|
55
|
-
|
|
50
|
+
value = 0
|
|
56
51
|
s = row[:data].count
|
|
57
52
|
s.times do |i|
|
|
58
|
-
|
|
53
|
+
value += calculate_nearness_between_texts(row[:data][i], r[:data][i])
|
|
59
54
|
end
|
|
60
|
-
|
|
61
|
-
r[:weight] =
|
|
55
|
+
value /= s
|
|
56
|
+
r[:weight] = value
|
|
62
57
|
end
|
|
63
58
|
end
|
|
64
59
|
list.sort! { |a, b| a[:weight] <=> b[:weight] }
|
|
65
60
|
list.reverse!
|
|
66
61
|
end
|
|
67
|
-
# rubocop:enable Metrics/MethodLength
|
|
68
|
-
# rubocop:enable Metrics/AbcSize
|
|
69
62
|
end
|
|
@@ -1,16 +1,13 @@
|
|
|
1
1
|
# frozen_string_literal: false
|
|
2
2
|
|
|
3
|
-
require_relative
|
|
4
|
-
require_relative
|
|
3
|
+
require_relative "../../lang/lang_factory"
|
|
4
|
+
require_relative "../../ai/question"
|
|
5
5
|
|
|
6
6
|
##
|
|
7
7
|
# BaseCodeAI class
|
|
8
8
|
class BaseCodeAI
|
|
9
9
|
attr_reader :questions
|
|
10
10
|
|
|
11
|
-
##
|
|
12
|
-
# Create CodeAI object from Code data
|
|
13
|
-
# @param code (Code)
|
|
14
11
|
def initialize(code)
|
|
15
12
|
@code = code
|
|
16
13
|
@lines = code.lines
|
|
@@ -19,9 +16,6 @@ class BaseCodeAI
|
|
|
19
16
|
make_questions
|
|
20
17
|
end
|
|
21
18
|
|
|
22
|
-
##
|
|
23
|
-
# Return the name of code
|
|
24
|
-
# @return String
|
|
25
19
|
def name
|
|
26
20
|
File.basename(@code.filename)
|
|
27
21
|
end
|
|
@@ -42,51 +36,32 @@ class BaseCodeAI
|
|
|
42
36
|
@code.lines
|
|
43
37
|
end
|
|
44
38
|
|
|
45
|
-
##
|
|
46
|
-
# Counter
|
|
47
|
-
# @return count
|
|
48
39
|
def num
|
|
49
40
|
@num += 1
|
|
50
41
|
end
|
|
51
42
|
|
|
52
|
-
##
|
|
53
|
-
# Clone array
|
|
54
|
-
# @param array (Array)
|
|
55
|
-
# @return Array
|
|
56
43
|
def clone_array(array)
|
|
57
44
|
out = []
|
|
58
45
|
array.each { |item| out << item.dup }
|
|
59
46
|
out
|
|
60
47
|
end
|
|
61
48
|
|
|
62
|
-
##
|
|
63
|
-
# Convert an array of lines into one String
|
|
64
|
-
# @param lines (Array)
|
|
65
|
-
# @return String
|
|
66
|
-
# rubocop:disable Style/FormatString
|
|
67
49
|
def lines_to_s(lines)
|
|
68
|
-
out =
|
|
50
|
+
out = ""
|
|
69
51
|
lines.each_with_index do |line, index|
|
|
70
52
|
out << "%2d: #{line}\n" % (index + 1)
|
|
71
53
|
end
|
|
72
54
|
out
|
|
73
55
|
end
|
|
74
56
|
|
|
75
|
-
##
|
|
76
|
-
# Convert an array of lines into one HTML String
|
|
77
|
-
# @param lines (Array)
|
|
78
|
-
# @return String
|
|
79
57
|
def lines_to_html(lines)
|
|
80
|
-
out =
|
|
58
|
+
out = ""
|
|
81
59
|
lines.each_with_index do |line, index|
|
|
82
60
|
out << "%2d: #{line}</br>" % (index + 1)
|
|
83
61
|
end
|
|
84
62
|
out
|
|
85
63
|
end
|
|
86
|
-
# rubocop:enable Style/FormatString
|
|
87
64
|
|
|
88
|
-
##
|
|
89
|
-
# Make questions
|
|
90
65
|
def make_questions
|
|
91
66
|
list = find_make_methods
|
|
92
67
|
list.each { |m| @questions += send m }
|
|
@@ -97,7 +72,7 @@ class BaseCodeAI
|
|
|
97
72
|
|
|
98
73
|
def find_make_methods
|
|
99
74
|
list = public_methods.sort
|
|
100
|
-
list.select! { |name| name.to_s.start_with?
|
|
75
|
+
list.select! { |name| name.to_s.start_with? "make_" }
|
|
101
76
|
list.delete(:make_questions)
|
|
102
77
|
list
|
|
103
78
|
end
|
|
@@ -1,13 +1,9 @@
|
|
|
1
|
+
require_relative "javascript_code_ai"
|
|
2
|
+
require_relative "python_code_ai"
|
|
3
|
+
require_relative "ruby_code_ai"
|
|
4
|
+
require_relative "sql_code_ai"
|
|
5
|
+
require_relative "../../logger"
|
|
1
6
|
|
|
2
|
-
require 'rainbow'
|
|
3
|
-
require_relative 'javascript_code_ai'
|
|
4
|
-
require_relative 'problem_code_ai'
|
|
5
|
-
require_relative 'python_code_ai'
|
|
6
|
-
require_relative 'ruby_code_ai'
|
|
7
|
-
require_relative 'sql_code_ai'
|
|
8
|
-
|
|
9
|
-
##
|
|
10
|
-
# CodeAI factory
|
|
11
7
|
module CodeAIFactory
|
|
12
8
|
##
|
|
13
9
|
# Return CodeAI associated to Code.type
|
|
@@ -18,8 +14,6 @@ module CodeAIFactory
|
|
|
18
14
|
case type
|
|
19
15
|
when :javascript
|
|
20
16
|
return JavascriptCodeAI.new(code)
|
|
21
|
-
when :problem
|
|
22
|
-
return ProblemCodeAI.new(code)
|
|
23
17
|
when :python
|
|
24
18
|
return PythonCodeAI.new(code)
|
|
25
19
|
when :ruby
|
|
@@ -29,7 +23,7 @@ module CodeAIFactory
|
|
|
29
23
|
when :vagrantfile
|
|
30
24
|
return RubyCodeAI.new(code)
|
|
31
25
|
else
|
|
32
|
-
|
|
26
|
+
Logger.warn "CodeAIFactory: Invalid type (#{type})"
|
|
33
27
|
end
|
|
34
28
|
nil
|
|
35
29
|
end
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
require_relative
|
|
3
|
-
require_relative
|
|
4
|
-
require_relative 'base_code_ai'
|
|
1
|
+
require_relative "../../lang/lang_factory"
|
|
2
|
+
require_relative "../../ai/question"
|
|
3
|
+
require_relative "base_code_ai"
|
|
5
4
|
|
|
6
5
|
class JavascriptCodeAI < BaseCodeAI
|
|
7
6
|
def initialize(code)
|
|
@@ -13,25 +12,25 @@ class JavascriptCodeAI < BaseCodeAI
|
|
|
13
12
|
questions = []
|
|
14
13
|
# error_lines = []
|
|
15
14
|
@lines.each_with_index do |line, index|
|
|
16
|
-
if line.strip.start_with?(
|
|
15
|
+
if line.strip.start_with?("//")
|
|
17
16
|
lines = clone_array @lines
|
|
18
|
-
lines[index].sub!(
|
|
17
|
+
lines[index].sub!("//", "").strip!
|
|
19
18
|
|
|
20
19
|
q = Question.new(:short)
|
|
21
20
|
q.name = "#{name}-#{num}-uncomment"
|
|
22
|
-
q.text = @lang.text_for(:code1,lines_to_html(lines))
|
|
23
|
-
q.shorts << (index+1)
|
|
24
|
-
q.feedback =
|
|
21
|
+
q.text = @lang.text_for(:code1, lines_to_html(lines))
|
|
22
|
+
q.shorts << (index + 1)
|
|
23
|
+
q.feedback = "Comment symbol removed"
|
|
25
24
|
questions << q
|
|
26
|
-
elsif line.strip.size>0
|
|
25
|
+
elsif line.strip.size > 0
|
|
27
26
|
lines = clone_array @lines
|
|
28
|
-
lines[index]=
|
|
27
|
+
lines[index] = "// " + lines[index]
|
|
29
28
|
|
|
30
29
|
q = Question.new(:short)
|
|
31
30
|
q.name = "#{name}-#{num}-comment"
|
|
32
|
-
q.text = @lang.text_for(:code1,lines_to_html(lines))
|
|
33
|
-
q.shorts << (index+1)
|
|
34
|
-
q.feedback =
|
|
31
|
+
q.text = @lang.text_for(:code1, lines_to_html(lines))
|
|
32
|
+
q.shorts << (index + 1)
|
|
33
|
+
q.feedback = "Comment symbol added"
|
|
35
34
|
questions << q
|
|
36
35
|
end
|
|
37
36
|
end
|
|
@@ -42,7 +41,7 @@ class JavascriptCodeAI < BaseCodeAI
|
|
|
42
41
|
questions = []
|
|
43
42
|
empty_lines = []
|
|
44
43
|
used_lines = []
|
|
45
|
-
@lines.each_with_index do |line,index|
|
|
44
|
+
@lines.each_with_index do |line, index|
|
|
46
45
|
if line.strip.size.zero?
|
|
47
46
|
empty_lines << index
|
|
48
47
|
else
|
|
@@ -52,24 +51,24 @@ class JavascriptCodeAI < BaseCodeAI
|
|
|
52
51
|
|
|
53
52
|
used_lines.each do |index|
|
|
54
53
|
lines = clone_array(@lines)
|
|
55
|
-
lines.insert(index,
|
|
54
|
+
lines.insert(index, " " * (rand(4).to_i + 1))
|
|
56
55
|
if @lines.size < 4 || rand(2) == 0
|
|
57
56
|
q = Question.new(:short)
|
|
58
57
|
q.name = "#{name}-#{num}-codeok"
|
|
59
|
-
q.text = @lang.text_for(:code1,lines_to_html(lines))
|
|
60
|
-
q.shorts <<
|
|
61
|
-
q.feedback =
|
|
58
|
+
q.text = @lang.text_for(:code1, lines_to_html(lines))
|
|
59
|
+
q.shorts << "0"
|
|
60
|
+
q.feedback = "Code is OK"
|
|
62
61
|
questions << q
|
|
63
62
|
else
|
|
64
63
|
q = Question.new(:choice)
|
|
65
64
|
q.name = "#{name}-#{num}-codeok"
|
|
66
|
-
q.text = @lang.text_for(:code2,lines_to_html(lines))
|
|
65
|
+
q.text = @lang.text_for(:code2, lines_to_html(lines))
|
|
67
66
|
others = (1..@lines.size).to_a.shuffle!
|
|
68
|
-
q.good =
|
|
67
|
+
q.good = "0"
|
|
69
68
|
q.bads << others[0].to_s
|
|
70
69
|
q.bads << others[1].to_s
|
|
71
70
|
q.bads << others[2].to_s
|
|
72
|
-
q.feedback =
|
|
71
|
+
q.feedback = "Code is OK"
|
|
73
72
|
end
|
|
74
73
|
end
|
|
75
74
|
|
|
@@ -79,13 +78,13 @@ class JavascriptCodeAI < BaseCodeAI
|
|
|
79
78
|
def make_syntax_error
|
|
80
79
|
questions = []
|
|
81
80
|
|
|
82
|
-
@lang.mistakes.each_pair do |key,values|
|
|
81
|
+
@lang.mistakes.each_pair do |key, values|
|
|
83
82
|
error_lines = []
|
|
84
|
-
@lines.each_with_index do |line,index|
|
|
83
|
+
@lines.each_with_index do |line, index|
|
|
85
84
|
error_lines << index if line.include?(key.to_s)
|
|
86
85
|
end
|
|
87
86
|
|
|
88
|
-
v = values.split(
|
|
87
|
+
v = values.split(",")
|
|
89
88
|
v.each do |value|
|
|
90
89
|
error_lines.each do |index|
|
|
91
90
|
lines = clone_array(@lines)
|
|
@@ -93,15 +92,15 @@ class JavascriptCodeAI < BaseCodeAI
|
|
|
93
92
|
if @lines.size < 4 || rand(2) == 0
|
|
94
93
|
q = Question.new(:short)
|
|
95
94
|
q.name = "#{name}-#{num}-syntaxerror"
|
|
96
|
-
q.text = @lang.text_for(:code1,lines_to_html(lines))
|
|
97
|
-
q.shorts << (index+1)
|
|
95
|
+
q.text = @lang.text_for(:code1, lines_to_html(lines))
|
|
96
|
+
q.shorts << (index + 1)
|
|
98
97
|
q.feedback = "Syntax error: '#{value}' must be '#{key}'"
|
|
99
98
|
else
|
|
100
99
|
q = Question.new(:choice)
|
|
101
100
|
q.name = "#{name}-#{num}-syntaxerror"
|
|
102
|
-
q.text = @lang.text_for(:code2,lines_to_html(lines))
|
|
101
|
+
q.text = @lang.text_for(:code2, lines_to_html(lines))
|
|
103
102
|
others = (1..@lines.size).to_a.shuffle!
|
|
104
|
-
others.delete(index+1)
|
|
103
|
+
others.delete(index + 1)
|
|
105
104
|
q.good = (index + 1).to_s
|
|
106
105
|
q.bads << others[0].to_s
|
|
107
106
|
q.bads << others[1].to_s
|
|
@@ -141,20 +140,20 @@ class JavascriptCodeAI < BaseCodeAI
|
|
|
141
140
|
if rand(2) == 0
|
|
142
141
|
q = Question.new(:short)
|
|
143
142
|
q.name = "#{name}-#{num}-variable"
|
|
144
|
-
q.text = @lang.text_for(:code1,lines_to_html(lines))
|
|
143
|
+
q.text = @lang.text_for(:code1, lines_to_html(lines))
|
|
145
144
|
q.shorts << (index + 1)
|
|
146
|
-
q.feedback = "Variable error! Swapped lines #{
|
|
145
|
+
q.feedback = "Variable error! Swapped lines #{index + 1} with #{k + 1}"
|
|
147
146
|
else
|
|
148
147
|
q = Question.new(:choice)
|
|
149
148
|
q.name = "#{name}-#{num}-variable"
|
|
150
|
-
q.text = @lang.text_for(:code2,lines_to_html(lines))
|
|
149
|
+
q.text = @lang.text_for(:code2, lines_to_html(lines))
|
|
151
150
|
others = (1..@lines.size).to_a.shuffle!
|
|
152
|
-
others.delete(index+1)
|
|
151
|
+
others.delete(index + 1)
|
|
153
152
|
q.good = (index + 1).to_s
|
|
154
153
|
q.bads << others[0].to_s
|
|
155
154
|
q.bads << others[1].to_s
|
|
156
155
|
q.bads << others[2].to_s
|
|
157
|
-
q.feedback = "Variable error! Swapped lines #{
|
|
156
|
+
q.feedback = "Variable error! Swapped lines #{index + 1} with #{k + 1}"
|
|
158
157
|
end
|
|
159
158
|
questions << q
|
|
160
159
|
end
|
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
require_relative
|
|
3
|
-
require_relative
|
|
4
|
-
require_relative 'base_code_ai'
|
|
1
|
+
require_relative "../../lang/lang_factory"
|
|
2
|
+
require_relative "../../ai/question"
|
|
3
|
+
require_relative "base_code_ai"
|
|
5
4
|
|
|
6
5
|
class PythonCodeAI < BaseCodeAI
|
|
7
6
|
def initialize(code)
|
|
8
|
-
@lang = LangFactory.instance.get(
|
|
7
|
+
@lang = LangFactory.instance.get("python")
|
|
9
8
|
super code
|
|
10
9
|
end
|
|
11
10
|
|
|
@@ -13,25 +12,25 @@ class PythonCodeAI < BaseCodeAI
|
|
|
13
12
|
questions = []
|
|
14
13
|
# error_lines = []
|
|
15
14
|
@lines.each_with_index do |line, index|
|
|
16
|
-
if line.strip.start_with?(
|
|
15
|
+
if line.strip.start_with?("#")
|
|
17
16
|
lines = clone_array @lines
|
|
18
|
-
lines[index].sub!(
|
|
17
|
+
lines[index].sub!("#", "").strip!
|
|
19
18
|
|
|
20
19
|
q = Question.new(:short)
|
|
21
20
|
q.name = "#{name}-#{num}-uncomment"
|
|
22
|
-
q.text = @lang.text_for(:code1,lines_to_html(lines))
|
|
23
|
-
q.shorts << (index+1)
|
|
24
|
-
q.feedback =
|
|
21
|
+
q.text = @lang.text_for(:code1, lines_to_html(lines))
|
|
22
|
+
q.shorts << (index + 1)
|
|
23
|
+
q.feedback = "Comment symbol removed"
|
|
25
24
|
questions << q
|
|
26
|
-
elsif line.strip.size>0
|
|
25
|
+
elsif line.strip.size > 0
|
|
27
26
|
lines = clone_array @lines
|
|
28
|
-
lines[index]=
|
|
27
|
+
lines[index] = "# " + lines[index]
|
|
29
28
|
|
|
30
29
|
q = Question.new(:short)
|
|
31
30
|
q.name = "#{name}-#{num}-comment"
|
|
32
|
-
q.text = @lang.text_for(:code1,lines_to_html(lines))
|
|
33
|
-
q.shorts << (index+1)
|
|
34
|
-
q.feedback =
|
|
31
|
+
q.text = @lang.text_for(:code1, lines_to_html(lines))
|
|
32
|
+
q.shorts << (index + 1)
|
|
33
|
+
q.feedback = "Comment symbol added"
|
|
35
34
|
questions << q
|
|
36
35
|
end
|
|
37
36
|
end
|
|
@@ -42,7 +41,7 @@ class PythonCodeAI < BaseCodeAI
|
|
|
42
41
|
questions = []
|
|
43
42
|
empty_lines = []
|
|
44
43
|
used_lines = []
|
|
45
|
-
@lines.each_with_index do |line,index|
|
|
44
|
+
@lines.each_with_index do |line, index|
|
|
46
45
|
if line.strip.size.zero?
|
|
47
46
|
empty_lines << index
|
|
48
47
|
else
|
|
@@ -52,24 +51,24 @@ class PythonCodeAI < BaseCodeAI
|
|
|
52
51
|
|
|
53
52
|
used_lines.each do |index|
|
|
54
53
|
lines = clone_array(@lines)
|
|
55
|
-
lines.insert(index,
|
|
54
|
+
lines.insert(index, " " * (rand(4).to_i + 1))
|
|
56
55
|
if @lines.size < 4 || rand(2) == 0
|
|
57
56
|
q = Question.new(:short)
|
|
58
57
|
q.name = "#{name}-#{num}-codeok"
|
|
59
|
-
q.text = @lang.text_for(:code1,lines_to_html(lines))
|
|
60
|
-
q.shorts <<
|
|
61
|
-
q.feedback =
|
|
58
|
+
q.text = @lang.text_for(:code1, lines_to_html(lines))
|
|
59
|
+
q.shorts << "0"
|
|
60
|
+
q.feedback = "Code is OK"
|
|
62
61
|
questions << q
|
|
63
62
|
else
|
|
64
63
|
q = Question.new(:choice)
|
|
65
64
|
q.name = "#{name}-#{num}-codeok"
|
|
66
|
-
q.text = @lang.text_for(:code2,lines_to_html(lines))
|
|
65
|
+
q.text = @lang.text_for(:code2, lines_to_html(lines))
|
|
67
66
|
others = (1..@lines.size).to_a.shuffle!
|
|
68
|
-
q.good =
|
|
67
|
+
q.good = "0"
|
|
69
68
|
q.bads << others[0].to_s
|
|
70
69
|
q.bads << others[1].to_s
|
|
71
70
|
q.bads << others[2].to_s
|
|
72
|
-
q.feedback =
|
|
71
|
+
q.feedback = "Code is OK"
|
|
73
72
|
end
|
|
74
73
|
end
|
|
75
74
|
|
|
@@ -79,13 +78,13 @@ class PythonCodeAI < BaseCodeAI
|
|
|
79
78
|
def make_syntax_error
|
|
80
79
|
questions = []
|
|
81
80
|
|
|
82
|
-
@lang.mistakes.each_pair do |key,values|
|
|
81
|
+
@lang.mistakes.each_pair do |key, values|
|
|
83
82
|
error_lines = []
|
|
84
|
-
@lines.each_with_index do |line,index|
|
|
83
|
+
@lines.each_with_index do |line, index|
|
|
85
84
|
error_lines << index if line.include?(key.to_s)
|
|
86
85
|
end
|
|
87
86
|
|
|
88
|
-
v = values.split(
|
|
87
|
+
v = values.split(",")
|
|
89
88
|
v.each do |value|
|
|
90
89
|
error_lines.each do |index|
|
|
91
90
|
lines = clone_array(@lines)
|
|
@@ -93,15 +92,15 @@ class PythonCodeAI < BaseCodeAI
|
|
|
93
92
|
if @lines.size < 4 || rand(2) == 0
|
|
94
93
|
q = Question.new(:short)
|
|
95
94
|
q.name = "#{name}-#{num}-syntaxerror"
|
|
96
|
-
q.text = @lang.text_for(:code1,lines_to_html(lines))
|
|
97
|
-
q.shorts << (index+1)
|
|
95
|
+
q.text = @lang.text_for(:code1, lines_to_html(lines))
|
|
96
|
+
q.shorts << (index + 1)
|
|
98
97
|
q.feedback = "Syntax error: '#{value}' must be '#{key}'"
|
|
99
98
|
else
|
|
100
99
|
q = Question.new(:choice)
|
|
101
100
|
q.name = "#{name}-#{num}-syntaxerror"
|
|
102
|
-
q.text = @lang.text_for(:code2,lines_to_html(lines))
|
|
101
|
+
q.text = @lang.text_for(:code2, lines_to_html(lines))
|
|
103
102
|
others = (1..@lines.size).to_a.shuffle!
|
|
104
|
-
others.delete(index+1)
|
|
103
|
+
others.delete(index + 1)
|
|
105
104
|
q.good = (index + 1).to_s
|
|
106
105
|
q.bads << others[0].to_s
|
|
107
106
|
q.bads << others[1].to_s
|
|
@@ -120,7 +119,7 @@ class PythonCodeAI < BaseCodeAI
|
|
|
120
119
|
# error_lines = []
|
|
121
120
|
@lines.each_with_index do |line, index|
|
|
122
121
|
# Search Variable assignment
|
|
123
|
-
m = /\s*(\w*)\s
|
|
122
|
+
m = /\s*(\w*)\s*=\w*/.match(line)
|
|
124
123
|
i = []
|
|
125
124
|
unless m.nil?
|
|
126
125
|
varname = (m.values_at 1)[0]
|
|
@@ -141,20 +140,20 @@ class PythonCodeAI < BaseCodeAI
|
|
|
141
140
|
if rand(2) == 0
|
|
142
141
|
q = Question.new(:short)
|
|
143
142
|
q.name = "#{name}-#{num}-variable"
|
|
144
|
-
q.text = @lang.text_for(:code1,lines_to_html(lines))
|
|
143
|
+
q.text = @lang.text_for(:code1, lines_to_html(lines))
|
|
145
144
|
q.shorts << (index + 1)
|
|
146
|
-
q.feedback = "Variable error! Swapped lines #{
|
|
145
|
+
q.feedback = "Variable error! Swapped lines #{index + 1} with #{k + 1}"
|
|
147
146
|
else
|
|
148
147
|
q = Question.new(:choice)
|
|
149
148
|
q.name = "#{name}-#{num}-variable"
|
|
150
|
-
q.text = @lang.text_for(:code2,lines_to_html(lines))
|
|
149
|
+
q.text = @lang.text_for(:code2, lines_to_html(lines))
|
|
151
150
|
others = (1..@lines.size).to_a.shuffle!
|
|
152
|
-
others.delete(index+1)
|
|
151
|
+
others.delete(index + 1)
|
|
153
152
|
q.good = (index + 1).to_s
|
|
154
153
|
q.bads << others[0].to_s
|
|
155
154
|
q.bads << others[1].to_s
|
|
156
155
|
q.bads << others[2].to_s
|
|
157
|
-
q.feedback = "Variable error! Swapped lines #{
|
|
156
|
+
q.feedback = "Variable error! Swapped lines #{index + 1} with #{k + 1}"
|
|
158
157
|
end
|
|
159
158
|
questions << q
|
|
160
159
|
end
|