エンジニアのソフトウェア的愛情

または私は如何にして心配するのを止めてプログラムを・愛する・ようになったか

Phoenix LiveView 0.18 の新しい構文の覚書とQRコード

Phoenix LiveView 0.18 の構文をいじっています。

具体的にはこれ。

hexdocs.pm

:if and :for

It is a syntax sugar for <%= if .. do %> and <%= for .. do %> that can be used in regular HTML, function components, and slots.

For example in an HTML tag:

<table id="admin-table" :if={@admin?}>
  <tr :for={user <- @users}>
    <td><%= user.name %>
  </tr>
<table>

この形の構文は、従来の Phoenix でも、ふだん仕事で使っている Ruby on Rails でも出てこない形なので、今でもこれを見るとむずむずする感じがあるのですが、入れ子が浅くなることで、反復する要素を実際の深さのレベルで書けるという点はわかりやすくてよいですね。

と、いうわけで。 LiveView 0.18 でQRコードを表示させてみました。

defmodule MyAppWeb.QrLive do
  use MyAppWeb, :live_view

  def mount(_, _, socket) do
    {:ok, assign(socket, view_box: "", size: 0, cells: [])}
  end

  def render(assigns) do
    ~H"""
    <form phx-change="change"><textarea name="qr[text]" /></form>

    <svg viewBox={@view_box} xmlns="http://www.w3.org/2000/svg" fill="black">
      <rect x="0" y="0" width={@size} height={@size} fill="white" />
      <rect :for={{x, y} <- @cells} x={x} y={y} width="1" height="1" />
    </svg>
    """
  end

  def handle_event("change", %{"qr" => %{"text" => text}}, socket) do
    socket =
      case QRCode.create(text) do
        {:ok, %QRCode.QR{matrix: matrix}} ->
          size = length(matrix)

          cells =
            for {row, y} <- Enum.with_index(matrix),
                {cell, x} <- Enum.with_index(row),
                cell == 1,
                do: {x, y}

          assign(socket, view_box: "0 0 #{size} #{size}", size: size, cells: cells)

        _ ->
          socket
      end

    {:noreply, socket}
  end
end

実行例。