Skip to content

Commit

Permalink
Initial release
Browse files Browse the repository at this point in the history
  • Loading branch information
ottojimb committed Mar 23, 2017
0 parents commit 656751b
Show file tree
Hide file tree
Showing 9 changed files with 224 additions and 0 deletions.
20 changes: 20 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# The directory Mix will write compiled artifacts to.
/_build

# If you run "mix test --cover", coverage assets end up here.
/cover

# The directory Mix downloads your dependencies sources to.
/deps

# Where 3rd-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
38 changes: 38 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# DeepClean

Provide functionality to exclude elements in nested maps or list.

## Installation

If [available in Hex](https://hex.pm/docs/publish), the package can be installed
by adding `deep_clean` to your list of dependencies in `mix.exs`:

```elixir
def deps do
[{:deep_clean, "~> 0.1.0"}]
end
```

Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc)
and published on [HexDocs](https://hexdocs.pm).
The docs can be found at [https://hexdocs.pm/deep_clean](https://hexdocs.pm/deep_clean).


## Usage

Simply call the `DeepClean.exclude_in/2` function sending the following params:

1. `deep_elem`: a *map* or *list* with nested elements
2. `clean_list`: a *list* with the keys to be exclude from the *deep_elem*
separated by dots by each nested level


## Example

```elixir
iex> DeepClean.exclude_in(%{a: %{aa: 1, ab: 2}, b: %{ba: 3, bb: 4}}, ["a.ab", "b.bb"])
.. > %{a: %{aa: 1}, b: %{ba: 3}}

iex> DeepClean.exclude_in(%{a: [%{aa: 1, ab: 2}, %{aa: 11, ab: 22},], b: [%{ba: 3, bb: 4}, %{ba: 33, bb: 44}]}, ["a.ab", "b.bb"])
.. > %{a: [%{aa: 1}, %{aa: 11}], b: [%{ba: 3}, %{ba: 33}]}
```
30 changes: 30 additions & 0 deletions config/config.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# This file is responsible for configuring your application
# and its dependencies with the aid of the Mix.Config module.
use Mix.Config

# This configuration is loaded before any dependency and is restricted
# to this project. If another project depends on this project, this
# file won't be loaded nor affect the parent project. For this reason,
# if you want to provide default values for your application for
# 3rd-party users, it should be done in your "mix.exs" file.

# You can configure for your application as:
#
# config :deep_clean, key: :value
#
# And access this configuration in your application as:
#
# Application.get_env(:deep_clean, :key)
#
# Or configure a 3rd-party app:
#
# config :logger, level: :info
#

# It is also possible to import configuration files, relative to this
# directory. For example, you can emulate configuration per environment
# by uncommenting the line below and defining dev.exs, test.exs and such.
# Configuration from the imported file will override the ones defined
# here (which is why it is important to import them last).
#
# import_config "#{Mix.env}.exs"
Binary file added deep_clean-0.1.0.tar
Binary file not shown.
61 changes: 61 additions & 0 deletions lib/deep_clean.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
defmodule DeepClean do
@moduledoc """
Provides functionality to remove elements from nested
`Map` or `List` elements.
Util to remove json attributes in responses
"""

@doc """
Cleans nested maps elements provided in a list.
## Examples
iex> DeepClean.exclude_in(%{a: %{aa: 1, ab: 2}, b: %{ba: 3, bb: 4}}, ["a.ab", "b.bb"])
%{a: %{aa: 1}, b: %{ba: 3}}
iex> DeepClean.exclude_in(%{a: [%{aa: 1, ab: 2}, %{aa: 11, ab: 22},], b: [%{ba: 3, bb: 4}, %{ba: 33, bb: 44}]}, ["a.ab", "b.bb"])
%{a: [%{aa: 1}, %{aa: 11}], b: [%{ba: 3}, %{ba: 33}]}
"""
@spec exclude_in(map | list, [String.t, ...]) :: (map | list)
def exclude_in(deep_elem, clean_list)
when (is_map(deep_elem) or is_list(deep_elem)) and
is_list(clean_list) do
exclude(deep_elem, clean_list, "")
end

defp update_current_level(level, key) do
key =
case key do
key when is_atom(key) -> Atom.to_string(key)
key -> key
end

case level do
"" -> key
_ -> "#{level}.#{key}"
end
end

defp exclude(enum, _, _) when (not is_map(enum) and not is_list(enum)) do
enum
end

defp exclude(enum, to_clean, level) when is_list(enum) do
for element <- enum, do: exclude(element, to_clean, level)
end

defp exclude(enum, to_clean, level) when is_map(enum) do
enum
|> Enum.map(fn({key, element}) ->
current_level = update_current_level(level, key)
unless Enum.member?(to_clean, current_level) do
respo = {key, exclude(element, to_clean, current_level)}
respo
end
end)
|> Enum.filter(&(not is_nil(&1)))
|> Enum.into(%{})
end
end
50 changes: 50 additions & 0 deletions mix.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
defmodule DeepClean.Mixfile do
use Mix.Project

def project do
[app: :deep_clean,
version: "0.1.0",
elixir: "~> 1.4",
build_embedded: Mix.env == :prod,
start_permanent: Mix.env == :prod,
description: description(),
package: package(),
deps: deps()]
end

defp package do
[
maintainers: ["Otto Jiménez"],
licenses: ["MIT"],
links: %{"GitHub" => "https://github.com/ottojimb/deep_clean"}
]
end

defp description do
"""
Exclude elements from deep nested maps or list
"""
end


# Configuration for the OTP application
#
# Type "mix help compile.app" for more information
def application do
# Specify extra applications you'll use from Erlang/Elixir
[extra_applications: [:logger]]
end

# Dependencies can be Hex packages:
#
# {:my_dep, "~> 0.3.0"}
#
# Or git/path repositories:
#
# {:my_dep, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"}
#
# Type "mix help deps" for more examples and options
defp deps do
[{:ex_doc, "~> 0.15.0", only: :dev}]
end
end
2 changes: 2 additions & 0 deletions mix.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
%{"earmark": {:hex, :earmark, "1.2.0", "bf1ce17aea43ab62f6943b97bd6e3dc032ce45d4f787504e3adf738e54b42f3a", [:mix], []},
"ex_doc": {:hex, :ex_doc, "0.15.0", "e73333785eef3488cf9144a6e847d3d647e67d02bd6fdac500687854dd5c599f", [:mix], [{:earmark, "~> 1.1", [hex: :earmark, optional: false]}]}}
22 changes: 22 additions & 0 deletions test/deep_clean_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
defmodule DeepCleanTest do
use ExUnit.Case
import DeepClean
doctest DeepClean

test "Avoid to remove if key is not found" do
map = %{a: %{aa: 1, ab: 2}, b: %{ba: 3, bb: 4}}
assert exclude_in(map, ["c"]) == map
end

test "Remove bb from b element in map" do
map = %{a: %{aa: 1, ab: 2}, b: %{ba: 3, bb: 4}}
res = %{a: %{aa: 1, ab: 2}, b: %{ba: 3}}
assert exclude_in(map, ["b.bb"]) == res
end

test "Remove bb from b element in list" do
map = [%{a: %{aa: 1, ab: 2}, b: %{ba: 3, bb: 4}}]
res = [%{a: %{aa: 1, ab: 2}, b: %{ba: 3}}]
assert exclude_in(map, ["b.bb"]) == res
end
end
1 change: 1 addition & 0 deletions test/test_helper.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ExUnit.start()

0 comments on commit 656751b

Please sign in to comment.