Elixir episode:0 実行ファイル

# 環境

```shell-session:sh
$ lsb_release -d
Description:    Ubuntu 18.04.2 LTS

$ elixir -v
Erlang/OTP 21 [erts-10.3.5] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [hipe]

Elixir 1.8.1 (compiled with Erlang/OTP 20)
```

# プロジェクトを作る

テーマが無い。
プロジェクト名は自分のハンドルネームから取ろう。
Figure という意味だよと後で嘘も付きやすい。（なんで？

```shell-session:sh
$ mix new fg --sup # アプリケーションを監視してもらおう
$ cd fg
```

まず4つのファイルを覗く。

```elixir:fg/mix.exs
defmodule Fg.MixProject do
  use Mix.Project

  def project do
    [
      app: :fg,
      version: "0.1.0",
      elixir: "~> 1.8",
      start_permanent: Mix.env() == :prod,
      deps: deps()
    ]
  end

  def application do
    [
      extra_applications: [:logger],
      mod: {Fg.Application, []}  # この定義を見ようと思う
    ]
  end

  defp deps do
    []
  end
end
```
```elixir:fg/lib/application.ex
defmodule Fg.Application do
  @moduledoc false

  use Application

  def start(_type, _args) do
    children = []
    # Fg.Supervisor で名前が登録されるらしいと思う
    opts = [strategy: :one_for_one, name: Fg.Supervisor]
    Supervisor.start_link(children, opts)
  end
end
```
```elixir:fg/lib/fg.ex
defmodule Fg do
  # ドキュメントはこう書くのかと思う
  @moduledoc """
  Documentation for Fg.
  """

  @doc """
  Hello world.

  ## Examples

      iex> Fg.hello()
      :world

  """
  # すでに関数が定義されていると知る
  def hello do
    :world
  end
end
```
```fg/test/fg_test.exs
defmodule FgTest do
  use ExUnit.Case
  doctest Fg

  # このテストは成功するだろうねと思う
  test "greets the world" do
    assert Fg.hello() == :world
  end
end
```

# テストする

```shell-session:sh
$ mix test
mix test
Compiling 2 files (.ex)
Generated fg app
..

Finished in 0.04 seconds
1 doctest, 1 test, 0 failures

Randomized with seed 923881
```

やっぱり成功した。私のアプリケーションは今完璧だ。

# アプリケーションを試す

`$ iex -S mix`

```elixir:iex
Erlang/OTP 21 [erts-10.3.5] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [hipe]

Interactive Elixir (1.8.1) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> Fg.hello()
:world
iex(2)> Process.whereis(Fg.Supervisor)    
#PID<0.144.0>
iex(3)> Process.whereis(Fg.Supervisor) |> Process.alive?()
true
iex(4)> Application. # tab
app_dir/1                 app_dir/2                 delete_env/2              
delete_env/3              ensure_all_started/1      ensure_all_started/2      
ensure_started/1          ensure_started/2          fetch_env!/2              
fetch_env/2               format_error/1            get_all_env/1             
get_application/1         get_env/2                 get_env/3                 
load/1                    loaded_applications/0     put_env/3                 
put_env/4                 spec/1                    spec/2                    
start/1                   start/2                   started_applications/0    
started_applications/1    stop/1                    unload/1                  

iex(4)> Application.started_applications()
[
  {:fg, 'fg', '0.1.0'},
  {:logger, 'logger', '1.8.1'},
  {:mix, 'mix', '1.8.1'},
  {:iex, 'iex', '1.8.1'},
  {:elixir, 'elixir', '1.8.1'},
  {:compiler, 'ERTS  CXC 138 10', '7.3.2'},
  {:stdlib, 'ERTS  CXC 138 10', '3.8.2'},
  {:kernel, 'ERTS  CXC 138 10', '6.3.1'}
]
iex(5)> Application.spec(:fg)
[
  description: 'fg',
  id: [],
  vsn: '0.1.0',
  modules: [Fg, Fg.Application],
  maxP: :infinity,
  maxT: :infinity,
  registered: [],
  included_applications: [],
  applications: [:kernel, :stdlib, :elixir, :logger],
  mod: {Fg.Application, []},
  start_phases: :undefined
]
iex(6)> Application.stop(:fg)

03:04:43.834 [info]  Application fg exited: :stopped
:ok
iex(7)> Fg.hello()
:world
iex(8)> Process.whereis(Fg.Supervisor)
nil
```

ちゃんとスーパーバイザに監視されてたようだ。

# 実行ファイルを作る

`$ touch lib/fg/cli.ex`

```elixir:fg/lib/fg/cli.ex
defmodule Fg.CLI do
  def main(_args) do
    Fg.hello()
    |> IO.puts()
  end
end
```
```elixir:fg/mix.exs
defmodule Fg.MixProject do
  use Mix.Project

  def project do
    [
      app: :fg,
      version: "0.1.0",
      elixir: "~> 1.8",
      start_permanent: Mix.env() == :prod,
      deps: deps(),
      escript: escript()  # 追加
    ]
  end

  # 追加
  def escript do
    [
      main_module: Fg.CLI,
      name: "hello",
      app: nil,         # アプリケーションは起動しない
      strip_beam: true  # 余計なものは省いておくれ
    ]
  end
...
```
```shell-session:sh
$ mix escript.build
Compiling 1 file (.ex)
Generated escript hello with MIX_ENV=dev

$ ./hello
world
```

# 関数を書き換える

```elixir:fg/test/fg_test.exs
defmodule FgTest do
  use ExUnit.Case
  doctest Fg

  test "与えられた文字列から挨拶文を作る。" do
    str = "feelinguy"
    assert Fg.greeting(str) == "こんちは feelinguy！"
  end
end
```
```shell-session:sh
$ mix test
.

  1) test 与えられた文字列から挨拶文を作る。 (FgTest)
     test/fg_test.exs:5
     ** (UndefinedFunctionError) function Fg.greeting/1 is undefined or private
     code: assert Fg.greeting(str) == "こんちは feelinguy！"
     stacktrace:
       (fg) Fg.greeting("feelinguy")
       test/fg_test.exs:7: (test)



Finished in 0.04 seconds
1 doctest, 1 test, 1 failure

Randomized with seed 761201
```

まぁ、怒られるわな。

```elixir:fg/lib/fg.ex
defmodule Fg do
  @moduledoc """
  Fg は日本を代表する野良猫である。
  """

  @doc """
  与えられた文字列から挨拶文を作る。

  ## Examples

      iex> Fg.greeting("世界")
      "こんちは 世界！"

  """
  def greeting(str) when is_binary(str) do
    "こんちは #{str}！"
  end
end
```
```shell-session:sh
mix test
Compiling 1 file (.ex)
warning: function Fg.hello/0 is undefined or private
  lib/fg/cli.ex:3

..

Finished in 0.04 seconds
1 doctest, 1 test, 0 failures

Randomized with seed 974820
```

あ、CLI ね。

```elixir:fg/lib/cli.ex
defmodule Fg.CLI do
  def main([arg | _args]) do
    arg
    |> Fg.greeting()
    |> IO.puts()
  end
end
```
```elixir:fg/mix.exs
defmodule Fg.MixProject do
  ...
  def escript do
    [
      main_module: Fg.CLI,
      name: "greet",  # 変更
      app: nil,
      strip_beam: true
    ]
  end
  ...
```
```shell-session:sh
$ mix test
Compiling 1 file (.ex)
..

Finished in 0.04 seconds
1 doctest, 1 test, 0 failures

Randomized with seed 124539

$ rm hello
$ mix escript.build
Compiling 3 files (.ex)
Generated fg app
Generated escript greet with MIX_ENV=dev

$ ./greet feelinguy
こんちは feelinguy！

$ ./greet World Wide Web
こんちは World！
```

また来てくれよなーノシ