differ v0.1.1 Differ View Source

Module that computes diff for terms

Using with structs

It is possible to use Differ with structs, you need to derive default implementation for Differ.Diffable and Differ.Patchable protocols:

defmodule User do
  @derive [Differ.Diffable, Differ.Patchable]
  defstruct name: "", age: 21
end

And now you can call Differ.diff/2 with your structs:

iex> Differ.diff(%User{name: "John"}, %User{name: "John Smith"})
[{:name, :diff, [eq: "John", ins: " Smith"]}, {:age, :eq, 21}]

You can skip some fields aswell (e.g. timestamps, id), by using skip option, when deriving default implementation

@derive [{Differ.Diffable, skip: [:updated_at, :diffs]}, Differ.Patchable]
schema "posts" do
  field :content, :string
  field :tags, {:array, :string}
  field :title, :string
  field :diffs, {:array, Diff}, default: []

  timestamps()
end

Link to this section Summary

Functions

Returns diff between 2 terms that implement Differ.Diffable protocol

Allows to visualize diff

Optimizes diff size

Applies diff and returns patched value

Same as Differ.patch/2, but returns value and throws on error

Reverts diff and returns patched value

Same as Differ.revert/2, but returns value and throws on error

Link to this section Functions

Returns diff between 2 terms that implement Differ.Diffable protocol

Diff here is edit script, that should be compatible with List.myers_difference/3

Examples

iex> Differ.diff(%{key: "value"}, %{key: "value"})
[eq: %{key: "value"}]

iex> Differ.diff("Hello!", "Hey!")
[eq: "He", del: "llo", ins: "y", eq: "!"]
Link to this function

explain(term, diff, cb, opts \\ [])

View Source (since 0.1.1)
explain(
  Differ.Patchable.t(),
  Differ.Diffable.diff(),
  (Differ.Diffable.operation() -> String.t()),
  [{:revert, true}]
) :: String.t()

Allows to visualize diff

Applies diff to a term and calls cb on each operation, result of cb will be used to construct new value for term

Options

  • revert - reverts term with given diff, before apply (default true)

Examples

iex> Differ.explain("qwerty", [eq: "qwer", del: "123", ins: "ty"],
...> fn {op, val} ->
...>   case op do
...>     :del -> "--" <> val
...>     :ins -> "++" <> val
...>     _ -> val
...>   end
...> end)
"qwer--123++ty"

Optimizes diff size

Optimizes size by removing data that is not relevant for change. There is 3 levels of optimization:

  1. Safe - can have conflicts, can be reverted
  2. Safe-ish - you lose ability to get conflicts, but still can be reverted
  3. Un-safe - no conflicts and no reverting

Examples

iex> regular_diff = Differ.diff(%{"same" => "same"}, %{"same" => "same", "new" => "val"})
[{"same", :eq, "same"}, {"new", :ins, "val"}]
iex> Differ.optimize(regular_diff)
[{"new", :ins, "val"}]

iex> diff = Differ.diff("Somewhat long string with a litle change athere", "Somewhat long string with a litle change here")
[eq: "Somewhat long string with a litle change ", del: "at", eq: "here"]
iex> Differ.optimize(diff, 2)
[skip: 41, del: "at", skip: 4]
iex> Differ.optimize(diff, 3)
[skip: 41, remove: 2, skip: 4]

Applies diff and returns patched value

Examples

iex> old_list = ["22", "1"]
iex> diff = Differ.diff(old_list, ["2", "1", "3"])
iex> Differ.patch(old_list, diff)
{:ok, ["2", "1", "3"]}

Same as Differ.patch/2, but returns value and throws on error

Reverts diff and returns patched value

Examples

iex> old_list = ["22", "1"]
iex> new_list = ["2", "1", "3"]
iex> diff = Differ.diff(old_list, new_list)
iex> Differ.revert(new_list, diff)
{:ok, ["22", "1"]}

Same as Differ.revert/2, but returns value and throws on error

Link to this function

show_diff(term, diff, cb, opts \\ [])

View Source (since 0.1.1)
This function is deprecated. Use Differ.explain/3 instead.