Skip to content

Commit

Permalink
Convert explain to yield function
Browse files Browse the repository at this point in the history
  • Loading branch information
Maurits Rijk committed May 23, 2017
1 parent d101e59 commit 740b5c6
Show file tree
Hide file tree
Showing 8 changed files with 57 additions and 53 deletions.
6 changes: 4 additions & 2 deletions lib/and.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,12 @@ function and(...predicates) {
unform: value => unform(predicates[0], value),
gen: () => gen(predicates[0]),
describe: () => [and.name, ...describe(predicates)],
explain: (value, {via}) => {
explain: function*(value, {via}) {
const problems = _.map(predicates, predicate => explainData(predicate, value, {via}));
const found = _.find(problems, p => !_.isNull(p));
return _.isUndefined(found) ? null : {problems: found.problems};
if (found) {
yield found.problems[0];
}
}
};
}
Expand Down
24 changes: 14 additions & 10 deletions lib/def.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,11 @@ function createArraySpec(predicate) {
return {
conform: (value, unwrap = false) => conform(value, unwrap, _.partial(_.includes, predicate)),
describe: () => predicate,
explain: value => _.includes(predicate, value) ? null : getExplanation(value),
explain: function*(value) {
if (!_.includes(predicate, value)) {
yield getExplanation(value);
}
},
gen: () => tcg.null.then(() => tcg.return(_.sample(predicate)))
};
}
Expand All @@ -29,23 +33,23 @@ function createFunctionSpec(predicate, gen) {
return {
conform: (value, unwrap = false) => conform(value, unwrap, predicate),
unform: _.identify,
explain: (value, options) => {
explain: function*(value, options) {
options.pred = _.isEmpty(predicate.name) || predicate.name === 'anonymous' ? `${predicate}` : predicate.name;
return predicate(value) ? null : getExplanation(value, options);
if (!predicate(value)) {
yield getExplanation(value, options);
}
},
gen: gen ? gen : () => functions.gen(predicate)
};
}

function getExplanation(value, {path, pred = unknownString, via}) {
return {
problems: [{
path,
pred,
val: value,
via,
'in': []
}]
path,
pred,
val: value,
via,
'in': []
};
}

Expand Down
5 changes: 3 additions & 2 deletions lib/explainData.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
const _ = require('lodash');

const {spec: specize} = require('./def');
const {isFunction, isString} = require('./utils');
const {isString} = require('./utils');

function explainData(spec, value, {path = [], via = []} = {}) {
const lookup = specize(spec);
if (lookup) {
const name = specName(spec);
const viaOut = _.isUndefined(name) ? via : [name, ...via];
return lookup.explain(value, {path, pred: name, via: viaOut});
const problems = [...lookup.explain(value, {path, pred: name, via: viaOut})];
return _.isEmpty(problems) ? null : {problems};
} else {
throw new Error(`Unable to resolve spec ${spec}`);
}
Expand Down
4 changes: 1 addition & 3 deletions lib/intIn.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,7 @@ function intIn(start, end) {
unform: _.identity,
gen: () => tcg.intWithin(start, end - 1),
describe: () => ['and', 'isInt', ['isIntInRange', start, end]],
explain: (value, {via}) => {
const problems = [];
return _.isEmpty(problems) ? null : {problems};
explain: function*(value, {via}) {
}
};
}
Expand Down
26 changes: 12 additions & 14 deletions lib/nilable.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,18 @@ function nilable(predicate) {
unform: _.identity,
gen: () => tcg.null.then(() => _.random(10) < 2 ? tcg.null : gen(predicate)),
describe: () => [nilable.name, ...describe([predicate])],
explain: (value, {via}) => {
return _.isNull(value) || isValid(predicate, value) ? null :
{
problems: [
explainData(predicate, value, {path: ['pred'], via}).problems[0],
{
path: ['null'],
pred: 'isNull',
val: value,
via,
'in': []
}
]
};
explain: function*(value, {via}) {
if (!(_.isNull(value) || isValid(predicate, value))) {
yield explainData(predicate, value, {path: ['pred'], via}).problems[0];

yield {
path: ['null'],
pred: 'isNull',
val: value,
via,
'in': []
}
}
}
};
}
Expand Down
8 changes: 6 additions & 2 deletions lib/or.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,13 @@ function or(...predicates) {
},
gen: () => tcg.null.then(() => gen(_.sample(pairs)[1])),
describe: () => [or.name, ...describe(predicates)],
explain: (value, {via}) => {
explain: function*(value, {via}) {
const problems = _.map(pairs, ([k, predicate]) => explainData(predicate, value, {path: [k], via}));
return _.some(problems, _.isNull) ? null : {problems: _.flatten(_.map(problems, 'problems'))};
if (!_.some(problems, _.isNull)) {
for (let i = 0; i < problems.length; i++) {
yield problems[i].problems[0];
}
}
}
};
}
Expand Down
27 changes: 11 additions & 16 deletions lib/plus.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,44 +17,39 @@ function plus(spec) {
unform: _.identity,
gen: () => tcg.null.then(() => tcg.array(gen(spec), {size: _.random(1, 5)})),
describe: () => [plus.name, ...describe([spec])],
explain: (values, {via}) => {
const problems = [];
explainEmptyInput(problems, values, via);
if (_.isEmpty(problems)) {
explainValidInput(problems, spec, values, via);
}
return _.isEmpty(problems) ? null : {problems};
explain: function*(values, {via}) {
yield* explainLength(values, via);
yield* explainInvalid(values, spec, via);
}
};
}

function explainEmptyInput(problems, values, via) {
if (values.length === 0) {
problems.push({
function* explainLength(values, via) {
if (_.isEmpty(values)) {
yield {
path: [],
reason: 'Insufficient input',
val: values,
via,
'in': []
});
};
}
return problems;
}

function explainValidInput(problems, spec, values, via) {
function* explainInvalid(values, spec, via) {
const index = _.findIndex(values, value => !isValid(spec, value));
if (index !== -1) {
const val = values[index];
console.log('***', explainData(spec, val));
const pred = explainData(spec, val).problems[0].pred;
problems.push({
yield {
path: [],
pred,
val,
via,
'in': [index]
});
};
}
return problems;
}

module.exports = plus;
10 changes: 6 additions & 4 deletions lib/tuple.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,17 @@ function tuple(...predicates) {
unform: _.identity,
gen: () => _.map(predicates, gen),
describe: () => [tuple.name, ...describe(predicates)],
explain: (value, {via}) => {
explain: function*(value, {via}) {
const f = new Function('values', `return values.length === ${predicates.length}`);
return explainPredicate(f, value, {via});
yield* explainPredicate(f, value, {via});
}
};
}

function explainPredicate(pred, value, options) {
return pred(value) ? null : explainData(pred, value, options);
function* explainPredicate(pred, value, options) {
if (!pred(value)) {
yield explainData(pred, value, options).problems[0];
}
}

module.exports = tuple;

0 comments on commit 740b5c6

Please sign in to comment.