Skip to content
This repository was archived by the owner on Jan 24, 2025. It is now read-only.

Commit bb6c03c

Browse files
committed
Release 0.7.0
1 parent 278c184 commit bb6c03c

File tree

13 files changed

+134
-37
lines changed

13 files changed

+134
-37
lines changed

generated-docs/out/index.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ Will result in:
7272

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

75-
`diffx` is available for Scala 2.12 and 2.13 both jvm and js.
75+
`diffx` is available for Scala 3, 2.13 and 2.12 both jvm and js.
7676

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

@@ -96,7 +96,7 @@ There is a number of similar projects from which diffx draws inspiration.
9696
Below is a list of some of them, which I am aware of, with their main differences:
9797
- [xotai/diff](https://github.com/xdotai/diff) - based on shapeless, seems not to be activly developed anymore
9898
- [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
99-
99+
- [difflicious](https://github.com/jatcwang/difflicious) - very similar feature set, different design under the hood, no auto-derivation
100100

101101
## Sponsors
102102

@@ -132,7 +132,7 @@ a software development and consulting company. We help clients scale their busin
132132
133133
usage/derivation
134134
usage/ignoring
135-
usage/replacing
135+
usage/modifying
136136
usage/extending
137137
usage/sequences
138138
usage/output

generated-docs/out/integrations/cats.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@ This module contains integration layer between [org.typelevel.cats](https://gith
55
## sbt
66

77
```scala
8-
"com.softwaremill.diffx" %% "diffx-cats" % "0.6.0" % Test
8+
"com.softwaremill.diffx" %% "diffx-cats" % "0.7.0" % Test
99
```
1010

1111
## mill
1212

1313
```scala
14-
ivy"com.softwaremill.diffx::diffx-cats::0.6.0"
14+
ivy"com.softwaremill.diffx::diffx-cats::0.7.0"
1515
```
1616

1717
## Usage
@@ -37,7 +37,7 @@ compare(t1, t2)
3737
// name = "TestData",
3838
// fields = ListMap(
3939
// "ints" -> DiffResultObject(
40-
// name = "List",
40+
// name = "NonEmptyList",
4141
// fields = ListMap(
4242
// "0" -> DiffResultString(
4343
// diffs = List(

generated-docs/out/integrations/refined.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@ This module contains integration layer between [eu.timepit.refined](https://gith
55
## sbt
66

77
```scala
8-
"com.softwaremill.diffx" %% "diffx-refined" % "0.6.0" % Test
8+
"com.softwaremill.diffx" %% "diffx-refined" % "0.7.0" % Test
99
```
1010

1111
## mill
1212

1313
```scala
14-
ivy"com.softwaremill.diffx::diffx-refined::0.6.0"
14+
ivy"com.softwaremill.diffx::diffx-refined::0.7.0"
1515
```
1616

1717
## Usage

generated-docs/out/integrations/tagging.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@ This module contains integration layer between [com.softwaremill.common.tagging]
55
## sbt
66

77
```scala
8-
"com.softwaremill.diffx" %% "diffx-tagging" % "0.6.0"
8+
"com.softwaremill.diffx" %% "diffx-tagging" % "0.7.0"
99
```
1010

1111
## mill
1212

1313
```scala
14-
ivy"com.softwaremill.diffx::diffx-tagging::0.6.0"
14+
ivy"com.softwaremill.diffx::diffx-tagging::0.7.0"
1515
```
1616

1717
## Usage

generated-docs/out/test-frameworks/munit.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@ To use with munit, add following dependency:
55
## sbt
66

77
```scala
8-
"com.softwaremill.diffx" %% "diffx-munit" % "0.6.0" % Test
8+
"com.softwaremill.diffx" %% "diffx-munit" % "0.7.0" % Test
99
```
1010

1111
## mill
1212

1313
```scala
14-
ivy"com.softwaremill.diffx::diffx-munit::0.6.0"
14+
ivy"com.softwaremill.diffx::diffx-munit::0.7.0"
1515
```
1616

1717
## Usage

generated-docs/out/test-frameworks/scalatest.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,24 +6,24 @@ To use with scalatest, add the following dependency:
66

77
For use with `should` matchers:
88
```scala
9-
"com.softwaremill.diffx" %% "diffx-scalatest-should" % "0.6.0" % Test
9+
"com.softwaremill.diffx" %% "diffx-scalatest-should" % "0.7.0" % Test
1010
```
1111

1212
For use with `must` matchers:
1313
```scala
14-
"com.softwaremill.diffx" %% "diffx-scalatest-should" % "0.6.0" % Test
14+
"com.softwaremill.diffx" %% "diffx-scalatest-must" % "0.7.0" % Test
1515
```
1616

1717
## mill
1818

1919
For use with `should` matchers:
2020
```scala
21-
ivy"com.softwaremill.diffx::diffx-scalatest-must::0.6.0"
21+
ivy"com.softwaremill.diffx::diffx-scalatest-must::0.7.0"
2222
```
2323

2424
For use with `must` matchers:
2525
```scala
26-
ivy"com.softwaremill.diffx::diffx-scalatest-must::0.6.0"
26+
ivy"com.softwaremill.diffx::diffx-scalatest-must::0.7.0"
2727
```
2828

2929
## Usage

generated-docs/out/test-frameworks/specs2.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@ To use with specs2, add the following dependency:
55
## sbt
66

77
```scala
8-
"com.softwaremill.diffx" %% "diffx-specs2" % "0.6.0" % Test
8+
"com.softwaremill.diffx" %% "diffx-specs2" % "0.7.0" % Test
99
```
1010

1111
## mill
1212

1313
```scala
14-
ivy"com.softwaremill.diffx::diffx-specs2::0.6.0"
14+
ivy"com.softwaremill.diffx::diffx-specs2::0.7.0"
1515
```
1616

1717
## Usage

generated-docs/out/test-frameworks/utest.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@ To use with utest, add following dependency:
55
## sbt
66

77
```scala
8-
"com.softwaremill.diffx" %% "diffx-utest" % "0.6.0" % Test
8+
"com.softwaremill.diffx" %% "diffx-utest" % "0.7.0" % Test
99
```
1010

1111
## mill
1212

1313
```scala
14-
ivy"com.softwaremill.diffx::diffx-utest::0.6.0"
14+
ivy"com.softwaremill.diffx::diffx-utest::0.7.0"
1515
```
1616

1717
## Usage

generated-docs/out/usage/derivation.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,22 @@ or extend trait
2121
`com.softwaremill.diffx.generic.auto.AutoDerivation`
2222

2323
**Auto derivation might have a huge impact on compilation times**, because of that it is recommended to use `semi-auto` derivation.
24+
25+
26+
Given that you have auto-derivation enabled you can summon diff instances as you would summon any other implicit type-class by using
27+
`implictly[Diff[T]]`. You can also write a shorter version `Diff[T]` which will be equivalent.
28+
However, if you would like to modify somehow (see [ignoring](./ignoring.md) and [modifying](./modifying.md)) given instance and
29+
put it back into to the implicit scope:
30+
```scala
31+
implict val diffForMyClass: Diff[MyClass] = Diff[MyClass].doSomething
32+
```
33+
you will get a forward reference error.
34+
35+
To overcome that issue there is a `Derived` wrapper which allows you to summon a wrapped instance.
36+
```scala
37+
implict val diffForMyClass: Diff[MyClass] = implicitly[Derived[Diff[MyClass]]].value.doSomething
38+
```
39+
There is a `summon` method to make it more convenient. Below code is equivalent to the one above.
40+
```scala
41+
implict val diffForMyClass: Diff[MyClass] = Diff.summon[MyClass].doSomething
42+
```

generated-docs/out/usage/ignoring.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ instance of the `Diff` typeclass into the implicit scope. The whole process look
1616

1717
```scala
1818
case class Person(name:String, age:Int)
19-
implicit val modifiedDiff: Diff[Person] = Derived[Diff[Person]].ignore(_.age)
19+
implicit val modifiedDiff: Diff[Person] = Diff.derived[Person].ignore(_.age)
2020
```
2121
```scala
2222
compare(Person("bob", 25), Person("bob", 30))
@@ -39,18 +39,18 @@ original comparison into ignored output:
3939
implicit val conf: DiffConfiguration = DiffConfiguration(makeIgnored =
4040
(original: Diff[Any]) =>
4141
(left: Any, right: Any, context: DiffContext) => {
42-
IdenticalValue(s"Ignored but was: ${original.apply(left, right, context).show()(ConsoleColorConfig.noColors)}")
42+
IdenticalValue(s"Ignored but was: ${original.apply(left, right, context).show()(ShowConfig.noColors)}")
4343
}
4444
)
4545
// conf: DiffConfiguration = DiffConfiguration(makeIgnored = <function1>)
4646
val d = Diff[Person].ignore(_.age)
47-
// d: Diff[Person] = com.softwaremill.diffx.Diff$$anon$1@2f232df9
47+
// d: Diff[Person] = com.softwaremill.diffx.Diff$$anon$1@71ed624c
4848
d(Person("bob", 25), Person("bob", 30))
4949
// res2: DiffResult = DiffResultObject(
5050
// name = "Person",
5151
// fields = ListMap(
5252
// "name" -> IdenticalValue(value = "bob"),
53-
// "age" -> IdenticalValue(value = "<ignored>")
53+
// "age" -> IdenticalValue(value = "Ignored but was: 25 -> 30")
5454
// )
5555
// )
5656
```

generated-docs/out/usage/modifying.md

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
# modifying
2+
3+
Sometimes you might want to compare some nested values using a different comparator but
4+
the type they share is not unique within that hierarchy.
5+
6+
Consider following example:
7+
```scala
8+
import com.softwaremill.diffx._
9+
import com.softwaremill.diffx.generic.auto._
10+
11+
case class Person(age: Int, weight: Int)
12+
```
13+
14+
If we would like to compare `weight` differently than `age` we would have to introduce a new type for `weight`
15+
in order to provide a different `Diff` typeclass for only that field. While in general, it is a good idea to have your types
16+
very precise it might not always be practical or even possible. Fortunately, diffx comes with a mechanism which allows
17+
the replacement of nested diff instances.
18+
19+
First we need to acquire a lens at given path using `modify` method,
20+
and then we can call `setTo` to replace a particular instance.
21+
22+
```scala
23+
implicit val diffPerson: Diff[Person] = Diff.summon[Person].modify(_.weight)
24+
.setTo(Diff.approximate(epsilon=5))
25+
```
26+
27+
```scala
28+
compare(Person(23, 60), Person(23, 62))
29+
// res0: DiffResult = DiffResultObject(
30+
// name = "Person",
31+
// fields = ListMap(
32+
// "age" -> IdenticalValue(value = 23),
33+
// "weight" -> IdenticalValue(value = 60)
34+
// )
35+
// )
36+
```
37+
38+
In fact, replacement is so powerful that ignoring is implemented as a replacement
39+
with the `Diff.ignore` instance.
40+
41+
42+
## collection support
43+
44+
Specify how objects within particular collection within particular diff instance should be matched.
45+
We distinguish free main types of collections:
46+
- seqLike collections where elements are indexed collections
47+
- setLike collections where elements aren't indexed
48+
- mapLike collections where elements(values) are indexed by some keys
49+
50+
Each collection should fall into one of above categories.
51+
Each category exposes different set of methods.
52+
53+
```scala
54+
case class Organization(peopleList: List[Person], peopleSet: Set[Person], peopleMap: Map[Person, Person])
55+
implicit val diffOrg: Diff[Organization] = Diff.summon[Organization]
56+
// seqLike methods:
57+
.modify(_.peopleList).matchByValue(_.age)
58+
.modify(_.peopleList).matchByIndex(index => index % 2)
59+
// setLike methods:
60+
.modify(_.peopleSet).matchBy(_.age)
61+
// mapLike methods:
62+
.modify(_.peopleMap).matchByValue(_.age)
63+
.modify(_.peopleMap).matchByKey(_.weight)
64+
```

generated-docs/out/usage/output.md

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -23,29 +23,38 @@ By default, the difference is shown in the following form:
2323

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

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

29-
30-
Where, by default, `rightColor` is green and `leftColor` is red.
31-
32-
Colors can be customized providing an implicit instance of `ConsoleColorConfig` class.
29+
Colors can be customized providing an implicit instance of `ShowConfig` class.
3330
In fact `rightColor` and `leftColor` are functions `string => string` so they can be modified to do whatever you want with the output.
3431
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.
3532

3633
````scala
37-
val colorConfigWithPlusMinus: ConsoleColorConfig =
38-
ConsoleColorConfig(default = identity, arrow = identity, right = s => "+" + s, left = s => "-" + s)
34+
val showConfigWithPlusMinus: ShowConfig =
35+
ShowConfig.default.copy(default = identity, arrow = identity, right = s => "+" + s, left = s => "-" + s)
3936
````
4037

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

4441
## skipping identical
4542

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

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

5160
val result = compare(Person("Bob", 23), Person("Alice", 23))
@@ -62,7 +71,10 @@ val result = compare(Person("Bob", 23), Person("Alice", 23))
6271
// "age" -> IdenticalValue(value = 23)
6372
// )
6473
// )
65-
result.show(renderIdentical = false)
74+
result.show()
6675
// res1: String = """Person(
6776
// name: Bob -> Alice)"""
68-
```
77+
```
78+
79+
There is a convenient method in `ShowConfig` called `skipIdentical` which does exactly that, so the relevant line from
80+
the example can be shortened to `ShowConfig.default.skipIdentical`

generated-docs/out/usage/sequences.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ val bob = Person("1","Bob")
2929
```scala
3030
compare(Set(bob), Set(bob, Person("2","Alice")))
3131
// res1: DiffResult = DiffResultSet(
32+
// typename = "Set",
3233
// diffs = Set(
3334
// DiffResultObject(
3435
// name = "Person",
@@ -57,6 +58,7 @@ val bob = Person("1","Bob")
5758
```scala
5859
compare(Map("1" -> bob), Map("2" -> bob))
5960
// res3: DiffResult = DiffResultMap(
61+
// typename = "Map",
6062
// entries = Map(
6163
// DiffResultString(
6264
// diffs = List(
@@ -85,7 +87,7 @@ import com.softwaremill.diffx.generic.auto._
8587

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

88-
implicit val personMatcher = ObjectMatcher.list[Person].byValue(_.id)
90+
implicit val personMatcher = ObjectMatcher.seq[Person].byValue(_.id)
8991
val bob = Person("1","Bob")
9092
val alice = Person("2","Alice")
9193
```
@@ -113,4 +115,4 @@ compare(List(bob, alice), List(alice, bob))
113115
```
114116

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

0 commit comments

Comments
 (0)