From 69fa3dd629168792f25206853f1515fa0344b8d3 Mon Sep 17 00:00:00 2001 From: ddworak Date: Tue, 19 Nov 2019 08:30:02 +0100 Subject: [PATCH 1/5] 2-way transform -> bitransform --- .../benchmarks/properties/ModelPropertyListeners.scala | 4 ++-- .../benchmarks/properties/SinglePropertyListeners.scala | 4 ++-- .../src/main/scala/io/udash/bootstrap/form/UdashForm.scala | 2 +- .../io/udash/properties/seq/TransformedSeqProperty.scala | 2 +- .../main/scala/io/udash/properties/single/Property.scala | 4 ++-- .../test/scala/io/udash/properties/ModelPropertyTest.scala | 5 +---- core/src/test/scala/io/udash/properties/PropertyTest.scala | 5 +---- .../test/scala/io/udash/properties/SeqPropertyTest.scala | 5 +---- .../guide/views/ext/demo/bootstrap/DatePickerDemo.scala | 4 +--- .../guide/views/ext/demo/bootstrap/ProgressBarDemo.scala | 2 +- .../guide/views/ext/demo/bootstrap/SimpleFormDemo.scala | 2 +- .../web/guide/views/frontend/demos/CheckboxDemo.scala | 7 ++----- .../web/guide/views/frontend/demos/IntroFormDemo.scala | 6 +++--- .../web/guide/views/frontend/demos/RadioButtonsDemo.scala | 5 +---- .../udash/web/guide/views/frontend/demos/SelectDemo.scala | 5 +---- .../web/guide/views/frontend/demos/TextInputDemo.scala | 2 +- 16 files changed, 22 insertions(+), 42 deletions(-) diff --git a/benchmarks/.js/src/main/scala/io/udash/benchmarks/properties/ModelPropertyListeners.scala b/benchmarks/.js/src/main/scala/io/udash/benchmarks/properties/ModelPropertyListeners.scala index bcebcf976..b3a5c2f2c 100644 --- a/benchmarks/.js/src/main/scala/io/udash/benchmarks/properties/ModelPropertyListeners.scala +++ b/benchmarks/.js/src/main/scala/io/udash/benchmarks/properties/ModelPropertyListeners.scala @@ -17,7 +17,7 @@ object ModelPropertyListeners extends BenchmarkUtils { }), ("both-ways transformed property", () => { val p = ModelProperty(ModelItem.random) - val t = p.transform((v: ModelItem) => v.copy(i = v.i + 1), (v: ModelItem) => v.copy(i = v.i - 1)) + val t = p.bitransform(v => v.copy(i = v.i + 1))(v => v.copy(i = v.i - 1)) (p, t) }), ("one-way transformed property with slow transformer", () => { @@ -27,7 +27,7 @@ object ModelPropertyListeners extends BenchmarkUtils { }), ("both-ways transformed property with slow transformer", () => { val p = ModelProperty(ModelItem.random) - val t = p.transform((v: ModelItem) => v.copy(i = slowInc(v.i)), (v: ModelItem) => v.copy(i = slowDec(v.i))) + val t = p.bitransform(v => v.copy(i = slowInc(v.i)))(v => v.copy(i = slowDec(v.i))) (p, t) }) ) diff --git a/benchmarks/.js/src/main/scala/io/udash/benchmarks/properties/SinglePropertyListeners.scala b/benchmarks/.js/src/main/scala/io/udash/benchmarks/properties/SinglePropertyListeners.scala index e8264d89a..aeeb7fe31 100644 --- a/benchmarks/.js/src/main/scala/io/udash/benchmarks/properties/SinglePropertyListeners.scala +++ b/benchmarks/.js/src/main/scala/io/udash/benchmarks/properties/SinglePropertyListeners.scala @@ -17,7 +17,7 @@ object SinglePropertyListeners extends BenchmarkUtils { }), ("both-ways transformed property", () => { val p = Property(0) - val t = p.transform(_ + 1, (v: Int) => v - 1) + val t = p.bitransform(_ + 1)(_ - 1) (p, t) }), ("one-way transformed property with slow transformer", () => { @@ -27,7 +27,7 @@ object SinglePropertyListeners extends BenchmarkUtils { }), ("both-ways transformed property with slow transformer", () => { val p = Property(0) - val t = p.transform(slowInc, (v: Int) => slowDec(v)) + val t = p.bitransform(slowInc)(slowDec) (p, t) }) ) diff --git a/bootstrap4/.js/src/main/scala/io/udash/bootstrap/form/UdashForm.scala b/bootstrap4/.js/src/main/scala/io/udash/bootstrap/form/UdashForm.scala index 54c2f5188..b9bccda2d 100644 --- a/bootstrap4/.js/src/main/scala/io/udash/bootstrap/form/UdashForm.scala +++ b/bootstrap4/.js/src/main/scala/io/udash/bootstrap/form/UdashForm.scala @@ -317,7 +317,7 @@ final class FormElementsFactory( validator: Validator[Double] = Validator.Default ): UdashBootstrapComponent = { externalBinding(new InputComponent( - NumberInput(property.transform(_.toString, _.toDouble), debounce)( + NumberInput(property.bitransform(_.toString)(_.toDouble), debounce)( id := inputId, BootstrapStyles.Form.control, inputModifier.map(_.apply(nestedInterceptor)), diff --git a/core/src/main/scala/io/udash/properties/seq/TransformedSeqProperty.scala b/core/src/main/scala/io/udash/properties/seq/TransformedSeqProperty.scala index 048a27836..eb8415735 100644 --- a/core/src/main/scala/io/udash/properties/seq/TransformedSeqProperty.scala +++ b/core/src/main/scala/io/udash/properties/seq/TransformedSeqProperty.scala @@ -49,7 +49,7 @@ private[properties] class TransformedSeqProperty[A, B]( with AbstractSeqProperty[B, Property[B]] { override protected def transformElement(el: Property[A]): Property[B] = - el.transform(transformer, revert) + el.bitransform(transformer)(revert) override def replaceSeq(idx: Int, amount: Int, values: BSeq[B]): Unit = origin.replaceSeq(idx, amount, values.map(revert)) diff --git a/core/src/main/scala/io/udash/properties/single/Property.scala b/core/src/main/scala/io/udash/properties/single/Property.scala index 50e55351e..09fb5b314 100644 --- a/core/src/main/scala/io/udash/properties/single/Property.scala +++ b/core/src/main/scala/io/udash/properties/single/Property.scala @@ -39,7 +39,7 @@ trait Property[A] extends ReadableProperty[A] { * @tparam B Type of new Property. * @return New Property[B], which will be synchronised with original Property[A]. */ - def transform[B](transformer: A => B, revert: B => A): Property[B] + def bitransform[B](transformer: A => B)(revert: B => A): Property[B] /** * Creates SeqProperty[B] linked to `this`. Changes will be synchronized with `this` in both directions. @@ -73,7 +73,7 @@ private[properties] trait AbstractProperty[A] extends AbstractReadableProperty[A oneTimeListeners.clear() } - override def transform[B](transformer: A => B, revert: B => A): Property[B] = + override def bitransform[B](transformer: A => B)(revert: B => A): Property[B] = new TransformedProperty[A, B](this, transformer, revert) override def transformToSeq[B : PropertyCreator](transformer: A => BSeq[B], revert: BSeq[B] => A): SeqProperty[B, Property[B]] = diff --git a/core/src/test/scala/io/udash/properties/ModelPropertyTest.scala b/core/src/test/scala/io/udash/properties/ModelPropertyTest.scala index 2ae13bc4b..23cb7b959 100644 --- a/core/src/test/scala/io/udash/properties/ModelPropertyTest.scala +++ b/core/src/test/scala/io/udash/properties/ModelPropertyTest.scala @@ -170,10 +170,7 @@ class ModelPropertyTest extends UdashCoreTest { val listener = (v: Any) => values += v val p = ModelProperty(null: TT) - val t = p.transform[Int]( - (p: TT) => p.i + p.t.c.i, - (x: Int) => newTT(x / 2, None, new C(x / 2, ""), Seq.empty) - ) + val t = p.bitransform(p => p.i + p.t.c.i)(x => newTT(x / 2, None, new C(x / 2, ""), Seq.empty)) val r1 = p.listen(listener) val r2 = t.listen(listener) diff --git a/core/src/test/scala/io/udash/properties/PropertyTest.scala b/core/src/test/scala/io/udash/properties/PropertyTest.scala index 8b27ff1e6..286874203 100644 --- a/core/src/test/scala/io/udash/properties/PropertyTest.scala +++ b/core/src/test/scala/io/udash/properties/PropertyTest.scala @@ -178,13 +178,10 @@ class PropertyTest extends UdashCoreTest { val oneTimeListener = (v: Any) => oneTimeValues += v val cp = Property[C](new C(1, "asd")) - val tp = cp.transform[(T, T)]( - (c: C) => Tuple2(TC1(c.i), TC2(c.s)), - (t: (T, T)) => t match { + val tp = cp.bitransform(c => Tuple2(TC1(c.i), TC2(c.s))) { case (TC1(i), TC2(s)) => new C(i, s) case _ => new C(0, "") } - ) tp.listen(listener) cp.listen(listener) diff --git a/core/src/test/scala/io/udash/properties/SeqPropertyTest.scala b/core/src/test/scala/io/udash/properties/SeqPropertyTest.scala index 55e3cc796..aff6dd0fc 100644 --- a/core/src/test/scala/io/udash/properties/SeqPropertyTest.scala +++ b/core/src/test/scala/io/udash/properties/SeqPropertyTest.scala @@ -376,10 +376,7 @@ class SeqPropertyTest extends UdashCoreTest { "transform into Property" in { val p = SeqProperty[Int](1, 2, 3) - val t = p.transform[Int]( - (s: BSeq[Int]) => s.sum, - (i: Int) => (1 to i) - ) + val t = p.bitransform(_.sum)(1 to _) p.get should be(Seq(1, 2, 3)) t.get should be(6) diff --git a/guide/guide/.js/src/main/scala/io/udash/web/guide/views/ext/demo/bootstrap/DatePickerDemo.scala b/guide/guide/.js/src/main/scala/io/udash/web/guide/views/ext/demo/bootstrap/DatePickerDemo.scala index 65d29f978..73351e0af 100644 --- a/guide/guide/.js/src/main/scala/io/udash/web/guide/views/ext/demo/bootstrap/DatePickerDemo.scala +++ b/guide/guide/.js/src/main/scala/io/udash/web/guide/views/ext/demo/bootstrap/DatePickerDemo.scala @@ -78,9 +78,7 @@ object DatePickerDemo extends AutoDemo with CssView { ), factory.input.formGroup()( input = _ => factory.input.select( - pickerOptions.subProp(_.locale).transform[String]( - (_: Option[String]).get, Some(_: String) - ), + pickerOptions.subProp(_.locale).bitransform(_.get)(Option.apply), Seq("en_GB", "pl", "ru", "af").toSeqProperty )(span(_)).render, labelContent = Some(_ => "Locale") diff --git a/guide/guide/.js/src/main/scala/io/udash/web/guide/views/ext/demo/bootstrap/ProgressBarDemo.scala b/guide/guide/.js/src/main/scala/io/udash/web/guide/views/ext/demo/bootstrap/ProgressBarDemo.scala index d382a87d2..83b996b8b 100644 --- a/guide/guide/.js/src/main/scala/io/udash/web/guide/views/ext/demo/bootstrap/ProgressBarDemo.scala +++ b/guide/guide/.js/src/main/scala/io/udash/web/guide/views/ext/demo/bootstrap/ProgressBarDemo.scala @@ -68,7 +68,7 @@ object ProgressBarDemo extends AutoDemo { )(), ), div(bottomMargin)( - NumberInput(value.transform(_.toString, _.toInt))( + NumberInput(value.bitransform(_.toString)(_.toInt))( Form.control, placeholder := "Percentage" ) ) diff --git a/guide/guide/.js/src/main/scala/io/udash/web/guide/views/ext/demo/bootstrap/SimpleFormDemo.scala b/guide/guide/.js/src/main/scala/io/udash/web/guide/views/ext/demo/bootstrap/SimpleFormDemo.scala index dd9e48026..f7a17ec8c 100644 --- a/guide/guide/.js/src/main/scala/io/udash/web/guide/views/ext/demo/bootstrap/SimpleFormDemo.scala +++ b/guide/guide/.js/src/main/scala/io/udash/web/guide/views/ext/demo/bootstrap/SimpleFormDemo.scala @@ -82,7 +82,7 @@ object SimpleFormDemo extends AutoDemo with CssView { ), factory.input.formGroup()( input = _ => factory.input.numberInput( - user.subProp(_.age).transform(_.toDouble, _.toInt), + user.subProp(_.age).bitransform(_.toDouble)(_.toInt), )(validator = age => if (age < 0) Invalid("Age should be a non-negative integer!") else Valid).render, labelContent = Some(_ => "Age": Modifier), invalidFeedback = Some(_ => "Age should be a non-negative integer!") diff --git a/guide/guide/.js/src/main/scala/io/udash/web/guide/views/frontend/demos/CheckboxDemo.scala b/guide/guide/.js/src/main/scala/io/udash/web/guide/views/frontend/demos/CheckboxDemo.scala index 0ec482797..145b4bb0e 100644 --- a/guide/guide/.js/src/main/scala/io/udash/web/guide/views/frontend/demos/CheckboxDemo.scala +++ b/guide/guide/.js/src/main/scala/io/udash/web/guide/views/frontend/demos/CheckboxDemo.scala @@ -19,10 +19,7 @@ object CheckboxDemo extends AutoDemo { val propA = Property(true) val propB = Property(false) val propC = Property("Yes") - val propCAsBoolean = propC.transform( - (s: String) => s.equalsIgnoreCase("yes"), - (b: Boolean) => if (b) "Yes" else "No" - ) + val propCAsBoolean = propC.bitransform(_.equalsIgnoreCase("yes"))(if (_) "Yes" else "No") def checkboxes: JsDom.TypedTag[Div] = div(Grid.row)( div(Grid.col(4, ResponsiveBreakpoint.Medium))( @@ -51,7 +48,7 @@ object CheckboxDemo extends AutoDemo { checkboxes.render (checkboxes, checkboxes) - }.withSourceCode + }.withSourceCode override protected def demoWithSource(): (Modifier, Iterator[String]) = { import io.udash.bootstrap.utils.BootstrapStyles._ diff --git a/guide/guide/.js/src/main/scala/io/udash/web/guide/views/frontend/demos/IntroFormDemo.scala b/guide/guide/.js/src/main/scala/io/udash/web/guide/views/frontend/demos/IntroFormDemo.scala index fba3f3e11..ee532b1fa 100644 --- a/guide/guide/.js/src/main/scala/io/udash/web/guide/views/frontend/demos/IntroFormDemo.scala +++ b/guide/guide/.js/src/main/scala/io/udash/web/guide/views/frontend/demos/IntroFormDemo.scala @@ -69,9 +69,9 @@ object IntroFormDemo extends AutoDemo { // String representations of the model subproperties // These values are synchronised with the original value - private val minimum = model.subProp(_.minimum).transform(i2s, s2i) - private val between = model.subProp(_.between).transform(i2s, s2i) - private val maximum = model.subProp(_.maximum).transform(i2s, s2i) + private val minimum = model.subProp(_.minimum).bitransform(i2s)(s2i) + private val between = model.subProp(_.between).bitransform(i2s)(s2i) + private val maximum = model.subProp(_.maximum).bitransform(i2s)(s2i) private val validation = model.transform { element: IntroFormDemoModel => val errors = mutable.ArrayBuffer[String]() diff --git a/guide/guide/.js/src/main/scala/io/udash/web/guide/views/frontend/demos/RadioButtonsDemo.scala b/guide/guide/.js/src/main/scala/io/udash/web/guide/views/frontend/demos/RadioButtonsDemo.scala index 5216be57c..2c3d8ebc3 100644 --- a/guide/guide/.js/src/main/scala/io/udash/web/guide/views/frontend/demos/RadioButtonsDemo.scala +++ b/guide/guide/.js/src/main/scala/io/udash/web/guide/views/frontend/demos/RadioButtonsDemo.scala @@ -22,14 +22,11 @@ object RadioButtonsDemo extends AutoDemo { case object Banana extends Fruit val favoriteFruit = Property[Fruit](Apple) - val favoriteFruitString = favoriteFruit.transform( - (f: Fruit) => f.toString, - (s: String) => s match { + val favoriteFruitString = favoriteFruit.bitransform(_.toString) { case "Apple" => Apple case "Orange" => Orange case "Banana" => Banana } - ) def radioButtons: UdashInputGroup = UdashInputGroup()( prependText("Fruits:"), diff --git a/guide/guide/.js/src/main/scala/io/udash/web/guide/views/frontend/demos/SelectDemo.scala b/guide/guide/.js/src/main/scala/io/udash/web/guide/views/frontend/demos/SelectDemo.scala index 0e19b44c6..0ec509c95 100644 --- a/guide/guide/.js/src/main/scala/io/udash/web/guide/views/frontend/demos/SelectDemo.scala +++ b/guide/guide/.js/src/main/scala/io/udash/web/guide/views/frontend/demos/SelectDemo.scala @@ -19,14 +19,11 @@ object SelectDemo extends AutoDemo { case object Banana extends Fruit val favoriteFruit = Property[Fruit](Apple) - val favoriteFruitString = favoriteFruit.transform( - (f: Fruit) => f.toString, - (s: String) => s match { + val favoriteFruitString = favoriteFruit.bitransform(_.toString) { case "Apple" => Apple case "Orange" => Orange case "Banana" => Banana } - ) def select: UdashInputGroup = UdashInputGroup()( UdashInputGroup.prependText("Fruits:"), diff --git a/guide/guide/.js/src/main/scala/io/udash/web/guide/views/frontend/demos/TextInputDemo.scala b/guide/guide/.js/src/main/scala/io/udash/web/guide/views/frontend/demos/TextInputDemo.scala index c94663d20..fb4dd225c 100644 --- a/guide/guide/.js/src/main/scala/io/udash/web/guide/views/frontend/demos/TextInputDemo.scala +++ b/guide/guide/.js/src/main/scala/io/udash/web/guide/views/frontend/demos/TextInputDemo.scala @@ -39,7 +39,7 @@ object TextInputDemo extends AutoDemo { div(Grid.col(4, ResponsiveBreakpoint.Medium))( UdashInputGroup()( UdashInputGroup.input( - NumberInput(age.transform(_.toString, _.toInt))(maxlength := "6").render + NumberInput(age.bitransform(_.toString)(_.toInt))(maxlength := "6").render ), UdashInputGroup.appendText(span(bind(age))) ).render From 6b55e2efaa05300f225f6b3b78f7f5618e56ae0c Mon Sep 17 00:00:00 2001 From: ddworak Date: Tue, 19 Nov 2019 08:59:42 +0100 Subject: [PATCH 2/5] Cleanup tuple2 instantiations --- .../udash/properties/CallbackSequencer.scala | 2 +- .../io/udash/properties/PropertyTest.scala | 38 +++++++++---------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/core/src/main/scala/io/udash/properties/CallbackSequencer.scala b/core/src/main/scala/io/udash/properties/CallbackSequencer.scala index 88c66a5e2..5130e3bc6 100644 --- a/core/src/main/scala/io/udash/properties/CallbackSequencer.scala +++ b/core/src/main/scala/io/udash/properties/CallbackSequencer.scala @@ -41,7 +41,7 @@ class CallbackSequencer { def queue(id: Id, fireListeners: () => Any): Unit = { if (starts == 0) fireListeners() - else queue += Tuple2(id, fireListeners) + else queue += id -> fireListeners } def sequence(code: => Any): Unit = { diff --git a/core/src/test/scala/io/udash/properties/PropertyTest.scala b/core/src/test/scala/io/udash/properties/PropertyTest.scala index 286874203..ed09e6bc1 100644 --- a/core/src/test/scala/io/udash/properties/PropertyTest.scala +++ b/core/src/test/scala/io/udash/properties/PropertyTest.scala @@ -178,7 +178,7 @@ class PropertyTest extends UdashCoreTest { val oneTimeListener = (v: Any) => oneTimeValues += v val cp = Property[C](new C(1, "asd")) - val tp = cp.bitransform(c => Tuple2(TC1(c.i), TC2(c.s))) { + val tp = cp.bitransform(c => (TC1(c.i), TC2(c.s))) { case (TC1(i), TC2(s)) => new C(i, s) case _ => new C(0, "") } @@ -190,55 +190,55 @@ class PropertyTest extends UdashCoreTest { cp.listenOnce(oneTimeListener) cp.get should be(new C(1, "asd")) - tp.get should be(Tuple2(TC1(1), TC2("asd"))) + tp.get should be(TC1(1) -> TC2("asd")) cp.set(new C(12, "asd2")) cp.get should be(new C(12, "asd2")) - tp.get should be(Tuple2(TC1(12), TC2("asd2"))) + tp.get should be(TC1(12) -> TC2("asd2")) - tp.set(Tuple2(TC1(-5), TC2("tp"))) + tp.set(TC1(-5) -> TC2("tp")) cp.get should be(new C(-5, "tp")) - tp.get should be(Tuple2(TC1(-5), TC2("tp"))) + tp.get should be(TC1(-5) -> TC2("tp")) - tp.set(Tuple2(TC1(-5), TC2("tp"))) + tp.set(TC1(-5) -> TC2("tp")) cp.get should be(new C(-5, "tp")) - tp.get should be(Tuple2(TC1(-5), TC2("tp"))) + tp.get should be(TC1(-5) -> TC2("tp")) tp.touch() cp.get should be(new C(-5, "tp")) - tp.get should be(Tuple2(TC1(-5), TC2("tp"))) + tp.get should be(TC1(-5) -> TC2("tp")) - tp.set(Tuple2(TC1(-5), TC2("tp")), force = true) + tp.set(TC1(-5) -> TC2("tp"), force = true) cp.get should be(new C(-5, "tp")) - tp.get should be(Tuple2(TC1(-5), TC2("tp"))) + tp.get should be(TC1(-5) -> TC2("tp")) tp.clearListeners() - tp.set(Tuple2(TC1(-12), TC2("tp"))) + tp.set(TC1(-12) -> TC2("tp")) tp.listen(listener) cp.listen(listener) - tp.set(Tuple2(TC1(-13), TC2("tp"))) + tp.set(TC1(-13) -> TC2("tp")) cp.clearListeners() - tp.set(Tuple2(TC1(-14), TC2("tp"))) + tp.set(TC1(-14) -> TC2("tp")) tp.listen(listener) cp.listen(listener) - tp.set(Tuple2(TC1(-15), TC2("tp"))) + tp.set(TC1(-15) -> TC2("tp")) values.size should be(12) values should contain(new C(12, "asd2")) - values should contain(Tuple2(TC1(12), TC2("asd2"))) - values should contain(Tuple2(TC1(-5), TC2("tp"))) + values should contain(TC1(12) -> TC2("asd2")) + values should contain(TC1(-5) -> TC2("tp")) values should contain(new C(-5, "tp")) - values should contain(Tuple2(TC1(-13), TC2("tp"))) + values should contain(TC1(-13) -> TC2("tp")) values should contain(new C(-13, "tp")) - values should contain(Tuple2(TC1(-15), TC2("tp"))) + values should contain(TC1(-15) -> TC2("tp")) values should contain(new C(-15, "tp")) oneTimeValues.size should be(2) oneTimeValues should contain(new C(12, "asd2")) - oneTimeValues should contain(Tuple2(TC1(12), TC2("asd2"))) + oneTimeValues should contain(TC1(12) -> TC2("asd2")) } "fire transform method when needed" in { From 185be2e4d67c3ff6ccafadf967bc555836b6ce77 Mon Sep 17 00:00:00 2001 From: ddworak Date: Tue, 19 Nov 2019 09:03:51 +0100 Subject: [PATCH 3/5] bitransformToSeq --- .../scala/io/udash/bindings/inputs/FileInput.scala | 2 +- .../scala/io/udash/properties/single/Property.scala | 4 ++-- .../scala/io/udash/properties/PropertyTest.scala | 12 ++++-------- 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/core/.js/src/main/scala/io/udash/bindings/inputs/FileInput.scala b/core/.js/src/main/scala/io/udash/bindings/inputs/FileInput.scala index b3fa16d41..27af10961 100644 --- a/core/.js/src/main/scala/io/udash/bindings/inputs/FileInput.scala +++ b/core/.js/src/main/scala/io/udash/bindings/inputs/FileInput.scala @@ -17,7 +17,7 @@ object FileInput { * @return */ def single(selectedFile: Property[File])(inputName: String, inputModifiers: Modifier*): InputBinding[JSInput] = { - apply(selectedFile.transformToSeq(Seq(_), _.head), false.toProperty)(inputName, inputModifiers) + apply(selectedFile.bitransformToSeq(Seq(_))(_.head), false.toProperty)(inputName, inputModifiers) } /** diff --git a/core/src/main/scala/io/udash/properties/single/Property.scala b/core/src/main/scala/io/udash/properties/single/Property.scala index 09fb5b314..cc267926b 100644 --- a/core/src/main/scala/io/udash/properties/single/Property.scala +++ b/core/src/main/scala/io/udash/properties/single/Property.scala @@ -49,7 +49,7 @@ trait Property[A] extends ReadableProperty[A] { * @tparam B Type of elements in new SeqProperty. * @return New ReadableSeqProperty[B], which will be synchronised with original Property[A]. */ - def transformToSeq[B : PropertyCreator](transformer: A => BSeq[B], revert: BSeq[B] => A): SeqProperty[B, Property[B]] + def bitransformToSeq[B: PropertyCreator](transformer: A => BSeq[B])(revert: BSeq[B] => A): SeqProperty[B, Property[B]] /** * Bidirectionally synchronizes Property[B] with `this`. The transformed value is synchronized from `this` @@ -76,7 +76,7 @@ private[properties] trait AbstractProperty[A] extends AbstractReadableProperty[A override def bitransform[B](transformer: A => B)(revert: B => A): Property[B] = new TransformedProperty[A, B](this, transformer, revert) - override def transformToSeq[B : PropertyCreator](transformer: A => BSeq[B], revert: BSeq[B] => A): SeqProperty[B, Property[B]] = + override def bitransformToSeq[B: PropertyCreator](transformer: A => BSeq[B])(revert: BSeq[B] => A): SeqProperty[B, Property[B]] = new SeqPropertyFromSingleValue(this, transformer, revert) override def sync[B](p: Property[B])(transformer: A => B, revert: B => A): Registration = { diff --git a/core/src/test/scala/io/udash/properties/PropertyTest.scala b/core/src/test/scala/io/udash/properties/PropertyTest.scala index ed09e6bc1..5db7d9bb9 100644 --- a/core/src/test/scala/io/udash/properties/PropertyTest.scala +++ b/core/src/test/scala/io/udash/properties/PropertyTest.scala @@ -690,10 +690,8 @@ class PropertyTest extends UdashCoreTest { } val p = Property("1,2,3,4,5") - val s: SeqProperty[Int, Property[Int]] = p.transformToSeq( - (v: String) => Try(v.split(",").map(_.toInt).toSeq).getOrElse(Seq[Int]()), - (s: BSeq[Int]) => s.mkString(",") - ) + val s: SeqProperty[Int, Property[Int]] = + p.bitransformToSeq(v => Try(v.split(",").map(_.toInt).toSeq).getOrElse(Seq[Int]()))(_.mkString(",")) p.listenersCount() should be(0) registerElementListener(s.elemProperties) @@ -866,9 +864,7 @@ class PropertyTest extends UdashCoreTest { val p = SeqProperty(new ClazzModel(42)) var fromListen = BSeq.empty[Int] - val s = p.transformToSeq( - (v: BSeq[ClazzModel]) => v.map(_.p), (v: BSeq[Int]) => v.map(new ClazzModel(_)) - ) + val s = p.bitransformToSeq(_.map(_.p))(_.map(new ClazzModel(_))) p.get.map(_.p) shouldBe Seq(42) s.get shouldBe Seq(42) @@ -886,7 +882,7 @@ class PropertyTest extends UdashCoreTest { "handle child modification in transformToSeq result" in { val s = Property("1,2,3,4,5,6") - val i = s.transformToSeq(_.split(",").map(_.toInt), (v: BSeq[Int]) => v.map(_.toString).mkString(",")) + val i = s.bitransformToSeq(_.split(",").map(_.toInt))(_.map(_.toString).mkString(",")) i.get should be(Seq(1, 2, 3, 4, 5, 6)) From a7f37d6447bf7e91c1e3e4bf7616d73b4fb010af Mon Sep 17 00:00:00 2001 From: ddworak Date: Tue, 19 Nov 2019 09:38:23 +0100 Subject: [PATCH 4/5] bitransformElements --- .../properties/TransformedSeqPropertyListeners.scala | 4 ++-- .../test/scala/io/udash/bindings/TagsBindingTest.scala | 2 +- .../main/scala/io/udash/properties/seq/SeqProperty.scala | 8 ++++---- .../test/scala/io/udash/properties/SeqPropertyTest.scala | 9 +++------ .../guide/views/frontend/demos/CheckButtonsDemo.scala | 5 +---- .../web/guide/views/frontend/demos/MultiSelectDemo.scala | 5 +---- 6 files changed, 12 insertions(+), 21 deletions(-) diff --git a/benchmarks/.js/src/main/scala/io/udash/benchmarks/properties/TransformedSeqPropertyListeners.scala b/benchmarks/.js/src/main/scala/io/udash/benchmarks/properties/TransformedSeqPropertyListeners.scala index 54ba67f3b..3a4449083 100644 --- a/benchmarks/.js/src/main/scala/io/udash/benchmarks/properties/TransformedSeqPropertyListeners.scala +++ b/benchmarks/.js/src/main/scala/io/udash/benchmarks/properties/TransformedSeqPropertyListeners.scala @@ -18,7 +18,7 @@ object TransformedSeqPropertyListeners extends BenchmarkUtils { }), ("both-ways transformed elements", () => { val p = SeqProperty(Seq.tabulate(seqSize)(identity)) - val t = p.transformElements(_ + 1, (v: Int) => v - 1) + val t = p.bitransformElements(_ + 1)(_ - 1) (p, t) }), ("one-way transformed elements with slow transformer", () => { @@ -28,7 +28,7 @@ object TransformedSeqPropertyListeners extends BenchmarkUtils { }), ("both-ways transformed elements with slow transformer", () => { val p = SeqProperty(Seq.tabulate(seqSize)(identity)) - val t = p.transformElements(slowInc, slowDec) + val t = p.bitransformElements(slowInc)(slowDec) (p, t) }) ) diff --git a/core/.js/src/test/scala/io/udash/bindings/TagsBindingTest.scala b/core/.js/src/test/scala/io/udash/bindings/TagsBindingTest.scala index 9d3a4ac71..23f7ff4ff 100644 --- a/core/.js/src/test/scala/io/udash/bindings/TagsBindingTest.scala +++ b/core/.js/src/test/scala/io/udash/bindings/TagsBindingTest.scala @@ -1487,7 +1487,7 @@ class TagsBindingTest extends UdashFrontendTest with Bindings { bindings: Bindin "work with filtered transformed SeqProperty" in { val doubles = seq.SeqProperty[Double](1.5, 2.3, 3.7) - val ints = doubles.transformElements(_.toInt, (i: Int) => i.toDouble) + val ints = doubles.bitransformElements(_.toInt)(_.toDouble) val evens = ints.filter(_ % 2 == 0) val dom = div( diff --git a/core/src/main/scala/io/udash/properties/seq/SeqProperty.scala b/core/src/main/scala/io/udash/properties/seq/SeqProperty.scala index 2e9a42373..0b0951223 100644 --- a/core/src/main/scala/io/udash/properties/seq/SeqProperty.scala +++ b/core/src/main/scala/io/udash/properties/seq/SeqProperty.scala @@ -44,11 +44,11 @@ trait SeqProperty[A, +ElemType <: Property[A]] extends ReadableSeqProperty[A, El /** Removes all elements from this SeqProperty. */ def clear(): Unit - /** Transforms SeqProperty[A] into SeqProperty[B] element by element. - * Prefer this to `transform` whenever you don't need the whole sequence to perform the transformation. + /** Creates Property[B] linked to `this`. Changes will be bidirectionally synchronized between `this` and new property. + * Prefer this to `bitransform` whenever you don't need the whole sequence to perform the transformation. * * @return New SeqProperty[B], which will be synchronised with original SeqProperty[A]. */ - def transformElements[B](transformer: A => B, revert: B => A): SeqProperty[B, Property[B]] + def bitransformElements[B](transformer: A => B)(revert: B => A): SeqProperty[B, Property[B]] /** Creates `SeqProperty[A]` providing reversed order of elements from `this`. */ override def reversed(): SeqProperty[A, Property[A]] @@ -77,7 +77,7 @@ private[properties] trait AbstractSeqProperty[A, +ElemType <: Property[A]] structureListeners.clear() } - override def transformElements[B](transformer: A => B, revert: B => A): SeqProperty[B, Property[B]] = + override def bitransformElements[B](transformer: A => B)(revert: B => A): SeqProperty[B, Property[B]] = new TransformedSeqProperty[A, B](this, transformer, revert) override def reversed(): SeqProperty[A, Property[A]] = diff --git a/core/src/test/scala/io/udash/properties/SeqPropertyTest.scala b/core/src/test/scala/io/udash/properties/SeqPropertyTest.scala index aff6dd0fc..e9a468d52 100644 --- a/core/src/test/scala/io/udash/properties/SeqPropertyTest.scala +++ b/core/src/test/scala/io/udash/properties/SeqPropertyTest.scala @@ -403,13 +403,10 @@ class SeqPropertyTest extends UdashCoreTest { val init: Seq[BadEquals] = (1 to 3).map(new BadEquals(_)) val p = SeqProperty[BadEquals](init) - val t = p.transformElements[T]( - (i: BadEquals) => TC1(i.v), - (t: T) => t match { + val t = p.bitransformElements[T](i => TC1(i.v)) { case TC1(i) => new BadEquals(i) case _: T => new BadEquals(0) } - ) p.get.map(_.v) should be(Seq(1, 2, 3)) t.get should be(Seq(TC1(1), TC1(2), TC1(3))) @@ -681,7 +678,7 @@ class SeqPropertyTest extends UdashCoreTest { "be able to modify after transformation" in { val numbers = SeqProperty[Int](1, 2, 3) - val strings = numbers.transformElements(_.toString, (s: String) => Integer.parseInt(s)) + val strings = numbers.bitransformElements(_.toString)(Integer.parseInt) strings.append("4", "5", "6") numbers.get should be(Seq(1, 2, 3, 4, 5, 6)) @@ -693,7 +690,7 @@ class SeqPropertyTest extends UdashCoreTest { "filter transformed property" in { val doubles = SeqProperty[Double](1.5, 2.3, 3.7) - val ints = doubles.transformElements(_.toInt, (i: Int) => i.toDouble) + val ints = doubles.bitransformElements(_.toInt)(_.toDouble) val evens = ints.filter(_ % 2 == 0) doubles.listenersCount() should be(0) diff --git a/guide/guide/.js/src/main/scala/io/udash/web/guide/views/frontend/demos/CheckButtonsDemo.scala b/guide/guide/.js/src/main/scala/io/udash/web/guide/views/frontend/demos/CheckButtonsDemo.scala index 406feb08c..17c620126 100644 --- a/guide/guide/.js/src/main/scala/io/udash/web/guide/views/frontend/demos/CheckButtonsDemo.scala +++ b/guide/guide/.js/src/main/scala/io/udash/web/guide/views/frontend/demos/CheckButtonsDemo.scala @@ -20,14 +20,11 @@ object CheckButtonsDemo extends AutoDemo { case object Banana extends Fruit val favoriteFruits = SeqProperty(Apple, Banana) - val favoriteFruitsStrings = favoriteFruits.transformElements( - _.toString, - (s: String) => s match { + val favoriteFruitsStrings = favoriteFruits.bitransformElements(_.toString) { case "Apple" => Apple case "Orange" => Orange case "Banana" => Banana } - ) def checkButtons: UdashInputGroup = UdashInputGroup()( UdashInputGroup.prependText("Fruits:"), diff --git a/guide/guide/.js/src/main/scala/io/udash/web/guide/views/frontend/demos/MultiSelectDemo.scala b/guide/guide/.js/src/main/scala/io/udash/web/guide/views/frontend/demos/MultiSelectDemo.scala index e2eb395e1..67907e80e 100644 --- a/guide/guide/.js/src/main/scala/io/udash/web/guide/views/frontend/demos/MultiSelectDemo.scala +++ b/guide/guide/.js/src/main/scala/io/udash/web/guide/views/frontend/demos/MultiSelectDemo.scala @@ -19,14 +19,11 @@ object MultiSelectDemo extends AutoDemo { case object Banana extends Fruit val favoriteFruits = SeqProperty(Apple, Banana) - val favoriteFruitsStrings = favoriteFruits.transformElements( - _.toString, - (s: String) => s match { + val favoriteFruitsStrings = favoriteFruits.bitransformElements(_.toString) { case "Apple" => Apple case "Orange" => Orange case "Banana" => Banana } - ) def multiSelect: UdashInputGroup = UdashInputGroup()( UdashInputGroup.prependText("Fruits:"), From bca184a8b49c540fda74c45fd60b8106dc99825c Mon Sep 17 00:00:00 2001 From: ddworak Date: Tue, 19 Nov 2019 09:50:48 +0100 Subject: [PATCH 5/5] Cosmetic doc update --- core/src/main/scala/io/udash/properties/seq/SeqProperty.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/scala/io/udash/properties/seq/SeqProperty.scala b/core/src/main/scala/io/udash/properties/seq/SeqProperty.scala index 0b0951223..1784149d8 100644 --- a/core/src/main/scala/io/udash/properties/seq/SeqProperty.scala +++ b/core/src/main/scala/io/udash/properties/seq/SeqProperty.scala @@ -44,7 +44,7 @@ trait SeqProperty[A, +ElemType <: Property[A]] extends ReadableSeqProperty[A, El /** Removes all elements from this SeqProperty. */ def clear(): Unit - /** Creates Property[B] linked to `this`. Changes will be bidirectionally synchronized between `this` and new property. + /** Creates SeqProperty[B] linked to `this`. Changes will be bidirectionally synchronized between `this` and new property. * Prefer this to `bitransform` whenever you don't need the whole sequence to perform the transformation. * * @return New SeqProperty[B], which will be synchronised with original SeqProperty[A]. */