Skip to content

A small utility to convert deep Elixir maps with mixed string/atom keys to atom-only keyed maps.

Notifications You must be signed in to change notification settings

ruby2elixir/atomic_map

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

47 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

AtomicMap

Build status Hex version Hex downloads

A small utility to convert Elixir maps with mixed string/atom keys to atom-only keyed maps. Optionally with a safe option, to prevent atom space exhaustion of the Erlang VM. Since v0.8 it also supports conversion of keys from CamelCase to under_score format.

AtomicMap can convert simple maps or nested structures such as lists of maps; see Nested Structures below for examples.

Usage

Safety

With no options, it safely converts string keys in maps to atoms, using String.to_existing_atom/1.

iex> AtomicMap.convert(%{"a" => "a", "b" => "b", c: "c"})
%{a: "a", b: "b", c: "c"}

Because safe conversion uses String.to_existing_atom/1, it will raise when the target atom does not exist.

iex> AtomicMap.convert(%{"abcdefg" => "a", "b" => "b"})
** (ArgumentError) argument error
    :erlang.binary_to_existing_atom("abcdefg", :utf8)

To have safe conversion can ignore unsafe keys, leaving them as strings, pass true for the ignore option.

iex> AtomicMap.convert(%{"abcdefg" => "a", "b" => "b"}, %{ignore: true})
%{:b => "b", "abcdefg" => "a"}

To disable safe conversion and allow new atoms to be created, pass false for the safe: option. (This makes the ignore option irrelevant.) If the input is user-generated, converting only expected keys will prevent excessive atom creation.

iex> map = %{"expected_key" => "a", "b" => "b", "unexpected_key" => "c"}
%{"expected_key" => "a", "b" => "b", "unexpected_key" => "c"}

iex> filtered_map = Map.take(map, ["expected_key", "b"])
%{"b" => "b", "expected_key" => "a"}

iex> AtomicMap.convert(filtered_map, %{safe: false})
%{b: "b", expected_key: "a"}

Underscoring

By default, "CamelCase" string keys will be converted to under_score atom keys.

iex> AtomicMap.convert(%{ "CamelCase" => "hi" })
** (ArgumentError) argument error
    :erlang.binary_to_existing_atom("camel_case", :utf8)

Note that "camel_case" was the string that failed conversion. If that atom is explicitly created first, the conversion will succeed.

iex> :camel_case
:camel_case
iex> AtomicMap.convert(%{ "CamelCase" => "hi" })
%{camel_case: "hi"}

Allowing unsafe conversions will also work. If the input is user-generated, converting only expected keys will prevent excessive atom creation.

iex> map = %{"CamelCase" => "a", "b" => "b", "AnotherCamelCase" => "c"}
%{"CamelCase" => "a", "b" => "b", "AnotherCamelCase" => "c"}

iex> filtered_map = Map.take(map, ["CamelCase", "b"])
%{"b" => "b", "CamelCase" => "a"}

iex> AtomicMap.convert(filtered_map, %{safe: false})
%{b: "b", camel_case: "a"}

Replacing Hyphens

"hyphenated-string" keys will always be converted to under_score atom keys. There is currently no way to disable this behavior.

iex> AtomicMap.convert(%{"some-key" => "a", "b" => "c"})
** (ArgumentError) argument error
    :erlang.binary_to_existing_atom("some_key", :utf8)

Note that "some_key" was the string that failed conversion. If that atom is explicitly created first, the conversion will succeed.

iex> :some_key
:some_key

iex> AtomicMap.convert(%{"some-key" => "a", "b" => "c"})
%{b: "c", some_key: "a"}

Allowing unsafe conversions will also work. If the input is user-generated, converting only expected keys will prevent excessive atom creation.

iex> map = %{"some-key" => "a", "b" => "b", "another-key" => "c"}
%{"some-key" => "a", "b" => "b", "another-key" => "c"}

iex> filtered_map = Map.take(map, ["some-key", "b"])
%{"b" => "b", "some-key" => "a"}

iex> AtomicMap.convert(filtered_map, %{safe: false})
%{b: "b", some_key: "a"}

Nested Structures

# works with nested maps
iex> AtomicMap.convert(%{"a" => 2, "b" => %{"c" => 4}})
%{a: 2, b: %{c: 4}}

# works with nested maps + lists + mixed key types (atoms + binaries)
iex> AtomicMap.convert([ %{"c" => 1}, %{:c => 2}, %{"c" => %{:b => 4}}], %{safe: true})
[%{c: 1}, %{c: 2}, %{c: %{b: 4}}]

Installation

  1. Add atomic_map to your list of dependencies in mix.exs:

    def deps do [{:atomic_map, "~> 0.8"}] end

Todo:

  • maybe allow direct conversion to a struct, like Poison does it: as: %SomeStruct{}...

Benchmark

$ mix bench

About

A small utility to convert deep Elixir maps with mixed string/atom keys to atom-only keyed maps.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy