asker-tool 2.1.5 → 2.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (105) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +13 -17
  3. data/bin/asker +2 -1
  4. data/lib/asker/ai/ai.rb +10 -3
  5. data/lib/asker/ai/ai_calculate.rb +20 -6
  6. data/lib/asker/ai/code/base_code_ai.rb +104 -0
  7. data/lib/asker/{code/ai → ai/code}/code_ai_factory.rb +11 -1
  8. data/lib/asker/{code/ai → ai/code}/javascript_code_ai.rb +2 -5
  9. data/lib/asker/ai/code/problem_code_ai.rb +176 -0
  10. data/lib/asker/{code/ai → ai/code}/python_code_ai.rb +2 -5
  11. data/lib/asker/{code/ai → ai/code}/ruby_code_ai.rb +14 -7
  12. data/lib/asker/{code/ai → ai/code}/sql_code_ai.rb +2 -5
  13. data/lib/asker/ai/concept_ai.rb +13 -3
  14. data/lib/asker/ai/question.rb +28 -6
  15. data/lib/asker/ai/stages/base_stage.rb +45 -6
  16. data/lib/asker/ai/stages/stage_b.rb +100 -50
  17. data/lib/asker/ai/stages/stage_d.rb +75 -90
  18. data/lib/asker/ai/stages/stage_f.rb +64 -36
  19. data/lib/asker/ai/stages/stage_i.rb +79 -92
  20. data/lib/asker/ai/stages/stage_s.rb +41 -36
  21. data/lib/asker/ai/stages/stage_t.rb +149 -108
  22. data/lib/asker/application.rb +19 -11
  23. data/lib/asker/cli.rb +31 -44
  24. data/lib/asker/data/code.rb +62 -0
  25. data/lib/asker/data/column.rb +31 -21
  26. data/lib/asker/data/concept.rb +109 -65
  27. data/lib/asker/data/data_field.rb +14 -0
  28. data/lib/asker/data/project_data.rb +63 -0
  29. data/lib/asker/data/row.rb +75 -52
  30. data/lib/asker/data/table.rb +91 -42
  31. data/lib/asker/data/template.rb +3 -1
  32. data/lib/asker/data/world.rb +51 -35
  33. data/lib/asker/displayer/code_displayer.rb +7 -0
  34. data/lib/asker/displayer/concept_ai_displayer.erb +10 -0
  35. data/lib/asker/displayer/concept_ai_displayer.rb +74 -53
  36. data/lib/asker/displayer/concept_displayer.rb +16 -9
  37. data/lib/asker/displayer/stats_displayer.rb +12 -3
  38. data/lib/asker/exporter/concept_ai_gift_exporter.rb +19 -11
  39. data/lib/asker/exporter/concept_ai_moodle_exporter.rb +44 -0
  40. data/lib/asker/exporter/concept_ai_yaml_exporter.rb +13 -6
  41. data/lib/asker/exporter/concept_doc_exporter.rb +14 -1
  42. data/lib/asker/exporter/data_gift_exporter.rb +29 -0
  43. data/lib/asker/exporter/output_file_exporter.rb +9 -6
  44. data/lib/asker/files/{config.ini → asker.ini} +48 -1
  45. data/lib/asker/files/example-concept.haml +0 -1
  46. data/lib/asker/files/language/du/connectors.yaml +81 -0
  47. data/lib/asker/{lang/locales/fr → files/language/du}/mistakes.yaml +1 -1
  48. data/lib/asker/files/language/du/templates.yaml +29 -0
  49. data/lib/asker/{lang/locales → files/language}/en/connectors.yaml +0 -0
  50. data/lib/asker/{lang/locales → files/language}/en/mistakes.yaml +0 -0
  51. data/lib/asker/files/language/en/templates.yaml +29 -0
  52. data/lib/asker/{lang/locales → files/language}/es/connectors.yaml +0 -0
  53. data/lib/asker/files/language/es/mistakes.yaml +84 -0
  54. data/lib/asker/files/language/es/templates.yaml +29 -0
  55. data/lib/asker/files/language/fr/connectors.yaml +76 -0
  56. data/lib/asker/{lang/locales/es → files/language/fr}/mistakes.yaml +0 -0
  57. data/lib/asker/files/language/fr/templates.yaml +29 -0
  58. data/lib/asker/{lang/locales → files/language}/javascript/connectors.yaml +0 -0
  59. data/lib/asker/{lang/locales → files/language}/javascript/mistakes.yaml +0 -0
  60. data/lib/asker/{lang/locales → files/language}/javascript/templates.yaml +0 -0
  61. data/lib/asker/{lang/locales → files/language}/math/connectors.yaml +0 -0
  62. data/lib/asker/{lang/locales → files/language}/math/mistakes.yaml +0 -0
  63. data/lib/asker/{lang/locales → files/language}/math/templates.yaml +0 -0
  64. data/lib/asker/{lang/locales → files/language}/python/connectors.yaml +0 -0
  65. data/lib/asker/{lang/locales → files/language}/python/mistakes.yaml +0 -0
  66. data/lib/asker/{lang/locales → files/language}/python/templates.yaml +0 -0
  67. data/lib/asker/{lang/locales → files/language}/ruby/connectors.yaml +0 -0
  68. data/lib/asker/{lang/locales → files/language}/ruby/mistakes.yaml +0 -0
  69. data/lib/asker/{lang/locales → files/language}/ruby/templates.yaml +0 -0
  70. data/lib/asker/{lang/locales → files/language}/sql/connectors.yaml +0 -0
  71. data/lib/asker/{lang/locales → files/language}/sql/mistakes.yaml +0 -0
  72. data/lib/asker/{lang/locales → files/language}/sql/templates.yaml +0 -0
  73. data/lib/asker/formatter/concept_doc_formatter.rb +0 -4
  74. data/lib/asker/formatter/concept_string_formatter.rb +7 -4
  75. data/lib/asker/formatter/moodle/matching.erb +38 -0
  76. data/lib/asker/formatter/moodle/multichoice.erb +49 -0
  77. data/lib/asker/formatter/moodle/shortanswer.erb +30 -0
  78. data/lib/asker/formatter/moodle/truefalse.erb +47 -0
  79. data/lib/asker/formatter/question_gift_formatter.rb +30 -20
  80. data/lib/asker/formatter/question_moodle_formatter.rb +27 -0
  81. data/lib/asker/{checker.rb → input_checker.rb} +126 -49
  82. data/lib/asker/lang/lang.rb +17 -10
  83. data/lib/asker/lang/lang_factory.rb +32 -5
  84. data/lib/asker/lang/text_actions.rb +87 -69
  85. data/lib/asker/loader/code_loader.rb +4 -4
  86. data/lib/asker/loader/content_loader.rb +21 -19
  87. data/lib/asker/loader/directory_loader.rb +1 -8
  88. data/lib/asker/loader/embedded_file.rb +42 -0
  89. data/lib/asker/loader/file_loader.rb +3 -14
  90. data/lib/asker/loader/haml_loader.rb +15 -0
  91. data/lib/asker/loader/image_url_loader.rb +8 -12
  92. data/lib/asker/loader/input_loader.rb +13 -15
  93. data/lib/asker/loader/project_loader.rb +25 -15
  94. data/lib/asker/logger.rb +36 -9
  95. data/lib/asker/skeleton.rb +23 -13
  96. data/lib/asker.rb +76 -42
  97. metadata +53 -54
  98. data/lib/asker/code/ai/base_code_ai.rb +0 -48
  99. data/lib/asker/code/code.rb +0 -53
  100. data/lib/asker/lang/locales/du/templates.yaml +0 -50
  101. data/lib/asker/lang/locales/en/templates.yaml +0 -29
  102. data/lib/asker/lang/locales/es/templates.yaml +0 -29
  103. data/lib/asker/lang/locales/fr/connectors.yaml +0 -92
  104. data/lib/asker/lang/locales/fr/templates.yaml +0 -29
  105. data/lib/asker/project.rb +0 -172
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 39bc74c80c6c83d62fb43bee32e10d3c3503880132cbaaa81f5e14115c9286d7
4
- data.tar.gz: b60194338ffb8429c665d726b62f784c7a0787efb79db4a079b4c13bcbcd6fe8
3
+ metadata.gz: cb2119553ee0f5bce53f1aebe3468aabb5488ce02c54004c09df4d1256867cf5
4
+ data.tar.gz: 29bc8b727e10beb791eac5a113751f6d26ec9036cf3158aec583a93505fb3ba5
5
5
  SHA512:
6
- metadata.gz: 11b8da624fedb21e507ec7f015e8e921d8d2a85efd613e1a85646114e4b505a73f303b96b2a76ce77653cf511143f495dffcb6477959eb43ad139446547e55ae
7
- data.tar.gz: f6c64ac247cada2b4099385e77b2e86b953f60d4250a01f2907ff811b92d10d50628ffeb0c1f8921bef5900be3f46bec18f664276e03441e8af7ae7183965f28
6
+ metadata.gz: b3f277896c860c2987c25b4088922328f922fa52c8e2bb32ba92b6d90c6b86e05f2c0c9a056f3c69139148266f6bd4443192ca4d6892ee6e6884fb1e6cb3bad4
7
+ data.tar.gz: f9bb53fa2c7d5ee05566eb19657e4997d84dea2f521e1445a64fb658b06a7b6b1326e8b3d010fa21b5758c8538fc33ed1f675752493db4a366be9ac881944057
data/README.md CHANGED
@@ -1,43 +1,40 @@
1
- # ASKER (version 2.1)
1
+ [![Gem Version](https://badge.fury.io/rb/asker-tool.svg)](https://badge.fury.io/rb/asker-tool)
2
2
 
3
- Generate a lot of questions from an _input file_ base on your own _definitions_.
3
+ # ASKER (devel 2.3)
4
4
 
5
- ---
6
- # Description
5
+ Generate a lot of questions from an _input_ text file with on your own _definitions_. In a way, this _input file_ is a concept map.
6
+
7
+ ![logo](./docs/images/logo.png)
7
8
 
8
9
  ASKER helps trainers to create a huge amount of questions, from a definitions (_conceptual entities_) input file.
9
10
 
10
- * Free Software [LICENSE](https://github.com/dvarrui/asker/blob/devel/LICENSE).
11
+ * Free Software [LICENSE](https://github.com/dvarrui/asker/blob/devel/LICENSE.txt).
11
12
  * Multiplatform.
12
13
  * Ruby program.
13
14
 
14
- ---
15
- # Installation
15
+ ## Installation
16
16
 
17
17
  1. Install Ruby on your system.
18
18
  2. `gem install asker-tool`
19
19
 
20
- ---
21
- # Usage
20
+ ## Usage
22
21
 
23
22
  Steps:
24
23
 
25
24
  1. Create an input file with your definitions (_conceptual entities_).
26
25
  1. Run _asker_ and get the results into `output` directory.
27
26
 
28
- Run `asker` with our example input file as argument (`jedi.haml`):
27
+ Example: Running `asker` with our example input file as argument (`acdc.haml`):
29
28
 
30
29
  ```
31
- asker docs/examples/starwars/jedi.haml
30
+ asker docs/examples/bands/acdc.haml
32
31
  ```
33
32
 
34
33
  * Output files created into the `output` folder.
35
- * This example use an example input definition file `docs/examples/starwars/jedi.haml`, with concepts about _"Jedi's"_. ;-)
36
- * More [example input files](https://github.com/dvarrui/asker/tree/devel/docs/examples).
34
+ * More [example input files](./docs/examples).
37
35
  * More asker input files at `github/dvarrui/asker-inputs` repository.
38
36
 
39
- ---
40
- # Documentation
37
+ ## Documentation
41
38
 
42
39
  * [Installation](https://github.com/dvarrui/asker/blob/devel/docs/install/README.md)
43
40
  * [Inputs](https://github.com/dvarrui/asker/blob/devel/docs/inputs/README.md)
@@ -46,8 +43,7 @@ asker docs/examples/starwars/jedi.haml
46
43
  * [Base idea](https://github.com/dvarrui/asker/blob/devel/docs/idea.md)
47
44
  * [History](https://github.com/dvarrui/asker/blob/devel/docs/history.md)
48
45
 
49
- ---
50
- # Contact
46
+ ## Contact
51
47
 
52
48
  * **Email**: `teuton.software@protonmail.com`
53
49
  * **Twitter**: `@SoftwareTeuton`
data/bin/asker CHANGED
@@ -1,4 +1,5 @@
1
- #!/usr/bin/ruby
1
+ #!/usr/bin/env ruby
2
2
  require 'asker/cli'
3
+
3
4
  # Start Asker command line interface
4
5
  CLI.start(ARGV)
data/lib/asker/ai/ai.rb CHANGED
@@ -6,14 +6,14 @@ require_relative 'ai_calculate'
6
6
  # Description: Method to be included into every ConceptAI instance.
7
7
  # * make_questions: use AI to fill @questions Array
8
8
  module AI
9
- include AI_calculate
9
+ include AICalculate
10
10
 
11
11
  def make_questions
12
- return unless process?
12
+ return unless concept.process?
13
13
 
14
14
  make_questions_stages_di
15
15
  # Process every table of this concept
16
- tables.each do |tab|
16
+ concept.tables.each do |tab|
17
17
  list1, list2 = get_list1_and_list2_from(tab)
18
18
  make_questions_stages_bsf(tab, list1, list2)
19
19
  make_questions_stages_t(tab, list1, list2)
@@ -23,11 +23,13 @@ module AI
23
23
  exclude_questions
24
24
  end
25
25
 
26
+ # Make questions for states D and I
26
27
  def make_questions_stages_di
27
28
  @questions[:d] = StageD.new(self).run # Process every def{type=text}
28
29
  @questions[:i] = StageI.new(self).run # Process every def{type=image_url}
29
30
  end
30
31
 
32
+ # Make questions for stages B, S and F
31
33
  def make_questions_stages_bsf(tab, list1, list2)
32
34
  # Stage B: process table to make match questions
33
35
  @questions[:b] += StageB.new(self).run(tab, list1, list2)
@@ -37,6 +39,7 @@ module AI
37
39
  @questions[:f] += StageF.new(self).run(tab, list1, list2)
38
40
  end
39
41
 
42
+ # Make questions for stage T
40
43
  def make_questions_stages_t(tab, list1, list2)
41
44
  # Stage T: process_tableXfields
42
45
  list3 = list1 + list2
@@ -46,6 +49,8 @@ module AI
46
49
  end
47
50
  end
48
51
 
52
+ # rubocop:disable Metrics/AbcSize
53
+ # rubocop:disable Metrics/MethodLength
49
54
  def exclude_questions
50
55
  param = Application.instance.config['questions']['exclude']
51
56
  return if param.nil?
@@ -61,6 +66,8 @@ module AI
61
66
  @questions = input
62
67
  @excluded_questions = output
63
68
  end
69
+ # rubocop:enable Metrics/AbcSize
70
+ # rubocop:enable Metrics/MethodLength
64
71
 
65
72
  def string_has_this_tags?(input, tags)
66
73
  flag = false
@@ -1,29 +1,39 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Methods that calculate something
4
- module AI_calculate
5
- def get_list1_and_list2_from(ltable)
4
+ module AICalculate
5
+ ##
6
+ # Calculate and return list1 and list2
7
+ # * return list1 (Array) List with all the rows from the table
8
+ # * return list2 (Array) List with similar rows (same table name) from the neighbours tables
9
+ # @param p_table (Table)
10
+ # rubocop:disable Metrics/MethodLength
11
+ # rubocop:disable Metrics/AbcSize
12
+ def get_list1_and_list2_from(p_table)
6
13
  # create <list1> with all the rows from the table
7
14
  list1 = []
8
15
  count = 1
9
- ltable.rows.each do |i|
16
+ p_table.rows.each do |i|
10
17
  list1 << { id: count, weight: 0, data: i }
11
18
  count += 1
12
19
  end
13
20
 
14
21
  # create a <list2> with similar rows (same table name) from the neighbours tables
15
22
  list2 = []
16
- neighbors.each do |n|
23
+ concept.neighbors.each do |n|
17
24
  n[:concept].tables.each do |t2|
18
- next if t2.name != ltable.name
25
+ next if t2.name != p_table.name
26
+
19
27
  t2.rows.each do |i|
20
28
  list2 << { id: count, weight: 0, data: i }
21
29
  count += 1
22
30
  end
23
31
  end
24
32
  end
25
- return list1, list2
33
+ [list1, list2]
26
34
  end
35
+ # rubocop:enable Metrics/MethodLength
36
+ # rubocop:enable Metrics/AbcSize
27
37
 
28
38
  def calculate_nearness_between_texts(text1, text2)
29
39
  return 0.0 if text2.nil? || text2.empty?
@@ -34,6 +44,8 @@ module AI_calculate
34
44
  (count * 100 / words.count)
35
45
  end
36
46
 
47
+ # rubocop:disable Metrics/MethodLength
48
+ # rubocop:disable Metrics/AbcSize
37
49
  def reorder_list_with_row(list, row)
38
50
  # evaluate every row of the list2
39
51
  list.each do |r|
@@ -52,4 +64,6 @@ module AI_calculate
52
64
  list.sort! { |a, b| a[:weight] <=> b[:weight] }
53
65
  list.reverse!
54
66
  end
67
+ # rubocop:enable Metrics/MethodLength
68
+ # rubocop:enable Metrics/AbcSize
55
69
  end
@@ -0,0 +1,104 @@
1
+ # frozen_string_literal: false
2
+
3
+ require_relative '../../lang/lang_factory'
4
+ require_relative '../../ai/question'
5
+
6
+ ##
7
+ # BaseCodeAI class
8
+ class BaseCodeAI
9
+ attr_reader :questions
10
+
11
+ ##
12
+ # Create CodeAI object from Code data
13
+ # @param code (Code)
14
+ def initialize(code)
15
+ @code = code
16
+ @lines = code.lines
17
+ @num = 0
18
+ @questions = []
19
+ make_questions
20
+ end
21
+
22
+ ##
23
+ # Return the name of code
24
+ # @return String
25
+ def name
26
+ File.basename(@code.filename)
27
+ end
28
+
29
+ def process?
30
+ @code.process?
31
+ end
32
+
33
+ def type
34
+ @code.type
35
+ end
36
+
37
+ def filename
38
+ @code.filename
39
+ end
40
+
41
+ def lines
42
+ @code.lines
43
+ end
44
+
45
+ ##
46
+ # Counter
47
+ # @return count
48
+ def num
49
+ @num += 1
50
+ end
51
+
52
+ ##
53
+ # Clone array
54
+ # @param array (Array)
55
+ # @return Array
56
+ def clone_array(array)
57
+ out = []
58
+ array.each { |item| out << item.dup }
59
+ out
60
+ end
61
+
62
+ ##
63
+ # Convert an array of lines into one String
64
+ # @param lines (Array)
65
+ # @return String
66
+ # rubocop:disable Style/FormatString
67
+ def lines_to_s(lines)
68
+ out = ''
69
+ lines.each_with_index do |line, index|
70
+ out << "%2d: #{line}\n" % (index + 1)
71
+ end
72
+ out
73
+ end
74
+
75
+ ##
76
+ # Convert an array of lines into one HTML String
77
+ # @param lines (Array)
78
+ # @return String
79
+ def lines_to_html(lines)
80
+ out = ''
81
+ lines.each_with_index do |line, index|
82
+ out << "%2d: #{line}</br>" % (index + 1)
83
+ end
84
+ out
85
+ end
86
+ # rubocop:enable Style/FormatString
87
+
88
+ ##
89
+ # Make questions
90
+ def make_questions
91
+ list = find_make_methods
92
+ list.each { |m| @questions += send m }
93
+ @questions
94
+ end
95
+
96
+ private
97
+
98
+ def find_make_methods
99
+ list = public_methods.sort
100
+ list.select! { |name| name.to_s.start_with? 'make_' }
101
+ list.delete(:make_questions)
102
+ list
103
+ end
104
+ end
@@ -1,15 +1,25 @@
1
1
 
2
+ require 'rainbow'
2
3
  require_relative 'javascript_code_ai'
4
+ require_relative 'problem_code_ai'
3
5
  require_relative 'python_code_ai'
4
6
  require_relative 'ruby_code_ai'
5
7
  require_relative 'sql_code_ai'
6
8
 
9
+ ##
10
+ # CodeAI factory
7
11
  module CodeAIFactory
12
+ ##
13
+ # Return CodeAI associated to Code.type
14
+ # @param code (Code)
15
+ # @return CodeAI
8
16
  def self.get(code)
9
17
  type = code.type
10
18
  case type
11
19
  when :javascript
12
20
  return JavascriptCodeAI.new(code)
21
+ when :problem
22
+ return ProblemCodeAI.new(code)
13
23
  when :python
14
24
  return PythonCodeAI.new(code)
15
25
  when :ruby
@@ -19,7 +29,7 @@ module CodeAIFactory
19
29
  when :vagrantfile
20
30
  return RubyCodeAI.new(code)
21
31
  else
22
- puts "[ERROR] <#{type}> is not valid type"
32
+ puts Rainbow("[ERROR] <#{type}> is not valid type").red.bright
23
33
  end
24
34
  nil
25
35
  end
@@ -4,12 +4,9 @@ require_relative '../../ai/question'
4
4
  require_relative 'base_code_ai'
5
5
 
6
6
  class JavascriptCodeAI < BaseCodeAI
7
- def initialize(data_object)
8
- @data_object = data_object
9
- @lines = data_object.lines
7
+ def initialize(code)
10
8
  @lang = LangFactory.instance.get('javascript')
11
- @num = 0
12
- @questions = []
9
+ super code
13
10
  end
14
11
 
15
12
  def make_comment_error
@@ -0,0 +1,176 @@
1
+
2
+ require_relative '../../lang/lang_factory'
3
+ require_relative '../../ai/question'
4
+ require_relative 'base_code_ai'
5
+
6
+ ##
7
+ # Class for RubyCodeAI objects
8
+ class ProblemCodeAI < BaseCodeAI
9
+ def initialize(code)
10
+ @reduce = 1
11
+ @reduce = 4 if code.lines.size > 25
12
+ @lang = LangFactory.instance.get('es')
13
+ super code
14
+ end
15
+
16
+ ##
17
+ # Make errors about comments
18
+ def make_comment_error
19
+ questions = []
20
+ error_lines = []
21
+ @lines.each_with_index do |line,index|
22
+ if line.strip.start_with?('#')
23
+ lines = clone_array @lines
24
+ lines[index].sub!('#','').strip!
25
+
26
+ q = Question.new(:short)
27
+ q.name = "#{name}-#{num}-uncomment"
28
+ q.text = @lang.text_for(:code1,lines_to_html(lines))
29
+ q.shorts << (index+1)
30
+ q.feedback = 'Comment symbol removed'
31
+ questions << q
32
+ elsif line.strip.size>0
33
+ lines = clone_array @lines
34
+ lines[index]='# ' + lines[index]
35
+
36
+ q = Question.new(:short)
37
+ q.name = "#{name}-#{num}-comment"
38
+ q.text = @lang.text_for(:code1,lines_to_html(lines))
39
+ q.shorts << (index+1)
40
+ q.feedback = 'Comment symbol added'
41
+ questions << q
42
+ end
43
+ end
44
+ questions.shuffle[0,@lines.size/@reduce]
45
+ end
46
+
47
+ ##
48
+ # Make questions without errors
49
+ def make_no_error_changes
50
+ questions = []
51
+ empty_lines = []
52
+ used_lines = []
53
+ @lines.each_with_index do |line,index|
54
+ if line.strip.size.zero?
55
+ empty_lines << index
56
+ else
57
+ used_lines << index
58
+ end
59
+ end
60
+
61
+ used_lines.each do |index|
62
+ lines = clone_array(@lines)
63
+ lines.insert(index, ' ' * (rand(4).to_i + 1))
64
+ if @lines.size < 4 || rand(2) == 0
65
+ q = Question.new(:short)
66
+ q.name = "#{name}-#{num}-codeok"
67
+ q.text = @lang.text_for(:code1,lines_to_html(lines))
68
+ q.shorts << '0'
69
+ q.feedback = 'Code is OK'
70
+ questions << q
71
+ else
72
+ q = Question.new(:choice)
73
+ q.name = "#{name}-#{num}-codeok"
74
+ q.text = @lang.text_for(:code2,lines_to_html(lines))
75
+ others = (1..@lines.size).to_a.shuffle!
76
+ q.good = '0'
77
+ q.bads << others[0].to_s
78
+ q.bads << others[1].to_s
79
+ q.bads << others[2].to_s
80
+ q.feedback = 'Code is OK'
81
+ end
82
+ end
83
+
84
+ questions.shuffle[0,@lines.size/@reduce]
85
+ end
86
+
87
+ ##
88
+ # Make questions with syntax errors
89
+ def make_syntax_error
90
+ questions = []
91
+
92
+ @lang.mistakes.each_pair do |key,values|
93
+ error_lines = []
94
+ @lines.each_with_index do |line,index|
95
+ error_lines << index if line.include?(key.to_s)
96
+ end
97
+
98
+ v = values.split(',')
99
+ v.each do |value|
100
+ error_lines.each do |index|
101
+ lines = clone_array(@lines)
102
+ lines[index].sub!(key.to_s, value)
103
+ if @lines.size < 4 || rand(2) == 0
104
+ q = Question.new(:short)
105
+ q.name = "#{name}-#{num}-syntaxerror"
106
+ q.text = @lang.text_for(:code1,lines_to_html(lines))
107
+ q.shorts << (index+1)
108
+ q.feedback = "Syntax error: '#{value}' must be '#{key}'"
109
+ else
110
+ q = Question.new(:choice)
111
+ q.name = "#{name}-#{num}-syntaxerror"
112
+ q.text = @lang.text_for(:code2,lines_to_html(lines))
113
+ others = (1..@lines.size).to_a.shuffle!
114
+ others.delete(index+1)
115
+ q.good = (index + 1).to_s
116
+ q.bads << others[0].to_s
117
+ q.bads << others[1].to_s
118
+ q.bads << others[2].to_s
119
+ q.feedback = "Syntax error: '#{value}' must be '#{key}'"
120
+ end
121
+ questions << q
122
+ end
123
+ end
124
+ end
125
+ questions.shuffle[0,@lines.size/@reduce]
126
+ end
127
+
128
+ ##
129
+ # Make questions with variable errors
130
+ def make_variable_error
131
+ questions = []
132
+ error_lines = []
133
+ @lines.each_with_index do |line, index|
134
+ # Search Variable assignment
135
+ m = /\s*(\w*)\s*\=\w*/.match(line)
136
+ i = []
137
+ unless m.nil?
138
+ varname = (m.values_at 1)[0]
139
+ # Search used Variable
140
+ @lines.each_with_index do |line2, index2|
141
+ next if index >= index2
142
+ i << index2 if line2.include?(varname)
143
+ end
144
+ end
145
+ next if i.size == 0
146
+ i.shuffle!
147
+ i.each do |k|
148
+ lines = clone_array @lines
149
+ temp = lines[index]
150
+ lines[index] = lines[k]
151
+ lines[k] = temp
152
+
153
+ if rand(2) == 0
154
+ q = Question.new(:short)
155
+ q.name = "#{name}-#{num}-variable"
156
+ q.text = @lang.text_for(:code1, lines_to_html(lines))
157
+ q.shorts << (index + 1)
158
+ q.feedback = "Variable error! Swapped lines #{(index+1)} with #{(k+1)}"
159
+ else
160
+ q = Question.new(:choice)
161
+ q.name = "#{name}-#{num}-variable"
162
+ q.text = @lang.text_for(:code2, lines_to_html(lines))
163
+ others = (1..@lines.size).to_a.shuffle!
164
+ others.delete(index+1)
165
+ q.good = (index + 1).to_s
166
+ q.bads << others[0].to_s
167
+ q.bads << others[1].to_s
168
+ q.bads << others[2].to_s
169
+ q.feedback = "Variable error! Swapped lines #{(index+1)} with #{(k+1)}"
170
+ end
171
+ questions << q
172
+ end
173
+ end
174
+ questions.shuffle[0,@lines.size/@reduce]
175
+ end
176
+ end
@@ -4,12 +4,9 @@ require_relative '../../ai/question'
4
4
  require_relative 'base_code_ai'
5
5
 
6
6
  class PythonCodeAI < BaseCodeAI
7
- def initialize(data_object)
8
- @data_object = data_object
9
- @lines = data_object.lines
7
+ def initialize(code)
10
8
  @lang = LangFactory.instance.get('python')
11
- @num = 0
12
- @questions = []
9
+ super code
13
10
  end
14
11
 
15
12
  def make_comment_error
@@ -3,17 +3,18 @@ require_relative '../../lang/lang_factory'
3
3
  require_relative '../../ai/question'
4
4
  require_relative 'base_code_ai'
5
5
 
6
+ ##
7
+ # Class for RubyCodeAI objects
6
8
  class RubyCodeAI < BaseCodeAI
7
- def initialize(data_object)
8
- @data_object = data_object
9
- @lines = data_object.lines
10
- @lang = LangFactory.instance.get('ruby')
11
- @num = 0
12
- @questions = []
9
+ def initialize(code)
13
10
  @reduce = 1
14
- @reduce = 4 if @lines.size > 25
11
+ @reduce = 4 if code.lines.size > 25
12
+ @lang = LangFactory.instance.get('ruby')
13
+ super code
15
14
  end
16
15
 
16
+ ##
17
+ # Make errors about comments
17
18
  def make_comment_error
18
19
  questions = []
19
20
  error_lines = []
@@ -43,6 +44,8 @@ class RubyCodeAI < BaseCodeAI
43
44
  questions.shuffle[0,@lines.size/@reduce]
44
45
  end
45
46
 
47
+ ##
48
+ # Make questions without errors
46
49
  def make_no_error_changes
47
50
  questions = []
48
51
  empty_lines = []
@@ -81,6 +84,8 @@ class RubyCodeAI < BaseCodeAI
81
84
  questions.shuffle[0,@lines.size/@reduce]
82
85
  end
83
86
 
87
+ ##
88
+ # Make questions with syntax errors
84
89
  def make_syntax_error
85
90
  questions = []
86
91
 
@@ -120,6 +125,8 @@ class RubyCodeAI < BaseCodeAI
120
125
  questions.shuffle[0,@lines.size/@reduce]
121
126
  end
122
127
 
128
+ ##
129
+ # Make questions with variable errors
123
130
  def make_variable_error
124
131
  questions = []
125
132
  error_lines = []
@@ -4,12 +4,9 @@ require_relative '../../ai/question'
4
4
  require_relative 'base_code_ai'
5
5
 
6
6
  class SQLCodeAI < BaseCodeAI
7
- def initialize(data_object)
8
- @data_object = data_object
9
- @lines = data_object.lines
7
+ def initialize(code)
10
8
  @lang = LangFactory.instance.get('sql')
11
- @num = 0
12
- @questions = []
9
+ super code
13
10
  end
14
11
 
15
12
  def make_comment_error
@@ -17,14 +17,21 @@ class ConceptAI
17
17
  attr_reader :questions
18
18
  attr_reader :excluded_questions
19
19
 
20
+ ##
21
+ # Initialize ConcepAI
22
+ # @param concept (Concept)
23
+ # @param world (World)
20
24
  def initialize(concept, world)
21
25
  @concept = concept
22
26
  @world = world
23
27
  @questions = { d: [], b: [], f: [], i: [], s: [], t: [] }
24
28
  @excluded_questions = { d: [], b: [], f: [], i: [], s: [], t: [] }
25
- @num = 0 # Used to add a unique number to every question
29
+ @num = 0 # Add a unique number to every question
30
+ make_questions
26
31
  end
27
32
 
33
+ ##
34
+ # Generates and return new "num" value
28
35
  def num
29
36
  @num += 1
30
37
  @num.to_s
@@ -32,11 +39,14 @@ class ConceptAI
32
39
 
33
40
  # If a method call is missing, then delegate to concept parent.
34
41
  def method_missing(method, *args, &block)
42
+ raise "[DEBUG] ConceptAI.#{method}(#{args})"
35
43
  @concept.send(method, *args, &block)
36
44
  end
37
45
 
46
+ ##
47
+ # Generates random image URL
38
48
  def random_image_for(_conceptname)
39
- return '' if rand <= Project.instance.get(:threshold)
49
+ return '' if rand <= ProjectData.instance.get(:threshold)
40
50
 
41
51
  keys = @world.image_urls.keys
42
52
  keys.shuffle!
@@ -44,6 +54,6 @@ class ConceptAI
44
54
  return '' if values.nil?
45
55
 
46
56
  values.shuffle!
47
- "<img src=\"#{values[0]}\" alt\=\"image\"><br/>"
57
+ "<img src=\"#{values[0]}\" alt=\"image\"><br/>"
48
58
  end
49
59
  end