asker-tool 2.1.3 → 2.2.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 (130) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +18 -19
  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 +12 -2
  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 +24 -7
  23. data/lib/asker/checker.rb +149 -52
  24. data/lib/asker/cli.rb +37 -32
  25. data/lib/asker/data/code.rb +76 -0
  26. data/lib/asker/data/column.rb +31 -21
  27. data/lib/asker/data/concept.rb +108 -65
  28. data/lib/asker/data/data_field.rb +14 -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 +61 -32
  33. data/lib/asker/{exporter/code_screen_exporter.rb → displayer/code_displayer.rb} +13 -6
  34. data/lib/asker/displayer/concept_ai_displayer.erb +10 -0
  35. data/lib/asker/displayer/concept_ai_displayer.rb +133 -0
  36. data/lib/asker/displayer/concept_displayer.rb +34 -0
  37. data/lib/asker/displayer/stats_displayer.rb +22 -0
  38. data/lib/asker/exporter/code_gift_exporter.rb +10 -11
  39. data/lib/asker/exporter/concept_ai_gift_exporter.rb +21 -13
  40. data/lib/asker/exporter/concept_ai_moodle_exporter.rb +44 -0
  41. data/lib/asker/exporter/concept_ai_yaml_exporter.rb +14 -9
  42. data/lib/asker/exporter/concept_doc_exporter.rb +21 -14
  43. data/lib/asker/exporter/data_gift_exporter.rb +29 -0
  44. data/lib/asker/exporter/output_file_exporter.rb +21 -0
  45. data/lib/asker/files/{config.ini → asker.ini} +48 -1
  46. data/lib/asker/files/example-concept.haml +24 -8
  47. data/lib/asker/files/language/du/connectors.yaml +81 -0
  48. data/lib/asker/files/language/du/mistakes.yaml +82 -0
  49. data/lib/asker/files/language/du/templates.yaml +29 -0
  50. data/lib/asker/files/language/en/connectors.yaml +44 -0
  51. data/lib/asker/files/language/en/mistakes.yaml +37 -0
  52. data/lib/asker/files/language/en/templates.yaml +29 -0
  53. data/lib/asker/files/language/es/connectors.yaml +92 -0
  54. data/lib/asker/files/language/es/mistakes.yaml +84 -0
  55. data/lib/asker/files/language/es/templates.yaml +29 -0
  56. data/lib/asker/files/language/fr/connectors.yaml +76 -0
  57. data/lib/asker/files/language/fr/mistakes.yaml +82 -0
  58. data/lib/asker/files/language/fr/templates.yaml +29 -0
  59. data/lib/asker/files/language/javascript/connectors.yaml +11 -0
  60. data/lib/asker/files/language/javascript/mistakes.yaml +30 -0
  61. data/lib/asker/files/language/javascript/templates.yaml +3 -0
  62. data/lib/asker/files/language/math/connectors.yaml +2 -0
  63. data/lib/asker/files/language/math/mistakes.yaml +2 -0
  64. data/lib/asker/files/language/math/templates.yaml +1 -0
  65. data/lib/asker/files/language/python/connectors.yaml +11 -0
  66. data/lib/asker/files/language/python/mistakes.yaml +26 -0
  67. data/lib/asker/files/language/python/templates.yaml +3 -0
  68. data/lib/asker/files/language/ruby/connectors.yaml +11 -0
  69. data/lib/asker/files/language/ruby/mistakes.yaml +33 -0
  70. data/lib/asker/files/language/ruby/templates.yaml +3 -0
  71. data/lib/asker/files/language/sql/connectors.yaml +6 -0
  72. data/lib/asker/files/language/sql/mistakes.yaml +11 -0
  73. data/lib/asker/files/language/sql/templates.yaml +2 -0
  74. data/lib/asker/formatter/concept_string_formatter.rb +13 -9
  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/lang/lang.rb +18 -12
  82. data/lib/asker/lang/lang_factory.rb +32 -5
  83. data/lib/asker/lang/text_actions.rb +87 -69
  84. data/lib/asker/loader/code_loader.rb +4 -4
  85. data/lib/asker/loader/content_loader.rb +16 -12
  86. data/lib/asker/loader/directory_loader.rb +3 -3
  87. data/lib/asker/loader/embedded_file.rb +42 -0
  88. data/lib/asker/loader/file_loader.rb +3 -12
  89. data/lib/asker/loader/haml_loader.rb +15 -0
  90. data/lib/asker/loader/image_url_loader.rb +9 -11
  91. data/lib/asker/loader/input_loader.rb +24 -8
  92. data/lib/asker/loader/project_loader.rb +42 -30
  93. data/lib/asker/logger.rb +30 -6
  94. data/lib/asker/project.rb +28 -117
  95. data/lib/asker/skeleton.rb +40 -29
  96. data/lib/asker.rb +68 -79
  97. metadata +57 -74
  98. data/docs/changelog/v2.1.md +0 -99
  99. data/docs/commands.md +0 -12
  100. data/docs/contributions.md +0 -18
  101. data/docs/history.md +0 -40
  102. data/docs/idea.md +0 -44
  103. data/docs/inputs/README.md +0 -39
  104. data/docs/inputs/code.md +0 -69
  105. data/docs/inputs/concepts.md +0 -142
  106. data/docs/inputs/jedi.md +0 -68
  107. data/docs/inputs/tables.md +0 -112
  108. data/docs/inputs/templates.md +0 -87
  109. data/docs/install/README.md +0 -38
  110. data/docs/install/manual.md +0 -26
  111. data/docs/install/scripts.md +0 -38
  112. data/docs/revise/asker-file.md +0 -41
  113. data/docs/revise/buenas-practicas/01-convocatoria.md +0 -30
  114. data/docs/revise/buenas-practicas/02-formulario.md +0 -35
  115. data/docs/revise/buenas-practicas/03-descripcion.md +0 -63
  116. data/docs/revise/buenas-practicas/04-resultados.md +0 -17
  117. data/docs/revise/buenas-practicas/05-reproducir.md +0 -10
  118. data/docs/revise/ejemplos/01/README.md +0 -27
  119. data/docs/revise/ejemplos/02/README.md +0 -31
  120. data/docs/revise/ejemplos/03/README.md +0 -31
  121. data/docs/revise/ejemplos/04/README.md +0 -37
  122. data/docs/revise/ejemplos/05/README.md +0 -25
  123. data/docs/revise/ejemplos/06/README.md +0 -43
  124. data/docs/revise/ejemplos/README.md +0 -11
  125. data/docs/revise/projects.md +0 -74
  126. data/lib/asker/code/ai/base_code_ai.rb +0 -48
  127. data/lib/asker/code/code.rb +0 -53
  128. data/lib/asker/exporter/concept_ai_screen_exporter.rb +0 -115
  129. data/lib/asker/exporter/concept_screen_exporter.rb +0 -25
  130. data/lib/asker/exporter/main.rb +0 -9
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 649acd19a295cc267a200754428f54c987a688cf6b81487d4ea0f2662bc4968a
4
- data.tar.gz: bebb65797eefd45784b3a1db72d0f41c15ec6fca9e8792ca893670712fe425f3
3
+ metadata.gz: a17926e45cfc0549f76ae3d8ec9c5313565847e3615653f7520344e03eea63f7
4
+ data.tar.gz: 717620e1a5d56c65dc0ec601de61ffef208f3e21087e71e84a4c421e9e65c67f
5
5
  SHA512:
6
- metadata.gz: 7aa8c6683ed5931197398b88d2651c06f99fa75f713643bbf04f6c31fbad900d2cdc08efc7ccc6f3ab255de04d6345e7a2751786e760444e91fda4cf84cac1eb
7
- data.tar.gz: 3440de3f9bd77a4c0b3d0ce023ef76bf3335dfe555d52d7bea91b7a9148ac0804659803ae5bd662452801e8c1cbdabc6bfe114b9ec4e2a4d74b5b5d3cef3ef8d
6
+ metadata.gz: 9ec3c2b84781c6c723edfbb0e5570edaabb8e26fd0d732bb9fa155d7b6fb5762115a44ba75899af7e0e0b399d6b764562de77dd31b0b2fe128c5dd97b39caf7d
7
+ data.tar.gz: 3f1aa7b3ce5a9f59f3c373bd246f5fd8e8000a163ec539f943f32144fff057f80b44ae06bc127a31eb3ad71de0bb431d010a737491e57695c202e97534674a69
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # ASKER (version 2.1)
1
+ # ASKER (version 2.2)
2
2
 
3
3
  Generate a lot of questions from an _input file_ base on your own _definitions_.
4
4
 
@@ -7,41 +7,40 @@ Generate a lot of questions from an _input file_ base on your own _definitions_.
7
7
 
8
8
  ASKER helps trainers to create a huge amount of questions, from a definitions (_conceptual entities_) input file.
9
9
 
10
- Steps:
11
-
12
- 1. Create an input file with your definitions (_conceptual entities_).
13
- 1. Run _asker_ and get the results into `output` directory.
14
-
15
- Features:
16
-
17
- * Free Software [LICENSE](https://github.com/dvarrui/asker/blob/devel/LICENSE).
10
+ * Free Software [LICENSE](https://github.com/dvarrui/asker/blob/devel/LICENSE.txt).
18
11
  * Multiplatform.
19
- * Input file formats: HAML, XML.
20
- * Output file format: GIFT (Moodle cuestionairs).
21
12
  * Ruby program.
22
13
 
14
+ ---
15
+ # Installation
16
+
17
+ 1. Install Ruby on your system.
18
+ 2. `gem install asker-tool`
19
+
23
20
  ---
24
21
  # Usage
25
22
 
26
- To execute ASKER, we use `asker` command, with a path to an input file as argument. For example, to run our `jedi.haml` input file example, we do:
23
+ Steps:
24
+
25
+ 1. Create an input file with your definitions (_conceptual entities_).
26
+ 1. Run _asker_ and get the results into `output` directory.
27
+
28
+ Example: Running `asker` with our example input file as argument (`jedi.haml`):
27
29
 
28
30
  ```
29
31
  asker docs/examples/starwars/jedi.haml
30
32
  ```
31
33
 
32
- * The program generates your output files into the `output` directory by default.
33
- * In this example, we use a demo input definition file `docs/examples/starwars/jedi.haml`, that contains conceptual entities about _"Jedi's"_ context.
34
- * [Example input files](https://github.com/dvarrui/asker/blob/devel/docs/examples).
35
- * More examples at `github/dvarrui/asker-inputs` repository.
34
+ * Output files created into the `output` folder.
35
+ * More [example input files](https://github.com/dvarrui/asker/tree/devel/docs/examples).
36
+ * More asker input files at `github/dvarrui/asker-inputs` repository.
36
37
 
37
38
  ---
38
39
  # Documentation
39
40
 
40
41
  * [Installation](https://github.com/dvarrui/asker/blob/devel/docs/install/README.md)
41
- 1. Install Ruby on your system.
42
- 2. `gem install asker-tool`
43
42
  * [Inputs](https://github.com/dvarrui/asker/blob/devel/docs/inputs/README.md)
44
- * [Commands](https://github.com/dvarrui/asker/blob/devel/docs/commands.md)
43
+ * [Usage](https://github.com/dvarrui/asker/blob/devel/docs/usage.md)
45
44
  * [Contributions](https://github.com/dvarrui/asker/blob/devel/docs/contributions.md)
46
45
  * [Base idea](https://github.com/dvarrui/asker/blob/devel/docs/idea.md)
47
46
  * [History](https://github.com/dvarrui/asker/blob/devel/docs/history.md)
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,9 +39,12 @@ 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
49
  return '' if rand <= Project.instance.get(:threshold)
40
50
 
@@ -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