Skip to content

Commit 2133de4

Browse files
Use mapper when converting list to table reader (#13)
1 parent 3ad8bc6 commit 2133de4

3 files changed

Lines changed: 31 additions & 14 deletions

File tree

lib/table/mapper.ex

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,46 +6,52 @@ defmodule Table.Mapper do
66
# This enumerable proxies traversal to the underlying enumerable,
77
# so it keeps the same properties, such as optimized slicing.
88

9-
defstruct [:enumerable, :mapper]
9+
defstruct [:enumerable, :fun]
1010

1111
@doc """
1212
Returns an enumerable that will apply the given function on
1313
enumeration.
1414
"""
1515
@spec map(Enumerable.t(), (any() -> any())) :: Enumerable.t()
16+
def map(enumerable, fun)
17+
18+
def map(%__MODULE__{} = mapper, fun) do
19+
%{mapper | fun: &fun.(mapper.fun.(&1))}
20+
end
21+
1622
def map(enumerable, fun) do
17-
%__MODULE__{enumerable: enumerable, mapper: fun}
23+
%__MODULE__{enumerable: enumerable, fun: fun}
1824
end
1925

2026
defimpl Enumerable do
21-
def count(proxy) do
22-
Enumerable.count(proxy.enumerable)
27+
def count(mapper) do
28+
Enumerable.count(mapper.enumerable)
2329
end
2430

2531
# The mapping is not necessarily reversible, so we fall
2632
# back to a linear search. For enumerables representing
2733
# data entries member? would generally be linear anyway
28-
def member?(_proxy, _element), do: {:error, __MODULE__}
34+
def member?(_mapper, _element), do: {:error, __MODULE__}
2935

30-
def reduce(proxy, acc, fun) do
31-
Enumerable.reduce(proxy.enumerable, acc, fn original, acc ->
32-
fun.(proxy.mapper.(original), acc)
36+
def reduce(mapper, acc, fun) do
37+
Enumerable.reduce(mapper.enumerable, acc, fn original, acc ->
38+
fun.(mapper.fun.(original), acc)
3339
end)
3440
end
3541

36-
def slice(proxy) do
37-
case Enumerable.slice(proxy.enumerable) do
42+
def slice(mapper) do
43+
case Enumerable.slice(mapper.enumerable) do
3844
{:ok, size, fun} ->
3945
fun =
4046
case fun do
4147
to_list_fun when is_function(to_list_fun, 1) ->
42-
&(to_list_fun.(&1) |> Enum.map(proxy.mapper))
48+
&(to_list_fun.(&1) |> Enum.map(mapper.fun))
4349

4450
slicing_fun when is_function(slicing_fun, 2) ->
45-
&(slicing_fun.(&1, &2) |> Enum.map(proxy.mapper))
51+
&(slicing_fun.(&1, &2) |> Enum.map(mapper.fun))
4652

4753
slicing_fun when is_function(slicing_fun, 3) ->
48-
&(slicing_fun.(&1, &2, &3) |> Enum.map(proxy.mapper))
54+
&(slicing_fun.(&1, &2, &3) |> Enum.map(mapper.fun))
4955
end
5056

5157
{:ok, size, fun}

lib/table/reader/enumerable.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ defmodule Table.Reader.Enumerable do
3737
case columns_for(head) do
3838
{:ok, columns} ->
3939
meta = %{columns: columns}
40-
enum = Stream.map(enum, &record_values(&1, columns))
40+
enum = Table.Mapper.map(enum, &record_values(&1, columns))
4141
{:rows, meta, enum}
4242

4343
:error ->

test/mapper_test.exs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,15 @@ defmodule Table.MapperTest do
2121
assert Enum.member?(enumerable, 36) == true
2222
assert Enum.member?(enumerable, 37) == false
2323
end
24+
25+
test "mapping multiple times retains a flat mapper" do
26+
enumerable =
27+
1..3
28+
|> Mapper.map(fn x -> x * x end)
29+
|> Mapper.map(fn x -> x + 1 end)
30+
31+
assert %Mapper{enumerable: 1..3} = enumerable
32+
33+
assert Enum.to_list(enumerable) == [2, 5, 10]
34+
end
2435
end

0 commit comments

Comments
 (0)