modifying

Sometimes you might want to compare some nested values using a different comparator but the type they share is not unique within that hierarchy.

Consider following example:

import com.softwaremill.diffx._
import com.softwaremill.diffx.generic.auto._

case class Person(age: Int, weight: Int)

If we would like to compare weight differently than age we would have to introduce a new type for weight in order to provide a different Diff typeclass for only that field. While in general, it is a good idea to have your types very precise it might not always be practical or even possible. Fortunately, diffx comes with a mechanism which allows the replacement of nested diff instances.

First we need to acquire a lens at given path using modify method, and then we can call setTo to replace a particular instance.

implicit val diffPerson: Diff[Person] = Diff.summon[Person].modify(_.weight)
        .setTo(Diff.approximate(epsilon=5))
compare(Person(23, 60), Person(23, 62))
// res0: DiffResult = DiffResultObject(
//   name = "Person",
//   fields = ListMap(
//     "age" -> IdenticalValue(value = 23),
//     "weight" -> IdenticalValue(value = 60)
//   )
// )

In fact, replacement is so powerful that ignoring is implemented as a replacement with the Diff.ignore instance.

collection support

Specify how objects within particular collection within particular diff instance should be matched. We distinguish free main types of collections:

  • seqLike collections where elements are indexed collections

  • setLike collections where elements aren’t indexed

  • mapLike collections where elements(values) are indexed by some keys

Each collection should fall into one of above categories. Each category exposes different set of methods.

case class Organization(peopleList: List[Person], peopleSet: Set[Person], peopleMap: Map[Person, Person])
implicit val diffOrg: Diff[Organization] = Diff.summon[Organization]
        // seqLike methods:
        .modify(_.peopleList).matchByValue(_.age)
        .modify(_.peopleList).matchByIndex(index => index % 2)
        // setLike methods:
        .modify(_.peopleSet).matchBy(_.age)
        // mapLike methods:
        .modify(_.peopleMap).matchByValue(_.age)
        .modify(_.peopleMap).matchByKey(_.weight)