diff

package
v0.3.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 27, 2021 License: MIT Imports: 11 Imported by: 6

Documentation

Overview

Package diff provides utilities to generate deep, walkable diffs of maps and slices

Index

Examples

Constants

This section is empty.

Variables

View Source
var ErrCyclic = errors.New("circular references not supported")

ErrCyclic is returned when one of the compared values contain circular references

Functions

func IsExcess

func IsExcess(d Differ) bool

IsExcess returns true if d represent value missing from the LHS (in a map or an array)

func IsIgnore added in v0.1.2

func IsIgnore(d Differ) bool

IsIgnore returns true if d is a diff created by NewIgnore

func IsMap added in v0.1.2

func IsMap(d Differ) bool

IsMap returns true if d is a diff between towo maps

func IsMissing

func IsMissing(d Differ) bool

IsMissing returns true if d represent value missing from the RHS (in a map or an array)

func IsScalar added in v0.1.2

func IsScalar(d Differ) bool

IsScalar returns true of d is a diff between two values that can be compared (int, float64, string, ...)

func IsSlice added in v0.1.2

func IsSlice(d Differ) bool

IsSlice returns true if d is a diff between towo slices

func IsStream added in v0.3.0

func IsStream(d Differ) bool

IsStream returns true if d is a diff between towo slices

func IsTypes added in v0.1.2

func IsTypes(d Differ) bool

IsTypes returns true if d is a diff between two values of different types that cannot be compared

func LHS added in v0.1.4

func LHS(d Differ) (interface{}, error)

LHS returns the lhs value associated with the Differ.

func RHS added in v0.1.4

func RHS(d Differ) (interface{}, error)

RHS returns the rhs value associated with the Differ.

func Report

func Report(d Differ, outConf Output) ([]string, error)

Report generates a flat list of differences encountered in the diff tree. Its output is less verbose than StringIndent as it doesn't report on matching values.

Example
package main

import (
	"fmt"

	"github.com/yazgazan/jaydiff/diff"
)

func main() {
	lhs := map[string]interface{}{
		"a": 42,
		"b": []int{1, 2},
		"c": "abc",
	}
	rhs := map[string]interface{}{
		"a": 21,
		"b": []int{1, 2, 3},
		"c": "abc",
	}

	d, _ := diff.Diff(lhs, rhs)

	reports, _ := diff.Report(d, diff.Output{
		Indent:    "  ",
		ShowTypes: true,
	})

	for _, report := range reports {
		fmt.Println(report)
	}

}
Output:

- .a: int 42
+ .a: int 21
+ .b[2]: int 3

Types

type ConfigOpt added in v0.1.3

type ConfigOpt func(config) config

ConfigOpt is used to pass configuration options to the diff algorithm

func UseSliceMyers added in v0.1.3

func UseSliceMyers() ConfigOpt

UseSliceMyers configures the Diff function to use Myers' algorithm for slices

type Differ

type Differ interface {
	Diff() Type
	Strings() []string
	StringIndent(key, prefix string, conf Output) string
}

Differ is implemented by all nodes in a diff-tree.

func Diff

func Diff(lhs, rhs interface{}, opts ...ConfigOpt) (Differ, error)

Diff generates a tree representing differences and similarities between two objects.

Diff supports maps, slices, Stream and scalars (comparables types such as int, string, etc ...). When an unsupported type is encountered, an ErrUnsupported error is returned.

Example
package main

import (
	"fmt"

	"github.com/yazgazan/jaydiff/diff"
)

func main() {
	lhs := map[string]interface{}{
		"a": 42,
		"b": []int{1, 2},
		"c": "abc",
	}
	rhs := map[string]interface{}{
		"a": 21,
		"b": []int{1, 2, 3},
		"c": "abc",
	}

	d, _ := diff.Diff(lhs, rhs)

	fmt.Println(d.StringIndent("", "", diff.Output{
		Indent:    "  ",
		ShowTypes: true,
	}))

}
Output:

map[string]interface {} map[
-  a: int 42
+  a: int 21
   b: []int [
     int 1
     int 2
+    int 3
   ]
   c: string abc
 ]
Example (Struct)
package main

import (
	"fmt"

	"github.com/yazgazan/jaydiff/diff"
)

func main() {
	type subStruct struct {
		Hello int
		World float64
	}
	type structA struct {
		Foo int
		Bar string
		Baz subStruct
		Ban [2]int

		priv int
	}
	type structB struct {
		Foo int
		Bar string
		Baz subStruct
		Ban [2]int

		priv int
	}

	lhs := structA{
		Foo: 42,
		Bar: "hello",
		Baz: subStruct{
			Hello: 11,
			World: 3.5,
		},
		Ban:  [2]int{3, 5},
		priv: 0,
	}
	rhs := structB{
		Foo: 21,
		Bar: "hello",
		Baz: subStruct{
			Hello: 11,
			World: 3.5,
		},
		Ban:  [2]int{3, 7},
		priv: 1,
	}

	d, err := diff.Diff(lhs, rhs)
	if err != nil {
		fmt.Printf("Error: %v\n", err)
		return
	}

	fmt.Println(d.StringIndent("", "", diff.Output{
		Indent:    "  ",
		ShowTypes: true,
	}))

}
Output:

diff_test.structA map[
   Ban: [2]int [
     int 3
-    int 5
+    int 7
   ]
   Bar: string hello
   Baz: diff_test.subStruct {11 3.5}
-  Foo: int 42
+  Foo: int 21
 ]

func Ignore

func Ignore() (Differ, error)

Ignore can be used in a WalkFn to ignore a non-matching diff. (See Walk example)

func Walk

func Walk(diff Differ, fn WalkFn) (Differ, error)

Walk allows to descend a diff tree and replace/edit its leaves and branches. When fn returns a non-nil Differ, the current node is replaced and the new node is walked over (if walkable).

Example
package main

import (
	"fmt"
	"strings"

	"github.com/yazgazan/jaydiff/diff"
)

func main() {
	lhs := map[string]interface{}{
		"a":               42,
		"b":               []int{1, 2},
		"will_be_ignored": []int{3, 4},
		"c":               "abc",
	}
	rhs := map[string]interface{}{
		"a":               41,
		"b":               []int{1, 2},
		"will_be_ignored": 5,
		"c":               "abc",
		"exess_key":       "will be ignored",
	}

	d, _ := diff.Diff(lhs, rhs)
	fmt.Println("Before:")
	fmt.Println(d.StringIndent("", "", diff.Output{
		Indent:    "  ",
		ShowTypes: true,
	}))

	d, _ = diff.Walk(d, func(parent diff.Differ, d diff.Differ, path string) (diff.Differ, error) {
		if strings.HasSuffix(path, ".will_be_ignored") || diff.IsExcess(d) {
			return diff.Ignore()
		}

		return nil, nil
	})

	fmt.Println("After:")
	fmt.Println(d.StringIndent("", "", diff.Output{
		Indent:    "  ",
		ShowTypes: true,
	}))

}
Output:

Before:
 map[string]interface {} map[
-  a: int 42
+  a: int 41
   b: []int [1 2]
   c: string abc
+  exess_key: string will be ignored
-  will_be_ignored: []int [3 4]
+  will_be_ignored: int 5
 ]
After:
 map[string]interface {} map[
-  a: int 42
+  a: int 41
   b: []int [1 2]
   c: string abc
 ]

type ErrLHSNotSupported added in v0.1.4

type ErrLHSNotSupported struct {
	Diff Differ
}

ErrLHSNotSupported is returned when calling diff.LHS on a Differ that does not contain an LHS value (i.e Ignore)

func (ErrLHSNotSupported) Error added in v0.1.4

func (e ErrLHSNotSupported) Error() string

type ErrRHSNotSupported added in v0.1.4

type ErrRHSNotSupported struct {
	Diff Differ
}

ErrRHSNotSupported is returned when calling diff.EHS on a Differ that does not contain an RHS value (i.e Ignore)

func (ErrRHSNotSupported) Error added in v0.1.4

func (e ErrRHSNotSupported) Error() string

type ErrUnsupported

type ErrUnsupported struct {
	LHS reflect.Type
	RHS reflect.Type
}

ErrUnsupported is returned when an unsupported type is encountered (func, struct ...).

func (ErrUnsupported) Error

func (e ErrUnsupported) Error() string

type JSONStream added in v0.3.0

type JSONStream struct {
	*json.Decoder
	// contains filtered or unexported fields
}

func (*JSONStream) NextValue added in v0.3.0

func (s *JSONStream) NextValue() (interface{}, error)

type Output

type Output struct {
	Indent     string
	ShowTypes  bool
	Colorized  bool
	JSON       bool
	JSONValues bool
}

Output is used to configure the output of the Strings and StringIndent functions.

type Stream added in v0.3.0

type Stream interface {
	NextValue() (interface{}, error)
}

type Type

type Type int

Type is used to specify the nature of the difference

const (
	// TypesDiffer is used when two values cannot be compared due to types differences
	// (for example: comparing a slice to an int)
	TypesDiffer Type = iota
	// ContentDiffer is used when the types matches but the content differs
	ContentDiffer
	// Identical is used when both the type and the content match.
	Identical
	// Invalid is used when calling Diff() on an inproperly constructed node
	Invalid
)

func (Type) String

func (t Type) String() string

type WalkFn

type WalkFn func(parent Differ, diff Differ, path string) (Differ, error)

WalkFn Should be implemented to walk down a diff tree. diff and path refer to the current node. If a WalkFn returns a non-nil value, the current diff will be replaced (and then walked over if possible).

type Walker

type Walker interface {
	// Walk receives its own path and the walking function.
	Walk(path string, fn WalkFn) error
}

Walker is implemented by types that can be walked (such as maps and slices)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL