🧪

iexで関数のドキュメントを調べる方法 他3本

2021/12/03に公開

はじめに

この記事は、Qiitaの「Elixir Advent Calendar 2021」の3日目の記事です。

https://qiita.com/advent-calendar/2021/elixir

2日目はtorifukukaiouさんによる「【Elixir】B - FizzBuzz Sum問題をEnum.map/2 |> Enum.filter/2 |> Enum.sum/1, Enum.reduce/3 を使って解く (2021/12/02)」でした。

https://qiita.com/torifukukaiou/items/b82dac53c79b4ee16b98

手続き型言語やオブジェクト指向型言語に慣れ親しんで来た方は、Elixirでの解法に驚いたかも知れませんね。
興味を持った方はぜひElixirへ入門してAlchemistへの一歩を踏み出してみてください。

Elixirで競技プログラミングしたい、Elixirを書きたいから何かお題が欲しい!という方は、昨日より「Advent of Code 2021」が開催されています。
「Advent of Code 2021」はアドベントカレンダーのように12月25日まで問題が1問ずつ出題され、それを解いていく遊びです。
個人的にはテキストベースのシンプルな見た目がお気に入りです。
https://adventofcode.com

ElixirのForumサイトでも解法について議論しているようなので参考になると思います。
ぜひ挑戦してみてください。
https://elixirforum.com/t/advent-of-code-2021-day-1/44179

本題

この記事は「iexで関数のドキュメントを調べる方法 他3本」です。
※ torifukukaiouさんの記事にあるタイトルが違うのは私が急な仕様変更したためです。

1. iexの実行スクリプト

LinuxやMac環境では、$> cat $(which iex)で実行スクリプトの中身を見ることができます。
環境の都合でcatコマンドを使っていますが、batコマンドがオススメです。

$> cat $(which iex)
#!/bin/sh
set -e

if [ "$1" = "--help" ] || [ "$1" = "-h" ]; then
  cat <<USAGE >&2
Usage: $(basename "$0") [options] [.exs file] [data]

The following options are exclusive to IEx:

  --dot-iex "PATH"    Overrides default .iex.exs file and uses path instead;
                      path can be empty, then no file will be loaded
  --remsh NAME        Connects to a node using a remote shell

It accepts all other options listed by "elixir --help".
USAGE
  exit 1
fi

readlink_f () {
  cd "$(dirname "$1")" > /dev/null
  filename="$(basename "$1")"
  if [ -h "$filename" ]; then
    readlink_f "$(readlink "$filename")"
  else
    echo "$(pwd -P)/$filename"
  fi
}

SELF=$(readlink_f "$0")
SCRIPT_PATH=$(dirname "$SELF")
exec "$SCRIPT_PATH"/elixir --no-halt --erl "-noshell -user Elixir.IEx.CLI" +iex "$@"

$>  elixir --no-halt --erl "-noshell -user Elixir.IEx.CLI"
Erlang/OTP 24 [erts-12.0.3] [source] [64-bit] [smp:4:1] [ds:4:1:10] [async-threads:1] [jit]

Interactive Elixir (1.12.0) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> 

2. iexでモジュールから呼び出せる関数を調べる方法 いくつか

A. _info_(:functions)

ドキュメント
https://hexdocs.pm/elixir/1.12/Module.html#callbacks

> IEx.Helpers.__info__(:functions)
[
  break!: 3,
  break!: 4,
  breaks: 0,
  c: 1,
  c: 2,
  cd: 1,
  clear: 0,
  continue: 0,
  exports: 0,
  exports: 1,
  flush: 0,
  h: 0,
  i: 0,
  i: 1,
  l: 1,
  ls: 0,
  ls: 1,
  nl: 1,
  nl: 2,
  open: 0,
  pid: 1,
  pid: 3,
  port: 1,
  port: 2,
  pwd: 0,
  r: 1,
  recompile: 0,
  recompile: 1,
  ref: 1,
  ref: 4,
  remove_breaks: 0,
  remove_breaks: 1,
  reset_break: 1,
  reset_break: 3,
  respawn: 0, 
  runtime_info: 0,
  runtime_info: 1,
  v: 0,
  v: 1, 
  whereami: 0,
  whereami: 1
]

B. module_info/1

ドキュメント(erlang)
https://www.erlang.org/doc/reference_manual/modules.html#module_info-1

> IEx.Helpers.module_info :exports
[
  __info__: 1,
  "MACRO-b": 2,
  "MACRO-break!": 2,
  "MACRO-break!": 3,
  break!: 3,
  break!: 4,
  breaks: 0,
  c: 1,
  c: 2,
  cd: 1,
  clear: 0,
  continue: 0,
  exports: 0,
  exports: 1,
  flush: 0,
  h: 0,
  "MACRO-h": 2,
  i: 0,
  i: 1,
  "MACRO-import_file": 2,
  "MACRO-import_file": 3,
  "MACRO-import_file_if_available": 2,
  "MACRO-import_if_available": 2,
  "MACRO-import_if_available": 3,
  l: 1,
  ls: 0,
  ls: 1,
  nl: 1,
  nl: 2,
  open: 0,
  "MACRO-open": 2,
  pid: 1,
  pid: 3,
  port: 1,
  port: 2,
  pwd: 0,
  r: 1,
  recompile: 0,
  recompile: 1,
  ref: 1,
  ref: 4,
  remove_breaks: 0,
  remove_breaks: 1,
  reset_break: 1,
  reset_break: 3,
  respawn: 0,
  runtime_info: 0,
  runtime_info: 1,
  "MACRO-t": 2,
  "MACRO-use_if_available": 2,
  ...
]

C. IEx.Helpers.exports/1

ドキュメント
https://hexdocs.pm/iex/1.12/IEx.Helpers.html#exports/1

> exports IEx.Helpers
b/1                            break!/1                       break!/2                       
h/1                            import_file/1                  import_file/2                  
import_file_if_available/1     import_if_available/1          import_if_available/2          
open/1                         t/1                            use_if_available/1             
use_if_available/2             break!/3                       break!/4                       
breaks/0                       c/1                            c/2                            
cd/1                           clear/0                        continue/0                     
exports/0                      exports/1                      flush/0                        
h/0                            i/0                            i/1                            
l/1                            ls/0                           ls/1                           
nl/1                           nl/2                           open/0                         
pid/1                          pid/3                          port/1                         
port/2                         pwd/0                          r/1                            
recompile/0                    recompile/1                    ref/1                          
ref/4                          remove_breaks/0                remove_breaks/1                
reset_break/1                  reset_break/3                  respawn/0                      
runtime_info/0                 runtime_info/1                 v/0                            
v/1                            whereami/0                     whereami/1         

3. モジュール情報を取得する方法 いくつか

A. IEx.Helpers.h/1

ドキュメント
https://hexdocs.pm/iex/1.12/IEx.Helpers.html#h/1

> h IEx.Helpers

                                  IEx.Helpers                                   

Welcome to Interactive Elixir. You are currently seeing the documentation for
the module IEx.Helpers which provides many helpers to make Elixir's shell more
joyful to work with.

This message was triggered by invoking the helper h(), usually referred to as
h/0 (since it expects 0 arguments).

You can use the h/1 function to invoke the documentation for any Elixir module
or function:

    iex> h(Enum)
    iex> h(Enum.map)
    iex> h(Enum.reverse/1)
(省略)

B. module_info/0

ドキュメント(erlang)
https://www.erlang.org/doc/reference_manual/modules.html#module_info-0

> IEx.Helpers.module_info
[
  module: IEx.Helpers,
  exports: [
    __info__: 1,
    "MACRO-b": 2,
    "MACRO-break!": 2,
    "MACRO-break!": 3,
    break!: 3,
    break!: 4,
    breaks: 0,
    c: 1,
    c: 2,
    cd: 1,
    clear: 0,
    continue: 0,
    exports: 0,
    exports: 1,
    flush: 0,
    h: 0,
    "MACRO-h": 2,
    i: 0,
    i: 1,
    "MACRO-import_file": 2,
    "MACRO-import_file": 3,
    "MACRO-import_file_if_available": 2,
    "MACRO-import_if_available": 2,
    "MACRO-import_if_available": 3,
    l: 1,
    ls: 0,
    ls: 1,
    nl: 1,
    nl: 2,
    open: 0,
    "MACRO-open": 2,
    pid: 1, 
    pid: 3,
    port: 1,
    port: 2,
    pwd: 0,
    r: 1,
    recompile: 0,
    recompile: 1,
    ref: 1, 
    ref: 4,
    remove_breaks: 0,
    remove_breaks: 1,
    reset_break: 1,
    reset_break: 3,
    respawn: 0,
    runtime_info: 0,
    runtime_info: 1,
    ...
  ],
  attributes: [vsn: [334571827834058247655098702395170864842]],
  compile: [
    version: '8.0',
    options: [:no_spawn_compiler_process, :from_core, :no_core_prepare,
     :no_auto_import],
    source: '/root/deb/elixir_1.12.0-1/lib/iex/lib/iex/helpers.ex'
  ],
  md5: <<251, 180, 48, 175, 119, 74, 106, 111, 122, 177, 39, 14, 81, 223, 190,
    202>>
]

C. IEx.Info.info/1

ドキュメント
https://hexdocs.pm/iex/1.12/IEx.Info.html#info/1

内部では、上記のmodule_infoを呼び出しています。

> IEx.Info.info IEx.Helpers
[
  {"Data type", "Atom"},
  {"Module bytecode",
   "/usr/lib/elixir/bin/../lib/iex/ebin/Elixir.IEx.Helpers.beam"},
  {"Source", "/root/deb/elixir_1.12.0-1/lib/iex/lib/iex/helpers.ex"},
  {"Version", "[334571827834058247655098702395170864842]"},
  {"Compile options",
   "[:no_spawn_compiler_process, :from_core, :no_core_prepare, :no_auto_import]"},
  {"Description",
   "Use h(IEx.Helpers) to access its documentation.\nCall IEx.Helpers.module_info() to access metadata."},
  {"Raw representation", ":\"Elixir.IEx.Helpers\""},
  {"Reference modules", "Module, Atom"}
]

4. 関数のドキュメントを表示する方法 いくつか

A. IEx.Helpers.h/1

ドキュメント
https://hexdocs.pm/iex/1.12/IEx.Helpers.html#h/1

> h IEx.Helpers.h  

                                    def h()                                     

Prints the documentation for IEx.Helpers.


                                defmacro h(term)                                

Prints the documentation for the given module or for the given function/arity
pair.

## Examples

    iex> h(Enum)

It also accepts functions in the format function/arity and
module.function/arity, for example:

    iex> h(receive/1)
    iex> h(Enum.all?/2)
    iex> h(Enum.all?)

B. IEx.Introspection.h/2

ソースコード(なぜかHexDocで見当たらない)
https://github.com/elixir-lang/elixir/blob/v1.12/lib/iex/lib/iex/introspection.ex

> IEx.Introspection.h {IEx.Helpers, :h}

                                    def h()                                     

Prints the documentation for IEx.Helpers.


                                defmacro h(term)                                

Prints the documentation for the given module or for the given function/arity
pair.

## Examples

    iex> h(Enum)

It also accepts functions in the format function/arity and
module.function/arity, for example:

    iex> h(receive/1)
    iex> h(Enum.all?/2)
    iex> h(Enum.all?)

おわり

iexの機能を使うことで、ブラウザでドキュメントを探す手間を省いたり、ドキュメントに載っていない関数を探したり、ソースコードの場所を調べることができます。
他にもiexにはさまざまな機能がありますので、気になった方は下記のディレクトリの中を探索してみると面白いと思います。
https://github.com/elixir-lang/elixir/tree/v1.12.3/lib/iex/lib/iex

明日は、takasehidekiさんによる「仏像さんに触発されてElixirをビルドしてみた」です。
お楽しみに。
https://qiita.com/advent-calendar/2021/elixir

おまけ

もとより予定していた「"phx.server"コマンドの実装を追い掛ける」はfukuoka.exさんのAdeventCalendarで投稿予定です。
https://qiita.com/advent-calendar/2021/fukuokaex

脚注
  1. https://www.b-ch.com/titles/4226/003 ↩︎

Discussion