[Elixir]RubyやRailsのメソッドは便利なものが多いので、それらをElixirでも使えるようにしたライブラリをリリースしました。

## 多言語を習得する際の困り事

「Rubyだと配列からnullを排除する時 `compact`で出来たけど、Elixirだとどう書くんだろう。。
あれ、`Enum.select` って無いのか `Enum.filter`を使えばいいのね！」

Elixirを学習中に、上記のような **ちょっと調べればわかるけれども、ちょっと調べないといけない**ような事が、ちょくちょく発生しました。
## RubyやRailsのEnumerable系メソッドをElixirでも使えるようにしました！

RubyやRailsはその歴史の長さや、コミュニティの厚さにより、便利なmethodや直感的なaliasが多数定義されてます。
それらの資産を有効活用できないかと思い、**REnum**という、ElixirのmoduleをRuby/Rails風に拡張したライブラリをリリースしました。

https://hexdocs.pm/r_enum/readme.html

なぜ、Enum（Enumerable）等に焦点を当てたかというと、Elixirの得意とするデータ変換にはEnum（Enumerable）等の拡張がもっとも有意に働くと思ったからです。

ElixirはRubyの文法の影響を大きく受けた言語でもあるので、Ruby => Elixirを学ぶ方はとても多いと感じております。そのような方の助けになりましたら幸いです。僕もそのうちの一人です。
## 機能紹介
### RubyのEnumerableから移植してきたおすすめな関数達
#### compact(enumerable)
与えられた`enumerable`からnil以外のすべての要素を排除。

```elixir
iex> [1, nil, 2, 3]
iex> |> REnum.compact()
[1, 2, 3]
```

#### each_slice(enumerable, amount, func)
`amount`毎に与えられた`enumerable`を分割し、各ブロックにfuncを適応して`enumerable`を返却。

```elixir
iex> ["a", "b", "c", "d", "e"]
iex> |> REnum.each_slice(2, &IO.inspect(&1))
# ["a", "b"]
# ["c", "d"]
# ["e"]
["a", "b", "c", "d", "e"]
```

#### tally(enumerable)
等しい要素をkey, それらのカウントをvalueに持つマップを返却。

```elixir
iex> ~w(a c d b c a)
iex> |> REnum.tally()
%{"a" => 2, "c" => 2, "d" => 1, "b" => 1}
```

#### grep(enumerable, func_or_pattern)
与えられた関数やパターンに一致する要素を選んで返却。

```elixir
iex> ["foo", "bar", "car", "moo"]
iex> |> REnum.grep(~r/ar/)
["bar", "car"]

iex> 1..10
iex> |> REnum.grep(3..8)
[3, 4, 5, 6, 7, 8]
```

#### Alias
 - select（filterのalias）
 - detect（findのalias）
 - each_with_object（reduce/3のalias）
 - inject（reduceのalias）
 - include?（member?のalias）

### RailsのActiveSupportから移植してきたおすすめな関数達
#### exclude?(enumerable, element)
`Enum.member?`の逆。`element`が`enumerable`に含まれない場合にtrueを返却。

```elixir
iex> REnum.exclude?([2], 1)
true

iex> REnum.exclude?([2], 2)
false
```

#### without(enumerable, elements)
`elements` を除いて `enumerable` を返却。

```elixir
iex> REnum.without(1..5, [1, 5])
[2, 3, 4]

iex> REnum.without(%{foo: 1, bar: 2, baz: 3}, [:bar])
%{foo: 1, baz: 3}

```

#### in_order_of(map_list, key, series)
元の `map_list` の要素の`key`に基づき、`series` で提供される順序に設定されたリストを返却。

```elixir
iex> payments = [
...>   %Payment{dollars: 5, cents: 99},
...>   %Payment{dollars: 10, cents: 0},
...>   %Payment{dollars: 0, cents: 5}
...> ]
iex> REnum.in_order_of(payments, :cents, [0, 5])
[
  %Payment{cents: 0, dollars: 10},
  %Payment{cents: 5, dollars: 0}
]
```

#### pluck(map_list, keys_or_key)
`map_list` から、与えられた`keys`のvalueを返却。

```elixir
iex> payments = [
...>   %Payment{dollars: 5, cents: 99},
...>   %Payment{dollars: 10, cents: 0},
...>   %Payment{dollars: 0, cents: 5}
...> ]
iex> REnum.pluck(payments, [:dollars, :cents])
[[5, 99], [10, 0], [0, 5]]
iex> REnum.pluck(payments, :dollars)
[5, 10, 0]
iex> REnum.pluck([], :dollars)
[]
```

#### blank?（any）
`any` が空白、偽、空、または空白文字列である場合にtrueを返却。
例えば、nil, "", " ", [], {}, falseはtrueに該当する。

```elixir
iex> REnum.Utils.blank?(%{})
true

iex> REnum.Utils.blank?([1])
false

iex> REnum.Utils.blank?("  ")
true
```

`present?（any）`は`blank?`の偽を示す。

### その他、個人的に解せなかった部分を解消した関数達
#### find_index_with_index(enumerable, func)
find_indexの際にfuncの第２引数としてcurrent_indexを渡せる用にした関数。

```elixir
iex> REnum.find_index_with_index(1..3, fn el, index ->
...>   IO.inspect(index)
...>   el == 2
...> end)
# 0
# 1
1
```
#### list_and_not_keyword?(enumerable)
keyword listとlistを区別する関数。

```elixir
iex> REnum.list_and_not_keyword?([1, 2, 3])
true

iex> REnum.list_and_not_keyword?([a: 1, b: 2])
false
```
#### map_and_not_range?(enumerable)
is_map(1..3) == trueなのが解せなくて作った関数。

```elixir
iex> REnum.map_and_not_range?(%{})
true

iex> REnum.map_and_not_range?(1..3)
false
```

## REnumは既存のEnum関数もすべて滞りなく使えます。

https://qiita.com/sotashiro/items/b06c33943dcb68d33d8b

REnumはメタプログラミングにより、,ElixirのEnumや対応するEnumerable系のfunctionsを全て移譲しています。
なので、以下動作も問題なく使うことが出来ます。

```elixir
iex> list = [1, 2, 3]
iex> REnum.find(list ,fn x -> rem(x, 2) == 1 end) == Enum.find(list ,fn x -> rem(x, 2) == 1 end)
true
iex> REnum.sort(list) == Enum.sort(list)
true
```

コード内の`Enum.*`を`REnum.*`に置き換えても問題なく動くはずです。

## 終わりに
実装に関しては手が空いたタイミングで少しずつ拡充していこうと思っています。現在はEnumerable系の実装が終わり、List系の実装を開始しております。
もしよろしければスター等頂けましたら幸いです。コントリビュートも大歓迎です。

https://github.com/tashirosota/ex-r_enum

ロードマップは以下通り。

```
- [x] 0.1.0
  - REnum.Enumerable.Native
  - REnum.Enumerable.Ruby
  - REnum.Enumerable.Support
  - REnum.List.Native
  - REnum.Map.Native
  - REnum.Range.Native
  - REnum.Stream.Native
  - REnum.Utils
- [x] 0.2.0
  - REnum.Enumerable.ActiveSupport
- [ ] 0.3.0
  - REnum.List.Ruby
- [ ] 0.4.0
  - REnum.List.ActiveSupport
- [ ] 0.5.0
  - REnum.Map.Ruby
  - REnum.Map.ActiveSupport
- [ ] 0.6.0
  - REnum.Range.Ruby
  - REnum.Range.ActiveSupport
- [ ] 0.7.0
  - REnum.Stream.Ruby
  - REnum.Stream.ActiveSupport
```