Elixir GUIDES を普通に読む6

Elixir GUIDES を読んだメモ

elixir-lang.jp

12. IOとファイルシステム

IOモジュール

  • IOモジュールは標準入出力:stdio、標準エラー:stderr、ファイルおよびそのほかのIOデバイスへの読み書きを行う
iex(1)> IO.puts "hello world" hello world 
:ok 
iex(2)> IO.gets "yes or no? " yes or no? yes 
"yes\n" 
  • デフォルトでは、IOモジュール内の関数は標準入力から読み取り、標準出力に書き込む
  • 引数に:stderrなどを渡すことで変更できる
iex(3)> IO.puts :stderr, "hello world" 
hello world 
:ok 

Fileモジュール

  • FileモジュールはIOデバイスとしてファイルを開くことができる機能を持つ
  • デフォルトではバイナリモードで開かれるためIO.binread/2, IO.binwrite/2を使う必要がある
iex(4)> {:ok, file} = File.open "hello", [:write] 
{:ok, #PID<0.109.0>} 
iex(5)> IO.binwrite file, "world" 
:ok 
iex(6)> File.close file 
:ok
iex(7)> File.read "hello" 
{:ok, "world"}
  • Fileモジュールにはファイルシステムを操作する機能もたくさんある
    • File.rm/1
    • File.mkdir/1
    • File.mkdir_p/1
    • File.cp_r/2
    • File.rm_rf/1
  • File モジュールには2つのバリアントがある
    • 通常のバリアント
      • File.read/1
    • 末尾に!がつくバリアント
      • File.read!/1
iex(8)> File.read "hello" 
{:ok, "world"}
 iex(9)> File.read! "hello" 
"world" 
iex(10)> File.read "unknown" 
{:error, :enoent} 
iex(11)> File.read! "unknown" 
** (File.Error) could not read file "unknown": no such file or directory 
      (elixir) lib/file.ex:353: File.read!/1 
  • !の時はファイル内容をそのまま返す
  • エラーの場合は、エラーを発生させる
  • パターンマッチングをする場合は!なしを使うと良い
case File.read(file) do
  {:ok, body}      -> # do something with the `body`
  {:error, reason} -> # handle the error caused by `reason`
end
  • エラー処理をしたくない場合はFile.read!/1を使うと良い

Pathモジュール

iex(12)> Path.join("foo", "bar") 
"foo/bar" 
iex(13)> Path.expand("~/hello") 
"/Users/mir3636/hello" 

プロセスとグループリーダー

  • 読んでもよくわからなかったのでググりました

daruiapprentice.blogspot.com

14. alias, require, and import

ailias

defmodule Stats do
  alias Math.List, as: List
  # In the remaining module definition List expands to Math.List.
end
  • alias Math.List, as: Listalias Math.List のように省略できる

require

  • モジュールのパブリック関数はグローバルに利用できるが、マクロはrequireしなくてはならない
iex(14)> Integer.is_odd(3) 
** (CompileError) iex:14: you must require Integer before invoking the macro Integer.is_odd/1 
      (elixir) src/elixir_dispatch.erl:97: :elixir_dispatch.dispatch_require/6 
iex(14)> require Integer 
Integer 
iex(15)> Integer.is_odd(3) 
true 

import

  • duplicate/2 のみの import
iex(18)> List.duplicate :ok, 3 
[:ok, :ok, :ok] 
iex(19)> duplicate :ok, 3 
** (CompileError) iex:19: undefined function duplicate/2 
iex(19)> import List, only: [duplicate: 2] 
List 
iex(20)> duplicate :ok, 3 
[:ok, :ok, :ok] 
  • すべてのマクロをインポートする時
import Integer, only: :macros 
  • すべての関数をインポートする時
import Integer, only: :functions 

use

  • use マクロは__using__/1コールバックを呼び出し、モジュールの定義を上書きすることができる
  • 難しかったので↓を見た

elixirschool.com

defmodule Hello do
  defmacro __using__(_opts) do
    quote do
      def hello(name), do: "Hi, #{name}"
    end
  end
end
defmodule Example do
  use Hello
end
iex(24)> Example.hello("Sean") 
"Hi, Sean" 
iex(25)> Example.hello("Taro") 
"Hi, Taro" 
  • use を使うことで他のモジュールを呼び出せる
defmodule Hello do
  defmacro __using__(opts) do
    greeting = Keyword.get(opts, :greeting, "Hi")

    quote do
      def hello(name), do: unquote(greeting) <> ", " <> name
    end
  end
end
defmodule Example do
  use Hello, greeting: "Hola"
end
iex(28)> Example.hello("Sean") "Hola, Sean" 
  • オプションを渡すことでモジュールの定義の変更もできる

マルチ alias/import/require/use

  • 複数のモジュールを alias/import/require/use できる
alias MyApp.{Foo, Bar, Baz} 
  • 書いてた内容を放置しすぎて消えてしまい、バックアップから書き直したためmd怪しいかもしれない