{"id":18828594,"url":"https://github.com/bizzabo/diff","last_synced_at":"2025-10-23T18:07:19.601Z","repository":{"id":50094502,"uuid":"51097868","full_name":"bizzabo/diff","owner":"bizzabo","description":"Visually compare Scala data structures with out of the box support for arbitrary case classes.","archived":false,"fork":false,"pushed_at":"2021-06-04T12:29:56.000Z","size":90,"stargazers_count":178,"open_issues_count":13,"forks_count":17,"subscribers_count":55,"default_branch":"master","last_synced_at":"2025-04-14T03:13:26.862Z","etag":null,"topics":["backend","rnd","xdotai"],"latest_commit_sha":null,"homepage":"","language":"Scala","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bizzabo.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-02-04T18:59:02.000Z","updated_at":"2024-12-09T19:53:13.000Z","dependencies_parsed_at":"2022-09-14T12:23:27.143Z","dependency_job_id":null,"html_url":"https://github.com/bizzabo/diff","commit_stats":null,"previous_names":["xdotai/diff"],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/bizzabo/diff","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bizzabo%2Fdiff","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bizzabo%2Fdiff/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bizzabo%2Fdiff/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bizzabo%2Fdiff/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bizzabo","download_url":"https://codeload.github.com/bizzabo/diff/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bizzabo%2Fdiff/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":270781393,"owners_count":24643820,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-16T02:00:11.002Z","response_time":91,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["backend","rnd","xdotai"],"created_at":"2024-11-08T01:33:32.029Z","updated_at":"2025-10-23T18:07:19.514Z","avatar_url":"https://github.com/bizzabo.png","language":"Scala","funding_links":[],"categories":[],"sub_categories":[],"readme":"## diff\n\n[![Join the chat at https://gitter.im/xdotai/diff](https://badges.gitter.im/xdotai/diff.svg)](https://gitter.im/xdotai/diff?utm_source=badge\u0026utm_medium=badge\u0026utm_campaign=pr-badge\u0026utm_content=badge)\n\nA tool to visually compare Scala data structures with out of the box support for arbitrary case classes.\n\nBe aware: Collections (List, Seq, etc.) are compared like sets, i.e. ignoring order.\n\n### SBT Dependencies\n\n#### Scala 2.11/2.12\n\n```scala\n\"ai.x\" %% \"diff\" % \"2.0.1\"\n```\n\n#### Scala 2.10\n\nStopped working in 1.2.0 due to what seems like a Scala compiler bug.\nSee https://github.com/xdotai/diff/issues/18\n\n\u003c!--\n```scala\n\"ai.x\" %% \"diff\" % \"1.1.0\"\ncompilerPlugin(\"org.scalamacros\" % \"paradise\" % \"2.1.0\" cross CrossVersion.full)\n```\n--\u003e\n\n### Usage\n\n```scala\nimport ai.x.diff.DiffShow\nimport ai.x.diff.conversions._\nprintln(  DiffShow.diff[Foo]( before, after ).string  )\n```\n\nBe aware that diff throws an Exception if a DiffShow type class instance for some field\ncan't be found rather than a type error.\nIf you use diff in a testing or debugging scenario that's usually not a problem.\nThe advantage is that the Exception can tell exactly which instance wasn't found. A type error\ncan only point to the outer most class (`Foo` in this case) even if it is actually one of it's deeply nested fields that is lacking an instance for it's type. Knowing only `Foo` would not be very helpful to pin point\nwhich instance is missing.\n\n#### Output\n\n\u003cimg width=\"422\" alt=\"example-output\" src=\"https://cloud.githubusercontent.com/assets/274947/15580477/e46957e6-2336-11e6-919c-3eaf00f60cff.png\"\u003e\n\n#### Code\n\n```scala\nsealed trait Parent\ncase class Bar( s: String, i: Int ) extends Parent\ncase class Foo( bar: Bar, b: List[Int], parent: Option[Parent] ) extends Parent\n\nval before: Foo = Foo(\n  Bar( \"asdf\", 5 ),\n  List( 123, 1234 ),\n  Some( Bar( \"asdf\", 5 ) )\n)\nval after: Foo = Foo(\n  Bar( \"asdf\", 66 ),\n  List( 1234 ),\n  Some( Bar( \"qwer\", 5 ) )\n)\n```\n\n### Helpful tips\n\n```scala\nimport ai.x.diff._\n```\n\n#### Custom comparison\n\nSometimes you may need to write your own type class instances. For example for non-case classes that don't compare well using ==.\n\n```scala\nimport ai.x.diff._\nimport org.joda.time.LocalTime\n\nimplicit def localTimeDiffShow: DiffShow[LocalTime] = new DiffShow[LocalTime] {\n  def show ( d: LocalTime ) = \"LocalTime(\" + d.toString + \")\"\n  def diff( l: LocalTime, r: LocalTime ) =\n    if ( l isEqual r ) Identical( l ) else Different( l, r )\n}\n```\n\n#### Ignore parts of data\n\nSometimes you may want to ignore some parts of your data during comparison.\nYou can do so by type, e.g. for non-deterministic parts like ObjectId, which always differ.\n\n```scala\ndef ignore[T]: DiffShow[T] = new DiffShow[T] {\n  def show( t: T ) = t.toString\n  def diff( left: T, right: T ) = Identical( \"\u003cnot compared\u003e\" )\n  override def diffable( left: T, right: T ) = true\n}\nimplicit def LocationIdShow: DiffShow[LocationId] = ignore[LocationId]\n```\n\n#### Influence comparison in collections\n\nWhen comparing collections you can influence if two elements should be compared or treated as completely different.\nComparing elements shows their partial differences. Not comparing them shows them as added or removed.\n\n```scala\nimplicit def PersonDiffShow[L \u003c: HList](\n  implicit\n  labelled:  LabelledGeneric.Aux[Person, L],\n  hlistShow: Lazy[DiffShowFields[L]]\n): DiffShow[Person] = new CaseClassDiffShow[Person, L] {\n  override def diffable( left: Person, right: Person ) = left._id === right._id\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbizzabo%2Fdiff","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbizzabo%2Fdiff","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbizzabo%2Fdiff/lists"}