diff --git a/README.md b/README.md index 64f1f7e..946d49f 100644 --- a/README.md +++ b/README.md @@ -64,6 +64,26 @@ Enum.each 1..100, fn (i) -> end ``` +But you can also simplify working with `Enum`: + +```elixir +1..100 +|> ProgressBar.from_enum(fn (i) -> + :timer.sleep 25 +end) +``` + +Or even can work with `Stream` (be careful, it will use a `Stream.count/1` to determine total number of elements): + +```elixir +1..100 +|> ProgressBar.from_stream() +|> Enum.map(fn (i) -> + :timer.sleep 25 +end) +|> Enum.into([]) +``` + #### Width The bar will automatically set its width to fit the terminal. If the terminal width can't be determined automatically, an 80 column width will be assumed. diff --git a/lib/progress_bar.ex b/lib/progress_bar.ex index 5a5b4f5..cd40ecf 100644 --- a/lib/progress_bar.ex +++ b/lib/progress_bar.ex @@ -22,4 +22,32 @@ defmodule ProgressBar do def render_spinner(custom_format, fun) do ProgressBar.Spinner.render(custom_format, fun) end + + def from_enum(list, fun, opts \\ []) do + total = Enum.count(list) + + ProgressBar.render(0, total, opts) + + list + |> Enum.with_index(1) + |> Enum.each(fn {el, i} -> + fun.(el) + ProgressBar.render(i, total, opts) + end) + + list + end + + def from_stream(list, opts \\ []) do + total = Enum.count(list) + + ProgressBar.render(0, total, opts) + + list + |> Stream.with_index(1) + |> Stream.map(fn {el, i} -> + ProgressBar.render(i, total, opts) + el + end) + end end diff --git a/lib/progress_bar/determinate.ex b/lib/progress_bar/determinate.ex index ad98976..b93cb58 100644 --- a/lib/progress_bar/determinate.ex +++ b/lib/progress_bar/determinate.ex @@ -10,7 +10,7 @@ defmodule ProgressBar.Determinate do suffix: false, bar_color: [], blank_color: [], - width: :auto, + width: :auto ] def render(current, total, custom_format \\ @default_format) when current <= total do @@ -21,7 +21,7 @@ defmodule ProgressBar.Determinate do suffix = [ formatted_percent(format[:percent], percent), formatted_suffix(format[:suffix], current, total), - newline_if_complete(current, total), + newline_if_complete(current, total) ] ProgressBar.BarFormatter.write( @@ -35,6 +35,7 @@ defmodule ProgressBar.Determinate do # Private defp formatted_percent(false, _), do: "" + defp formatted_percent(true, number) do number |> Integer.to_string() diff --git a/test/determinate_test.exs b/test/determinate_test.exs index 325f619..7080d0f 100644 --- a/test/determinate_test.exs +++ b/test/determinate_test.exs @@ -118,16 +118,39 @@ defmodule DeterminateTest do mb = 1_000_000 format = [suffix: :bytes, width: @width] - assert_bar ProgressBar.render(0, mb, format) == "| | 0% (0.00/1.00 MB)" - assert_bar ProgressBar.render(mb / 2, mb, format) == "|================================================== | 50% (0.50/1.00 MB)" - assert_bar ProgressBar.render(mb, mb, format) == "|====================================================================================================| 100% (1.00 MB)" + assert_bar( + ProgressBar.render(0, mb, format) == + "| | 0% (0.00/1.00 MB)" + ) + + assert_bar( + ProgressBar.render(mb / 2, mb, format) == + "|================================================== | 50% (0.50/1.00 MB)" + ) + + assert_bar( + ProgressBar.render(mb, mb, format) == + "|====================================================================================================| 100% (1.00 MB)" + ) end test "suffix: :count" do mb = 100 format = [suffix: :count, width: @width] - assert_bar ProgressBar.render(0, mb, format) == "| | 0% (0/100)" - assert_bar ProgressBar.render(50, mb, format) == "|================================================== | 50% (50/100)" - assert_bar ProgressBar.render(mb, mb, format) == "|====================================================================================================| 100% (100)" + + assert_bar( + ProgressBar.render(0, mb, format) == + "| | 0% (0/100)" + ) + + assert_bar( + ProgressBar.render(50, mb, format) == + "|================================================== | 50% (50/100)" + ) + + assert_bar( + ProgressBar.render(mb, mb, format) == + "|====================================================================================================| 100% (100)" + ) end end diff --git a/test/enum_test.exs b/test/enum_test.exs new file mode 100644 index 0000000..21e567c --- /dev/null +++ b/test/enum_test.exs @@ -0,0 +1,76 @@ +defmodule EnumTest do + use ExUnit.Case + + alias ProgressBar.Utils + import ExUnit.CaptureIO + + test "it works with enums" do + test_pid = self() + + io = + capture_io(fn -> + list = ProgressBar.from_enum([1, 2, 3, 4, 5], fn _ -> send(test_pid, :fn_run) end) + + assert list == [1, 2, 3, 4, 5] + end) + + assert split_bars(io) == [ + "|", + "|", + "0%", + "|===============", + "|", + "20%", + "|=============================", + "|", + "40%", + "|============================================", + "|", + "60%", + "|==========================================================", + "|", + "80%", + "|=========================================================================|", + "100%" + ] + + for _ <- 1..5, do: assert_received(:fn_run) + refute_received :fn_run + end + + test "it works with streams" do + io = + capture_io(fn -> + list = + [1, 2, 3, 4, 5] + |> ProgressBar.from_stream() + |> Enum.into([]) + + assert list == [1, 2, 3, 4, 5] + end) + + assert split_bars(io) == [ + "|", + "|", + "0%", + "|===============", + "|", + "20%", + "|=============================", + "|", + "40%", + "|============================================", + "|", + "60%", + "|==========================================================", + "|", + "80%", + "|=========================================================================|", + "100%" + ] + end + + defp split_bars(string) do + string |> String.replace(Utils.ansi_prefix(), "\n") |> String.split() + end +end