9
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Elixir 1.12で増えた関数を調べたい

Last updated at Posted at 2021-06-05

はじめに

  • Elixir 楽しんでいますか:bangbang::bangbang::bangbang:
  • 1.12で追加された関数を調べたいとおもいます
  • Elixirのバージョン切り替えは、asdfを使っています
  • この記事は、2021/06/05(土) 00:00〜2021/06/07(月) 23:59 開催のautoracex #31の成果です

ところで、Elixirってなにに使えるの?

方法①

方法②

  • それぞれバージョンの違うノードをたてて、:code.all_loaded()でそれぞれのノードの結果を比較する
  • 今回はこっちでやってみます
  • プログラミングElixir(第2版)の223ページをとても参考にしました

ディレクトリ構成

├── node_new
│   └── new.ex
└── node_old
    └── old.ex

node_old

node_old/old.ex
defmodule FunctionsAnswer do
  @version "1.11.4"

  def start do
    pid = spawn(__MODULE__, :generator, [])
    :global.register_name(Utils.name(), pid)
  end

  def generator do
    receive do
      {:get, pid} ->
        send(pid, {:get, {Utils.functions(), @version}})
        generator()
    end
  end
end

defmodule Utils do
  @name "awesome"

  def name, do: @name

  def functions do
    :code.all_loaded()
    |> Enum.filter(fn {mod, _} -> "#{mod}" =~ ~r{^[A-Z]} end)
    |> Enum.map(fn {mod, _} -> mod end)
    |> Enum.reduce(%{}, fn mod, acc ->
      Map.put(acc, mod, mod.__info__(:functions))
    end)
  end
end
$ cd node_old
$ asdf local elixir 1.11.4-otp-23
$ asdf local erlang 23.0.1
$ asdf reshim elixir 1.11.4-otp-23
$ asdf reshim erlang 23.0.1
$ iex --sname node_old

iex> c "old.ex"

iex> FunctionsAnswer.start

node_new

node_new/new.ex
defmodule Differ do
  @version "1.12.1"

  def start do
    pid = spawn(__MODULE__, :receiver, [])
    send :global.whereis_name(Utils.name()), {:get, pid}
  end

  def receiver do
    receive do
      {:get, {got_functions, got_version}} ->
        diff(got_functions, got_version)
        |> Enum.filter(fn {mod, _} -> "#{mod}" |> String.split(".") |> Enum.count |> Kernel.==(2) end)
        |> Map.new
        |> write_markdown(got_version)
    end
  end

  defp diff(got_functions, got_version) do
    Utils.functions()
    |> Enum.map(fn {mod, functions} ->
      {new_functions, old_functions} = if Version.compare(@version, got_version) == :gt,
        do: {functions, got_functions},
        else: {got_functions, functions}

      old_elixir = Map.get(old_functions, mod, []) |> MapSet.new()
      new_elixir = new_functions |> MapSet.new()
      {mod, [MapSet.difference(new_elixir, old_elixir), MapSet.difference(old_elixir, new_elixir)]}
    end)
    |> Enum.reject(fn {_mod, [only_new, only_old]} -> only_new == MapSet.new and only_old == MapSet.new end)
    |> Map.new
  end

  defp write_markdown(diff_map, got_version) do
    create_markdown(diff_map, got_version)
    |> (&(File.write("output.md", &1))).()
  end

  defp create_markdown(diff_map, got_version) do
    {only_new_index, only_old_index, new_version, old_version} = if Version.compare(@version, got_version) == :gt,
        do: {0, 1, @version, got_version},
        else: {1, 0, @version, got_version}

    """
    # はじめに
    - [Elixir](https://elixir-lang.org/) 楽しんでいますか:bangbang::bangbang::bangbang:
    - この記事では`#{old_version}` => `#{new_version}`の差異をお示しします

    # [#{old_version}](https://hexdocs.pm/elixir/#{old_version}/Kernel.html) => [#{new_version}](https://hexdocs.pm/elixir/#{new_version}/Kernel.html)増えた関数

    #{diff_content(diff_map, only_new_index, new_version)}

    # [#{old_version}](https://hexdocs.pm/elixir/#{old_version}/Kernel.html) => [#{new_version}](https://hexdocs.pm/elixir/#{new_version}/Kernel.html)なくなった関数

    #{if diff_content(diff_map, only_old_index, old_version) == [],
      do: "- 差分なし",
      else: diff_content(diff_map, only_old_index, old_version)}

    # Wrapping up :lgtm::lgtm::lgtm::lgtm:
    - Enjoy [Elixir](https://elixir-lang.org/) :bangbang::bangbang::bangbang:
    """
  end

  defp diff_content(diff_map, index, version) do
    diff_map
    |> Enum.reject(fn {mod, _} -> mod == __MODULE__ end)
    |> Enum.map(fn {mod, diffs} -> {mod, Enum.at(diffs, index)} end)
    |> Enum.map(fn {mod, map_set} ->
      module_name = "#{mod}" |> String.split(".") |> Enum.at(-1)

      diff_functions =
        Enum.reject(map_set, fn {name, _} -> Atom.to_string(name) |> String.starts_with?("__") end)
        |> Enum.map(fn {name, arity} ->
          "- [#{name}/#{arity}](https://hexdocs.pm/elixir/#{version}/#{module_name}.html##{name}/#{arity})"
        end)
        |> Enum.join("\n")

      if diff_functions == "" do
        ""
      else
        """
        ## [#{module_name}](https://hexdocs.pm/elixir/#{version}/#{module_name}.html)

        #{diff_functions}

        """
      end
    end)
    |> Enum.reject(& &1 == "")
  end

end

defmodule Utils do
  @name "awesome"

  def name, do: @name

  def functions do
    :code.all_loaded()
    |> Enum.filter(fn {mod, _} -> "#{mod}" =~ ~r{^[A-Z]} end)
    |> Enum.map(fn {mod, _} -> mod end)
    |> Enum.reduce(%{}, fn mod, acc ->
      Map.put(acc, mod, mod.__info__(:functions))
    end)
  end
end
  • ちょっと長いですが、.mdを吐き出すためのゴニョゴニョが長いだけです
$ cd node_new
$ asdf local elixir 1.12.1-otp-24
$ asdf local erlang 24.0.2
$ asdf reshim elixir 1.12.1-otp-24
$ asdf reshim erlang 24.0.2
$ iex --sname node_new

iex> Node.connect :"node_old@20-02noMacBook-Pro"

iex> c "new.ex"

iex> Differ.start
  • Node.connect/1で、node_oldにつないでいます
    • 逆からつないでもいいはずです
  • Differ.startを実行すると、output.mdを吐き出します
  • 実行結果は別の記事であげます

Wrapping up :lgtm::lgtm::lgtm::lgtm:

9
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?