/var/log/messages

Feb 28, 2019 - 2 minute read - Comments - programming

プログラミング Elixir (21)

13.8 変換: データを並び替える、の節。

Enum.sort/2

パイプでどんどん繋いでいくさまがとても気持ち良いですね。ベルトコンベアな「デザイン」というのも分かりやすくて良いです。また、今回については試験も作っています。

  def process([user, project, _count]) do
    Issues.GithubIssues.fetch(user, project)
    |> decode_response
    |> convert_to_list_of_maps
    |> sort_into_ascending_order
  end

  def decode_response({:ok, body}), do: body

  def docode_response({:error, error}) do
    {_, message} = List.keyfind(error, "message", 0)
    IO.puts "Error fetching from Github: #{message}"
    System.halt(2)
  end

  def convert_to_list_of_maps(list) do
    list
    |> Enum.map(&Enum.into(&1, Map.new))
  end

  def sort_into_ascending_order(list_of_issues) do
    Enum.sort list_of_issues
              fn l1, l2 -> l1["created_at"] <= l2["created_at"] end
  end

今回は sort に渡してる手続きな比較が大丈夫なのかどうかが心配なので試験を書くとのこと。issues/test 配下に試験があるのは良いのですがいくつかの試験が既に欠いてある状態 (後天性記憶不全?)。以下を追加しています。

issues/test/cli_test.exs

  test "sort ascending orders the correct way" do
    result = sort_into_ascending_order(fake_created_at_list(["c", "b", "a"]))
    issues = for issue <- result, do: issue["created_at"]
    assert issues == ~2{a, b, c}
  end

  defp fake_created_at_list(values) do
    data = for value <- values, do: [{"created_at", value}, {"other_data", "xxx"}]
    convert_to_list_of_maps data
  end

で、試験実行してみるに

== Compilation error in file lib/issues/github_issues.ex ==

ええと、github_issues.exs が以下になってました。

  @github_url Application.get_env(:issues, github_url:)

以下に修正。

  @github_url Application.get_env(:issues, :github_url)

で再度試験実行。

$ mix test
....

  1) test sort ascending orders the correct way (CliTest)
     test/cli_test.exs:22
     ** (FunctionClauseError) no function clause matching in Access.get/3

     The following arguments were given to Access.get/3:
     
         # 1
         {:cont, []}
     
         # 2
         "created_at"
     
         # 3
         nil
     
     Attempted function clauses (showing 5 out of 5):
     
         def get(%module{} = container, key, default)
         def get(map, key, default) when is_map(map)
         def get(list, key, default) when is_list(list) and is_atom(key)
         def get(list, key, _default) when is_list(list)
         def get(nil, _key, default)
     
     code: issues = for issue <- result, do: issue["created_at"]
     stacktrace:
       (elixir) lib/access.ex:316: Access.get/3
       (issues) lib/issues/cli.ex:71: anonymous fn/2 in Issues.CLI.sort_into_ascending_order/1
       (elixir) lib/enum.ex:2979: Enum.reduce/3
       test/cli_test.exs:24: (test)

..

Finished in 0.1 seconds
2 doctests, 5 tests, 1 failure

Randomized with seed 801121

ありゃ、色々駄目じゃないスか。そもそも試験の記述もきちんと理解できていないのでそこから確認します。

むむむ

~w は sigil でした。iex にて確認。

iex(1)> ~w{a b c}
["a", "b", "c"]

あ、comma で区切ってましたorz

    assert issues == ~w{a, b, c}

ただしくは以下。

    assert issues == ~w{a b c}

で、試験実行してみたのですがまだ駄目ですね。メセジてきにも変化なし。

発見orz

こうなっておりました。

  def sort_into_ascending_order(list_of_issues) do
    Enum.sort list_of_issues
              fn l1, l2 -> l1["created_at"] <= l2["created_at"] end
  end

これで sort_into_ascending_order から手続きオブジェクトが戻されてた模様。以下に修正して

  def sort_into_ascending_order(list_of_issues) do
    Enum.sort list_of_issues,
              fn l1, l2 -> l1["created_at"] <= l2["created_at"] end
  end

テスツ合格。

$ mix test
.......

Finished in 0.2 seconds
2 doctests, 5 tests, 0 failures

Randomized with seed 363252

IO.inspect を使って云々しました。

  test "sort ascending orders the correct way" do
    result = sort_into_ascending_order(fake_created_at_list(["c", "b", "a"]))
    IO.inspect(result)
    issues = for issue <- result, do: issue["created_at"]
    IO.inspect(issues)
    assert issues == ~w{a b c}
  end

出力が以下。

$ mix test
.[
  %{"created_at" => "a", "other_data" => "xxx"},
  %{"created_at" => "b", "other_data" => "xxx"},
  %{"created_at" => "c", "other_data" => "xxx"}
]
["a", "b", "c"]
......

Finished in 0.1 seconds
2 doctests, 5 tests, 0 failures

Randomized with seed 711905

以下を試そうとしたのですが

require IEx; IEx.pry

これは iex 使ってないとダウトらしいです。

この節

さくっと流せると思ってたら微妙なハマり方をしてしまいましたorz

rake task の引数 明日

comments powered by Disqus