diff --git a/README.md b/README.md index 575cb56..c24834d 100644 --- a/README.md +++ b/README.md @@ -15,11 +15,11 @@ CircularBuffer provides a general-purpose circular buffer data structure. ```elixir # Create a new circular buffer that holds 5 elements iex> cb = CircularBuffer.new(5) -#CircularBuffer<[]> +CircularBuffer.new([], 5) # Fill it up iex> cb = Enum.into(1..5, cb) -#CircularBuffer<[1, 2, 3, 4, 5]> +CircularBuffer.new([1, 2, 3, 4, 5], 5) # Verify that 1 is the oldest and 5 is the newest element in the buffer iex> CircularBuffer.oldest(cb) @@ -29,7 +29,7 @@ iex> CircularBuffer.newest(cb) # Add another element. 1 gets pushed out. iex> cb = CircularBuffer.insert(cb, 6) -#CircularBuffer<[2, 3, 4, 5, 6]> +CircularBuffer.new([2, 3, 4, 5, 6], 5) # CircularBuffer implements Enumerable so all Enum.* functions work iex> Enum.sum(cb) diff --git a/lib/circular_buffer.ex b/lib/circular_buffer.ex index 152602f..ccc4767 100644 --- a/lib/circular_buffer.ex +++ b/lib/circular_buffer.ex @@ -24,7 +24,6 @@ defmodule CircularBuffer do like the following works: iex> cb = Enum.into([1, 2, 3, 4], CircularBuffer.new(3)) - #CircularBuffer<[2, 3, 4]> iex> Enum.map(cb, fn x -> x * 2 end) [4, 6, 8] """ @@ -48,6 +47,14 @@ defmodule CircularBuffer do %CB{a: [], b: [], max_size: size, count: 0} end + @doc """ + Creates a new circular buffer with a given size and contents + """ + @spec new(Enumerable.t(), non_neg_integer()) :: t() + def new(enumerable, size) when is_integer(size) and size >= 0 do + Enum.reduce(enumerable, new(size), &insert(&2, &1)) + end + @doc """ Inserts a new item into the next location of the circular buffer """ @@ -120,6 +127,12 @@ defmodule CircularBuffer do cb.count == 0 end + @doc """ + Return the max size of the buffer + """ + @spec max_size(t()) :: non_neg_integer() + def max_size(%CB{max_size: max_size}), do: max_size + defimpl Enumerable do def count(cb) do {:ok, cb.count} @@ -160,7 +173,13 @@ defmodule CircularBuffer do import Inspect.Algebra def inspect(cb, opts) do - concat(["#CircularBuffer<", to_doc(CB.to_list(cb), opts), ">"]) + concat([ + "CircularBuffer.new(", + to_doc(CB.to_list(cb), opts), + ", ", + to_doc(CB.max_size(cb), opts), + ")" + ]) end end end diff --git a/test/circular_buffer_test.exs b/test/circular_buffer_test.exs index 9f01299..fa21dc7 100644 --- a/test/circular_buffer_test.exs +++ b/test/circular_buffer_test.exs @@ -128,9 +128,23 @@ defmodule CircularBufferTest do end end - test "can be inspected" do - str = inspect(Enum.into([1, 2, 3, 4], CB.new(4))) - assert str == "#CircularBuffer<[1, 2, 3, 4]>" + property "inspect matches contents" do + forall {size, is} <- size_and_list() do + buffer = Enum.reduce(is, CB.new(size), fn i, cb -> CB.insert(cb, i) end) + {inspected, _} = Code.eval_string(inspect(buffer, limit: :infinity)) + + buffer.max_size == inspected.max_size and CB.to_list(inspected) == CB.to_list(buffer) + end + end + + test "inspecting zero-length buffer" do + str = inspect(CB.new(0)) + assert str == "CircularBuffer.new([], 0)" + end + + test "max_size matches created size" do + cb = CB.new(15) + assert CB.max_size(cb) == 15 end test "Enum.slice" do