【#FizzBuzz】Elixirで”1から100までの数字を数えて3の倍数と3の付く数字のときにだけアホになる”というのを書いてみる

# はじめに
- @kukita さんの [【#FizzBuzz】いろいろな言語で”1から100までの数字を数えて3の倍数と3の付く数字のときにだけアホになる”というのを書いてみる](https://qiita.com/kukita/items/c56f241c036a7e1a3ebe) を拝見しまして、私はぜひ[Elixir](https://elixir-lang.org/)でやってみようとおもいました
- [Elixir](https://elixir-lang.org/)は、`1.10.3`を使いました

```
$ elixir -v
Erlang/OTP 23 [erts-11.0.2] [source] [64-bit] [smp:72:2] [ds:72:2:10] [async-threads:1] [hipe]

Elixir 1.10.3 (compiled with Erlang/OTP 23)
```

# ハイライト

```elixir:nabeatsu.ex
defmodule Nabeatsu do
  def fizz_buzz(n) when rem(n, 3) == 0, do: do_joke(n)
  def fizz_buzz(n), do: do_fizz_buzz(n, String.contains?("#{n}", "3"))
  defp do_fizz_buzz(n, true), do: do_joke(n)
  defp do_fizz_buzz(n, false), do: "#{n}"
  defp do_joke(n), do: "#{n} : ٩( ᐛ )و"
end
```
- `Nabeatsu.fizz_buzz/1`がキモです
- `n`が3で割り切れる場合には、`do_joke`を実行しています
- `n`が3で割り切れない場合には、`do_fizz_buzz`を呼び出して、3が含まれれいるかどうかで返す結果を変えています


# 0. 準備
- まずは[Elixir](https://elixir-lang.org/)をインストールしましょう
- Windowsの方は
    - [公式](https://elixir-lang.org/install.html#windows) のインストーラーがあります
- macOSの方は
    - a. [asdf-vm](https://asdf-vm.com/#/)を使ってインストールする(オススメ)
        - (参考) [macOS Catalina(10.15.5)にasdfでElixirをインストールする](https://qiita.com/torifukukaiou/items/75fa25c55ce2f0b92496)
        - [Erlang](https://www.erlang.org/)のインストールにけっこう時間がかかります
    - b. [Homebrew](https://brew.sh/index_ja)を使ってインストールする
        - `$ brew install elixir`
        - まず手軽に試してみる感じならこちらのほうが詰まるところは少ないとおもいます
- Linuxの方は、[asdf-vm](https://asdf-vm.com/#/)がよいとおもいます(ふだんあまり使っていないのでよくわかっていません)

# 1. プロジェクト作成(mix new)

```
$ mix new playground
``` 
- `playground` はプロジェクト名です
- お好きな名前でかまいません

# 2. ソースコードを書く

```elixir:nabeatsu.ex
defmodule Nabeatsu do
  @moduledoc false

  @doc ~S"""
  世界のナベアツ
  Would you please see https://ja.wikipedia.org/wiki/%E6%A1%82%E4%B8%89%E5%BA%A6 ?

  ## Examples

      iex> Nabeatsu.fizz_buzz(1)
      "1"
      iex> Nabeatsu.fizz_buzz(3)
      "3 : ٩( ᐛ )و"
      iex> Nabeatsu.fizz_buzz(13)
      "13 : ٩( ᐛ )و"
      iex> Nabeatsu.fizz_buzz(30)
      "30 : ٩( ᐛ )و"
      iex> Nabeatsu.fizz_buzz(100)
      "100"

  """
  def fizz_buzz(n) when rem(n, 3) == 0, do: do_joke(n)
  def fizz_buzz(n), do: do_fizz_buzz(n, String.contains?("#{n}", "3"))
  defp do_fizz_buzz(n, true), do: do_joke(n)
  defp do_fizz_buzz(n, false), do: "#{n}"
  defp do_joke(n), do: "#{n} : ٩( ᐛ )و"
end
```

- `Nabeatsu.fizz_buzz/1` という関数を定義しています
    - `/1`は引数の数です
- `Nabeatsu.fizz_buzz(3)`のように呼び出します
- [Doctests](https://elixir-lang.org/getting-started/mix-otp/docs-tests-and-with.html#doctests)で、`Nabeatsu.fizz_buzz/1`関数のテストを書いています

# 3. テストを実行する

```elixir:playground_test.exs
defmodule PlaygroundTest do
  use ExUnit.Case
  doctest Playground
  doctest Nabeatsu # 追加
```

```
$ mix test
```
- `playground`フォルダ(`mix.exs`があるところ)で実行してください

```elixir:nabeatsu.ex
  ## Examples

      iex> Nabeatsu.fizz_buzz(1)
      "3"
```
- たとえば上記のように書きかえるとテストが失敗します
- ちゃんとテストが実行されていることを確かめたら正しい結果に戻しておきましょう

# 4. 1から100までの数字を数えて3の倍数と3の付く数字のときにだけアホになる
- テストで`Nabeatsu.fizz_buzz/1`関数に自信がもてました
- `run`関数を追加しました
    - `max \\ 100` はmaxの指定がない場合に100になるという意味です
    - [Default arguments](https://elixir-lang.org/getting-started/modules-and-functions.html#default-arguments)
- ソースコード全体を掲載しておきます

```elixir:nabeatsu.ex
defmodule Nabeatsu do
  @moduledoc false

  def run(max \\ 100) do
    1..max
    |> Enum.map(&fizz_buzz/1)
    |> Enum.each(&IO.puts/1)
  end

  @doc ~S"""
  世界のナベアツ
  Would you please see https://ja.wikipedia.org/wiki/%E6%A1%82%E4%B8%89%E5%BA%A6 ?

  ## Examples

      iex> Nabeatsu.fizz_buzz(1)
      "1"
      iex> Nabeatsu.fizz_buzz(3)
      "3 : ٩( ᐛ )و"
      iex> Nabeatsu.fizz_buzz(13)
      "13 : ٩( ᐛ )و"
      iex> Nabeatsu.fizz_buzz(30)
      "30 : ٩( ᐛ )و"
      iex> Nabeatsu.fizz_buzz(100)
      "100"

  """
  def fizz_buzz(n) when rem(n, 3) == 0, do: do_joke(n)
  def fizz_buzz(n), do: do_fizz_buzz(n, String.contains?("#{n}", "3"))
  defp do_fizz_buzz(n, true), do: do_joke(n)
  defp do_fizz_buzz(n, false), do: "#{n}"
  defp do_joke(n), do: "#{n} : ٩( ᐛ )و"
end
```

```elixir
$ iex -S mix

iex> Nabeatsu.run
1
2
3 : ٩( ᐛ )و
4
5
6 : ٩( ᐛ )و
7
8
9 : ٩( ᐛ )و
10
11
12 : ٩( ᐛ )و
13 : ٩( ᐛ )و
14
15 : ٩( ᐛ )و
16
17
18 : ٩( ᐛ )و
19
20
21 : ٩( ᐛ )و
22
23 : ٩( ᐛ )و
24 : ٩( ᐛ )و
25
26
27 : ٩( ᐛ )و
28
29
30 : ٩( ᐛ )و
31 : ٩( ᐛ )و
32 : ٩( ᐛ )و
33 : ٩( ᐛ )و
34 : ٩( ᐛ )و
35 : ٩( ᐛ )و
36 : ٩( ᐛ )و
37 : ٩( ᐛ )و
38 : ٩( ᐛ )و
39 : ٩( ᐛ )و
40
41
42 : ٩( ᐛ )و
43 : ٩( ᐛ )و
44
45 : ٩( ᐛ )و
46
47
48 : ٩( ᐛ )و
49
50
51 : ٩( ᐛ )و
52
53 : ٩( ᐛ )و
54 : ٩( ᐛ )و
55
56
57 : ٩( ᐛ )و
58
59
60 : ٩( ᐛ )و
61
62
63 : ٩( ᐛ )و
64
65
66 : ٩( ᐛ )و
67
68
69 : ٩( ᐛ )و
70
71
72 : ٩( ᐛ )و
73 : ٩( ᐛ )و
74
75 : ٩( ᐛ )و
76
77
78 : ٩( ᐛ )و
79
80
81 : ٩( ᐛ )و
82
83 : ٩( ᐛ )و
84 : ٩( ᐛ )و
85
86
87 : ٩( ᐛ )و
88
89
90 : ٩( ᐛ )و
91
92
93 : ٩( ᐛ )و
94
95
96 : ٩( ᐛ )و
97
98
99 : ٩( ᐛ )و
100
:ok
```

- iexは`System.halt`で終わらせましょう

# Wrapping Up
- **Enjoy!!!**