環境
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 という意味だよと後で嘘も付きやすい。(なんで?
sh
$ mix new fg --sup # アプリケーションを監視してもらおう
$ cd fg
まず4つのファイルを覗く。
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
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
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
テストする
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
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
fg/lib/fg/cli.ex
defmodule Fg.CLI do
def main(_args) do
Fg.hello()
|> IO.puts()
end
end
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
...
sh
$ mix escript.build
Compiling 1 file (.ex)
Generated escript hello with MIX_ENV=dev
$ ./hello
world
関数を書き換える
fg/test/fg_test.exs
defmodule FgTest do
use ExUnit.Case
doctest Fg
test "与えられた文字列から挨拶文を作る。" do
str = "feelinguy"
assert Fg.greeting(str) == "こんちは feelinguy!"
end
end
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
まぁ、怒られるわな。
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
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 ね。
fg/lib/cli.ex
defmodule Fg.CLI do
def main([arg | _args]) do
arg
|> Fg.greeting()
|> IO.puts()
end
end
fg/mix.exs
defmodule Fg.MixProject do
...
def escript do
[
main_module: Fg.CLI,
name: "greet", # 変更
app: nil,
strip_beam: true
]
end
...
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!
また来てくれよなーノシ