README.md

# DeeplyEnumerable and DataLeafWalker

Traverse and map values of deeply nested data structures: Provides a
`map_deeply/2` function for Maps and Lists and Keyword Lists. 

rroouugghhllyy based on ideas from Perl's Data::Leaf::Walker

## Synopsis

```
data = [1, 2, 3, [{:a, 2}, {:b, 4}], %{ a: 2 } ]
DeeplyEnumerable.map_deeply map, &( &1 + 1 )

# yields
[2, 3, 4,[a: 3, b: 5], %{a: 3}]
```

## Usage

```
DeeplyEnumerable.map_deeply( data, fn( value ) -> ...transform value... end )
```

Where data can ba a map, list or keyword list. 

## Direct usage of DataLeafWalker

Or, you may DataLeafWalker's `map/2` directly (_discouraged_):
```
DataLeafWalker.map( data, fn( value ) -> ...transform value... end )
```

The difference beetween the _module_ DataLeafWalker and the _protocol_
DeeplyEnumerable is that by implementing the latter for your structs
you may add in extra functionality to the transformation or make it
conditionally transform or whatever. I needed this feature, that's why
it's here. For Lists and Maps, DeeplyEnumerable is already implemented
(simply calling to `DataLeafWalker.map/2`). Though it seems overkill
at first glance, having an extension entry point to your
transformations of complex structs is usually a safe thing.

## Structs

In order to support structs you may either use `DataLeafWalker.map/2`
or (better) implement `DeeplyEnumerable` for you struct type, most
often like this:

```
defimpl DeeplyEnumerable, for: MyStruct do
  def map_deeply( struct, fn_transform ) do
    DataLeafWalker.map( struct, fn_transform )
  end
end
```

## What I use this for

I have to migrate ancient projects that use YAML-serialized in database columns.
Unfortunately they are doubly UTF-8 encoded so I convert these deeply-nested
maps into maps of the same structure with all values decoded into proper UTF-8.

## Installation

The package can be installed as:

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

        def deps do
          [{:data_leaf_walker, "~> 0.1.0"}]
        end

## Todo

- [ ] make keys subject to mappability, too.
- [x] support structs.
- [ ] add proper docs
- [x] really a protocol? _Yes_
- [ ] add property-based tests. more tests.