Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ ruby '~> 2.3'

gem 'puma'

gem 'mumuki-domain', github: 'mumuki/mumuki-domain'
gem 'mumuki-domain', github: 'mumuki/mumuki-domain', branch: 'feature-cumparsita'
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line only adds offline tests. We should merge them instead

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Local evaluation

gem 'mulangjs', path: '../mulang/ghcjslib/gem'
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not necessary in the first iteration

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Local evaluation


gem 'execjs'
gem 'therubyracer', platforms: :ruby
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,8 @@ which are granted to be safe and stable.
* `setUpDeleteFiles`
* `setUpDeleteFile`
* `updateButtonsVisibility`
* `mumuki.registerLocalTestRunner`
* `mumuki.registerLocalExpectationsRunner`
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK. Perhaps could be namespaced into mumuki.local

This steps may not always be necessary for local evaluation. They should be documented

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Local evaluation

* `mumuki.version`

### Bridge Response Format
Expand All @@ -204,9 +206,7 @@ which are granted to be safe and stable.
{
"status": "failed",
"guide_finished_by_solution": false,
"class_for_progress_list_item":"progress-list-item text-center danger active",
"html":"...",
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Although this is not strictly necessary for a first iteration, it has a lot of sense

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pre rendering

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done here: #1435

"title_html":"...",
"button_html":"...",
"expectations_html":"...",
"remaining_attempts_html":null,
Expand Down
11 changes: 1 addition & 10 deletions app/assets/javascripts/mumuki_laboratory/application.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,24 +14,15 @@
//= require moment/es.js
//= require moment/pt.js
//= require webcomponents-lite
//= require mulang
//= require rails-ujs
//= require turbolinks
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rollback

//= require mumuki-styles
//= require nprogress
//= require nprogress-turbolinks
//= require nprogress-ajax
//= require jquery-console

//= require codemirror.min
//= require codemirror-simple-mode.js
//= require codemirror-autorefresh
//= require codemirror-modes
//= require analytics
//= require hotjar
//= require muvment

//= require_tree ./application

NProgress.configure({
showSpinner: false
});
105 changes: 53 additions & 52 deletions app/assets/javascripts/mumuki_laboratory/application/bridge.js
Original file line number Diff line number Diff line change
@@ -1,68 +1,69 @@
var mumuki = mumuki || {};

(function (mumuki) {
var lastSubmission = {};

function Laboratory(exerciseId){
this.exerciseId = exerciseId;
}

function asString(json){
return JSON.stringify(json);
}

function sameAsLastSolution(newSolution){
return asString(lastSubmission.content) === asString(newSolution);
}

function lastSubmissionFinishedSuccessfully(){
return lastSubmission.result && lastSubmission.result.status !== 'aborted';
}

function sendNewSolution(solution){
var token = new mumuki.CsrfToken();
var request = token.newRequest({
type: 'POST',
url: window.location.origin + window.location.pathname + '/solutions' + window.location.search,
data: solution
});

return $.ajax(request).done(function (result) {
lastSubmission = { content: solution, result: result };
});
}

mumuki.load(function () {
lastSubmission = {};
});

Laboratory.prototype = {

(() => {
class Laboratory {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done #1443

// ==========
// Public API
// ==========

// Runs tests for the current exercise using the given submission
// content.
runTests: function(content) {
return this._submitSolution({ solution: content });
},
runTests(content) {
return this.runCurrentExerciseSolution({ solution: content });
}

// Runs the current exercise solution, trying to get the response from cache first
runCurrentExerciseSolution(solution) {
const cachedSolution = mumuki.SubmissionsStore.getCachedResultFor(mumuki.currentExerciseId, solution);
if(cachedSolution) {
return $.Deferred().resolve(cachedSolution);
}
return this._runNewSolution(mumuki.currentExerciseId, solution);
}

// Actually sends the solution to server
submitCurrentExerciseSolution(_exerciseId, solution) { // TODO use exerciseId instead of window.location
const token = new mumuki.CsrfToken();
const request = token.newRequest({
type: 'POST',
url: window.location.origin + window.location.pathname + '/solutions' + window.location.search,
data: solution
});
return $.ajax(request);
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Local evaluation + local progress + local sync

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in #1443


// ===========
// Private API
// ===========

_submitSolution: function (solution) {
if(lastSubmissionFinishedSuccessfully() && sameAsLastSolution(solution)){
return $.Deferred().resolve(lastSubmission.result);
} else {
return sendNewSolution(solution);
_runNewSolution(exerciseId, solution){
const responsePromise = mumuki.Connection.runNewSolution(exerciseId, solution, this);
return responsePromise.then((result) => {
this._preRenderResult(exerciseId, result);
const lastSubmission = { content: solution, result: result };
mumuki.SubmissionsStore.setLastSubmission(exerciseId, lastSubmission);
return result;
});
}

// pre-renders some html parts of submission that are normally
// generated by server, but will be empty in offline mode
_preRenderResult(exerciseId, result) {
// TODO defer rendering calculation.
// Caching them may introduce bugs with the next-button
try {
const status = result.status;
const exercise = mumuki.ExercisesStore.get(exerciseId);

result.button_html = result.button_html || mumuki.renderButtonHtml(status);
result.html = result.html || mumuki.renderCorollaryHtml(status, exercise);
} catch (e) {
console.log(`[Mumuki::Laboratory::Bridge] pre-rendering failed ${e}`);
throw e;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pre rendering

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in #1435

}
},
};
}

}

mumuki.bridge = {
Laboratory: Laboratory
};

}(mumuki));
})();
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,17 @@ var mumuki = mumuki || {};
});
}

function setContent(content) {
mumuki.page.editors.each(function (_, editor) {
editor.getDoc().setValue(content);
});
}

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

???

mumuki.editor = mumuki.editor || {};
mumuki.editor.toggleFullscreen = toggleFullscreen;
mumuki.editor.indentWithSpaces = indentWithSpaces;
mumuki.editor.syncContent = syncContent;
mumuki.editor.setContent = setContent;

mumuki.page = mumuki.page || {};
mumuki.page.dynamicEditors = [];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ mumuki.load(function () {
url: $(this).data('confirmation-url'),
xhrFields: {withCredentials: true},
success: function(data){
mumuki.updateProgressBarAndShowModal(data);
mumuki.updateCurrentExerciseProgressBarAndShowModal(data);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rollback. Heavily backward incompatible

}
}));

Expand Down
58 changes: 58 additions & 0 deletions app/assets/javascripts/mumuki_laboratory/application/connection.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
(() => {

const OfflineMode = new class {
// Runs solution by evaluating it locally
runNewSolution(exerciseId, solution, _bridge) {
return mumuki.runSolutionLocally(exerciseId, solution);
}

// Renders progress from SubmissionsStore
renderExercisesProgressBar() {
$('.progress-list-item').each((_, it) => this._updateProgressListItemClass($(it)));
}

configureExerciseEditorValue() {
const lastSubmission = mumuki.SubmissionsStore.getLastSubmission(mumuki.currentExerciseId);
if (lastSubmission) {
// TODO extract
if (lastSubmission.content.solution) {
$('#mu-custom-editor-value').val(lastSubmission.content.solution.content);
} else {
mumuki.editor.setContent(lastSubmission.content['solution[content]']);
}
}
}

_updateProgressListItemClass(a) {
const exerciseId = a.data('mu-exercise-id');
const status = mumuki.SubmissionsStore.getLastSubmissionStatus(exerciseId);
a.attr('class', mumuki.progressListItemClassForStatus(status, exerciseId == mumuki.currentExerciseId));
}
}

const OnlineMode = new class {
// Runs solution by sending it to server
runNewSolution(exerciseId, solution, bridge) {
return bridge.submitCurrentExerciseSolution(exerciseId, solution);
}

// Does nothing. Progress is rendered by server
renderExercisesProgressBar() {
}

// Does nothing. Editor value is configured by server
configureExerciseEditorValue() {
}

}

mumuki.goOnline = function () {
mumuki.Connection = OnlineMode;
};

mumuki.goOffline = function () {
mumuki.Connection = OfflineMode;
};

mumuki.goOnline();
})();
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ var mumuki = mumuki || {};
$('.submission-results').show();
$('.submission-results').html(response.html);
mumuki.pin.scroll();
mumuki.updateProgressBarAndShowModal(response);
mumuki.updateCurrentExerciseProgressBarAndShowModal(response);
} else {
$('.submission-results').hide();
$('.progress-list-item.active').attr('class', "progress-list-item text-center danger active");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
(() => {
mumuki.load(() => {
// Set global currentExerciseId
const $muExerciseId = $('#mu-exercise-id')[0];
const $muExerciseResource = $('#mu-exercise-resource')[0];
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Partially done in #1443

if ($muExerciseId) {
mumuki.currentExerciseId = Number($muExerciseId.value);
mumuki.ExercisesStore.saveJson(mumuki.currentExerciseId, $muExerciseResource.value);
} else {
mumuki.currentExerciseId = null;
}
})
})();
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
(() => {
const ExercisesStore = new class {
find(exerciseId) {
const exercise = window.localStorage.getItem(this._keyFor(exerciseId));
if (!exercise) return null;
return JSON.parse(exercise);
}

// Saves an exercise object
save(exerciseId, exercise) {
this.saveJson(exerciseId, JSON.stringify(exercise));
}

// Saves an exercise json string
saveJson(exerciseId, exerciseJson) {
window.localStorage.setItem(this._keyFor(exerciseId), exerciseJson);
}

// Finds and existent exercise
// Fails if exercise is missing
get(exerciseId) {
const exercise = this.find(exerciseId);
if (!exercise) throw new Error(`Missing exercise ${exerciseId}`);
return exercise;
}

_keyFor(exerciseId) {
return `/exercise/${exerciseId}`;
}
};
mumuki.ExercisesStore = ExercisesStore;
})();
12 changes: 8 additions & 4 deletions app/assets/javascripts/mumuki_laboratory/application/kids.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ mumuki.load(function () {
// This method needs to be called by the runner's editor.html extension
// in order to finish an exercise
showResult: function (data) {
mumuki.updateProgressBarAndShowModal(data);
mumuki.updateCurrentExerciseProgressBarAndShowModal(data);
if (data.guide_finished_by_solution) return;
mumuki.kids.resultAction[data.status](data);
},
Expand Down Expand Up @@ -172,11 +172,15 @@ mumuki.load(function () {
mumuki.kids._getOverlay().hide();
},

_titleHtml: function (data) {
return mumuki.renderTitleHtml(data.status);
},

_showMessageOnCharacterBubble: function (data) {
var $bubble = mumuki.kids._getCharacterBubble();
$bubble.find('.mu-kids-character-speech-bubble-tabs').hide();
$bubble.find('.mu-kids-character-speech-bubble-normal').hide();
$bubble.find('.mu-kids-character-speech-bubble-failed').show().html(data.title_html);
$bubble.find('.mu-kids-character-speech-bubble-failed').show().html(mumuki.kids._titleHtml(data));
$bubble.addClass(data.status);
if (data.status === 'passed_with_warnings') {
$bubble.find('.mu-kids-character-speech-bubble-failed').append(data.expectations_html);
Expand All @@ -203,7 +207,7 @@ mumuki.load(function () {
backdrop: 'static',
keyboard: false
});
$resultsKidsModal.find('.modal-header').first().html(data.title_html);
$resultsKidsModal.find('.modal-header').first().html(mumuki.kids._titleHtml(data));
$resultsKidsModal.find('.modal-footer').first().html(data.button_html);
mumuki.kids._showCorollaryCharacter();
$('.mu-close-modal').click(() => mumuki.kids._getResultsModal().modal('hide'));
Expand All @@ -228,7 +232,7 @@ mumuki.load(function () {

_stateScaler: function ($state, fullMargin, preferredWidth, preferredHeight) {
var $table = $state.find('gs-board > table');
if (!$table.length) return setTimeout(() => this.scaleState($state, fullMargin));
if (!$table.length) return setTimeout(() => mumuki.kids.scaleState($state, fullMargin));

console.warn("You are using the default states scaler, which is gobstones-specific. Please register your own scaler in the future");

Expand Down

This file was deleted.

Loading