deepmerge

package module
v0.0.0-...-009b1fa Latest Latest
Warning

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

Go to latest
Published: Jul 9, 2026 License: BSD-3-Clause Imports: 4 Imported by: 0

README

deep-merge

ci Go Reference

A pure-Go (CGO_ENABLED=0, standard library only) port of the Ruby deep_merge gem: recursive hash/array merge with the gem's full option set.

It operates on Go values that model Ruby data:

Ruby Go
Hash map[string]any
Array []any
scalar any other value

Install

go get github.com/go-ruby-deep-merge/deep-merge
import deepmerge "github.com/go-ruby-deep-merge/deep-merge"

Usage

dest := map[string]any{"property": []any{"2", "4"}}
source := map[string]any{"property": []any{"1", "3"}}

merged := deepmerge.DeepMerge(dest, source, deepmerge.Options{})
// merged == {"property": ["2", "4", "1", "3"]}  (dest ∪ source; dest untouched)

source is merged into dest (equivalent to Ruby deep_merge!(source, dest)): source values take precedence.

  • DeepMerge(dest, source, opts) — merges into a deep copy of dest, returns the copy; the caller's dest is left untouched.
  • DeepMergeInto(dest, source, opts) — merges into dest in place and returns the result. Always use the return value: the top-level value can be replaced (for example when dest is nil or a scalar).

Options

Field deep_merge option Effect
Overwrite / PreserveUnmergeables bang vs non-bang Effective overwrite = Overwrite || !PreserveUnmergeables (default: overwrite, like deep_merge!). Preserve keeps existing dest values on a type mismatch.
KnockoutPrefix :knockout_prefix A source string prefixed with it removes the matching element from dest.
OverwriteArrays :overwrite_arrays Replace dest arrays instead of merging.
SortMergedArrays :sort_merged_arrays Sort every merged array.
UnpackArrays :unpack_arrays Join + split arrays on this separator before merging.
MergeHashArrays :merge_hash_arrays Merge arrays of hashes element-wise (by index).
ExtendExistingArrays :extend_existing_arrays Push a source hash/scalar onto a dest array.
KeepArrayDuplicates :keep_array_duplicates Concatenate arrays keeping duplicates instead of taking the union.
MergeNilValues :merge_nil_values Merge nil source values instead of skipping them.
Notes on fidelity
  • Ruby truthiness is honoured: a dest key whose value is nil or false is treated as absent, so source creates/overwrites it.
  • Because Go cannot distinguish an unset string from an empty one, an empty KnockoutPrefix means "no knockout" rather than the gem's InvalidParameter error. Combining a KnockoutPrefix with disabled overwrite panics with *InvalidOptionError, matching the gem's refusal of that combination.
  • Ruby Hashes with non-string keys (e.g. symbols, integers) are out of scope; keys are string.

License

BSD-3-Clause. See LICENSE.

Documentation

Overview

Package deepmerge is a pure-Go (no cgo) port of the Ruby deep_merge gem (https://github.com/danielsdeleo/deep_merge). It recursively merges values that model Ruby data: hashes as map[string]any, arrays as []any, and any other Go value as a scalar.

Entry points

  • DeepMerge merges source into a deep copy of dest and returns the copy; the caller's dest is left untouched (non-destructive).
  • DeepMergeInto merges source into dest in place and returns the result. Because the top-level value may be replaced (for example when dest is nil or a scalar), callers must use the return value.

In both, source values take precedence over dest values, mirroring the Ruby call deep_merge!(source, dest): source is merged into dest.

Merge rules

Two hashes are merged key by key. For a key present in both, the values are merged recursively. A key whose dest value is nil or false is treated as absent (Ruby truthiness), so source creates/overwrites it.

Two arrays are combined. By default the result is the set union of dest then source (dest | source in Ruby: duplicates removed, dest order first). See the Options fields for element-wise hash merging, duplicate keeping, sorting, overwrite, unpacking and knockout behaviour.

A type mismatch (for example a scalar meeting a hash) is unmergeable: source overwrites dest when Overwrite is in effect, otherwise dest is preserved.

Options

Options mirrors the deep_merge gem. Overwrite and PreserveUnmergeables map to the gem's bang / non-bang variants: the effective "overwrite unmergeables" flag is Overwrite || !PreserveUnmergeables, which is true by default (like deep_merge!). Set PreserveUnmergeables to true (and leave Overwrite false) for the non-destructive-of-conflicts deep_merge behaviour.

KnockoutPrefix enables the gem's knockout feature: a source string element prefixed with it removes the matching element from dest. Because Go cannot distinguish an unset string from an empty one, an empty KnockoutPrefix means "no knockout" rather than the gem's InvalidParameter error. Specifying a KnockoutPrefix while overwrite is disabled panics with *InvalidOptionError, matching the gem's refusal to combine knockout with preserve_unmergeables.

The package has no dependency on any Ruby runtime and imports only the standard library. A consumer such as go-embedded-ruby (rbgo) can adapt a Ruby Hash#deep_merge call onto these functions by marshalling Ruby values to the Go value model above.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func DeepMerge

func DeepMerge(dest, source any, opts Options) any

DeepMerge merges source into a deep copy of dest and returns the copy. The caller's dest is not modified.

func DeepMergeInto

func DeepMergeInto(dest, source any, opts Options) any

DeepMergeInto merges source into dest in place and returns the result. The return value must be used because the top-level value may be replaced.

Types

type InvalidOptionError

type InvalidOptionError struct{ Message string }

InvalidOptionError is the value passed to panic when Options combine in a way the deep_merge gem rejects.

func (*InvalidOptionError) Error

func (e *InvalidOptionError) Error() string

type Options

type Options struct {
	// Overwrite forces overwriting of unmergeable/conflicting values. Together
	// with PreserveUnmergeables it selects the gem's bang vs non-bang variant:
	// the effective flag is Overwrite || !PreserveUnmergeables.
	Overwrite bool

	// PreserveUnmergeables keeps existing dest values when a value cannot be
	// merged (type mismatch), matching Ruby's deep_merge (non-bang).
	PreserveUnmergeables bool

	// KnockoutPrefix, when non-empty, enables knockout: a source string element
	// prefixed with it removes the matching element from dest.
	KnockoutPrefix string

	// OverwriteArrays replaces dest arrays with source arrays instead of merging
	// them (the gem's :overwrite_arrays).
	OverwriteArrays bool

	// SortMergedArrays sorts every array produced by a merge.
	SortMergedArrays bool

	// UnpackArrays, when non-empty, joins then splits every merged array on this
	// separator before merging, unpacking compound string elements.
	UnpackArrays string

	// MergeHashArrays merges arrays of hashes element-wise (by index) when both
	// the source and dest arrays contain only hashes.
	MergeHashArrays bool

	// ExtendExistingArrays pushes a source hash/scalar onto a dest array rather
	// than overwriting the array.
	ExtendExistingArrays bool

	// KeepArrayDuplicates concatenates arrays keeping duplicate elements instead
	// of taking their set union.
	KeepArrayDuplicates bool

	// MergeNilValues merges nil source values instead of skipping them.
	MergeNilValues bool
}

Options mirrors the option set of the Ruby deep_merge gem. The zero value behaves like Ruby's deep_merge! (overwrite unmergeable/conflicting values).

Jump to

Keyboard shortcuts

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