Help us understand the problem. What is going on with this article?

Elixir episode:0 実行ファイル

環境

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!

また来てくれよなーノシ

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした