Было бы намного проще, если бы рассмотреть более декларативный подход: - определить стандартную quest
структуры - определить стандартную task
структуры с родовыми входными форматами - определить общие валидатор и повторно использовать их
Вы начали по правому пути с объектом grammar_hints
, но я бы на самом деле положил все свойства, изображающие одну задачу в одном и том же объекте.
Предложение:
var quests = [
{
name: 'Quest 1',
tasks: [
{
name: 'Task 1',
solution: 'hi I want to eat',
validators: [
validators.first('hi'),
validators.verbAfterNoun('want', 'I'),
]
}
],
},
];
Вы сможете повторно использовать много валидаторов в нескольких задачах, так что вы хотите, чтобы они были максимально стандартизованы, вот один пример:
var validators = {
first: function (input, term) {
if (input[0] !== term) {
return 'The sentence needs to start with: ' + term;
}
},
verbAfterNoun: function (input, verb, noun) {
if (input.indexOf(verb) < input.indexOf(noun)) {
return 'The verb, ' + verb + ', needs to come after the noun ' + noun;
}
}
};
Теперь, поскольку вы хотите иметь декларативный формат (я пошел с фактической инициализацией валидаторов с их вводом и передачей результата в массиве validators
), нам понадобится фабрика валидатора, которая принимает общий валидатор и возвращает вспомогательный метод, который может быть повторно использован w с только входом.Это поможет нам вниз линии, поэтому наша система тестирования не нужно будет знать, сколько входов, чтобы перейти к каждому из валидатора обратных вызовов
// This is a factory method that applies the given callback (with the given arguments)
function makeValidator (fn) {
return function inputFN() {
var args = [].slice.call(arguments);
return function validate (input) {
return fn.apply(null, [input].concat(args));
}
}
}
// Apply the makeValidator() method on all the validators
for (var key in validators) {
validators[key] = makeValidator(validators[key]);
}
И, наконец, мы также хотим, стандартный способ проверки наших задач на входе:
// This method provides the generic validation framework for any task given any input
function validate (task, input) {
var wordList = input.split(' ');
if (input === task.solution) return {success: true, errors: []};
var errors = [];
task.validators.forEach(function (fn) {
var error = fn(wordList);
if (error) errors.push(error);
});
return {success: false, errors: errors};
}
И некоторые примеры:
var task = quests[0].tasks[0];
console.log(validate(task, 'hi I want to eat'));
console.log(validate(task, 'I want to eat hi'));
console.log(validate(task, 'hi want I to eat'));
console.log(validate(task, 'want I to eat hi'));
Собираем все вместе:
// This is a factory method that applies the given callback (with the given arguments)
function makeValidator (fn) {
return function inputFN() {
var args = [].slice.call(arguments);
return function validate (input) {
return fn.apply(null, [input].concat(args));
}
}
}
var validators = {
first: function (input, term) {
if (input[0] !== term) {
return 'The sentence needs to start with: ' + term;
}
},
verbAfterNoun: function (input, verb, noun) {
if (input.indexOf(verb) < input.indexOf(noun)) {
return 'The verb, ' + verb + ', needs to come after the noun ' + noun;
}
}
};
// Apply the makeValidator() method on all the validators
for (var key in validators) {
validators[key] = makeValidator(validators[key]);
}
var quests = [
{
name: 'Quest 1',
tasks: [
{
name: 'Task 1',
solution: 'hi I want to eat',
validators: [
validators.first('hi'),
validators.verbAfterNoun('want', 'I'),
]
}
],
},
];
// This method provides the generic validation framework for any task given any input
function validate (task, input) {
var wordList = input.split(' ');
if (input === task.solution) return {success: true, errors: []};
var errors = [];
task.validators.forEach(function (fn) {
var error = fn(wordList);
if (error) errors.push(error);
});
return {success: false, errors: errors};
}
function printTask (input) {
var task = quests[0].tasks[0];
var result = validate(task, input);
document.body.innerHTML += '<div><b>checking:</b> ' + input + '<pre>' + JSON.stringify(result, null, 4) + '</pre><hr />';
}
// Lets look at some examples
printTask('I want to eat hi');
printTask('hi want I to eat');
printTask('want I to eat hi');
printTask('hi I want to eat');
Это является удивительным и право рядный с тем, что я искал. На самом деле, я начал делать родовые слова, передавая часть речи сразу после того, как я опубликовал LOL. Это круто! – Growler
Итак, вместо инициализации каждого валидатора в 'validators' как функции я бы динамически создавал их с помощью' makeValidator'? – Growler
почти все, да. это облегчает работу/понимание, если валидаторы являются функциями без состояния: они принимают все аргументы и возвращают один и тот же результат для одного и того же ввода. Помощник 'makeValidator' позволяет вам просто повторно использовать валидаторы, а также в основном жестко кодировать свои аргументы для каждого отдельного случая, но в каждом конкретном случае. Вы можете отказаться от логики 'makeValidator', выбрав другой синтаксис, например. используя имена валидатора и сделать логику аргументов в 'VALIDATE method' задачу: {валидаторов: [ [первая,«привет»], } , а затем делает аргумент сплайсинг в' validate' – Stefan