這將是容易得多,如果你考慮一個更聲明的方式: - 定義一個標準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');
這是真棒,右側管線與我所期待的。其實,我發佈哈哈後,我開始通過詞類通過詞類傳遞。這太棒了! – Growler
因此,我不會將'validators'中的每個驗證器初始化爲函數,而是使用'makeValidator'動態創建它們? – Growler
差不多,是的。它使得工作/理解驗證器是否爲無狀態函數更容易:它們接受所有參數併爲相同輸入返回相同的結果。 'makeValidator'助手只是允許你輕鬆地重用驗證器,同時也基本上將它們的參數硬編碼到每個個案中,但是在個案的基礎上。 您可以通過選擇不同的語法來放棄'makeValidator'邏輯,例如使用驗證器的名字,做論證邏輯在'驗證method' 任務:{驗證:[ [第一,「喜」], } ,然後做在'validate' – Stefan