{"id":15494268,"url":"https://github.com/andyglow/scala-patch","last_synced_at":"2025-04-22T20:23:06.620Z","repository":{"id":57727712,"uuid":"267967551","full_name":"andyglow/scala-patch","owner":"andyglow","description":"Scala Structured Patch","archived":false,"fork":false,"pushed_at":"2022-08-26T17:28:22.000Z","size":143,"stargazers_count":5,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-29T18:36:29.105Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Scala","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/andyglow.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-05-29T22:31:49.000Z","updated_at":"2023-07-02T16:51:28.000Z","dependencies_parsed_at":"2022-09-11T17:01:26.312Z","dependency_job_id":null,"html_url":"https://github.com/andyglow/scala-patch","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andyglow%2Fscala-patch","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andyglow%2Fscala-patch/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andyglow%2Fscala-patch/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andyglow%2Fscala-patch/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/andyglow","download_url":"https://codeload.github.com/andyglow/scala-patch/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250316523,"owners_count":21410558,"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","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":[],"created_at":"2024-10-02T08:12:57.497Z","updated_at":"2025-04-22T20:23:06.597Z","avatar_url":"https://github.com/andyglow.png","language":"Scala","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Scala GPL\n\u003e GPL: Generic Programming Library\n\nThe library aims to provide several concepts missed in vanilla scala:\n- (make) enhanced approach to create new instances of case classes\n- (patch) ability to compare, create patch, apply patch for standard scala types\n\n[![Build Status](https://cloud.drone.io/api/badges/andyglow/scala-patch/status.svg)](https://cloud.drone.io/andyglow/scala-patch)\n![Maven Central](https://img.shields.io/maven-central/v/com.github.andyglow/scala-gpl_2.13?color=%234c1\u0026label=maven)\n![Codecov](https://img.shields.io/codecov/c/gh/andyglow/scala-patch)\n\nSupported types:\n- basic types like `string`, `boolean`, `numeric`\n- temporal types (`java.time`, `java.util`, `java.sql`)\n- collections\n  - `unordered` (Seq, Iterable, ...)\n  - `ordered` (LinerSeq, List, LazyList, ...)\n  - `indexed` (Array, Vector, ...)\n  - `keyed` (Maps)\n- generic sum types (Option, Either)\n- product types (case classes)\n   \n## Example\n```scala\nimport scalax.patch._\n\n// values\nval left = List(1, 2, 3)\nval right = List(1, 3, 4, 5)\n\n// make a patch\nval patch = Patch.make(left, right)\n\n// apply a patch\npatch(left) == right\n\n// apply inverted patch\npatch.inverted(right) == left\n\n// patch is structured\n// toString\nprintln(patch)\npatch\u003e UpdateOrdered(Diff(Upgrade(IncreaseValue(1),IncreaseValue(1)),Insert(4)))\n\n// patch rendered \nPatchVisitor stringify patch\npatch\u003e upgrade\npatch\u003e - increase 1\npatch\u003e - increase 1\npatch\u003e insert\npatch\u003e - 4\n```\n\n## Introduction\nOften we need more specific explanation of why one value is not equal to another or, more specifically,\nwhat is a delta of two values, or\nwhat should be modified in value `A` (and how) so it become equal to value `B`.\n\nWhen we may need it?\n- Testing. More detailed difference reports.\n- In network enabled applications where update remote state (patch size is in average less in size then an updated state copy) \n- In CQRS applications it might be helpful to disassemble a diff of 2 states into a sequence of events.\n\n## Design\n\n### Algebra\nThe Patch is a sum type of following definition\n```\nPatch[T] =\n    UpdateValue                     (from: T, to: T)                                                |\n    SetValue                        (to: T)                                                         |\n    UnsetValue                      (from: T)                                                       |\n    IncreaseValue                   (delta: ArithmeticAdapter[T]#Delta)                             |\n    DecreaseValue                   (delta: ArithmeticAdapter[T]#Delta)                             |\n    UpdateIndexed   [F[_], V]       (delta: Map[Int, Patch[V]], sizeDelta: Int) where T = F[V]      |\n    UpdateKeyed     [F[_, _], K, V] (delta: Map[K, Patch[T]])                   where T = F[K, V]   |      \n    UpdateUnordered [F[_], V]       (delta: UnorderedAdapter[F, T]#Diff)        where T = F[V] and \n        UnorderedAdapter.Diff[T] = Seq[UnorderedAdapter.Diff.Evt[T]] where\n            UnorderedAdapter.Diff.Evt[T] =\n                Add(items: Seq[T])    |\n                Remove(items: Seq[T])                                                               |\n    UpdateOrdered   [F[_], V]       (delta: OrderedAdapter[F, T]#Diff)          \n        OrderedAdapter.Diff[T] = List[OrderedAdapter.Diff.Evt[T]] where\n            OrderedAdapter.Diff.Evt[T] =\n                Skip(n: Int)                    |\n                Insert(items: List[T])          |\n                Drop(items: List[T])            |\n                Update(patches: List[Patch[T]])\n  \n```\n\n## Derivation\nPatch Maker derivation is provided for case classes.\n\n```scala\n// case classes\ncase class CC(\n  name: String,\n  age: Int,\n  props: Map[String, String])\n\nobject CC {\n  implicit val ccPM: PatchMaker[CC] = DerivePatchMaker.derive[CC]\n}\n\nval left = CC(\"shelly\", 23, Map(\"prop1\" -\u003e \"v1\", \"prop2\" -\u003e \"v2\"))\nval right = CC(\"cristine\", 37, Map(\"prop1\" -\u003e \"vv1\", \"prop2\" -\u003e \"vv2\"))\n\nval patch = Patch.make(left, right)\nprintln(patch)\npatch\u003e $CC$Patch(UpdateValue(shelly,cristine),IncreaseValue(14),UpdateKeyed(Map(prop1 -\u003e UpdateValue(v1,vv1), prop2 -\u003e UpdateValue(v2,vv2))))\n\nPatchVisitor stringify patch\npatch\u003e field 'name' {\npatch\u003e   update: from shelly\npatch\u003e         : to   cristine\npatch\u003e }\npatch\u003e field 'age' {\npatch\u003e   increase 14\npatch\u003e }\npatch\u003e field 'props' {\npatch\u003e   key 'prop1' {\npatch\u003e     update: from v1\npatch\u003e           : to   vv1\npatch\u003e   }\npatch\u003e   key 'prop2' {\npatch\u003e     update: from v2\npatch\u003e           : to   vv2\npatch\u003e   }\npatch\u003e } \n```   \n\n## Text\nBy default string patch gives you a Constant patch (SetValue, UpdateValue, UnsetValue), \nwhich under some circumstances may look non optimal.\n\nFor more sophisticated string manipulation you can use `texts` module`\n```scala\nlibraryDependencies += \"com.github.andyglow\" %% \"scala-patch-texts\" % $version\n```\n\nIt is based on google's `patch-match-diff` library and give more detailed patches over strings.\n\nAll you need is\n```scala\nimport scalax.patch.texts._\n```\n\nExample:\n```scala\nimport scalax.patch.texts._\n\nval patch = Patch.make(\"hello, dear friend!\", \"hello, my friend!\")\npatch\u003e TextPatch(Step(3, 3, 12, 10, Equal(\"lo, \"), Delete(\"dear\"), Insert(\"my\"), Equal(\" fri\"))) \n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandyglow%2Fscala-patch","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fandyglow%2Fscala-patch","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandyglow%2Fscala-patch/lists"}