✅ Tester les mécanismes du et logique, de l'aiguillage
parent
9b427690ec
commit
8ca86d0029
|
@ -71,4 +71,23 @@ describe('analyseSituation with mecanisms', function() {
|
|||
expect(analyseSituation(rules,"startHere")(stateSelector)).to.have.property('nodeValue',true)
|
||||
});
|
||||
|
||||
it('should handle n-way "and"', function() {
|
||||
let rawRules = [
|
||||
{nom: "startHere", formule: {"toutes ces conditions": ["1 > 2", "1 > 0", "0 > 2"]}}],
|
||||
rules = rawRules.map(enrichRule)
|
||||
expect(analyseSituation(rules,"startHere")(stateSelector)).to.have.property('nodeValue',false)
|
||||
});
|
||||
|
||||
it('should handle switch statements', function() {
|
||||
let rawRules = [
|
||||
{nom: "startHere", formule: {"logique numérique": {
|
||||
"1 > dix":"10",
|
||||
"3 < dix":"11",
|
||||
"3 > dix":"12"
|
||||
}}, espace: "top"},
|
||||
{nom: "dix", formule: 10, espace: "top"}],
|
||||
rules = rawRules.map(enrichRule)
|
||||
expect(analyseSituation(rules,"startHere")(stateSelector)).to.have.property('nodeValue',11)
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
@ -246,6 +246,139 @@ let treat = (situationGate, rules, rule) => rawNode => {
|
|||
console.log() // eslint-disable-line no-console
|
||||
throw 'Cette donnée : ' + rawNode + ' doit être un Number, String ou Object'
|
||||
},
|
||||
mecanismOneOf = (k, v) => {
|
||||
let result = R.pipe(
|
||||
R.unless(R.is(Array), () => {throw 'should be array'}),
|
||||
R.reduce( (memo, next) => {
|
||||
let {nodeValue, explanation} = memo,
|
||||
child = reTreat(next),
|
||||
{nodeValue: nextValue} = child
|
||||
return {...memo,
|
||||
// c'est un OU logique mais avec une préférence pour null sur false
|
||||
nodeValue: nodeValue || nextValue || (
|
||||
nodeValue == null ? null : nextValue
|
||||
),
|
||||
explanation: [...explanation, child]
|
||||
}
|
||||
}, {
|
||||
nodeValue: false,
|
||||
category: 'mecanism',
|
||||
name: 'une de ces conditions',
|
||||
type: 'boolean',
|
||||
explanation: []
|
||||
}) // Reduce but don't use R.reduced to set the nodeValue : we need to treat all the nodes
|
||||
)(v)
|
||||
return {...result,
|
||||
jsx: <Node
|
||||
classes="mecanism conditions list"
|
||||
name={result.name}
|
||||
value={result.nodeValue}
|
||||
child={
|
||||
<ul>
|
||||
{result.explanation.map(item => <li key={item.name || item.text}>{item.jsx}</li>)}
|
||||
</ul>
|
||||
}
|
||||
/>
|
||||
}
|
||||
},
|
||||
mecanismAllOf = (k,v) => {
|
||||
return R.pipe(
|
||||
R.unless(R.is(Array), () => {throw 'should be array'}),
|
||||
R.reduce( (memo, next) => {
|
||||
let {nodeValue, explanation} = memo,
|
||||
child = reTreat(next),
|
||||
{nodeValue: nextValue} = child
|
||||
return {...memo,
|
||||
// c'est un ET logique avec une possibilité de null
|
||||
nodeValue: ! nodeValue ? nodeValue : nextValue,
|
||||
explanation: [...explanation, child]
|
||||
}
|
||||
}, {
|
||||
nodeValue: true,
|
||||
category: 'mecanism',
|
||||
name: 'toutes ces conditions',
|
||||
type: 'boolean',
|
||||
explanation: []
|
||||
}) // Reduce but don't use R.reduced to set the nodeValue : we need to treat all the nodes
|
||||
)(v)
|
||||
},
|
||||
mecanismNumericalLogic = (k,v) =>
|
||||
R.ifElse(
|
||||
R.is(String),
|
||||
rate => ({ //TODO unifier ce code
|
||||
nodeValue: transformPercentage(rate),
|
||||
type: 'numeric',
|
||||
category: 'percentage',
|
||||
percentage: rate,
|
||||
explanation: null,
|
||||
jsx:
|
||||
<span className="percentage" >
|
||||
<span className="name">{rate}</span>
|
||||
</span>
|
||||
}),
|
||||
R.pipe(
|
||||
R.unless(
|
||||
v => R.is(Object)(v) && R.keys(v).length >= 1,
|
||||
() => {throw 'Le mécanisme "logique numérique" et ses sous-logiques doivent contenir au moins une proposition'}
|
||||
),
|
||||
R.toPairs,
|
||||
R.reduce( (memo, [condition, consequence]) => {
|
||||
let
|
||||
{nodeValue, explanation} = memo,
|
||||
conditionNode = reTreat(condition), // can be a 'comparison', a 'variable', TODO a 'negation'
|
||||
childNumericalLogic = mecanismNumericalLogic(condition, consequence),
|
||||
nextNodeValue = conditionNode.nodeValue == null ?
|
||||
// Si la proposition n'est pas encore résolvable
|
||||
null
|
||||
// Si la proposition est résolvable
|
||||
: conditionNode.nodeValue == true ?
|
||||
// Si elle est vraie
|
||||
childNumericalLogic.nodeValue
|
||||
// Si elle est fausse
|
||||
: false
|
||||
|
||||
return {...memo,
|
||||
nodeValue: nodeValue == null ?
|
||||
null
|
||||
: nodeValue !== false ?
|
||||
nodeValue // l'une des propositions renvoie déjà une valeur numérique donc différente de false
|
||||
: nextNodeValue,
|
||||
explanation: [...explanation, {
|
||||
nodeValue: nextNodeValue,
|
||||
category: 'condition',
|
||||
text: condition,
|
||||
condition: conditionNode,
|
||||
conditionValue: conditionNode.nodeValue,
|
||||
type: 'boolean',
|
||||
explanation: childNumericalLogic,
|
||||
jsx: <div className="condition">
|
||||
{conditionNode.jsx}
|
||||
<div>
|
||||
{childNumericalLogic.jsx}
|
||||
</div>
|
||||
</div>
|
||||
}],
|
||||
}
|
||||
}, {
|
||||
nodeValue: false,
|
||||
category: 'mecanism',
|
||||
name: "logique numérique",
|
||||
type: 'boolean || numeric', // lol !
|
||||
explanation: []
|
||||
}),
|
||||
node => ({...node,
|
||||
jsx: <Node
|
||||
classes="mecanism numericalLogic list"
|
||||
name="logique numérique"
|
||||
value={node.nodeValue}
|
||||
child={
|
||||
<ul>
|
||||
{node.explanation.map(item => <li key={item.name || item.text}>{item.jsx}</li>)}
|
||||
</ul>
|
||||
}
|
||||
/>
|
||||
})
|
||||
))(v),
|
||||
treatObject = rawNode => {
|
||||
let mecanisms = R.intersection(R.keys(rawNode), R.keys(knownMecanisms))
|
||||
|
||||
|
@ -257,145 +390,9 @@ let treat = (situationGate, rules, rule) => rawNode => {
|
|||
let k = R.head(mecanisms),
|
||||
v = rawNode[k]
|
||||
|
||||
if (k === 'une de ces conditions') {
|
||||
let result = R.pipe(
|
||||
R.unless(R.is(Array), () => {throw 'should be array'}),
|
||||
R.reduce( (memo, next) => {
|
||||
let {nodeValue, explanation} = memo,
|
||||
child = reTreat(next),
|
||||
{nodeValue: nextValue} = child
|
||||
return {...memo,
|
||||
// c'est un OU logique mais avec une préférence pour null sur false
|
||||
nodeValue: nodeValue || nextValue || (
|
||||
nodeValue == null ? null : nextValue
|
||||
),
|
||||
explanation: [...explanation, child]
|
||||
}
|
||||
}, {
|
||||
nodeValue: false,
|
||||
category: 'mecanism',
|
||||
name: 'une de ces conditions',
|
||||
type: 'boolean',
|
||||
explanation: []
|
||||
}) // Reduce but don't use R.reduced to set the nodeValue : we need to treat all the nodes
|
||||
)(v)
|
||||
return {...result,
|
||||
jsx: <Node
|
||||
classes="mecanism conditions list"
|
||||
name={result.name}
|
||||
value={result.nodeValue}
|
||||
child={
|
||||
<ul>
|
||||
{result.explanation.map(item => <li key={item.name || item.text}>{item.jsx}</li>)}
|
||||
</ul>
|
||||
}
|
||||
/>
|
||||
}
|
||||
}
|
||||
if (k === 'toutes ces conditions') {
|
||||
return R.pipe(
|
||||
R.unless(R.is(Array), () => {throw 'should be array'}),
|
||||
R.reduce( (memo, next) => {
|
||||
let {nodeValue, explanation} = memo,
|
||||
child = reTreat(next),
|
||||
{nodeValue: nextValue} = child
|
||||
return {...memo,
|
||||
// c'est un ET logique avec une possibilité de null
|
||||
nodeValue: ! nodeValue ? nodeValue : nextValue,
|
||||
explanation: [...explanation, child]
|
||||
}
|
||||
}, {
|
||||
nodeValue: true,
|
||||
category: 'mecanism',
|
||||
name: 'toutes ces conditions',
|
||||
type: 'boolean',
|
||||
explanation: []
|
||||
}) // Reduce but don't use R.reduced to set the nodeValue : we need to treat all the nodes
|
||||
)(v)
|
||||
}
|
||||
|
||||
//TODO perf: declare this closure somewhere else ?
|
||||
let treatNumericalLogicRec =
|
||||
R.ifElse(
|
||||
R.is(String),
|
||||
rate => ({ //TODO unifier ce code
|
||||
nodeValue: transformPercentage(rate),
|
||||
type: 'numeric',
|
||||
category: 'percentage',
|
||||
percentage: rate,
|
||||
explanation: null,
|
||||
jsx:
|
||||
<span className="percentage" >
|
||||
<span className="name">{rate}</span>
|
||||
</span>
|
||||
}),
|
||||
R.pipe(
|
||||
R.unless(
|
||||
v => R.is(Object)(v) && R.keys(v).length >= 1,
|
||||
() => {throw 'Le mécanisme "logique numérique" et ses sous-logiques doivent contenir au moins une proposition'}
|
||||
),
|
||||
R.toPairs,
|
||||
R.reduce( (memo, [condition, consequence]) => {
|
||||
let
|
||||
{nodeValue, explanation} = memo,
|
||||
conditionNode = reTreat(condition), // can be a 'comparison', a 'variable', TODO a 'negation'
|
||||
childNumericalLogic = treatNumericalLogicRec(consequence),
|
||||
nextNodeValue = conditionNode.nodeValue == null ?
|
||||
// Si la proposition n'est pas encore résolvable
|
||||
null
|
||||
// Si la proposition est résolvable
|
||||
: conditionNode.nodeValue == true ?
|
||||
// Si elle est vraie
|
||||
childNumericalLogic.nodeValue
|
||||
// Si elle est fausse
|
||||
: false
|
||||
|
||||
return {...memo,
|
||||
nodeValue: nodeValue == null ?
|
||||
null
|
||||
: nodeValue !== false ?
|
||||
nodeValue // l'une des propositions renvoie déjà une valeur numérique donc différente de false
|
||||
: nextNodeValue,
|
||||
explanation: [...explanation, {
|
||||
nodeValue: nextNodeValue,
|
||||
category: 'condition',
|
||||
text: condition,
|
||||
condition: conditionNode,
|
||||
conditionValue: conditionNode.nodeValue,
|
||||
type: 'boolean',
|
||||
explanation: childNumericalLogic,
|
||||
jsx: <div className="condition">
|
||||
{conditionNode.jsx}
|
||||
<div>
|
||||
{childNumericalLogic.jsx}
|
||||
</div>
|
||||
</div>
|
||||
}],
|
||||
}
|
||||
}, {
|
||||
nodeValue: false,
|
||||
category: 'mecanism',
|
||||
name: "logique numérique",
|
||||
type: 'boolean || numeric', // lol !
|
||||
explanation: []
|
||||
}),
|
||||
node => ({...node,
|
||||
jsx: <Node
|
||||
classes="mecanism numericalLogic list"
|
||||
name="logique numérique"
|
||||
value={node.nodeValue}
|
||||
child={
|
||||
<ul>
|
||||
{node.explanation.map(item => <li key={item.name}>{item.jsx}</li>)}
|
||||
</ul>
|
||||
}
|
||||
/>
|
||||
})
|
||||
))
|
||||
|
||||
if (k === 'logique numérique') {
|
||||
return treatNumericalLogicRec(v)
|
||||
}
|
||||
if (k === 'une de ces conditions') return mecanismOneOf(k,v)
|
||||
if (k === 'toutes ces conditions') return mecanismAllOf(k,v)
|
||||
if (k === 'logique numérique') return mecanismNumericalLogic(k,v)
|
||||
|
||||
if (k === 'taux') {
|
||||
let reg = /^(\d+(\.\d+)?)\%$/
|
||||
|
|
Loading…
Reference in New Issue