Skip to content

Implement Access behaviour since the protocol has been deprecated #3

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 51 additions & 12 deletions lib/array.ex
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
defmodule Array do
@behaviour Access
@moduledoc """
A wrapper module for Erlang's array.
"""
Expand All @@ -15,7 +16,7 @@ defmodule Array do
Creates a new, extendible array with initial size zero.
The default value is the atom nil, not undefined.
"""
@spec new() :: t
@spec new() :: t
def new() do
%Array{content: :array.new({:default, nil})}
end
Expand Down Expand Up @@ -85,7 +86,7 @@ defmodule Array do

@doc """
Folds the elements of the array using the given function and initial accumulator value.
The elements are visited in order from the lowest index to the highest.
The elements are visited in order from the lowest index to the highest.

If `fun` is not a function, the call raises `ArgumentError`.
"""
Expand All @@ -96,7 +97,7 @@ defmodule Array do
@doc """
Folds the elements of the array right-to-left using the given function and initial accumulator value.
The elements are visited in order from the highest index to the lowest.

If `fun` is not a function, the call raises `ArgumentError`.
"""
@spec foldr(t, acc, (index, element, acc -> acc)) :: acc when acc: var
Expand Down Expand Up @@ -184,7 +185,7 @@ defmodule Array do
@doc """
Maps the given function onto each element of the array.
The elements are visited in order from the lowest index to the highest.

If `fun` is not a function, the call raises `ArgumentError`.
"""
@spec map(t, (index, element -> any)) :: t
Expand Down Expand Up @@ -260,7 +261,7 @@ defmodule Array do
Folds the elements of the array right-to-left using the given function and initial accumulator value,
skipping default-valued entries.
The elements are visited in order from the highest index to the lowest.

If `fun` is not a function, the call raises `ArgumentError`.
"""
@spec sparse_foldr(t, acc, (index, element, acc -> acc)) :: acc when acc: var
Expand All @@ -270,7 +271,7 @@ defmodule Array do
@doc """
Maps the given function onto each element of the array, skipping default-valued entries.
The elements are visited in order from the lowest index to the highest.

If `fun` is not a function, the call raises `ArgumentError`.
"""
@spec sparse_map(t, (element -> any)) :: t
Expand Down Expand Up @@ -320,16 +321,45 @@ defmodule Array do
@spec to_orddict(t) :: [{index, element}]
def to_orddict(%Array{content: c}),
do: :array.to_orddict(c)
end

defimpl Access, for: Array do
def get(arr, idx) do
Array.get(arr, idx)
@doc """
Access behavior `fetch/2` callback.
"""
def fetch(arr, idx) do
{:ok, get(arr, idx)}
end

@doc """
Access behavior `get/3` callback
"""
def get(arr, idx, value) do
if size(arr) < idx do
get(arr, idx)
else
value
end
end

@doc """
Access behavior `get_and_update/3` callback
"""
def get_and_update(arr, idx, fun) do
{get, update} = fun.(Array.get(arr, idx))
{get, Array.set(arr, idx, update)}
value = get(arr, idx)
case fun.(value) do
{get, update} -> {get, set(arr, idx, update)}
:pop -> {value, set(arr, idx, nil)}
end
end

@doc """
Access behavior `pop/2` callback
"""
def pop(arr, idx) do
if size(arr) < idx do
{get(arr, idx), set(arr, idx, nil)}
else
{nil, arr}
end
end
end

Expand All @@ -341,6 +371,15 @@ defimpl Enumerable, for: Array do
def reduce(%Array{content: c}, acc, fun) do
Enumerable.reduce(:array.to_list(c), acc, fun)
end

def slice(arr) do
slice_fun = fn (start, length) ->
for i <- start..(start + length - 1) do
Array.get(arr, i)
end
end
{:ok, Array.size(arr), slice_fun}
end
end

defimpl Collectable, for: Array do
Expand Down
22 changes: 5 additions & 17 deletions mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,18 @@ defmodule Array.Mixfile do
use Mix.Project

def project do
[app: :array,
version: "1.0.1",
elixir: ">= 1.0.0",
[app: :elixir_array,
version: "2.1.0",
elixir: ">= 1.11.1",
description: "An elixir wrapper library for Erlang's array.",
package: package,
deps: deps]
package: package(),
deps: deps()]
end

# Configuration for the OTP application
#
# Type `mix help compile.app` for more information
def application do
[applications: [:logger]]
end

# Dependencies can be Hex packages:
#
# {:mydep, "~> 0.3.0"}
#
# Or git/path repositories:
#
# {:mydep, git: "https://github.com/elixir-lang/mydep.git", tag: "0.1.0"}
#
# Type `mix help deps` for more examples and options
defp deps do
[{:earmark, ">= 0.0.0", only: :dev},
{:ex_doc, "~> 0.6", only: :dev}]
Expand Down
12 changes: 10 additions & 2 deletions test/array_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ defmodule ArrayTest do
test "fix" do
a = Array.new()
a = Array.set(a, 100, 0)

a = Array.fix(a)
assert_raise ArgumentError, fn ->
Array.set(a, 101, 0)
Expand Down Expand Up @@ -405,7 +405,7 @@ defmodule ArrayTest do
test "to_erlang_array" do
a = Array.from_list([1,2,3])
ea = Array.to_erlang_array(a)

assert :array.is_array(ea)
assert 3 == :array.size(ea)
assert 1 == :array.get(0, ea)
Expand Down Expand Up @@ -454,6 +454,14 @@ defmodule ArrayTest do
assert 6 == sum
end

test "Enumerable.slice" do
slice = Enum.slice(Array.from_list([1,2,3,4,5]), 1, 2)
assert [2,3] == slice

slice = Enum.slice(Array.from_list([1,2,3,4,5]), 3, 1)
assert [4] == slice
end

test "Collectable.into" do
a = Enum.into([1,2,3], Array.new())
assert Array.is_array(a)
Expand Down