From 345c8e90e9975990537063ea110dee98815b0935 Mon Sep 17 00:00:00 2001 From: Tashiro Date: Mon, 24 Jan 2022 14:17:25 +0900 Subject: [PATCH 1/9] setup 0.5.0 --- CHANGELOG.md | 6 ++++++ README.md | 4 ++-- lib/r_enum.ex | 1 + lib/r_enum/active_support.ex | 2 +- lib/r_list.ex | 1 + lib/r_list/active_support.ex | 32 +++++++++++++++++++++++++++++++- mix.exs | 2 +- 7 files changed, 43 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4ad233a..13e39a4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ # Changelog +## v0.5.0 (2022-1-xx) + +### Features + +- RList.ActiveSupport + ## v0.4.0 (2022-1-24) ### Features diff --git a/README.md b/README.md index 2d2432d..dbc02e4 100644 --- a/README.md +++ b/README.md @@ -105,7 +105,7 @@ See **[hexdocs](https://hexdocs.pm/r_enum)**. - REnum.ActiveSupport - [x] 0.4.0 - RList.Ruby -- [ ] 0.5.0 +- [x] 0.5.0 - RList.ActiveSupport - [ ] 0.6.0 - RMap.Ruby @@ -122,7 +122,7 @@ See **[hexdocs](https://hexdocs.pm/r_enum)**. | REnum | Elixir Module | Ruby Class | Elixir | Ruby | ActiveSupport | | ------- | ------------- | ---------------- | :----: | :--: | :-----------: | | REnum | Enum | Enumerable | ✅ | ✅ | ✅ | -| RList | List | Array | ✅ | ✅ | TODO | +| RList | List | Array | ✅ | ✅ | ✅ | | RMap | Map | Hash | ✅ | TODO | TODO | | RRange | Range | Range | ✅ | TODO | TODO | | RStream | Stream | Enumerator::Lazy | ✅ | TODO | TODO | diff --git a/lib/r_enum.ex b/lib/r_enum.ex index 4dbeed5..3afe46e 100644 --- a/lib/r_enum.ex +++ b/lib/r_enum.ex @@ -4,6 +4,7 @@ defmodule REnum do See also - [REnum.Native](https://hexdocs.pm/r_enum/REnum.Native.html#content) - [REnum.Ruby](https://hexdocs.pm/r_enum/REnum.Ruby.html#content) + - [REnum.ActiveSupport](https://hexdocs.pm/r_enum/REnum.ActiveSupport.html#content) - [REnum.Support](https://hexdocs.pm/r_enum/REnum.Support.html#content) """ defmacro __using__(opts) do diff --git a/lib/r_enum/active_support.ex b/lib/r_enum/active_support.ex index 2dd985d..157f6c8 100644 --- a/lib/r_enum/active_support.ex +++ b/lib/r_enum/active_support.ex @@ -6,7 +6,7 @@ defmodule REnum.ActiveSupport do @moduledoc """ Summarized all of Enumerable functions in Rails.ActiveSupport. If a function with the same name already exists in Elixir, that is not implemented. - Defines all of here functions when `use RUtils`. + Defines all of here functions when `use ActiveSupport`. """ @spec __using__(any) :: list defmacro __using__(_opts) do diff --git a/lib/r_list.ex b/lib/r_list.ex index c2ebe29..1a8df77 100644 --- a/lib/r_list.ex +++ b/lib/r_list.ex @@ -4,6 +4,7 @@ defmodule RList do See also. - [RList.Native](https://hexdocs.pm/r_enum/RList.Native.html#content) - [RList.Ruby](https://hexdocs.pm/r_enum/RList.Ruby.html#content) + - [RList.ActiveSupport](https://hexdocs.pm/r_enum/RList.ActiveSupport.html#content) - [REnum](https://hexdocs.pm/r_enum/REnum.html#content) """ use RList.Native diff --git a/lib/r_list/active_support.ex b/lib/r_list/active_support.ex index 83384b1..f40b64e 100644 --- a/lib/r_list/active_support.ex +++ b/lib/r_list/active_support.ex @@ -1,9 +1,39 @@ defmodule RList.ActiveSupport do @moduledoc """ - Unimplemented. + Summarized all of List functions in Rails.ActiveSupport. + If a function with the same name already exists in Elixir, that is not implemented. + Defines all of here functions when `use ActiveSupport`. """ @spec __using__(any) :: list defmacro __using__(_opts) do RUtils.define_all_functions!(__MODULE__) end + + @type type_enumerable :: Enumerable.t() + @type type_pattern :: number() | String.t() | Range.t() | Regex.t() + + # https://www.rubydoc.info/gems/activesupport/Array + # [:as_json, :compact_blank!, :deep_dup, :excluding, :extract!, :extract_options!, :fifth, :forty_two, :fourth, :from, :in_groups, :in_groups_of, :including, :inquiry, :second, :second_to_last, :split, :sum, :third, :third_to_last, :to, :to_default_s, :to_formatted_s, :to_param, :to_query, :to_s, :to_sentence, :to_xml] + # |> RUtils.required_functions([List, REnum]) + # as_json + # deep_dup + # fifth + # forty_two + # fourth + # from + # in_groups + # in_groups_of + # inquiry + # second + # second_to_last + # third + # third_to_last + # to + # to_default_s + # to_formatted_s + # to_param + # to_query + # to_s + # to_sentence + # to_xml end diff --git a/mix.exs b/mix.exs index 5a4daf0..6a68273 100644 --- a/mix.exs +++ b/mix.exs @@ -1,6 +1,6 @@ defmodule REnum.MixProject do use Mix.Project - @versoin "0.4.0" + @versoin "0.5.0" @source_url "https://github.com/tashirosota/ex-r_enum" @description "REnum is Enum extended with convenient functions inspired by Ruby and Rails ActiveSupport." def project do From 687b591a8b0e591680e4cd9dcfcc31a24cff84f7 Mon Sep 17 00:00:00 2001 From: Tashiro Date: Wed, 26 Jan 2022 12:01:32 +0900 Subject: [PATCH 2/9] fifth, forty_two, fourth, from, second, second_to_last, third, third_to_last, to --- lib/r_enum/active_support.ex | 2 +- lib/r_list/active_support.ex | 175 +++++++++++++++++++++++++--- mix.lock | 2 +- test/r_list/active_support_test.exs | 5 +- 4 files changed, 167 insertions(+), 17 deletions(-) diff --git a/lib/r_enum/active_support.ex b/lib/r_enum/active_support.ex index 157f6c8..d286fac 100644 --- a/lib/r_enum/active_support.ex +++ b/lib/r_enum/active_support.ex @@ -20,7 +20,7 @@ defmodule REnum.ActiveSupport do # https://www.rubydoc.info/gems/activesupport/Enumerable # ruby_enumerable = [:as_json, :compact_blank, :exclude?, :excluding, :in_order_of, :including, :index_by, :index_with, :many?, :maximum, :minimum, :pick, :pluck, :sole, :without] # |> RUtils.required_functions([Enum]) - # as_json + # × as_json # ✔ compact_blank # ✔ exclude? # ✔ excluding diff --git a/lib/r_list/active_support.ex b/lib/r_list/active_support.ex index f40b64e..802d12e 100644 --- a/lib/r_list/active_support.ex +++ b/lib/r_list/active_support.ex @@ -9,26 +9,23 @@ defmodule RList.ActiveSupport do RUtils.define_all_functions!(__MODULE__) end - @type type_enumerable :: Enumerable.t() - @type type_pattern :: number() | String.t() | Range.t() | Regex.t() - # https://www.rubydoc.info/gems/activesupport/Array # [:as_json, :compact_blank!, :deep_dup, :excluding, :extract!, :extract_options!, :fifth, :forty_two, :fourth, :from, :in_groups, :in_groups_of, :including, :inquiry, :second, :second_to_last, :split, :sum, :third, :third_to_last, :to, :to_default_s, :to_formatted_s, :to_param, :to_query, :to_s, :to_sentence, :to_xml] # |> RUtils.required_functions([List, REnum]) - # as_json - # deep_dup - # fifth - # forty_two - # fourth - # from + # × as_json + # × deep_dup + # ✔ fifth + # ✔ forty_two + # ✔ fourth + # ✔ from # in_groups # in_groups_of # inquiry - # second - # second_to_last - # third - # third_to_last - # to + # ✔ second + # ✔ second_to_last + # ✔ third + # ✔ third_to_last + # ✔ to # to_default_s # to_formatted_s # to_param @@ -36,4 +33,154 @@ defmodule RList.ActiveSupport do # to_s # to_sentence # to_xml + + @doc """ + Returns the tail of the list from position. + ## Examples + iex> ~w[a b c d] + ...> |> RList.from(0) + ["a", "b", "c", "d"] + + iex> ~w[a b c d] + ...> |> RList.from(2) + ["c", "d"] + + iex> ~w[a b c d] + ...> |> RList.from(10) + [] + + iex> ~w[] + ...> |> RList.from(0) + [] + + iex> ~w[a b c d] + ...> |> RList.from(-2) + ["c", "d"] + + iex> ~w[a b c d] + ...> |> RList.from(-10) + [] + """ + @spec from(list(), integer()) :: list() + def from(list, position) do + list + |> Enum.slice(position..Enum.count(list)) + end + + @doc """ + Returns the beginning of the list up to position. + ## Examples + iex> ~w[a b c d] + ...> |> RList.to(0) + ["a"] + + iex> ~w[a b c d] + ...> |> RList.to(2) + ["a", "b", "c"] + + iex> ~w[a b c d] + ...> |> RList.to(10) + ["a", "b", "c", "d"] + + iex> ~w[] + ...> |> RList.to(0) + [] + + iex> ~w[a b c d] + ...> |> RList.to(-2) + ["a", "b", "c"] + + iex> ~w[a b c d] + ...> |> RList.to(-10) + [] + """ + @spec to(list(), integer()) :: list() + def to(list, position) do + list + |> Enum.slice(0..position) + end + + @doc """ + Equal to `Enum.at(list, 1)`. + ## Examples + iex> ~w[a b c d] + ...> |> RList.second() + "b" + """ + @spec second(list()) :: any() + def second(list) do + Enum.at(list, 1) + end + + @doc """ + Equal to `Enum.at(list, 2)`. + ## Examples + iex> ~w[a b c d] + ...> |> RList.third() + "c" + """ + @spec third(list()) :: any() + def third(list) do + Enum.at(list, 2) + end + + @doc """ + Equal to `Enum.at(list, 3)`. + ## Examples + iex> ~w[a b c d] + ...> |> RList.fourth() + "d" + """ + @spec fourth(list()) :: any() + def fourth(list) do + Enum.at(list, 3) + end + + @doc """ + Equal to `Enum.at(list, 4)`. + ## Examples + iex> ~w[a b c d e] + ...> |> RList.fifth() + "e" + """ + @spec fifth(list()) :: any() + def fifth(list) do + Enum.at(list, 4) + end + + @doc """ + Equal to `Enum.at(list, 41)`. Also known as accessing "the reddit". + ## Examples + iex> 1..42 + ...> |> RList.forty_two() + 42 + """ + @spec forty_two(list()) :: any() + def forty_two(list) do + Enum.at(list, 41) + end + + @doc """ + Equal to `Enum.at(list, -2)`. + ## Examples + iex> ~w[a b c d e] + ...> |> RList.second_to_last() + "d" + """ + @spec second_to_last(list()) :: any() + def second_to_last(list) do + Enum.at(list, -2) + end + + @doc """ + Equal to `Enum.at(list, -3)`. + ## Examples + iex> ~w[a b c d e] + ...> |> RList.third_to_last() + "c" + """ + @spec third_to_last(list()) :: any() + def third_to_last(list) do + Enum.at(list, -3) + end end diff --git a/mix.lock b/mix.lock index 2e9c833..374d0ab 100644 --- a/mix.lock +++ b/mix.lock @@ -2,7 +2,7 @@ "dialyxir": {:hex, :dialyxir, "1.1.0", "c5aab0d6e71e5522e77beff7ba9e08f8e02bad90dfbeffae60eaf0cb47e29488", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "07ea8e49c45f15264ebe6d5b93799d4dd56a44036cf42d0ad9c960bc266c0b9a"}, "earmark_parser": {:hex, :earmark_parser, "1.4.19", "de0d033d5ff9fc396a24eadc2fcf2afa3d120841eb3f1004d138cbf9273210e8", [:mix], [], "hexpm", "527ab6630b5c75c3a3960b75844c314ec305c76d9899bb30f71cb85952a9dc45"}, "erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"}, - "ex_doc": {:hex, :ex_doc, "0.27.3", "d09ed7ab590b71123959d9017f6715b54a448d76b43cf909eb0b2e5a78a977b2", [:mix], [{:earmark_parser, "~> 1.4.19", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "ee60b329d08195039bfeb25231a208749be4f2274eae42ce38f9be0538a2f2e6"}, + "ex_doc": {:hex, :ex_doc, "0.28.0", "7eaf526dd8c80ae8c04d52ac8801594426ae322b52a6156cd038f30bafa8226f", [:mix], [{:earmark_parser, "~> 1.4.19", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "e55cdadf69a5d1f4cfd8477122ebac5e1fadd433a8c1022dafc5025e48db0131"}, "makeup": {:hex, :makeup, "1.0.5", "d5a830bc42c9800ce07dd97fa94669dfb93d3bf5fcf6ea7a0c67b2e0e4a7f26c", [:mix], [{:nimble_parsec, "~> 0.5 or ~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "cfa158c02d3f5c0c665d0af11512fed3fba0144cf1aadee0f2ce17747fba2ca9"}, "makeup_elixir": {:hex, :makeup_elixir, "0.15.2", "dc72dfe17eb240552857465cc00cce390960d9a0c055c4ccd38b70629227e97c", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.1", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "fd23ae48d09b32eff49d4ced2b43c9f086d402ee4fd4fcb2d7fad97fa8823e75"}, "makeup_erlang": {:hex, :makeup_erlang, "0.1.1", "3fcb7f09eb9d98dc4d208f49cc955a34218fc41ff6b84df7c75b3e6e533cc65f", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "174d0809e98a4ef0b3309256cbf97101c6ec01c4ab0b23e926a9e17df2077cbb"}, diff --git a/test/r_list/active_support_test.exs b/test/r_list/active_support_test.exs index e151d4a..d952491 100644 --- a/test/r_list/active_support_test.exs +++ b/test/r_list/active_support_test.exs @@ -1 +1,4 @@ -# TODO: +defmodule RList.ActiveSupportTest do + use ExUnit.Case + doctest RList.ActiveSupport +end From 39c42d794dc4b5e690ff0ceb8aa91ccad4d28ba9 Mon Sep 17 00:00:00 2001 From: Tashiro Date: Wed, 26 Jan 2022 12:08:21 +0900 Subject: [PATCH 3/9] readme --- CHANGELOG.md | 2 +- README.md | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 13e39a4..3b6b7e6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ # Changelog -## v0.5.0 (2022-1-xx) +## v0.5.0 (2022-1-26) ### Features diff --git a/README.md b/README.md index dbc02e4..c22e04b 100644 --- a/README.md +++ b/README.md @@ -30,15 +30,18 @@ You can use all of `Enum.Enumerable.*` functions through REnum Module. iex> [1, nil, 2, 3] iex> |> REnum.compact() [1, 2, 3] + # REnum.Ruby.grep/2 iex> ["foo", "bar", "car", "moo"] iex> |> REnum.grep(~r/ar/) ["bar", "car"] + # REnum.Ruby.each_slice/2 iex> [1, 2, 3, 4, 5, 6, 7] iex> |> REnum.each_slice(3) iex> |> REnum.to_list() [[1, 2, 3], [4, 5, 6], [7]] + # REnum.ActiveSupport.pluck/2 iex> payments = [ ...> %Payment{dollars: 5, cents: 99}, @@ -47,9 +50,11 @@ iex> payments = [ ...> ] iex> |> REnum.pluck(:dollars) [5, 10, 0] + # REnum.ActiveSupport.maximum/2 iex> REnum.maximum(payments, :dollars) 10 + # REnum.ActiveSupport.without/2 iex> 1..5 iex> |> REnum.without([1, 5]) @@ -62,22 +67,37 @@ iex> |> Enum.to_list() [[1,2,3],[1,2,4],[1,3,4],[2,3,4]] # See also RList.Ruby.repeated_combination, RList.Ruby.permutation, RList.Ruby.repeated_permutation +# RList.Ruby.push/2 iex> [:foo, 'bar', 2] iex> |> RList.push([:baz, :bat]) [:foo, 'bar', 2, :baz, :bat] # See also RList.Ruby.pop, RList.Ruby.shift, RList.Ruby.unshift +# RList.ActiveSupport.second/1 +iex> [:foo, 'bar', 2] +iex> |> RList.second() +'bar' +# See also RList.ActiveSupport.second, RList.ActiveSupport.third, RList.ActiveSupport.fourth, RList.ActiveSupport.fifth, RList.ActiveSupport.forty_two + +# RList.ActiveSupport.from/2 +iex> ~w[a b c d] +iex> |> RList.from(2) +["c", "d"] +# See also RList.ActiveSupport.to + # Aliases. # REnum.Ruby.select2 iex> [1, 2, 3] iex> |> REnum.select(fn x -> rem(x, 2) == 0 end) == iex> Enum.filter([1, 2, 3], fn x -> rem(x, 2) == 0 end) true + # Can use Elixir's Enum functions too. # REnum.Ruby.find/2 iex> [1, 2, 3] iex> |> REnum.find(fn x -> rem(x, 2) == 1 end) 3 + # REnum.Ruby.sort/1 iex> [1, 2, 3] iex> REnum.sort() From 128138ae2df4c810f02603245874807128768915 Mon Sep 17 00:00:00 2001 From: Tashiro Date: Wed, 26 Jan 2022 12:41:26 +0900 Subject: [PATCH 4/9] to_sentence --- README.md | 15 ++++---- lib/r_list/active_support.ex | 68 ++++++++++++++++++++++++++++++++++-- 2 files changed, 73 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index c22e04b..da3b44b 100644 --- a/README.md +++ b/README.md @@ -51,10 +51,6 @@ iex> payments = [ iex> |> REnum.pluck(:dollars) [5, 10, 0] -# REnum.ActiveSupport.maximum/2 -iex> REnum.maximum(payments, :dollars) -10 - # REnum.ActiveSupport.without/2 iex> 1..5 iex> |> REnum.without([1, 5]) @@ -85,11 +81,16 @@ iex> |> RList.from(2) ["c", "d"] # See also RList.ActiveSupport.to +# RList.ActiveSupport.to_sentence/2 +iex> ["one", "two", "three"] +iex> |> RList.to_sentence(words_connector: " or ", last_word_connector: " or at least ") +"one or two or at least three" + # Aliases. -# REnum.Ruby.select2 +# REnum.Ruby.select/2 iex> [1, 2, 3] iex> |> REnum.select(fn x -> rem(x, 2) == 0 end) == -iex> Enum.filter([1, 2, 3], fn x -> rem(x, 2) == 0 end) +...> Enum.filter([1, 2, 3], fn x -> rem(x, 2) == 0 end) true # Can use Elixir's Enum functions too. @@ -100,7 +101,7 @@ iex> |> REnum.find(fn x -> rem(x, 2) == 1 end) # REnum.Ruby.sort/1 iex> [1, 2, 3] -iex> REnum.sort() +iex> |> REnum.sort() [1, 2, 3] ``` diff --git a/lib/r_list/active_support.ex b/lib/r_list/active_support.ex index 802d12e..04b8466 100644 --- a/lib/r_list/active_support.ex +++ b/lib/r_list/active_support.ex @@ -26,12 +26,12 @@ defmodule RList.ActiveSupport do # ✔ third # ✔ third_to_last # ✔ to - # to_default_s + # × to_default_s # to_formatted_s # to_param # to_query - # to_s - # to_sentence + # ✔ to_s + # ✔ to_sentence # to_xml @doc """ @@ -183,4 +183,66 @@ defmodule RList.ActiveSupport do def third_to_last(list) do Enum.at(list, -3) end + + @doc """ + Equal to `inspect(list)`. + ## Examples + iex> [1, 2, 3, 4] + ...> |> RList.to_s() + "[1, 2, 3, 4]" + """ + @spec to_s(list()) :: String.t() + def to_s(list) do + list |> inspect() + end + + @doc """ + Converts the list to a comma-separated sentence where the last element is + joined by the connector word. + + You can pass the following options to change the default behavior. If you + pass an option key that doesn't exist in the list below, it will raise an + + ** Options ** + * `:words_connector` - The sign or word used to join all but the last + element in lists with three or more elements (default: ", "). + * `:last_word_connector` - The sign or word used to join the last element + in lists with three or more elements (default: ", and "). + * `:two_words_connector` - The sign or word used to join the elements + in lists with two elements (default: " and "). + + ## Examples + iex> ["one", "two"] + ...> |> RList.to_sentence() + "one and two" + + iex> ["one", "two", "three"] + ...> |> RList.to_sentence() + "one, two, and three" + + iex> ["one", "two"] + ...> |> RList.to_sentence(two_words_connector: "-") + "one-two" + + iex> ["one", "two", "three"] + ...> |> RList.to_sentence(words_connector: " or ", last_word_connector: " or at least ") + "one or two or at least three" + + iex> ["one", "two", "three"] + ...> |> RList.to_sentence() + "one, two, and three" + """ + @spec to_sentence(list(), list(keyword()) | nil) :: String.t() + def to_sentence(list, opts \\ []) do + words_connector = Keyword.get(opts, :words_connector) || ", " + two_words_connector = Keyword.get(opts, :two_words_connector) || " and " + last_word_connector = Keyword.get(opts, :last_word_connector) || ", and " + + case Enum.count(list) do + 0 -> "" + 1 -> "#{Enum.at(list, 0)}" + 2 -> "#{Enum.at(list, 0)}#{two_words_connector}#{Enum.at(list, 1)}" + _ -> "#{to(list, -2) |> Enum.join(words_connector)}#{last_word_connector}#{List.last(list)}" + end + end end From 18e4d54b71ffff9531bd6926c9fef6614d7f47b4 Mon Sep 17 00:00:00 2001 From: Tashiro Date: Wed, 26 Jan 2022 13:13:18 +0900 Subject: [PATCH 5/9] wip in_groups --- README.md | 4 ++ lib/r_list/active_support.ex | 100 +++++++++++++++++++++-------------- lib/r_list/ruby.ex | 1 - 3 files changed, 63 insertions(+), 42 deletions(-) diff --git a/README.md b/README.md index da3b44b..869ca94 100644 --- a/README.md +++ b/README.md @@ -135,6 +135,10 @@ See **[hexdocs](https://hexdocs.pm/r_enum)**. - RRange.Ruby - RRange.ActiveSupport - [ ] 0.8.0 + - to_param + - to_query + - to_xml +- [ ] 0.9.0 - RStream.Ruby - RStream.ActiveSupport diff --git a/lib/r_list/active_support.ex b/lib/r_list/active_support.ex index 04b8466..01635df 100644 --- a/lib/r_list/active_support.ex +++ b/lib/r_list/active_support.ex @@ -11,14 +11,14 @@ defmodule RList.ActiveSupport do # https://www.rubydoc.info/gems/activesupport/Array # [:as_json, :compact_blank!, :deep_dup, :excluding, :extract!, :extract_options!, :fifth, :forty_two, :fourth, :from, :in_groups, :in_groups_of, :including, :inquiry, :second, :second_to_last, :split, :sum, :third, :third_to_last, :to, :to_default_s, :to_formatted_s, :to_param, :to_query, :to_s, :to_sentence, :to_xml] - # |> RUtils.required_functions([List, REnum]) + # |> RUtils.required_functions([List, RList.Ruby, REnum]) # × as_json # × deep_dup # ✔ fifth # ✔ forty_two # ✔ fourth # ✔ from - # in_groups + # ✔ in_groups # in_groups_of # inquiry # ✔ second @@ -26,11 +26,10 @@ defmodule RList.ActiveSupport do # ✔ third # ✔ third_to_last # ✔ to - # × to_default_s - # to_formatted_s + # ✔ to_default_s + # × to_formatted_s # to_param # to_query - # ✔ to_s # ✔ to_sentence # to_xml @@ -38,27 +37,27 @@ defmodule RList.ActiveSupport do Returns the tail of the list from position. ## Examples iex> ~w[a b c d] - ...> |> RList.from(0) + iex> |> RList.from(0) ["a", "b", "c", "d"] iex> ~w[a b c d] - ...> |> RList.from(2) + iex> |> RList.from(2) ["c", "d"] iex> ~w[a b c d] - ...> |> RList.from(10) + iex> |> RList.from(10) [] iex> ~w[] - ...> |> RList.from(0) + iex> |> RList.from(0) [] iex> ~w[a b c d] - ...> |> RList.from(-2) + iex> |> RList.from(-2) ["c", "d"] iex> ~w[a b c d] - ...> |> RList.from(-10) + iex> |> RList.from(-10) [] """ @spec from(list(), integer()) :: list() @@ -71,27 +70,27 @@ defmodule RList.ActiveSupport do Returns the beginning of the list up to position. ## Examples iex> ~w[a b c d] - ...> |> RList.to(0) + iex> |> RList.to(0) ["a"] iex> ~w[a b c d] - ...> |> RList.to(2) + iex> |> RList.to(2) ["a", "b", "c"] iex> ~w[a b c d] - ...> |> RList.to(10) + iex> |> RList.to(10) ["a", "b", "c", "d"] iex> ~w[] - ...> |> RList.to(0) + iex> |> RList.to(0) [] iex> ~w[a b c d] - ...> |> RList.to(-2) + iex> |> RList.to(-2) ["a", "b", "c"] iex> ~w[a b c d] - ...> |> RList.to(-10) + iex> |> RList.to(-10) [] """ @spec to(list(), integer()) :: list() @@ -104,7 +103,7 @@ defmodule RList.ActiveSupport do Equal to `Enum.at(list, 1)`. ## Examples iex> ~w[a b c d] - ...> |> RList.second() + iex> |> RList.second() "b" """ @spec second(list()) :: any() @@ -116,7 +115,7 @@ defmodule RList.ActiveSupport do Equal to `Enum.at(list, 2)`. ## Examples iex> ~w[a b c d] - ...> |> RList.third() + iex> |> RList.third() "c" """ @spec third(list()) :: any() @@ -128,7 +127,7 @@ defmodule RList.ActiveSupport do Equal to `Enum.at(list, 3)`. ## Examples iex> ~w[a b c d] - ...> |> RList.fourth() + iex> |> RList.fourth() "d" """ @spec fourth(list()) :: any() @@ -140,7 +139,7 @@ defmodule RList.ActiveSupport do Equal to `Enum.at(list, 4)`. ## Examples iex> ~w[a b c d e] - ...> |> RList.fifth() + iex> |> RList.fifth() "e" """ @spec fifth(list()) :: any() @@ -152,7 +151,7 @@ defmodule RList.ActiveSupport do Equal to `Enum.at(list, 41)`. Also known as accessing "the reddit". ## Examples iex> 1..42 - ...> |> RList.forty_two() + iex> |> RList.forty_two() 42 """ @spec forty_two(list()) :: any() @@ -164,7 +163,7 @@ defmodule RList.ActiveSupport do Equal to `Enum.at(list, -2)`. ## Examples iex> ~w[a b c d e] - ...> |> RList.second_to_last() + iex> |> RList.second_to_last() "d" """ @spec second_to_last(list()) :: any() @@ -176,7 +175,7 @@ defmodule RList.ActiveSupport do Equal to `Enum.at(list, -3)`. ## Examples iex> ~w[a b c d e] - ...> |> RList.third_to_last() + iex> |> RList.third_to_last() "c" """ @spec third_to_last(list()) :: any() @@ -184,18 +183,6 @@ defmodule RList.ActiveSupport do Enum.at(list, -3) end - @doc """ - Equal to `inspect(list)`. - ## Examples - iex> [1, 2, 3, 4] - ...> |> RList.to_s() - "[1, 2, 3, 4]" - """ - @spec to_s(list()) :: String.t() - def to_s(list) do - list |> inspect() - end - @doc """ Converts the list to a comma-separated sentence where the last element is joined by the connector word. @@ -213,23 +200,23 @@ defmodule RList.ActiveSupport do ## Examples iex> ["one", "two"] - ...> |> RList.to_sentence() + iex> |> RList.to_sentence() "one and two" iex> ["one", "two", "three"] - ...> |> RList.to_sentence() + iex> |> RList.to_sentence() "one, two, and three" iex> ["one", "two"] - ...> |> RList.to_sentence(two_words_connector: "-") + iex> |> RList.to_sentence(two_words_connector: "-") "one-two" iex> ["one", "two", "three"] - ...> |> RList.to_sentence(words_connector: " or ", last_word_connector: " or at least ") + iex> |> RList.to_sentence(words_connector: " or ", last_word_connector: " or at least ") "one or two or at least three" iex> ["one", "two", "three"] - ...> |> RList.to_sentence() + iex> |> RList.to_sentence() "one, two, and three" """ @spec to_sentence(list(), list(keyword()) | nil) :: String.t() @@ -245,4 +232,35 @@ defmodule RList.ActiveSupport do _ -> "#{to(list, -2) |> Enum.join(words_connector)}#{last_word_connector}#{List.last(list)}" end end + + @doc """ + ## Examples + iex> ~w[1 2 3 4 5 6 7 8 9 10] + iex> |> RList.in_groups(3) + [ + ["1", "2", "3", "4"], + ["5", "6", "7", nil], + ["8", "9", "10", nil] + ] + + iex> ~w[1 2 3 4 5 6 7 8 9 10] + iex> |> RList.in_groups(3, ' ') + [ + ["1", "2", "3", "4"], + ["5", "6", "7", " "], + ["8", "9", "10", " "] + ] + + iex> ~w[1 2 3 4 5 6 7] + iex> |> RList.in_groups(3, false) + [ + ["1", "2", "3"], + ["4", "5"], + ["6", "7"] + ] + """ + def in_groups(list, number, fill_with \\ nil) do + end + + defdelegate to_default_s(list), to: Kernel, as: :inspect end diff --git a/lib/r_list/ruby.ex b/lib/r_list/ruby.ex index 07a8a00..6e7d568 100644 --- a/lib/r_list/ruby.ex +++ b/lib/r_list/ruby.ex @@ -25,7 +25,6 @@ defmodule RList.Ruby do # × bsearch_index # ✔ clear # ✔ combination - # deconstruct # × deconstruct # ✔ delete_if # ✔ difference From 4a93924df71e2f9a3a0d0b361a4beaddd3c2e8bb Mon Sep 17 00:00:00 2001 From: Tashiro Date: Wed, 26 Jan 2022 13:15:34 +0900 Subject: [PATCH 6/9] actions --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4e85786..fde34b6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,5 +1,5 @@ name: CI -on: [push, pull_request] +on: [push] jobs: native_test: name: OTP ${{matrix.otp}} / Elixir ${{matrix.elixir}} From 653892b6c346009fd34597739abc2700981ec431 Mon Sep 17 00:00:00 2001 From: Tashiro Date: Wed, 26 Jan 2022 14:46:19 +0900 Subject: [PATCH 7/9] in_groups --- lib/r_list/active_support.ex | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/lib/r_list/active_support.ex b/lib/r_list/active_support.ex index 01635df..ccbd7a4 100644 --- a/lib/r_list/active_support.ex +++ b/lib/r_list/active_support.ex @@ -234,6 +234,7 @@ defmodule RList.ActiveSupport do end @doc """ + Splits or iterates over the list in number of groups, padding any remaining slots with fill_with unless it is false. ## Examples iex> ~w[1 2 3 4 5 6 7 8 9 10] iex> |> RList.in_groups(3) @@ -244,7 +245,7 @@ defmodule RList.ActiveSupport do ] iex> ~w[1 2 3 4 5 6 7 8 9 10] - iex> |> RList.in_groups(3, ' ') + iex> |> RList.in_groups(3, " ") [ ["1", "2", "3", "4"], ["5", "6", "7", " "], @@ -259,7 +260,36 @@ defmodule RList.ActiveSupport do ["6", "7"] ] """ + @spec in_groups(list(), non_neg_integer(), any() | nil) :: list() def in_groups(list, number, fill_with \\ nil) do + division = div(Enum.count(list), number) + modulo = rem(Enum.count(list), number) + range = 0..(number - 1) + + length_list = + range + |> Enum.map(&(division + if(modulo > 0 && modulo > &1, do: 1, else: 0))) + |> IO.inspect() + + range + |> Enum.reduce([], fn index, acc -> + length = length_list |> Enum.at(index) + + group = + Enum.slice( + list, + length_list + |> Enum.take(index) + |> Enum.sum(), + length + ) + + if fill_with != false && modulo > 0 && length == division do + acc ++ [group ++ [fill_with]] + else + acc ++ [group] + end + end) end defdelegate to_default_s(list), to: Kernel, as: :inspect From c322a78a6cf13411b3d0b07ea83bb6b3e4c8dc95 Mon Sep 17 00:00:00 2001 From: Tashiro Date: Wed, 26 Jan 2022 15:17:24 +0900 Subject: [PATCH 8/9] in_groups_of --- lib/r_list.ex | 1 + lib/r_list/active_support.ex | 44 +++++++++++++++++++++++++++++++++++- lib/r_list/support.ex | 38 +++++++++++++++++++++++++++++++ test/r_list/support_test.exs | 4 ++++ 4 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 lib/r_list/support.ex create mode 100644 test/r_list/support_test.exs diff --git a/lib/r_list.ex b/lib/r_list.ex index 1a8df77..3ae154f 100644 --- a/lib/r_list.ex +++ b/lib/r_list.ex @@ -10,5 +10,6 @@ defmodule RList do use RList.Native use RList.Ruby use RList.ActiveSupport + use RList.Support use REnum, undelegate_functions: List.module_info()[:exports] |> Keyword.keys() end diff --git a/lib/r_list/active_support.ex b/lib/r_list/active_support.ex index ccbd7a4..f56c9d5 100644 --- a/lib/r_list/active_support.ex +++ b/lib/r_list/active_support.ex @@ -9,6 +9,8 @@ defmodule RList.ActiveSupport do RUtils.define_all_functions!(__MODULE__) end + alias RList.Support + # https://www.rubydoc.info/gems/activesupport/Array # [:as_json, :compact_blank!, :deep_dup, :excluding, :extract!, :extract_options!, :fifth, :forty_two, :fourth, :from, :in_groups, :in_groups_of, :including, :inquiry, :second, :second_to_last, :split, :sum, :third, :third_to_last, :to, :to_default_s, :to_formatted_s, :to_param, :to_query, :to_s, :to_sentence, :to_xml] # |> RUtils.required_functions([List, RList.Ruby, REnum]) @@ -19,7 +21,7 @@ defmodule RList.ActiveSupport do # ✔ fourth # ✔ from # ✔ in_groups - # in_groups_of + # ✔ in_groups_of # inquiry # ✔ second # ✔ second_to_last @@ -292,5 +294,45 @@ defmodule RList.ActiveSupport do end) end + @doc """ + Splits or iterates over the list in groups of size number, padding any remaining slots with fill_with unless it is +false+. + ## Examples + iex> ~w[1 2 3 4 5 6 7 8 9 10] + iex> |> RList.in_groups_of(3) + [ + ["1", "2", "3"], + ["4", "5", "6"], + ["7", "8", "9"], + ["10", nil, nil] + ] + + iex> ~w[1 2 3 4 5] + iex> |> RList.in_groups_of(2, " ") + [ + ["1", "2"], + ["3", "4"], + ["5", " "] + ] + + iex> ~w[1 2 3 4 5] + iex> |> RList.in_groups_of(2, false) + [ + ["1", "2"], + ["3", "4"], + ["5"] + ] + """ + @spec in_groups_of(list(), non_neg_integer(), any() | nil) :: list() + def in_groups_of(list, number, fill_with \\ nil) do + if(fill_with == false) do + list + else + padding = rem(number - rem(Enum.count(list), number), number) + list ++ Support.new(fill_with, padding) + end + |> REnum.each_slice(number) + |> Enum.to_list() + end + defdelegate to_default_s(list), to: Kernel, as: :inspect end diff --git a/lib/r_list/support.ex b/lib/r_list/support.ex new file mode 100644 index 0000000..ad55d73 --- /dev/null +++ b/lib/r_list/support.ex @@ -0,0 +1,38 @@ +defmodule RList.Support do + @moduledoc """ + Summarized other useful functions related to Lit. + Defines all of here functions when `use RList.Support`. + """ + @spec __using__(any) :: list + defmacro __using__(_opts) do + RUtils.define_all_functions!(__MODULE__) + end + + @type type_enumerable :: Enumerable.t() + + @spec new(any) :: [...] + @doc """ + Equal to `[el]`. + ## Examples + iex> 1 + iex> |> RList.new() + [1] + """ + def new(el) do + [el] + end + + @doc """ + Make a list of size amount. + ## Examples + iex> 1 + iex> |> RList.new(3) + [1, 1, 1] + """ + def new(el, amount) do + 1..amount + |> Enum.map(fn _ -> + el + end) + end +end diff --git a/test/r_list/support_test.exs b/test/r_list/support_test.exs new file mode 100644 index 0000000..ff29409 --- /dev/null +++ b/test/r_list/support_test.exs @@ -0,0 +1,4 @@ +defmodule RList.RList.SupportTest do + use ExUnit.Case + doctest RList.Support +end From 88678c66d845980c35c6d02c2331b9f1c1d0d2b9 Mon Sep 17 00:00:00 2001 From: Tashiro Date: Wed, 26 Jan 2022 15:22:50 +0900 Subject: [PATCH 9/9] @spec --- lib/r_list/support.ex | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/r_list/support.ex b/lib/r_list/support.ex index ad55d73..a604b0e 100644 --- a/lib/r_list/support.ex +++ b/lib/r_list/support.ex @@ -10,7 +10,6 @@ defmodule RList.Support do @type type_enumerable :: Enumerable.t() - @spec new(any) :: [...] @doc """ Equal to `[el]`. ## Examples @@ -18,6 +17,7 @@ defmodule RList.Support do iex> |> RList.new() [1] """ + @spec new(any()) :: list() def new(el) do [el] end @@ -29,6 +29,7 @@ defmodule RList.Support do iex> |> RList.new(3) [1, 1, 1] """ + @spec new(any(), non_neg_integer()) :: list() def new(el, amount) do 1..amount |> Enum.map(fn _ ->