Skip to content

Commit

Permalink
Release 0.7.0
Browse files Browse the repository at this point in the history
  • Loading branch information
ghostbuster91 committed Dec 22, 2021
1 parent 278c184 commit bb6c03c
Show file tree
Hide file tree
Showing 13 changed files with 134 additions and 37 deletions.
6 changes: 3 additions & 3 deletions generated-docs/out/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ Will result in:

![](https://github.com/softwaremill/diffx/blob/master/example.png?raw=true)

`diffx` is available for Scala 2.12 and 2.13 both jvm and js.
`diffx` is available for Scala 3, 2.13 and 2.12 both jvm and js.

The core of `diffx` comes in a single jar.

Expand All @@ -96,7 +96,7 @@ There is a number of similar projects from which diffx draws inspiration.
Below is a list of some of them, which I am aware of, with their main differences:
- [xotai/diff](https://github.com/xdotai/diff) - based on shapeless, seems not to be activly developed anymore
- [ratatool-diffy](https://github.com/spotify/ratatool/tree/master/ratatool-diffy) - the main purpose is to compare large data sets stored on gs or hdfs

- [difflicious](https://github.com/jatcwang/difflicious) - very similar feature set, different design under the hood, no auto-derivation

## Sponsors

Expand Down Expand Up @@ -132,7 +132,7 @@ a software development and consulting company. We help clients scale their busin
usage/derivation
usage/ignoring
usage/replacing
usage/modifying
usage/extending
usage/sequences
usage/output
Expand Down
6 changes: 3 additions & 3 deletions generated-docs/out/integrations/cats.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ This module contains integration layer between [org.typelevel.cats](https://gith
## sbt

```scala
"com.softwaremill.diffx" %% "diffx-cats" % "0.6.0" % Test
"com.softwaremill.diffx" %% "diffx-cats" % "0.7.0" % Test
```

## mill

```scala
ivy"com.softwaremill.diffx::diffx-cats::0.6.0"
ivy"com.softwaremill.diffx::diffx-cats::0.7.0"
```

## Usage
Expand All @@ -37,7 +37,7 @@ compare(t1, t2)
// name = "TestData",
// fields = ListMap(
// "ints" -> DiffResultObject(
// name = "List",
// name = "NonEmptyList",
// fields = ListMap(
// "0" -> DiffResultString(
// diffs = List(
Expand Down
4 changes: 2 additions & 2 deletions generated-docs/out/integrations/refined.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ This module contains integration layer between [eu.timepit.refined](https://gith
## sbt

```scala
"com.softwaremill.diffx" %% "diffx-refined" % "0.6.0" % Test
"com.softwaremill.diffx" %% "diffx-refined" % "0.7.0" % Test
```

## mill

```scala
ivy"com.softwaremill.diffx::diffx-refined::0.6.0"
ivy"com.softwaremill.diffx::diffx-refined::0.7.0"
```

## Usage
Expand Down
4 changes: 2 additions & 2 deletions generated-docs/out/integrations/tagging.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ This module contains integration layer between [com.softwaremill.common.tagging]
## sbt

```scala
"com.softwaremill.diffx" %% "diffx-tagging" % "0.6.0"
"com.softwaremill.diffx" %% "diffx-tagging" % "0.7.0"
```

## mill

```scala
ivy"com.softwaremill.diffx::diffx-tagging::0.6.0"
ivy"com.softwaremill.diffx::diffx-tagging::0.7.0"
```

## Usage
Expand Down
4 changes: 2 additions & 2 deletions generated-docs/out/test-frameworks/munit.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ To use with munit, add following dependency:
## sbt

```scala
"com.softwaremill.diffx" %% "diffx-munit" % "0.6.0" % Test
"com.softwaremill.diffx" %% "diffx-munit" % "0.7.0" % Test
```

## mill

```scala
ivy"com.softwaremill.diffx::diffx-munit::0.6.0"
ivy"com.softwaremill.diffx::diffx-munit::0.7.0"
```

## Usage
Expand Down
8 changes: 4 additions & 4 deletions generated-docs/out/test-frameworks/scalatest.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,24 @@ To use with scalatest, add the following dependency:

For use with `should` matchers:
```scala
"com.softwaremill.diffx" %% "diffx-scalatest-should" % "0.6.0" % Test
"com.softwaremill.diffx" %% "diffx-scalatest-should" % "0.7.0" % Test
```

For use with `must` matchers:
```scala
"com.softwaremill.diffx" %% "diffx-scalatest-should" % "0.6.0" % Test
"com.softwaremill.diffx" %% "diffx-scalatest-must" % "0.7.0" % Test
```

## mill

For use with `should` matchers:
```scala
ivy"com.softwaremill.diffx::diffx-scalatest-must::0.6.0"
ivy"com.softwaremill.diffx::diffx-scalatest-must::0.7.0"
```

For use with `must` matchers:
```scala
ivy"com.softwaremill.diffx::diffx-scalatest-must::0.6.0"
ivy"com.softwaremill.diffx::diffx-scalatest-must::0.7.0"
```

## Usage
Expand Down
4 changes: 2 additions & 2 deletions generated-docs/out/test-frameworks/specs2.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ To use with specs2, add the following dependency:
## sbt

```scala
"com.softwaremill.diffx" %% "diffx-specs2" % "0.6.0" % Test
"com.softwaremill.diffx" %% "diffx-specs2" % "0.7.0" % Test
```

## mill

```scala
ivy"com.softwaremill.diffx::diffx-specs2::0.6.0"
ivy"com.softwaremill.diffx::diffx-specs2::0.7.0"
```

## Usage
Expand Down
4 changes: 2 additions & 2 deletions generated-docs/out/test-frameworks/utest.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ To use with utest, add following dependency:
## sbt

```scala
"com.softwaremill.diffx" %% "diffx-utest" % "0.6.0" % Test
"com.softwaremill.diffx" %% "diffx-utest" % "0.7.0" % Test
```

## mill

```scala
ivy"com.softwaremill.diffx::diffx-utest::0.6.0"
ivy"com.softwaremill.diffx::diffx-utest::0.7.0"
```

## Usage
Expand Down
19 changes: 19 additions & 0 deletions generated-docs/out/usage/derivation.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,22 @@ or extend trait
`com.softwaremill.diffx.generic.auto.AutoDerivation`

**Auto derivation might have a huge impact on compilation times**, because of that it is recommended to use `semi-auto` derivation.


Given that you have auto-derivation enabled you can summon diff instances as you would summon any other implicit type-class by using
`implictly[Diff[T]]`. You can also write a shorter version `Diff[T]` which will be equivalent.
However, if you would like to modify somehow (see [ignoring](./ignoring.md) and [modifying](./modifying.md)) given instance and
put it back into to the implicit scope:
```scala
implict val diffForMyClass: Diff[MyClass] = Diff[MyClass].doSomething
```
you will get a forward reference error.

To overcome that issue there is a `Derived` wrapper which allows you to summon a wrapped instance.
```scala
implict val diffForMyClass: Diff[MyClass] = implicitly[Derived[Diff[MyClass]]].value.doSomething
```
There is a `summon` method to make it more convenient. Below code is equivalent to the one above.
```scala
implict val diffForMyClass: Diff[MyClass] = Diff.summon[MyClass].doSomething
```
8 changes: 4 additions & 4 deletions generated-docs/out/usage/ignoring.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ instance of the `Diff` typeclass into the implicit scope. The whole process look

```scala
case class Person(name:String, age:Int)
implicit val modifiedDiff: Diff[Person] = Derived[Diff[Person]].ignore(_.age)
implicit val modifiedDiff: Diff[Person] = Diff.derived[Person].ignore(_.age)
```
```scala
compare(Person("bob", 25), Person("bob", 30))
Expand All @@ -39,18 +39,18 @@ original comparison into ignored output:
implicit val conf: DiffConfiguration = DiffConfiguration(makeIgnored =
(original: Diff[Any]) =>
(left: Any, right: Any, context: DiffContext) => {
IdenticalValue(s"Ignored but was: ${original.apply(left, right, context).show()(ConsoleColorConfig.noColors)}")
IdenticalValue(s"Ignored but was: ${original.apply(left, right, context).show()(ShowConfig.noColors)}")
}
)
// conf: DiffConfiguration = DiffConfiguration(makeIgnored = <function1>)
val d = Diff[Person].ignore(_.age)
// d: Diff[Person] = com.softwaremill.diffx.Diff$$anon$1@2f232df9
// d: Diff[Person] = com.softwaremill.diffx.Diff$$anon$1@71ed624c
d(Person("bob", 25), Person("bob", 30))
// res2: DiffResult = DiffResultObject(
// name = "Person",
// fields = ListMap(
// "name" -> IdenticalValue(value = "bob"),
// "age" -> IdenticalValue(value = "<ignored>")
// "age" -> IdenticalValue(value = "Ignored but was: 25 -> 30")
// )
// )
```
64 changes: 64 additions & 0 deletions generated-docs/out/usage/modifying.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# 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:
```scala
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.

```scala
implicit val diffPerson: Diff[Person] = Diff.summon[Person].modify(_.weight)
.setTo(Diff.approximate(epsilon=5))
```

```scala
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.

```scala
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)
```
34 changes: 23 additions & 11 deletions generated-docs/out/usage/output.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,29 +23,38 @@ By default, the difference is shown in the following form:

When comparing collection types the difference is calculated against the `right` value

`rightColor(additionalValue)` when there is an additional entity on the left-hand side
`leftColor(missingValue)` when there is a missing entity on the left-hand side
`additionalColor(additionalValue)` when there is an additional entity on the left-hand side
`missingColor(missingValue)` when there is a missing entity on the left-hand side


Where, by default, `rightColor` is green and `leftColor` is red.

Colors can be customized providing an implicit instance of `ConsoleColorConfig` class.
Colors can be customized providing an implicit instance of `ShowConfig` class.
In fact `rightColor` and `leftColor` are functions `string => string` so they can be modified to do whatever you want with the output.
One example of that would be to use some special characters instead of colors, which might be useful on some environments like e.g. CI.

````scala
val colorConfigWithPlusMinus: ConsoleColorConfig =
ConsoleColorConfig(default = identity, arrow = identity, right = s => "+" + s, left = s => "-" + s)
val showConfigWithPlusMinus: ShowConfig =
ShowConfig.default.copy(default = identity, arrow = identity, right = s => "+" + s, left = s => "-" + s)
````

There are two predefined set of colors - light and dark theme.
The default theme is dark, and it can be changed using environment variable - `DIFFX_COLOR_THEME`(`light`/`dark`).

## skipping identical

In some cases it might be desired to skip rendering the identical fields, to do that simple set `showIgnored` to `false`.
In some cases it might be desired to skip rendering identical fields.
This can be achieved by using a specific DiffResult transformer. DiffResult transformer is a part of `ShowConfig`.
By default, it is set to an identical function.

```scala
implicit val showConfig = ShowConfig.default.copy(transformer = DiffResultTransformer.skipIdentical)
// showConfig: ShowConfig = ShowConfig(
// left = com.softwaremill.diffx.ShowConfig$$$Lambda$11597/0x0000000842d62840@4292838c,
// right = com.softwaremill.diffx.ShowConfig$$$Lambda$11597/0x0000000842d62840@7e50258,
// missing = com.softwaremill.diffx.ShowConfig$$$Lambda$11597/0x0000000842d62840@5a59b1a9,
// additional = com.softwaremill.diffx.ShowConfig$$$Lambda$11597/0x0000000842d62840@352a9ee1,
// default = com.softwaremill.diffx.ShowConfig$$$Lambda$11600/0x0000000842d61840@6372f52b,
// arrow = com.softwaremill.diffx.ShowConfig$$$Lambda$11597/0x0000000842d62840@4c2adcdf,
// transformer = com.softwaremill.diffx.DiffResultTransformer$$$Lambda$11636/0x0000000842d02840@5b69f80a
// )
case class Person(name:String, age:Int)

val result = compare(Person("Bob", 23), Person("Alice", 23))
Expand All @@ -62,7 +71,10 @@ val result = compare(Person("Bob", 23), Person("Alice", 23))
// "age" -> IdenticalValue(value = 23)
// )
// )
result.show(renderIdentical = false)
result.show()
// res1: String = """Person(
// name: Bob -> Alice)"""
```
```

There is a convenient method in `ShowConfig` called `skipIdentical` which does exactly that, so the relevant line from
the example can be shortened to `ShowConfig.default.skipIdentical`
6 changes: 4 additions & 2 deletions generated-docs/out/usage/sequences.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ val bob = Person("1","Bob")
```scala
compare(Set(bob), Set(bob, Person("2","Alice")))
// res1: DiffResult = DiffResultSet(
// typename = "Set",
// diffs = Set(
// DiffResultObject(
// name = "Person",
Expand Down Expand Up @@ -57,6 +58,7 @@ val bob = Person("1","Bob")
```scala
compare(Map("1" -> bob), Map("2" -> bob))
// res3: DiffResult = DiffResultMap(
// typename = "Map",
// entries = Map(
// DiffResultString(
// diffs = List(
Expand Down Expand Up @@ -85,7 +87,7 @@ import com.softwaremill.diffx.generic.auto._

case class Person(id: String, name: String)

implicit val personMatcher = ObjectMatcher.list[Person].byValue(_.id)
implicit val personMatcher = ObjectMatcher.seq[Person].byValue(_.id)
val bob = Person("1","Bob")
val alice = Person("2","Alice")
```
Expand Down Expand Up @@ -113,4 +115,4 @@ compare(List(bob, alice), List(alice, bob))
```

*Note: `ObjectMatcher` can be also passed explicitly, either upon creation or during modification*
*See [replacing](replacing.md) for details.*
*See [modifying](modifying.md) for details.*

0 comments on commit bb6c03c

Please sign in to comment.