Tambourine作業メモ

主にスキル習得のためにやった作業のメモ。他人には基本的に無用のものです。

Elixirで遊んでみる(10)

13章の続き。

さて、GitHubAPIからJSONが返ってきているので、これを処理してやる必要がある。

JSONのライブラリとしてはpoisonを使うみたい。 hex.pmに行って検索し、depsの記述をコピってmix.exsに入れる。

P.156の記述を元に、Issues.GithubIssues.handle_responseを修正する。ここで、

  def handle_response({_, %{status_code: status_code, body: body}}) do
    {
        status_code |> check_for_error(),
        body |> Poison.Parser.parse!()
    }
  end

のようにしてるんだけど、これはwarningが出る。

warning: Poison.Parser.parse!/1 is undefined or private. Did you mean one of:

      * parse!/2

  lib/issues/github_issues.ex:17: Issues.GithubIssues.handle_response/1

parse!には引数が2つ必要だと言ってるんだけど、それがwarningなのがよくわからない。 実行時エラーになるのかな?このままにしておいてみよう。

ちなみに、2つ目の引数にはパースのオプションを入れるみたい。何も指定しないなら%{}を渡す。 %{keys: :atoms!}を渡すと、戻ってくるマップのキーがアトムになる。でも、この!は何だろう?

Poisonのドキュメントにこう注釈してある

Note that keys: :atoms! reuses existing atoms, i.e. if :name was not allocated before the call, you will encounter an argument error message.

keys: :atoms!はアトムを再利用する。例えば、:nameがそれ以前に使われてなければ、エラーになる」・・・なるほど?

You can use the keys: :atoms variant to make sure all atoms are created as needed. However, unless you absolutely know what you’re doing, do not do it. Atoms are not garbage-collected, see Erlang Efficiency Guide for more info

keys: :atomsを使うこともできるが、全てのアトムが必要になった時点で作られる。これが意味するところを完全に理解していないならば、これを使うべきではない。アトムは決してGCされないから」。な、なるほど。しかし、JSONのキーに出てくる名前の全部のアトムを使うことがそんなに問題なのかな?

本ではここでちょっと寄り道。ソースコードにハードコードしたGitHubのURLをconfig.exsへ出すのだと。ふむふむ。

mix new で新しいプロジェクトを作ったとき、config/ というディレクトリが作られたのを 思い出してほしい。config ディレクトリには、config.exs というファイルが含まれていた。 このファイルは、アプリケーションレベルの設定だ。

アレ?私の手元には作られてないんだけど?

ググってみると、これは1.9での変更らしい。

dev.to

まず、mix newconfig/config.exsをつくらなくなりました。設定ファイルに依存することは、ライブラリやその作者にとって望ましくないとされてきたからです。つぎに、mix new --umbrella は、子アプリケーションごとの設定はつくりません。すべての設定は、アンブレラプロジェクトのルートで宣言することになります。理由については「No longer generate config for mix new」をご参照ください。

ふむ・・・

use Mix.Configはやわらかな非推奨(soft-deprecated)となります。これからは、Elixirに新たに備わったConfigモジュールをimport Configとしてお使いください。

ここは後でフォローするとして、いったんは本の通りにしてみようかな。

> mkdir config
> echo "use Mix.Config" > config/config.exs

これで良いのかな?

これで、P.157の通りにconfig.exsとgithub_issues.exを修正。

実行してみよう。

> iex -S mix
Erlang/OTP 23 [erts-11.1.5] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [hipe] [dtrace]

Compiling 3 files (.ex)
warning: Poison.Parser.parse!/1 is undefined or private. Did you mean one of:

      * parse!/2

  lib/issues/github_issues.ex:18: Issues.GithubIssues.handle_response/1

Generated issues app
Interactive Elixir (1.11.2) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> Issues.GithubIssues.fetch("elixir-lang", "elixir")
** (UndefinedFunctionError) function Poison.Parser.parse!/1 is undefined or private. Did you mean one of:

      * parse!/2

    (poison 4.0.1) Poison.Parser.parse!("{\"message\":\"Not Found\",\"documentation_url\":\"https://docs.github.com/rest\"}")
    (issues 0.1.0) lib/issues/github_issues.ex:18: Issues.GithubIssues.handle_response/1

あー、やっぱり実行時エラーになった。

というわけで、

body |> Poison.Parser.parse!(%{})

のように引数を足す。 これでOK。

後は、Issues.CLI.processにソートと指定の件数だけ取り出す機能を追加する。 これは本の通りにやって、特に不明なところはない。