Scala: is there a general way to trim all string fields of case classes?

I need a general way (for example, some function) that takes an instance of the case class (of any type) and returns a copy of that instance, but with a trimmed string.

(preferably without reflection)

Any idea?

+4
source share
2 answers

You can use shapeless to do this:

import shapeless._
import shapeless.ops.hlist._

// Trims if passed a String value, otherwise returns the value unchanged
object Trimmer extends Poly1 {
  implicit val stringTrim = at[String] { _.trim }
  implicit def noop[T]    = at[T] { identity }
}

// Uses a Generic to transform the instance into an HList, maps over it 
// and convert it back into the case class
def trimCaseClass[C, H <: HList](c: C)
    (implicit g: Generic.Aux[C, H], m: Mapper.Aux[Trimmer.type, H, H]): C = {
  val hlist = g.to(c)
  val trimmed = hlist.map(Trimmer)
  g.from(trimmed)
}

Then:

scala> case class A(s1: String, s2: String, i: Int)
defined class A

scala> val a = A("   1   ", "2", 3)
a: A = A(   1   ,2,3)

scala> trimCaseClass(a)
res0: A = A(1,2,3)
+3
source

Using shapeless :

import shapeless._, ops.hlist._

object trimString extends Poly1 {
  implicit val stringCase = at[String](_.trim)
  implicit def restCase[A] = at[A](a => a)
}

def trimAllIn[A, R <: HList](a: A)(implicit
    gen: Generic.Aux[A, R],
  mapper: Mapper.Aux[trimString.type, R, R]
) = gen.from(mapper(gen.to(a)))

case class Foo(string: String, int: Int)
case class Bar(string1: String, string2: String)

assert { trimAllIn(Foo("  trim me ", 42)) == Foo("trim me", 42) }
assert { trimAllIn(Bar("  trim me", "and me too   ")) == Bar("trim me", "and me too") }

Runnable version here

+2
source

Source: https://habr.com/ru/post/1684483/


All Articles