今日のElixirSchoolメモ15「IEx Helpers」

ElixirSchoolの勉強メモです。

https://elixirschool.com/ja/lessons/basics/iex_helpers

## 概要

IEｘが開発の強力な手助けになるでしょう。IExはREPLでありながら、コードの開発をより簡単にするための多くの機能を備えています。

### オートコンプリート

シェルで作業していると、自力ではわからない、新しいモジュールを発見できるでしょう。
利用できる機能の中でもオートコンプリート機能は素晴らしい機能です。
モジュール名の後に`.`を入力し、続いて`Tab`を押してみてください。

```elixir
iex(1)> Map.
...(1)>
...(1)>
!/1                           !=/2
!==/2                         %/2
%{}/1                         &&/2
&/1                           **/2
*/2                           ++/2
+/1                           +/2
--/2                          -/1
-/2                           ..///3
../0                          ../2
```

これでモジュールが持つ関数及びその引数を知ることができる。

### .iex.exs

IExを起動するとき、毎回`.iex.exs`という設定ファイルを参照している。

オプションやコードをこのファイルに設定するときIEｘ上で利用可能になる。たとえば、新しいIEｘ上で利用したいヘルパー関数がある場合は`.iex.exs`を変更します。

```.iex.exs
defmodule IExHelpers do
  def whats_this?(term) when is_nil(term), do: "Type: Nil"
  def whats_this?(term) when is_binary(term), do: "Type: Binary"
  def whats_this?(term) when is_boolean(term), do: "Type: Boolean"
  def whats_this?(term) when is_atom(term), do: "Type: Atom"
  def whats_this?(_term), do: "Type: Unknown"
end
```

IExを起動すると、`IExHelpers`モジュールが利用可能になるので、実際に試してみる。

```elixir
iex
Erlang/OTP 25 [erts-13.0] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [jit:ns]

Interactive Elixir (1.14.2) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> IExHelpers.whats_this?("a string")
"Type: Binary"
iex(2)> IExHelpers.whats_this?(%{})
"Type: Unknown"
iex(3)> IExHelpers.whats_this?(:test)
"Type: Atom"
```

### h

`h`ヘルパーを使うと、言語機能によって提供されたドキュメントに到達することができる。

```elixir
iex(7)> h Enum

                                      Enum

Functions for working with collections (known as enumerables).

In Elixir, an enumerable is any data type that implements the Enumerable
protocol. Lists ([1, 2, 3]), Maps (%{foo: 1, bar: 2}) and Ranges (1..3) are
common data types used as enumerables:

    iex> Enum.map([1, 2, 3], fn x -> x * 2 end)
    [2, 4, 6]

    iex> Enum.sum([1, 2, 3])
    6
```

モジュールの関数が利用可能かということだけではなく、それぞれの関数のドキュメンテーションやたくさんの利用例を見ることができる。

```elixir
iex(10)> h Map.merge/2

                             def merge(map1, map2)

  @spec merge(map(), map()) :: map()

delegate_to: :maps.merge/2

Merges two maps into one.

All keys in map2 will be added to map1, overriding any existing one (i.e., the
keys in map2 "have precedence" over the ones in map1).

If you have a struct and you would like to merge a set of keys into the struct,
do not use this function, as it would merge all keys on the right side into the
struct, even if the key is not part of the struct. Instead, use struct/2.

Inlined by the compiler.

## Examples

    iex> Map.merge(%{a: 1, b: 2}, %{a: 3, d: 4})
    %{a: 3, b: 2, d: 4}
```

### i

```elixir
iex(12)> h i

                              def i(term \\ v(-1))

Prints information about the data type of any given term.

If no argument is given, the value of the previous expression is used.

## Examples

    iex> i(1..5)

Will print:

    Term
      1..5
    Data type
      Range
    Description
      This is a struct. Structs are maps with a __struct__ key.
    Reference modules
      Range, Map
```

```elixir
iex(13)> i Map
Term
  Map
Data type
  Atom
Module bytecode
  /Users/kanako/.asdf/installs/elixir/1.14.2/bin/../lib/elixir/ebin/Elixir.Map.beam
Source
  /home/build/elixir/lib/elixir/lib/map.ex
Version
  [148837424277005364663382250045098907215]
Compile options
  [:no_spawn_compiler_process, :from_core, :no_core_prepare, :no_auto_import, {:inline, [replace!: 3, has_key?: 2, delete: 2, put: 3, get: 2, fetch!: 2, fetch: 2]}, {:no_warn_undefined, {:maps, :from_keys, 2}}]
Description
  Use h(Map) to access its documentation.
  Call Map.module_info() to access metadata.
Raw representation
  :"Elixir.Map"
Reference modules
  Module, Atom
Implemented protocols
  IEx.Info, Inspect, List.Chars, String.Chars
```

`Map`に関するソースコードの所在や関連するモジュールなどの情報を見ることができる。
この機能によって簡単に慣習や外部データ型や新しい関数について調べることができる。

* MapはAtom型である
* ソースコードがどこにあるか
* そのバージョンとコンパイルオプション
* 一般的な説明文
* Mapにアクセスする方法
* 他にどのモジュールを参照しているか

### r

モジュール単位や部分的に再コンパイルしたいときは`r`ヘルパーを使う。コードを変更したときや新しい関数を再コンパイルしたいときに使ってみましょう。
今回は変更を加えた`r`ヘルパーによって再コンパイルしてみます。

```elixir
iex> r MyProject
```

### t

```elixir
iex(14)> t Map
@type key() :: any()
@type value() :: any()
```

このようにMapモジュールがkeyとvalueに定義している型が分かる。`Map`のソースを読んで確認してみる。

```elixir
defmodule Map do
# ...
  @type key :: any
  @type value :: any
# ...
```

keyやvalueの値はどのような型でも構いませんが知っておくと便利。

これらのすべての内臓機能を活用することで、簡単にコードを探索したり、どのように実行されるか学ぶことができる。