mumuki-gobstones-runner 2.8.5 → 2.11.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5a1f462df1de2aa09e7025bc39fb066ebae0cf95203e2863276e549c57b35550
4
- data.tar.gz: b1e8fbb1a19f96b130b5a5a25b3d8e582932b5c1d4063ece0ddcfe5358394980
3
+ metadata.gz: 1636b8a5a322c4a74f84a725e8df8fa0118e38362b3732a70e76deba7b87e620
4
+ data.tar.gz: 41d818b4cb24ce921ed45f0c539437ac0395ddc4152e2f5a4ebf3e2a19168b07
5
5
  SHA512:
6
- metadata.gz: dbb901882298f1c889730748bfb60ba8016535198e2953d6f5b72f986f617c65230cdf06b7a7a6326459d9a11b2d46945df9dc1c9faf10c5b46f05fcab65fa8e
7
- data.tar.gz: 3ce96b0e01751e64a831a56565352eb378b612aee687d074e116911d305004f97e7c9feacb5522b2582b264a1ad90c1a67fdb4ded965504c2a56aa1a427bfe5e
6
+ metadata.gz: bb2ac8c37f98b4239de66fdc9f4b73982a013769add4d71172561e7d399774038647690468193a2dee19d2c8cf886582538f4bfc13479057a3837918affec4d0
7
+ data.tar.gz: aba3b7d54384b3c44587219236ccfb4d3720560d63f5d7ac8193bc95604e4ec1ddd3de32544c8fcbaf0d3f396d19c62b3c9b6576b036e27f17d7d207d155b827
@@ -54,6 +54,8 @@ class Mumukit::Server::App < Sinatra::Base
54
54
 
55
55
  get '/assets/editor/editor.html' do
56
56
  cross_origin
57
+ content_type 'text/html'
58
+
57
59
  @game_framework_extra = Gobstones::CompilationMode::GameFramework.extra_code
58
60
  @game_framework_program = Gobstones::CompilationMode::GameFramework.program_code
59
61
  @game_framework_default = Gobstones::CompilationMode::GameFramework.default_code
@@ -113,6 +113,7 @@ module Gobstones
113
113
  return "no_stones" if code == 'cannot-remove-stone'
114
114
  return "out_of_board" if code == 'cannot-move-to'
115
115
  return "unassigned_variable" if code == 'undefined-variable'
116
+ return "boom_called" if code == 'boom-called'
116
117
  return "wrong_argument_type" if has_wrong_argument_type? code
117
118
  return "wrong_arguments_quantity" if code.include? 'arity-mismatch'
118
119
 
@@ -0,0 +1,210 @@
1
+ class GobstonesFeedbackHook < Mumukit::Hook
2
+ def run!(request, results)
3
+ content = request.content
4
+ test_results = results.test_results[0]
5
+
6
+ GobstonesExplainer.new.explain(content, test_results) if test_results.is_a? String
7
+ end
8
+
9
+ class GobstonesExplainer < Mumukit::Explainer
10
+ def explain_program_has_a_name(submission, result)
11
+ if identifier_instead_of_brace? result
12
+ (submission.match malformed_program_header_with_name).try do |it|
13
+ { name: it[1] }
14
+ end
15
+ end
16
+ end
17
+
18
+ def explain_program_has_no_opening_curly_brace(submission, result)
19
+ if identifier_instead_of_brace? result
20
+ /#{malformed_program_header_with_no_curly_braces}/ =~ submission
21
+ end
22
+ end
23
+
24
+ def explain_program_before_closing_structure_when_program(submission, result)
25
+ if program_instead_of_command?(result) && missing_brace_end?(submission) && function_or_procedure?(submission)
26
+ (submission.match program).try do |it|
27
+ { keyword: last_function_or_procedure(submission) }
28
+ end
29
+ end
30
+ end
31
+
32
+ def explain_program_before_closing_structure_when_no_program(submission, result)
33
+ if program_instead_of_command?(result) && missing_brace_end?(submission) && function_or_procedure?(submission)
34
+ if /#{program}/ =~ submission
35
+ nil
36
+ else
37
+ { keyword: last_function_or_procedure(submission) }
38
+ end
39
+ end
40
+ end
41
+
42
+ def explain_surplus_closing_brace(_, result)
43
+ if unbalanced_closing_braces? result
44
+ (error_line(result)).try do |it|
45
+ { line: it[1] }
46
+ end
47
+ end
48
+ end
49
+
50
+ def explain_upper_function_typo(submission, result)
51
+ if upper_identifier_instead_of_definition? result
52
+ /#{uppercase_function}/ =~ submission
53
+ end
54
+ end
55
+
56
+ def explain_upper_procedure_typo(submission, result)
57
+ if upper_identifier_instead_of_definition? result
58
+ /#{uppercase_procedure}/ =~ submission
59
+ end
60
+ end
61
+
62
+ def explain_upper_program_typo(submission, result)
63
+ if upper_identifier_instead_of_definition? result
64
+ /#{uppercase_program}/ =~ submission
65
+ end
66
+ end
67
+
68
+ def explain_missing_closing_brace_after_procedure(submission, result)
69
+ if procedure_instead_of_command?(result) && missing_brace_end?(submission)
70
+ (error_line(result)).try do |it|
71
+ { line: it[1] }
72
+ end
73
+ end
74
+ end
75
+
76
+ def explain_lower_builtin_procedure_typo(submission, result)
77
+ if open_paren_instead_of_assign?(result)
78
+ (submission.match lower_builtin_procedure).try do |it|
79
+ { lower: it[1][0...5], upper: it[1][0...5].capitalize }
80
+ end
81
+ end
82
+ end
83
+
84
+ def explain_upper_builtin_function_typo(submission, result)
85
+ if procedure_invocation_instead_of_expression?(result)
86
+ (submission.match upper_builtin_function).try do |it|
87
+ { upper: it[1], lower: it[1].camelize(:lower) }
88
+ end
89
+ end
90
+ end
91
+
92
+ def explain_color_typo(_, result)
93
+ if roja_not_defined?(result) || negra_not_defined?(result)
94
+ (result.match color_not_defined).try do |it|
95
+ { color: it[1], rectified_color: rectified_color(it[1]) }
96
+ end
97
+ end
98
+ end
99
+
100
+ private
101
+
102
+ def malformed_program_header_with_name
103
+ '.*program +([A-Za-z]\w*)'
104
+ end
105
+
106
+ def upper_identifier_instead_of_brace?(result)
107
+ identifier_instead_of_brace?(result, 'may')
108
+ end
109
+
110
+ def lower_identifier_instead_of_brace?(result)
111
+ identifier_instead_of_brace?(result, 'min')
112
+ end
113
+
114
+ def identifier_instead_of_brace?(result, capital='...')
115
+ result.match? /<pre>\[\d+:\d+\]: Se esperaba una llave izquierda \("{"\).\nSe encontró: un identificador con #{capital}úsculas.<\/pre>/
116
+ end
117
+
118
+ def malformed_program_header_with_no_curly_braces
119
+ '.*program *[\r\n]\s*[^{]\w+'
120
+ end
121
+
122
+ def program_instead_of_command?(result)
123
+ result.match? /<pre>\[\d+:\d+\]: Se esperaba un comando.\nSe encontró: la palabra clave "program".<\/pre>/
124
+ end
125
+
126
+ def missing_brace_end?(submission)
127
+ submission.count('{') > submission.count('}')
128
+ end
129
+
130
+ def function_or_procedure?(submission)
131
+ submission.match? function_or_procedure
132
+ end
133
+
134
+ def function_or_procedure
135
+ '(function)\s*\w+\s*\([\w\d\s,]*\)\s*{|(procedure)\s*\w+\s*\([\w\d\s,]*\)\s*{'
136
+ end
137
+
138
+ def last_function_or_procedure(submission)
139
+ submission.scan(/#{function_or_procedure}/).last.compact.first
140
+ end
141
+
142
+ def program
143
+ 'program\s*{'
144
+ end
145
+
146
+ def unbalanced_closing_braces?(result)
147
+ result.match? /<pre>\[\d+:\d+\]: Se encontró un "}" pero no había una llave abierta "{".<\/pre>/
148
+ end
149
+
150
+ def error_line(result)
151
+ result.match /<pre>\[(\d+):\d+\]:/
152
+ end
153
+
154
+ def upper_identifier_instead_of_definition?(result)
155
+ result.match? /<pre>\[\d+:\d+\]: Se esperaba una definición \(de programa, función, procedimiento, o tipo\).\nSe encontró: un identificador con mayúsculas.<\/pre>/
156
+ end
157
+
158
+ def uppercase_function
159
+ 'Function\s'
160
+ end
161
+
162
+ def uppercase_procedure
163
+ 'Procedure\s'
164
+ end
165
+
166
+ def uppercase_program
167
+ 'Program[\s{]*'
168
+ end
169
+
170
+ def procedure_instead_of_command?(result)
171
+ result.match? /<pre>\[\d+:\d+\]: Se esperaba un comando.\nSe encontró: la palabra clave "procedure".<\/pre>/
172
+ end
173
+
174
+ def open_paren_instead_of_assign?(result)
175
+ result.match? /<pre>\[\d+:\d+\]: Se esperaba un operador de asignación \(":="\).\nSe encontró: un paréntesis izquierdo \("\("\).<\/pre>/
176
+ end
177
+
178
+ def lower_builtin_procedure
179
+ '(mover[\s(]|poner[\s(]|sacar[\s(])'
180
+ end
181
+
182
+ def procedure_invocation_instead_of_expression?(result)
183
+ result.match? /<pre>\[\d+:\d+\]: Se esperaba una expresión.\nSe encontró: una invocación a un procedimiento.<\/pre>/
184
+ end
185
+
186
+ def upper_builtin_function
187
+ '(PuedeMover|NroBolitas|HayBolitas)'
188
+ end
189
+
190
+ def roja_not_defined?(result)
191
+ color_not_defined? result, 'Roja'
192
+ end
193
+
194
+ def negra_not_defined?(result)
195
+ color_not_defined? result, 'Negra'
196
+ end
197
+
198
+ def color_not_defined?(result, color)
199
+ result.match?(color_not_defined(color))
200
+ end
201
+
202
+ def color_not_defined(color='\w+')
203
+ /<pre>\[\d+:\d+\]: El constructor "(#{color})" no está definido.<\/pre>/
204
+ end
205
+
206
+ def rectified_color(color)
207
+ color.chop + "o"
208
+ end
209
+ end
210
+ end
@@ -21,9 +21,10 @@ require_relative './render/html_renderer'
21
21
 
22
22
  require_relative './multiple_executions_runner'
23
23
 
24
+ require_relative './checker'
25
+ require_relative './expectations_hook'
26
+ require_relative './feedback_hook'
24
27
  require_relative './metadata_hook'
25
28
  require_relative './precompile_hook'
26
29
  require_relative './test_hook'
27
30
  require_relative './version_hook'
28
- require_relative './expectations_hook'
29
- require_relative './checker'
@@ -12,7 +12,19 @@ en:
12
12
  code_wrong_argument_type: 'wrong arguments type'
13
13
  code_unassigned_variable: 'unassigned variable'
14
14
  code_wrong_arguments_quantity: 'wrong arguments quantity'
15
+ color_typo: 'It seems you wrote %{color}. Maybe you meant %{rectified_color}?'
15
16
  expected_board: 'Expected final board'
16
17
  final_board: 'Final board'
17
18
  initial_board: 'Initial board'
19
+ lower_builtin_procedure_typo: 'Looks lie you wrote <code>%{lower}</code> in lowercase. Remember procedures such as <code>%{upper}()</code> should start in uppercase!'
20
+ missing_closing_brace_after_procedure: "Looks like you're missing a <code>}</code> to close a <code>procedure</code>. Maybe it's on line <strong>%{line}</strong> or near it?"
18
21
  no_program_found: 'No program definition was found'
22
+ program_before_closing_structure_when_no_program: "Looks like you're missing a <code>}</code> to close the last <code>%{keyword}</code>."
23
+ program_before_closing_structure_when_program: "Looks like you're missing a <code>}</code> to close the last <code>%{keyword}</code> before <code>program</code>."
24
+ program_has_a_name: "Looks like you named your <code>program</code> <code>%{name}</code>, but <code>program</code>s shouldn't be named."
25
+ program_has_no_opening_curly_brace: "Looks like a <code>{</code> is missing on <code>program</code>. Remember the content in <code>program</code> should be between curly braces."
26
+ surplus_closing_brace: "The amount of <code>{</code> and <code>}</code> doesn't match. Maybe there's an extra <code>}</code> on line <strong>%{line}</strong> or near it?"
27
+ upper_builtin_function_typo: 'Looks like you wrote <code>%{upper}</code> starting in uppercase. Remember functions such as <code>%{lower}</code> should start in lowercase!'
28
+ upper_function_typo: 'Looks like you wrote <code>Function</code> instead of <code>function</code>. Remember it should start in lowercase!'
29
+ upper_procedure_typo: 'Looks like you wrote <code>Procedure</code> instead of <code>procedure</code>. Remember it should start in lowercase!'
30
+ upper_program_typo: 'Looks like you wrote <code>Program</code> instead of <code>program</code>. Remember it should start in lowercase!'
@@ -12,7 +12,19 @@ es:
12
12
  code_wrong_argument_type: 'problema de tipos en los argumentos'
13
13
  code_unassigned_variable: 'variable no asignada'
14
14
  code_wrong_arguments_quantity: 'cantidad errónea de argumentos'
15
+ color_typo: 'Parece que escribiste %{color}. ¿Quisiste referirte al color %{rectified_color}?'
15
16
  expected_board: 'Tablero final esperado'
16
17
  final_board: 'Tablero final'
17
18
  initial_board: 'Tablero inicial'
19
+ lower_builtin_procedure_typo: 'Parece que escribiste <code>%{lower}</code> en minúsculas. ¡Recordá que los procedimientos como <code>%{upper}()</code> deben comenzar en mayúsculas!'
20
+ missing_closing_brace_after_procedure: 'Parece que te falta una <code>}</code> que cierre un <code>procedure</code>. ¿Puede que sea en la línea <strong>%{line}</strong> o cerca de ella?'
18
21
  no_program_found: 'No se encontró ninguna definición de programa'
22
+ program_before_closing_structure_when_no_program: 'Parece que te falta una <code>}</code> que cierre el último <code>%{keyword}</code>.'
23
+ program_before_closing_structure_when_program: 'Parece que te falta una <code>}</code> que cierre el <code>%{keyword}</code> antes de <code>program</code>.'
24
+ program_has_a_name: 'Parece que llamaste <code>%{name}</code> a <code>program</code>, pero los <code>program</code> no llevan nombre.'
25
+ program_has_no_opening_curly_brace: 'Parece que a <code>program</code> le falta <code>{</code>. Recordá que el contenido de <code>program</code> va entre llaves.'
26
+ surplus_closing_brace: 'La cantidad de <code>{</code> y <code>}</code> no coincide. ¿Puede que sobre una <code>}</code> en la línea <strong>%{line}</strong> o cerca de ella?'
27
+ upper_builtin_function_typo: 'Parece que escribiste <code>%{upper}</code> comenzando en mayúsculas. ¡Recordá que las funciones como <code>%{lower}</code> deben comenzar en minúsculas!'
28
+ upper_function_typo: 'Parece que escribiste <code>Function</code> en lugar de <code>function</code>. ¡Recordá que debe comenzar en minúsculas!'
29
+ upper_procedure_typo: 'Parece que escribiste <code>Procedure</code> en lugar de <code>procedure</code>. ¡Recordá que debe comenzar en minúsculas!'
30
+ upper_program_typo: 'Parece que escribiste <code>Program</code> en lugar de <code>program</code>. ¡Recordá que debe comenzar en minúsculas!'
@@ -12,7 +12,19 @@ pt:
12
12
  code_wrong_argument_type: 'problema de tipos nos argumentos'
13
13
  code_unassigned_variable: 'variável não atribuída'
14
14
  code_wrong_arguments_quantity: 'quantidade errada de argumentos'
15
+ color_typo: 'Parece que você escreveu %{color}. Você quis se referir à cor %{rectified_color}?'
15
16
  expected_board: 'Tabuleiro final esperado'
16
17
  final_board: 'Tabuleiro final'
17
18
  initial_board: 'Tabuleiro inicial'
19
+ lower_builtin_procedure_typo: 'Parece que você escreveu <code>%{lower}</code> em letras minúsculas. Lembre-se de que procedimentos como <code>%{upper}()</code> devem começar em maiúsculas!'
20
+ missing_closing_brace_after_procedure: 'Parece que está faltando um <code>}</code> que fecha um <code>procedure</code>. Pode ser na linha <strong>%{line}</strong> ou perto dela?'
18
21
  no_program_found: 'Nenhuma definição de programa foi encontrada'
22
+ program_before_closing_structure_when_no_program: 'Parece que está faltando um <code>}</code> que fecha a última <code>%{keyword}</code>.'
23
+ program_before_closing_structure_when_program: 'Parece que está faltando um <code>}</code> que fecha o <code>%{keyword}</code> antes do <code>program</code>.'
24
+ program_has_a_name: 'Parece que você chamou <code>%{name}</code> para <code>program</code>, mas <code>program</code>as não têm nomes.'
25
+ program_has_no_opening_curly_brace: 'Parece que a <code>program</code> está faltando <code>{</code>. Lembre-se de que o conteúdo do <code>program</code> está entre colchetes.'
26
+ surplus_closing_brace: 'A quantidade de <code>{</code> e <code>}</code> não corresponde. Pode ser sobre um <code>}</code> na linha <strong>%{line}</strong> ou próximo a ela?'
27
+ upper_builtin_function_typo: 'Parece que você digitou <code>%{upper}</code> começando com letras maiúsculas. Lembre-se de que funções como <code>%{lower}</code> devem começar em minúsculas!'
28
+ upper_function_typo: 'Parece que você escreveu <code>Function</code> em vez de <code>function</code>. Lembre-se de começar em letras minúsculas!'
29
+ upper_procedure_typo: 'Parece que você escreveu <code>Procedure</code> em vez de <code>procedure</code>. Lembre-se de começar em letras minúsculas!'
30
+ upper_program_typo: 'Parece que você escreveu <code>Program</code> em vez de <code>program</code>. Lembre-se de começar em letras minúsculas!'
Binary file
@@ -116,7 +116,6 @@
116
116
  }
117
117
  }
118
118
 
119
-
120
119
  .mu-kids-exercise.mu-kindergarten .gbs_boom {
121
120
  display: none;
122
121
  }
@@ -124,3 +123,13 @@
124
123
  .mu-kids-exercise.mu-kindergarten .mu-scenario.active table.gbs_board {
125
124
  display: block !important;
126
125
  }
126
+
127
+ .mu-kids-exercise.mu-kindergarten .gbs_gh {
128
+ outline: 0 !important;
129
+ }
130
+
131
+ .mu-kids-exercise.mu-kindergarten .mu-kids-state .mu-kids-state-image gs-board>table {
132
+ background-color: #6D6E70!important;
133
+ border: 1px solid #6D6E70 !important;
134
+ border-radius: 4px;
135
+ }
@@ -5,6 +5,29 @@
5
5
  <script src="./hammer.min.js"></script>
6
6
 
7
7
  <script>
8
+ Blockly.FieldImage.prototype.__setValue__ = Blockly.FieldImage.prototype.setValue;
9
+ Blockly.FieldImage.prototype.setValue = function(a) {
10
+ if (a && a.startsWith("undefined")) {
11
+ console.debug(`Ignoring unavailable image ${a}`);
12
+ } else if (a) {
13
+ const absoluteUrl = a
14
+ .replace("../media/", "../local-media/")
15
+ .replace("../local-media/", "<%= @assets_url %>/local-media/");
16
+ this.__setValue__(absoluteUrl);
17
+ } else {
18
+ this.__setValue__(a);
19
+ }
20
+ }
21
+
22
+ Blockly.FieldImage.prototype.__setTooltip__ = Blockly.FieldImage.prototype.setTooltip;
23
+ Blockly.FieldImage.prototype.setTooltip = function(a) {
24
+ try {
25
+ this.__setTooltip__(a);
26
+ } catch (_e) {
27
+ console.debug('Could not set tooltip');
28
+ }
29
+ }
30
+
8
31
  function postpone(action) {
9
32
  return setTimeout(action, 50);
10
33
  }
@@ -115,10 +138,28 @@
115
138
  this._scrollToMainBlock();
116
139
  },
117
140
 
118
- setToolbox(toolboxXml) {
119
- this._getBlockly().toolbox = { defaultToolbox: toolboxXml };
120
- // Blockly's workspace is destroyed when toolbox changes, so we initialize it here.
121
- this._initializeBlocklyWorkspace();
141
+ /**
142
+ * Configures a custom toolbox using a toolbox url
143
+ * This method does nothing if editor is read-only, but
144
+ * assumes a gs-toolbox element is present - otherwise it would
145
+ * have no sense to have a toolboxUrl.
146
+ */
147
+ configureCustomToolboxFromUrl(toolboxUrl) {
148
+ if (this.readOnly) return;
149
+
150
+ console.debug('Configuring custom toolbox');
151
+
152
+ $.get(toolboxUrl, (toolboxXml) => {
153
+ this._initializeCustomToolboxBlocklyWorkspace(toolboxXml);
154
+ });
155
+ },
156
+
157
+ /**
158
+ * Wether a custom toolbox is required. Read only editors and gs-toolbox-less context
159
+ * don't require it
160
+ */
161
+ hasCustomToolbox() {
162
+ return !this.readOnly && $('gs-toolbox').length;
122
163
  },
123
164
 
124
165
  compile(code) {
@@ -129,10 +170,6 @@
129
170
  return this._getBlockly().initialXml.indexOf("block type=\"InteractiveProgram\"") !== -1;
130
171
  },
131
172
 
132
- hasCustomToolbox() {
133
- return $('gs-toolbox').length;
134
- },
135
-
136
173
  toggleInteractiveMode() {
137
174
  this.$exerciseContainer.toggleClass('play-mode');
138
175
  this._triggerResize();
@@ -191,12 +228,7 @@
191
228
  _configureBlocklyBehavior() {
192
229
  this._setTeacherActions();
193
230
  this._setGameActions();
194
-
195
- // Blockly's workspace is destroyed when toolbox changes, so it doesn't make sense to initialize it here.
196
- if (!this.hasCustomToolbox()) {
197
- this._initializeBlocklyWorkspace();
198
- }
199
-
231
+ this._initializeNonCustomToolboxBlocklyWorkspace();
200
232
  this._registerLayoutChangedEvent();
201
233
  },
202
234
 
@@ -208,7 +240,34 @@
208
240
  $(window).resize(() => this._relocateTrash());
209
241
  },
210
242
 
243
+
244
+ /**
245
+ * Initializes a workspace using a custom toolbox.
246
+ *
247
+ * Blockly's workspace is destroyed when toolbox changes, so initialization
248
+ * is performed here
249
+ */
250
+ _initializeCustomToolboxBlocklyWorkspace(toolboxXml) {
251
+ this._getBlockly().toolbox = { defaultToolbox: toolboxXml };
252
+ this._initializeBlocklyWorkspace();
253
+ },
254
+
255
+ /**
256
+ * Initializes a workspace using a non-custom toolbox.
257
+ *
258
+ * Blockly's workspace is destroyed when toolbox changes,
259
+ * so this method will initialize it only if a there is a custom toolbox
260
+ * that will be called later.
261
+ */
262
+ _initializeNonCustomToolboxBlocklyWorkspace() {
263
+ if (!this.hasCustomToolbox()) {
264
+ this._initializeBlocklyWorkspace();
265
+ }
266
+ },
267
+
211
268
  _initializeBlocklyWorkspace() {
269
+ console.debug('Initializing Blockly Workspace');
270
+
212
271
  this._setInitialXml();
213
272
  this._initializeWorkspace();
214
273
  this._subscribeToWorkspace(() => this._updateSolution());
@@ -228,12 +287,18 @@
228
287
  },
229
288
 
230
289
  _updateSolution() {
290
+ console.debug("Updating solution");
231
291
  const blockly = this._getBlockly();
232
-
292
+ let changed;
233
293
  if (this.teacherMode) {
234
- this._setExtraCode(blockly.workspaceXml);
294
+ changed = this._setExtraCode(blockly.workspaceXml);
235
295
  } else {
236
- this._setStudentSolution(blockly.workspaceXml);
296
+ changed = this._setStudentSolution(blockly.workspaceXml);
297
+ }
298
+
299
+ if (!changed) {
300
+ console.debug("No solution update required")
301
+ return;
237
302
  }
238
303
 
239
304
  // TODO: this hack enables Angular two-way binding for Bibliotheca. Should be replaced with Mumuki events system
@@ -326,22 +391,44 @@
326
391
  return;
327
392
  }
328
393
 
329
- const blockly = this._getBlockly();
394
+ console.debug("Set teacher actions");
330
395
  const actions = new Parser().getActionsFromSource(teacherCode);
331
- blockly.primitiveProcedures = this._withDefaultIcons(actions, 'procedureDeclarations');
332
- blockly.primitiveFunctions = this._withDefaultIcons(actions, 'functionDeclarations');
396
+
397
+ this._setPrimitiveProcedures(this._withDefaultIcons(actions, 'procedureDeclarations'));
398
+ this._setPrimitiveFunctions(this._withDefaultIcons(actions, 'functionDeclarations'));
333
399
  },
334
400
 
335
401
  _setGameActions() {
402
+ if (!this._isGame()) {
403
+ return;
404
+ }
405
+
406
+ console.debug("Set game actions");
336
407
  const blockly = this._getBlockly();
337
- if (this._isGame()) {
338
- blockly.primitiveProcedures = blockly.primitiveProcedures || [];
339
- blockly.primitiveProcedures = blockly.primitiveProcedures.concat([
340
- this._gamePrimitive('ShiftUp'),
341
- this._gamePrimitive('ShiftDown'),
342
- this._gamePrimitive('ShiftLeft'),
343
- this._gamePrimitive('ShiftRight')
344
- ]);
408
+
409
+ this._setPrimitiveProcedures((blockly.primitiveProcedures || []).concat([
410
+ this._gamePrimitive('ShiftUp'),
411
+ this._gamePrimitive('ShiftDown'),
412
+ this._gamePrimitive('ShiftLeft'),
413
+ this._gamePrimitive('ShiftRight')
414
+ ]));
415
+ },
416
+
417
+ _setPrimitiveProcedures(procedures) {
418
+ this._setBlocklyActions("primitiveProcedures", procedures);
419
+ },
420
+
421
+ _setPrimitiveFunctions(functions) {
422
+ this._setBlocklyActions("primitiveFunctions", functions);
423
+ },
424
+
425
+ _setBlocklyActions(key, actions) {
426
+ try {
427
+ this._getBlockly()[key] = actions
428
+ } catch (e) {
429
+ if (this._getBlockly()[key] !== actions) {
430
+ throw e;
431
+ }
345
432
  }
346
433
  },
347
434
 
@@ -362,8 +449,12 @@
362
449
  * to user content in laboratory, and default content in bibliotheca
363
450
  */
364
451
  _setStudentSolution(code) {
365
- console.debug(`Setting student ${code}`)
366
- this._getStudentEditor().value = code;
452
+ if (this._getStudentEditor().value !== code) {
453
+ console.debug(`Setting student ${code}`)
454
+ this._getStudentEditor().value = code;
455
+ return true;
456
+ }
457
+ return false;
367
458
  },
368
459
 
369
460
  _getDefaultCode() {
@@ -375,8 +466,12 @@
375
466
  },
376
467
 
377
468
  _setExtraCode(code) {
378
- console.debug(`Setting extra ${code}`)
379
- this._getEditorExtra().value = code;
469
+ if (this._getEditorExtra().value !== code) {
470
+ console.debug(`Setting extra ${code}`)
471
+ this._getEditorExtra().value = code;
472
+ return true;
473
+ }
474
+ return false;
380
475
  },
381
476
 
382
477
  _getEditorExtra: function() {
@@ -945,10 +1040,12 @@
945
1040
  },
946
1041
 
947
1042
  _setEditorToolbox: function () {
948
- const editor = $("mu-gobstones-custom-editor")[0];
949
- $.get(this.toolboxUrl, function (toolboxXml) {
950
- editor.setToolbox(toolboxXml);
951
- });
1043
+ const $editor = $("mu-gobstones-custom-editor")[0];
1044
+
1045
+ // there is no editor to configure
1046
+ if (!$editor) return;
1047
+
1048
+ $editor.configureCustomToolboxFromUrl(this.toolboxUrl);
952
1049
  }
953
1050
  });
954
1051
  </script>
@@ -1,3 +1,3 @@
1
1
  module GobstonesVersionHook
2
- VERSION = '2.8.5'
2
+ VERSION = '2.11.0'
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mumuki-gobstones-runner
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.8.5
4
+ version: 2.11.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rodrigo Alfonso
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2020-10-16 00:00:00.000000000 Z
12
+ date: 2020-11-10 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: gobstones-board
@@ -59,14 +59,14 @@ dependencies:
59
59
  requirements:
60
60
  - - "~>"
61
61
  - !ruby/object:Gem::Version
62
- version: '2.36'
62
+ version: '2.37'
63
63
  type: :runtime
64
64
  prerelease: false
65
65
  version_requirements: !ruby/object:Gem::Requirement
66
66
  requirements:
67
67
  - - "~>"
68
68
  - !ruby/object:Gem::Version
69
- version: '2.36'
69
+ version: '2.37'
70
70
  - !ruby/object:Gem::Dependency
71
71
  name: nokogiri
72
72
  requirement: !ruby/object:Gem::Requirement
@@ -183,6 +183,7 @@ files:
183
183
  - lib/checker.rb
184
184
  - lib/expectations_hook.rb
185
185
  - lib/extensions/string.rb
186
+ - lib/feedback_hook.rb
186
187
  - lib/game_framework/default.gbs.erb
187
188
  - lib/game_framework/default.xml.erb
188
189
  - lib/game_framework/extra.gbs.erb