diff --git a/.formatter.exs b/.formatter.exs index 939d646..7c68d77 100644 --- a/.formatter.exs +++ b/.formatter.exs @@ -2,3 +2,4 @@ [ inputs: ["{mix,.formatter}.exs", "{config,lib,test,samples,mix}/**/*.{ex,exs}"] ] + diff --git a/.gitignore b/.gitignore index 6e1db0f..6923f88 100644 --- a/.gitignore +++ b/.gitignore @@ -1,17 +1,26 @@ # The directory Mix will write compiled artifacts to. -/_build +/_build/ # If you run "mix test --cover", coverage assets end up here. -/cover +/cover/ # The directory Mix downloads your dependencies sources to. -/deps +/deps/ -# Where 3rd-party dependencies like ExDoc output generated docs. -/doc +# Where third-party dependencies like ExDoc output generated docs. +/doc/ + +# Ignore .fetch files in case you like to edit your project deps locally. +/.fetch # If the VM crashes, it generates a dump, let's ignore it too. erl_crash.dump # Also ignore archive artifacts (built via "mix archive.build"). *.ez + +# Ignore package tarball (built via "mix hex.build"). +deep_merge-*.tar + +# Temporary files for e.g. tests. +/tmp/ diff --git a/CHANGELOG.md b/CHANGELOG.md index 5202dcb..60f8791 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + ## 1.0.0 (2019-03-26) * Added the possibility to `@derive [DeepMerge.Resolver]` if you want your custom structs to also easily be deep_mergeable diff --git a/README.md b/README.md index fe6d8ee..5d29108 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# DeepMerge [![Hex Version](https://img.shields.io/hexpm/v/deep_merge.svg)](https://hex.pm/packages/deep_merge) [![docs](https://img.shields.io/badge/docs-hexpm-blue.svg)](https://hexdocs.pm/deep_merge/) [![CI](https://github.com/PragTob/deep_merge/actions/workflows/main.yml/badge.svg)](https://github.com/PragTob/deep_merge/actions/workflows/main.yml) [![Coverage Status](https://coveralls.io/repos/github/PragTob/deep_merge/badge.svg?branch=master)](https://coveralls.io/github/PragTob/deep_merge?branch=master) [![Inline docs](http://inch-ci.org/github/PragTob/deep_merge.svg?branch=master)](http://inch-ci.org/github/PragTob/deep_merge) +# DeepMerge [![Hex Version](https://img.shields.io/hexpm/v/deep_merge.svg)](https://hex.pm/packages/deep_merge) [![docs](https://img.shields.io/badge/docs-hexpm-blue.svg)](https://hexdocs.pm/deep_merge/) [![CI](https://github.com/PragTob/deep_merge/actions/workflows/main.yml/badge.svg)](https://github.com/PragTob/deep_merge/actions/workflows/main.yml) [![Coverage Status](https://coveralls.io/repos/github/PragTob/deep_merge/badge.svg?branch=master)](https://coveralls.io/github/PragTob/deep_merge?branch=master) [![Total Download](https://img.shields.io/hexpm/dt/deep_merge.svg)](https://hex.pm/packages/deep_merge) [![License](https://img.shields.io/hexpm/l/deep_merge.svg)](https://github.com/PragTob/deep_merge/blob/main/LICENSE) Provides functionality for "deep merging" maps and keyword lists in elixir, which is if during merging both values at the same key are maps/keyword lists merge them recursively. This is done via a protocol so can be extended for your own structs/data types if needbe. @@ -24,13 +24,15 @@ I wanted this to be a feature of Elixir itself, however the proposal [was reject ## Installation -Add `deep_merge` to your list of dependencies in `mix.exs`: +Add `:deep_merge` to your list of dependencies in `mix.exs`: - ```elixir - def deps do - [{:deep_merge, "~> 1.0"}] - end - ``` +```elixir +def deps do + [ + {:deep_merge, "~> 1.0"} + ] +end +``` ## General Usage - deep_merge/2 @@ -50,7 +52,7 @@ It is worth noting that structs are not deeply merged - not with each other and What is merged and how is defined by implementing the `DeepMerge.Resolver` protocol. This library implements it for `Map`, `List` and falls back to `Any` (where the right hand side value/override is taken). -If you want your own struct to be deeply merged you can simply `@derive` the protocole: +If you want your own struct to be deeply merged you can simply `@derive` the protocol: ```elixir defmodule Derived do @@ -98,7 +100,7 @@ iex> DeepMerge.deep_merge(%{a: %{b: 1}, c: [d: 1]}, %{a: %{b: 1, z: 5}, c: [x: 0]} ``` -This function is called for a given merge conflict with the key where it occured and the two conflicting values. Whatever value is returned in this function is inserted at that point in the structure - unless `DeepMerge.continue_deep_merge` is returned in which case the deep merge continues as normal. +This function is called for a given merge conflict with the key where it occurred and the two conflicting values. Whatever value is returned in this function is inserted at that point in the structure - unless `DeepMerge.continue_deep_merge` is returned in which case the deep merge continues as normal. When would you want to use this versus a protocol? The best use case I can think of is when you want to alter behavior for which a protocol is already implemented or if you care about specific keys. @@ -111,7 +113,7 @@ Well not necessarily, no. There are [very simple implementations for maps that u There are subtle things that can be missed there though (and I missed the first time around): * the most simple implementation also merges structs which is not always what you want -* For keyword lists on the other hand you gotta be careful that you don't accidentally merge keyword lists with lists as that's [currently possible](https://github.com/elixir-lang/elixir/issues/5395) +* for keyword lists on the other hand you gotta be careful that you don't accidentally merge keyword lists with lists as that's [currently possible](https://github.com/elixir-lang/elixir/issues/5395) * you might want to further adopt the implementation, in [benchee](https://github.com/bencheeorg/benchee) we have 2 custom implementations of the protocol due to our needs This library takes care of those problems and will take care of further problems/edge cases should they appear so you can focus on your business logic. @@ -120,10 +122,17 @@ At the same time it offers extension mechanisms through protocols and a function ## Performance -You can check out [a benchmark and its results](https://github.com/PragTob/deep_merge/blob/master/benches/bench/deep_merge.exs). +You can check out [a benchmark and its results](https://github.com/PragTob/deep_merge/blob/main/benches/bench/deep_merge.exs). The TLDR; is this: In the sample it is about 30 times slower than `Map.merge/2` - however, less than twice as slow as calling `Map.merge/3` with simple overriding behaviour (same behaviour as `Map.merge/2`). This is because `Map.merge/2` is highly optimized, but we need to do much more than the `Map.merge/3` sample in the benchmark so I think it's a very passable result. We're still talking about a couple of μs. ## Considered feature-complete Unless you come with great feature ideas of course ;) So if you come here and there are no recent commits, don't worry - there are no known bugs or whatever. It's a small little library that does its job. + +## Copyright and License + +Copyright (c) 2016 Tobias Pfeiffer + +This library is MIT licensed. See the +[LICENSE](https://github.com/PragTob/deep_merge/blob/main/LICENSE.txt) for details. diff --git a/mix.exs b/mix.exs index ed8da0e..59a2b82 100644 --- a/mix.exs +++ b/mix.exs @@ -1,6 +1,7 @@ defmodule DeepMerge.Mixfile do use Mix.Project + @source_url "https://github.com/PragTob/deep_merge" @version "1.0.0" def project do @@ -12,37 +13,33 @@ defmodule DeepMerge.Mixfile do start_permanent: Mix.env() == :prod, elixirc_paths: elixirc_paths(Mix.env()), deps: deps(), - docs: [source_ref: @version], + docs: docs(), test_coverage: [tool: ExCoveralls], - preferred_cli_env: [ - coveralls: :test, - "coveralls.detail": :test, - "coveralls.post": :test, - "coveralls.html": :test, - "coveralls.travis": :test - ], package: package(), name: "deep_merge", - source_url: "https://github.com/PragTob/deep_merge", + description: """ + Deep (recursive) merging for maps, keyword lists and whatever else + you may want via implementing a simple protocol. + """, dialyzer: [ flags: [:error_handling, :underspecs], ignore_warnings: ".dialyzer_ignore.exs", list_unused_filters: true ], - description: """ - Deep (recursive) merging for maps, keyword lists and whatever else - you may want via implementing a simple protocol. - """ + preferred_cli_env: [ + docs: :docs, + coveralls: :test, + "coveralls.detail": :test, + "coveralls.post": :test, + "coveralls.html": :test, + "coveralls.travis": :test + ] ] end - # Specifies which paths to compile per environment. defp elixirc_paths(:test), do: ["lib", "test/support"] defp elixirc_paths(_), do: ["lib"] - # Configuration for the OTP application - # - # Type "mix help compile.app" for more information def application do [] end @@ -50,20 +47,29 @@ defmodule DeepMerge.Mixfile do defp deps do [ {:credo, "~> 1.0", only: :dev}, - {:ex_doc, "~> 0.11", only: :dev}, - {:earmark, "~> 1.2", only: :dev}, + {:ex_doc, ">= 0.0.0", only: :docs, runtime: false}, {:excoveralls, "~> 0.7", only: :test}, {:inch_ex, "~> 2.0", only: :docs}, {:dialyxir, "~> 1.0", only: [:dev], runtime: false} ] end + defp docs do + [ + extras: ["CHANGELOG.md", "README.md"], + main: "readme", + source_url: @source_url, + source_ref: @version + ] + end + defp package do [ maintainers: ["Tobias Pfeiffer"], licenses: ["MIT"], links: %{ - "github" => "https://github.com/PragTob/deep_merge" + "Changelog" => "https://hexdocs.pm/deep_merge/changelog.html", + "GitHub" => @source_url } ] end