yu-tarrrrの日記

完全に個人の趣味でその時々書きたいことを書く

Elixir School 2日目

はじめに

  • 前回の続き
  • 今回もiexをベースに基礎編のインプット・アウトプットをする

モジュールについて

モジュール

  • classみたいな感じで、複数の関数などを束ねることが可能
  • defmoduleで定義することが可能。またmoduleはネストすることも可能である。

構造体

  • データクラスみたいな感じ
  • defstructで定義する
iex(1)> defmodule Example.User do
...(1)>   defstruct id: 1, last_name: "", family_name: "", roles: []
...(1)> end
{:module, Example.User,
 <<70, 79, 82, 49, 0, 0, 6, 220, 66, 69, 65, 77, 65, 116, 85, 56, 0, 0, 0, 189,
   0, 0, 0, 18, 19, 69, 108, 105, 120, 105, 114, 46, 69, 120, 97, 109, 112, 108,
   101, 46, 85, 115, 101, 114, 8, 95, 95, ...>>,
 %Example.User{family_name: "", id: 1, last_name: "", roles: []}}
iex(2)> user = %Example.User{last_name: "Steve"}
%Example.User{family_name: "", id: 1, last_name: "Steve", roles: []}
iex(3)> user = %{user | family_name: "John"}
%Example.User{family_name: "John", id: 1, last_name: "Steve", roles: []}

コンポジション

alias

  • moduleに対してaliasを貼ることが可能
  • ネストしてるmoduleはalias貼った方が可読性があがる。
  • 命名が衝突してなければ、 alias XXX.YYYY でYYYYに対してアクセスできるようになるし、衝突するもしくは任意の名前に変更したい場合はalias XXX.YYYY, as: ZZZZZみたいなことが可能
  • 一度に複数のモジュールに対してalias貼ることもalias XXX.{YYYY, ZZZZ}みたいな感じで可能

import

  • モジュールをエイリアスするよりも、関数を取り込みたいという場合には、 import を使う
  • importは全ての関数およびマクロをimportするので、:onlyexceptで絞ることが可能 。import List, only: [last: 1]

mix

  • mix newを叩くことで、プロジェクトのフォルダ構成と必要なボイラープレート(決まりきったソースコード断片)が生成される
  • package managerみたいな役割を果たしてくれる

ドキュメントの作成

  • #使うか@doc使うか @moduledoc使うかという話。
  • あんまりdocを書かない人間なので割愛

テスト

  • Elixirに組み込まれているテストフレームワークはExUnitという
  • テストを走らせる前にExUnitを ExUnit.start() で開始する必要があり、これは通常 test/test_helper.exs 内で行われる
  • 雑に mix newで作成したプロジェクトの中で引数を足し算する実装とテストを作成してみる
defmodule ElixirSchool do
  def hello do
    :world
  end

  def add(args1, args2) do
    args1 + args2
  end
end
defmodule ElixirSchoolTest do
  use ExUnit.Case
  doctest ElixirSchool

  test "add" do
    assert ElixirSchool.add(1, 2) == 3
  end
end
  • assertは他の言語のテストでもおなじみの感じで、refuteassert_raise, assert_receiveがある
  • テストのセットアップは setupsetup_all マクロを使うことができる。 setup は各テストの前、 setup_all は全体のテストの前に一度だけ実行される。どちらも {:ok, state} のタプルを返すことが期待されていて、stateはテスト内で利用可能。
  • モックについては下記の通りらしい

    Elixirでのモックに対する単純な解答は、使うな、です。本能のままにモックへと手を伸ばしているかもしれませんが、Elixirのコミュニティや正当な理由からはとても推奨されていないものです。

内包表記

  • for文でコレクションなどを操作することができる
  • 回せるものはリストに限らない
  • あくまでも syntax sugarなので必要なときのみにした方がいいというスタンスのよう
iex(1)> for x <- 1..5, do: x*x
[1, 4, 9, 16, 25]

# キーワードリスト
iex> for {_key, val} <- [one: 1, two: 2, three: 3], do: val
[1, 2, 3]

# マップ
iex> for {k, v} <- %{"a" => "A", "b" => "B"}, do: {k, v}
[{"a", "A"}, {"b", "B"}]

# バイナリ
iex> for <<c <- "hello">>, do: <<c>>
["h", "e", "l", "l", "o"]

フィルタ

  • フィルタは内包表記のためのある種のガードと考えることができる
  • false, nilの場合は取り除くことが可能
import Integer
iex> for x <- 1..10, is_even(x), do: x
[2, 4, 6, 8, 10]

おまけ

  • 基礎編最後に個人的にFizzbuzzをやってみる
defmodule ElixirSchool do
  def fizzbuzz(args) do 
    cond do
      rem(args, 15) == 0 ->  "fizzbuzz" 
      rem(args, 3) == 0 ->  "fizz" 
      rem(args, 5) == 0 -> "buzz"
      true -> nil
    end
  end
end
defmodule ElixirSchoolTest do
  use ExUnit.Case
  doctest ElixirSchool

  test "fizzbuzz" do
    assert ElixirSchool.fizzbuzz(15) == "fizzbuzz"
  end

  test "fizz" do
    assert ElixirSchool.fizzbuzz(3) == "fizz"
  end

  test "buzz" do
    assert ElixirSchool.fizzbuzz(5) == "buzz"
  end

  test "nul" do
    assert ElixirSchool.fizzbuzz(4) == nil
  end
end

こんな感じ。

  • ElixirSchoolの基礎編をやりきってfizzbuzzするのに半日くらいしかかからなかったので、結構楽しかったです。
  • 次回からElixirSchoolの応用編をやってみる