diff --git a/spec/value_ref/value_ref.spec.ts b/spec/value_ref/value_ref.spec.ts index b631be093a13ce286db3728c9f5e3015548ebbfd..b0b2fb6c1f3f856de127c92849189036e3f851d2 100644 --- a/spec/value_ref/value_ref.spec.ts +++ b/spec/value_ref/value_ref.spec.ts @@ -8,56 +8,189 @@ import { NubTest, NubTestParams } from "../nubtest"; import { precDigits } from "../test_config"; +import { ParamValueMode } from "../../src"; let nub1: NubTest; let nub2: NubTest; let prm1: NubTestParams; let prm2: NubTestParams; +/** + * crée l'environnement de test. + * répété dans à chaque test car il manque un mock de beforeEach + */ +function createEnv() { + // Nub maître (dont on référence la valeur du paramètre A) + nub1 = new NubTest(new NubTestParams()); + prm1 = nub1.parameters as NubTestParams; + + // Nub esclave (qui utilise la valeur de A du Nub maître) + nub2 = new NubTest(new NubTestParams()); + prm2 = nub2.parameters as NubTestParams; +} + describe("tests ValueReference : ", () => { - beforeEach(() => { - // Nub maître (dont on référence la valeur du paramètre A) - nub1 = new NubTest(new NubTestParams()); - prm1 = nub1.parameters as NubTestParams; - - // Nub esclave (qui utilise la valeur de A du Nub maître) - nub2 = new NubTest(new NubTestParams()); - prm2 = nub2.parameters as NubTestParams; - }); + describe("classe ParamValues : ", () => { + it("test 1", () => { + // cas de figure : + // nub2.A est lié à nub1.A (valeur fixe) + // lecture des valeurs de tous les paramètres - it("test 1", () => { - prm1.A.v = 1; // valeur maître - prm2.A.v = 0; // valeur esclave (doit être masquée par la valeur maître) - prm2.A.paramValues.referencedObject = prm1.A.paramValues; + createEnv(); - expect(prm1.A.v).toEqual(1); - expect(prm2.A.v).toEqual(1); - }); + prm2.A.v = 0; // valeur esclave, doit être masquée par la valeur maître (cad prm1.A, normalement 1) + prm2.A.defineReference(nub1, "A"); - it('test 2', () => { - prm1.A.v = 2; // valeur maître - prm2.A.v = 0; // valeur esclave (doit être masquée par la valeur maître) - prm2.A.paramValues.referencedObject = prm1.A.paramValues; + expect(prm1.A.v).toEqual(1); + expect(prm1.B.v).toEqual(2); + expect(prm1.C.v).toEqual(3); + expect(prm2.A.v).toEqual(1); + expect(prm2.B.v).toEqual(2); + expect(prm2.C.v).toEqual(3); + }); - expect(nub1.Calc("C").vCalc).toBeCloseTo(4, precDigits); - expect(nub2.Calc("C").vCalc).toBeCloseTo(4, precDigits); - }); + it("test 2", () => { + // cas de figure : + // nub2.B est lié à nub1.B (valeur fixe) + // lecture des valeurs de tous les paramètres + + createEnv(); + + prm2.B.v = 0; // valeur esclave, doit être masquée par la valeur maître (cad prm1.B, normalement 2) + prm2.B.defineReference(nub1, "B"); + + expect(prm1.A.v).toEqual(1); + expect(prm1.B.v).toEqual(2); + expect(prm1.C.v).toEqual(3); + expect(prm2.A.v).toEqual(1); + expect(prm2.B.v).toEqual(2); + expect(prm2.C.v).toEqual(3); + }); + + it("test 3", () => { + // cas de figure : + // nub2.C est lié à nub1.C (valeur fixe) + // lecture des valeurs de tous les paramètres + + createEnv(); + + prm2.C.v = 0; // valeur esclave, doit être masquée par la valeur maître (cad prm1.C, normalement 3) + prm2.C.defineReference(nub1, "C"); + + expect(prm1.A.v).toEqual(1); + expect(prm1.B.v).toEqual(2); + expect(prm1.C.v).toEqual(3); + expect(prm2.A.v).toEqual(1); + expect(prm2.B.v).toEqual(2); + expect(prm2.C.v).toEqual(3); + }); + + it('test 4', () => { + // cas de figure : + // nub2.A est lié à nub1.A (valeur fixe) + // calcul de tous les paramètres + + createEnv(); + + prm2.A.v = 0; // valeur esclave, doit être masquée par la valeur maître (cad prm1.A, normalement 1) + prm2.A.defineReference(nub1, "A"); + + expect(nub1.Calc("A").vCalc).toBeCloseTo(1, precDigits); + expect(nub1.Calc("B").vCalc).toBeCloseTo(2, precDigits); + expect(nub1.Calc("C").vCalc).toBeCloseTo(3, precDigits); + + expect(nub2.Calc("A").vCalc).toBeCloseTo(1, precDigits); + expect(nub2.Calc("B").vCalc).toBeCloseTo(2, precDigits); + expect(nub2.Calc("C").vCalc).toBeCloseTo(3, precDigits); + }); - it('test 3', () => { - prm1.B.v = 3; // valeur maître - prm2.B.v = 0; // valeur esclave (doit être masquée par la valeur maître) - prm2.B.paramValues.referencedObject = prm1.B.paramValues; + it('test 5', () => { + // cas de figure : + // nub2.B est lié à nub1.B (valeur fixe) + // calcul de tous les paramètres - expect(nub1.Calc("A").vCalc).toBeCloseTo(0, precDigits); - expect(nub2.Calc("A").vCalc).toBeCloseTo(0, precDigits); + createEnv(); + + prm1.B.v = 3; // valeur maître + prm2.B.v = 0; // valeur esclave (doit être masquée par la valeur maître) + prm2.B.defineReference(nub1, "B"); + + expect(nub1.Calc("A").vCalc).toBeCloseTo(0, precDigits); + expect(nub1.Calc("B").vCalc).toBeCloseTo(3, precDigits); + expect(nub1.Calc("C").vCalc).toBeCloseTo(3, precDigits); + + expect(nub2.Calc("A").vCalc).toBeCloseTo(0, precDigits); + expect(nub2.Calc("B").vCalc).toBeCloseTo(3, precDigits); + expect(nub2.Calc("C").vCalc).toBeCloseTo(3, precDigits); + }); + + it('test 6', () => { + // cas de figure : + // nub2.C est lié à nub1.C (valeur fixe) + // calcul de tous les paramètres + + createEnv(); + + prm2.C.v = 0; // valeur esclave, doit être masquée par la valeur maître (cad prm1.C, normalement 3) + prm2.C.defineReference(nub1, "C"); + + + expect(nub1.Calc("A").vCalc).toBeCloseTo(1, precDigits); + expect(nub1.Calc("B").vCalc).toBeCloseTo(2, precDigits); + expect(nub1.Calc("C").vCalc).toBeCloseTo(3, precDigits); + + expect(nub2.Calc("A").vCalc).toBeCloseTo(1, precDigits); + expect(nub2.Calc("B").vCalc).toBeCloseTo(2, precDigits); + expect(nub2.Calc("C").vCalc).toBeCloseTo(3, precDigits); + }); }); - it('test 4', () => { - prm1.C.v = 4; // valeur maître - prm2.C.v = 0; // valeur esclave (doit être masquée par la valeur maître) - prm2.C.paramValues.referencedObject = prm1.C.paramValues; + describe("classe Result : ", () => { + it('test 1', () => { + // cas de figure : + // nub2.A est lié à nub1.C (valeur calculée) + // lecture de nub2.A + + createEnv(); + + // Nub maître + nub1 = new NubTest(new NubTestParams()); + prm1 = nub1.parameters as NubTestParams; + + // Nub esclave + nub2 = new NubTest(new NubTestParams()); + prm2 = nub2.parameters as NubTestParams; + + prm1.C.v = 10; // valeur maître bidon + prm1.C.paramValues.valueMode = ParamValueMode.CALCUL; + prm2.A.v = 0; // valeur esclave (doit être masquée par la valeur maître, cad prm1.C, normalement 3) + prm2.A.defineReference(nub1, "C"); + + expect(prm2.A.v).toBeCloseTo(3, precDigits); + }); + + it('test 2', () => { + // cas de figure : + // nub2.A est lié à nub1.C (valeur calculée) + // calcul de nub2.C + + createEnv(); + + // Nub maître + nub1 = new NubTest(new NubTestParams()); + prm1 = nub1.parameters as NubTestParams; + + // Nub esclave + nub2 = new NubTest(new NubTestParams()); + prm2 = nub2.parameters as NubTestParams; + + prm1.C.v = 0; // valeur bidon, doit être 3 après calcul + prm1.C.paramValues.valueMode = ParamValueMode.CALCUL; + prm2.C.v = 0; // valeur bidon, doit être 5 après calcul + prm2.A.v = 0; // valeur esclave bidon, doit être masquée par la valeur maître (cad prm1.C, normalement 3) + prm2.A.defineReference(nub1, "C"); - expect(nub1.Calc("B").vCalc).toBeCloseTo(3, precDigits); - expect(nub2.Calc("B").vCalc).toBeCloseTo(3, precDigits); + expect(nub2.Calc("C").vCalc).toBeCloseTo(5, precDigits); + }); }); }); diff --git a/src/nub.ts b/src/nub.ts index 26f285efb765b6246d56e01cd459fdd35a023056..4eab2b51507074e387dfd02681286cd4e5f71ad4 100644 --- a/src/nub.ts +++ b/src/nub.ts @@ -4,11 +4,12 @@ import { ComputeNode } from "./compute-node"; import { Result } from "./util/result"; import { ParamValues, ParamValueMode } from "./param/param-values"; import { ParamDefinition } from "."; +import { IReferencedObject } from "./value_ref/object_ref"; /** * Classe abstraite de Noeud de calcul : classe de base pour tous les calculs */ -export abstract class Nub extends ComputeNode { +export abstract class Nub extends ComputeNode implements IReferencedObject { private _dichoStartIntervalMaxSteps: number = 100; /** @@ -144,4 +145,36 @@ export abstract class Nub extends ComputeNode { public get result(): Result { return this._result; } + + // interface IReferencedObject + + /** + * getter de la (des) valeurs référencées + */ + public getReferencedValues(desc: string): number[] { + const p: ParamDefinition = this.getParameter(desc); + if (p !== undefined) { + switch (p.valueMode) { + case ParamValueMode.CALCUL: + { + this.CalcSerie(0.001, 0.1, p.symbol); + const res: number[] = []; + for (const re of this._result.resultElements) + res.push(re.vCalc); + return res; + } + + case ParamValueMode.LINK: + return p.referencedValues; + + default: + const res: number[] = []; + for (const v of p.paramValues.getValuesIterator()) + res.push(v); + return res; + } + } + + throw new Error(`Nub : appel à IReferencedObject.getReferencedValues('${desc}') invalide`); + } } diff --git a/src/object_ref.ts b/src/object_ref.ts deleted file mode 100644 index 5d461e48e82e5cd817242da537d0a9ad334ea866..0000000000000000000000000000000000000000 --- a/src/object_ref.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { IJalhydObject } from "./jalhyd_object"; -import { ParamValues } from "."; - -/** - * objet (paramètre ou résultat) dont les valeurs sont référençables pour réutilisation - * (d'une calculette sur une autre par ex) - */ -export interface IReferencedObject extends IJalhydObject { - /** - * getter de la (des) valeurs - */ - readonly values: number[]; -} - -/** - * référence vers un objet - */ -export interface IObjectReference { - /** - * référence à l'objet pointé sous forme symbolique - * exemples : <uid calculette>.Q, <uid calculette>.<n° d'ouvrage>.Z1 - */ - refDefinition: string; - - /** - * valeurs de l'objet IReferencedObject référencé - */ - readonly referencedValues: number[]; -} - -/** - * implémentation par défaut de IObjectReference - */ -export class ObjectReference implements IObjectReference { - private _referencedObject: IReferencedObject; - - private _refDefinition: string; - - public get referencedValues(): number[] { - return this._referencedObject.values; - } - - public get refDefinition(): string { - return this._refDefinition; - } - - public set refDefinition(def: string) { - // RAZ de l'objet référencé - if (this._refDefinition !== def) - this._referencedObject = undefined; - this._refDefinition = def; - } - - /** - * objet référencé - */ - public get referencedObject(): IReferencedObject { - return this._referencedObject; - } - - /** - * MAJ de l'objet référencé - */ - public set referencedObject(rv: IReferencedObject) { - this._referencedObject = rv; - } -} diff --git a/src/param/param-definition.ts b/src/param/param-definition.ts index a3ee7daa6fb9dec90ee2de3c54138950f8111eea..c8c009cc530ed1ca181892aa38dbe456674b6a5d 100644 --- a/src/param/param-definition.ts +++ b/src/param/param-definition.ts @@ -2,6 +2,8 @@ import { Message, MessageCode } from "../util/message"; import { BaseParam } from "./param-base"; import { ParamDomain, ParamDomainValue } from "./param-domain"; +import { ParamValueMode } from "./param-values"; +import { IReferencedObject, IObjectReference, ObjectReference } from "../value_ref/object_ref"; /** * calculabilité du paramètre @@ -32,19 +34,34 @@ export enum ParamCalculability { * définition d'un paramètre d'un noeud de calcul */ // tslint:disable-next-line:max-classes-per-file -export class ParamDefinition extends BaseParam { +export class ParamDefinition extends BaseParam implements IObjectReference { /** * calculabilité */ private _calc: ParamCalculability; + /** + * implémentation par délégation de IObjectReference + */ + private _valueRef: ObjectReference; + constructor(s: string, d: ParamDomain | ParamDomainValue, val?: number) { super(s, d, val); + this._valueRef = new ObjectReference(); this._calc = ParamCalculability.FREE; } get v(): number { - return super.getValue(); + switch (this.valueMode) { + case ParamValueMode.SINGLE: + return super.getValue(); + + case ParamValueMode.LINK: + return this._valueRef.referencedValues[0]; + + default: + throw new Error(`mode de valeur ${ParamValueMode[this.valueMode]} invalide`); + } } set v(val: number) { @@ -87,4 +104,18 @@ export class ParamDefinition extends BaseParam { res._calc = this._calc; return res; } + + // interface IObjectReference + + public defineReference(target: IReferencedObject, desc: string) { + this.paramValues.valueMode = ParamValueMode.LINK; + this._valueRef.defineReference(target, desc); + } + + /** + * valeurs de l'objet IReferencedObject référencé + */ + public get referencedValues(): number[] { + return this._valueRef.referencedValues; + } } diff --git a/src/param/param-values.ts b/src/param/param-values.ts index 24f46e4d416ecc26dd621549596cd530215ab179..1f2f84e884f59f179ea6ad99ae22182fd67ddd42 100644 --- a/src/param/param-values.ts +++ b/src/param/param-values.ts @@ -1,6 +1,6 @@ import { Pair } from "../util/pair" import { DefinedNumber } from "../util/definedvalue"; -import { IReferencedObject, IObjectReference, ObjectReference } from "../object_ref"; +import { IReferencedObject, IObjectReference, ObjectReference } from "../value_ref/object_ref"; import { JalhydObject } from "../jalhyd_object"; /** @@ -180,7 +180,7 @@ export class ParamValueIterator implements IterableIterator<number> { } } -export class ParamValues extends JalhydObject implements IReferencedObject, IObjectReference { +export class ParamValues { /** * mode de génération des valeurs : min/max, liste, ... */ @@ -216,15 +216,8 @@ export class ParamValues extends JalhydObject implements IReferencedObject, IObj */ private _iterator: ParamValueIterator; - /** - * implémentation par délégation de IObjectReference - */ - private _valueRef: ObjectReference; - constructor() { - super(); this._singleValue = new DefinedNumber(); - this._valueRef = new ObjectReference(); } public setValues(o: number | any, max?: number, step?: number) { @@ -283,12 +276,8 @@ export class ParamValues extends JalhydObject implements IReferencedObject, IObj throw new Error(`ParamValues : liste de valeurs non définie`); break; - case ParamValueMode.CALCUL: - break; - case ParamValueMode.LINK: - if (this.referencedObject instanceof ParamValues) - this.referencedObject.check(); + case ParamValueMode.CALCUL: break; default: @@ -297,16 +286,7 @@ export class ParamValues extends JalhydObject implements IReferencedObject, IObj } public get singleValue() { - switch (this.valueMode) { - case ParamValueMode.SINGLE: - return this._singleValue.value; - - case ParamValueMode.LINK: - return this._valueRef.referencedObject.values[0]; - - default: - throw new Error(`mode de valeur ${ParamValueMode[this.valueMode]} invalide`); - } + return this._singleValue.value; } public get uncheckedValue() { @@ -405,46 +385,4 @@ export class ParamValues extends JalhydObject implements IReferencedObject, IObj this._singleValue.value = this._iterator.next().value; return this._singleValue.value; } - - - // interface IReferencedObject - - /** - * getter de la (des) valeurs référencées - */ - public get values(): number[] { - const res: number[] = []; - for (const v of this.getValuesIterator()) - res.push(v); - return res; - } - - // interface IObjectReference - - /** - * référence à l'objet pointé sous forme symbolique - * exemples : <uid calculette>.Q, <uid calculette>.<ouvrage>.Z1 - */ - public get refDefinition(): string { - return this._valueRef.refDefinition; - } - - public set refDefinition(def: string) { - this._valueRef.refDefinition = def; - } - - /** - * valeurs de l'objet IReferencedObject référencé - */ - public get referencedValues(): number[] { - return this._valueRef.referencedValues; - } - - /** - * MAJ de l'objet référencé - */ - public set referencedObject(rv: IReferencedObject) { - this.valueMode = ParamValueMode.LINK; - this._valueRef.referencedObject = rv; - } } diff --git a/src/value_ref/object_ref.ts b/src/value_ref/object_ref.ts new file mode 100644 index 0000000000000000000000000000000000000000..0b1922ba8ba921812683ce927d42272582f49ef9 --- /dev/null +++ b/src/value_ref/object_ref.ts @@ -0,0 +1,52 @@ +/** + * objet (paramètre ou résultat) dont les valeurs sont référençables pour réutilisation + * (d'une calculette sur une autre par ex) + */ +export interface IReferencedObject { + /** + * getter de la (des) valeurs + */ + getReferencedValues(desc?: string): number[]; +} + +/** + * référence vers un objet + */ +export interface IObjectReference { + /** + * définition de l'objet référencé + * @param target objet contenant la valeur qu'on va référencer + * @param desc : description de la valeur pointée sous forme symbolique. Exemples : Q, <n° d'ouvrage>.Z1 + */ + defineReference(target: IReferencedObject, desc: string): void; + + /** + * valeurs de l'objet IReferencedObject référencé + */ + readonly referencedValues: number[]; +} + +/** + * implémentation par défaut de IObjectReference + */ +export class ObjectReference implements IObjectReference { + private _referencedObject: IReferencedObject; + + private _refDefinition: string; + + public get referencedValues(): number[] { + return this._referencedObject.getReferencedValues(this._refDefinition); + } + + public defineReference(target: IReferencedObject, desc: string) { + this._referencedObject = target; + this._refDefinition = desc; + } + + /** + * objet référencé + */ + public get referencedObject(): IReferencedObject { + return this._referencedObject; + } +}