fceruti

fceruti

A tiny macro to clean LiveView code

Sup ppl, I just wanted to share a little macro I created to simplify LiveView code. It allows you to convert

socket.assings.variable

into

~a|variable|

For instance here’s a function from Chris McCord’s live_trek

  def handle_event("delete", %{"id" => id}, socket) do
    todo = Todos.get_todo!(socket.assigns.scope, id)
    {:ok, _} = Todos.delete_todo(socket.assigns.scope, todo)

    {:noreply, socket}
  end

Would be

  def handle_event("delete", %{"id" => id}, socket) do
    todo = Todos.get_todo!(~a|scope|, id)
    {:ok, _} = Todos.delete_todo(~a|scope|, todo)

    {:noreply, socket}
  end

Necessary? Not really.

But I thought it looks much better, specially when you have lot’s of socket.assigns and want to reduce verbosit, avoid unpacking assigns and reduce formatter line breaks.

Here’s v0.1

  defmacro sigil_a(expr, _modifiers) do
    socket = Macro.var(:socket, nil)

    quote do
      Map.get(unquote(socket).assigns, String.to_existing_atom(unquote(expr)))
    end
  end

And here’s a vim command to search and replace:

:%s/socket\.assigns\.\([a-zA-Z0-9_]*\)/\~a|\1|

Most Liked

zachallaun

zachallaun

If you wanted to be really evil, you could overload the @ operator if the caller environment contains socket :smiling_imp:

defmodule Evil do
  defmacro __using__(_) do
    quote do
      import Kernel, except: [@: 1]
      import Evil
    end
  end

  import Kernel, except: [@: 1]

  defmacro @name do
    var = Macro.var(:socket, nil)

    if assigns_call?(__CALLER__, name) do
      {name, _, _} = name
      quote(do: Map.fetch!(unquote(var).assigns, unquote(name)))
    else
      quote(do: Kernel.@(unquote(name)))
    end
  end

  defp assigns_call?(env, {name, _, nil}) when is_atom(name) do
    Macro.Env.has_var?(env, {:socket, nil})
  end

  defp assigns_call?(_, _), do: false
end

defmodule Hmm do
  use Evil

  @okay :foo

  def maybe(socket) do
    @okay
  end

  def wow do
    @okay
  end
end

dbg(Hmm.maybe(%{assigns: %{okay: :NEAT!}}))
dbg(Hmm.wow())

(don’t do this)

tfwright

tfwright

Nice idea. Curious, why Map.get rather than fetch? I think the behavior being replaced raises if the expected key is missing, whereas this will return nil I think

sodapopcan

sodapopcan

Innnnnteresting. I was trying to figure out how to do something like this and couldn’t figure it out. I was trying to use var!/2 for this to no avail. I never understood that you can check the caller env.

I was looking to create a single guard that would work on both socket and assigns. I have a lot of single module CRUD LiveViews so I wanted something like:

def handle_event("update", %{"user" => user_params}, socket) when in_action([:edit]) do
  #...
end

def render(assigns) when in_action([:edit]) do
  ~H"""
  """
end

This would check whichever existed of socket.assigns.live_action or assigns.live_action was in [:edit].

Even though I don’t think that is particularly evil (that is, what I wanted to do—what you’re suggesting is absolutely pure evil :see_no_evil: :sweat_smile:) , I ultimately decided I’d rather not do anything out the ordinary like this so I never bothered to seek help figuring it out, but it’s nice to know how it could be done, so thanks!

(that is, if that would even solve the problem… I haven’t actually tried, just responded immediately, lol, but still informative for me)

ityonemo

ityonemo

  1. You can also move String.to_existing_atom to just String.to_atom outside of the quoted block, this saves you a function call at runtime.
  2. might want to try var!(socket) inside the quote instead of Macro.var outside the quote. I think they are equivalent but var!(…) Is slightly more legible and idiomatic IMO
v0idpwn

v0idpwn

This would have a lot of potential if there were good overridable unary operators in Elixir.

Unfortunately, +, -, !, ^, not, @, & are too useful and meaningful to be overriden. There is ~~~ but its ugly and too hard to write :stuck_out_tongue: .

Makes me think Elixir maybe could support an unary $ operator.

Where Next?

Popular in Guides/Tuts Top

siever
I just wrote a simple guide on how you can setup a productive elixir development environment in vim. Its really easy, just a few steps. ...
New
annad
I’m posting this for developers who are totally new to Phoenix like myself. This is all probably obvious to more skilled Phoenix develope...
New
1player
A question I had when first learning contexts and Ecto was how to expand the default context API to support more flexible queries. Usuall...
New
dkuku
I Created a blog post about setting up svelte with phoenix. I found it a bit tricky and the only blog post I found was written using som...
New
dkuhlman
For those of you who might be interested in using ZeroMQ in Elixir, I converted the Erlang examples in the ZeroMQ “zguide” to Elixir. I ...
New
berts-4865
Here is a quick guide to uploading a file from the browser to DO spaces. It is crude, but will hopefully save sometime time and frustrat...
New
bluegene
Hi guys, I’ve been on a personal journey to learn Elixir for the past two years. During this journey I’ve been using the spaced repetiti...
New
alejandroErik
POST IN CONSTRUCTION Process for compile erlang otp 20 with odbc-unix for Oracle connections on Solaris 11.3 for 64 bits: Introductio...
New
fuelen
Hi all! Just want to share a small code snippet which allows writing CASE expressions using macro which is similar to cond. Here is an ...
New
KoviRobi
Hi, I’ve written the following to debug function calls, not sure if it’s useful for anyone else, and if so should I put it somewhere? i...
New

Other popular topics Top

JakeBecker
TL;DR: I’ve just released an implementation of Microsoft’s IDE-independent Language Server Protocol for Elixir. It adds language support ...
1140 51847 244
New
senggen
Erlang/OTP 25 [erts-13.2.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] 15:22:35.803 [error] gen_event {lager_file_backend...
New
dotdotdotPaul
Okay, I'm having a heck of a time trying to figure out how to best handle the validation of belongs_to associations in Ecto. I'm sure I'...
New
lessless
I believe there are people here who are dealing with CSV files import on the daily basis, and since Excel is a really popular tool there ...
New
New
polypush135
As many of you may have realized by now (sorry for all the posts here) I’ve been working on a db problem where I’m trying to aggregate a ...
New
nsuchy
Hi. I’ve noticed that Windows Powershell has it’s own IEX command and you cannot access Elixir’s IEX due to the conflict. This isn’t a cr...
New
rms.mrcs
Hi, I need to transform a list of numbers into a map where the keys are the indexes and the values are the original values of the list....
New
belgoros
I’m not a pro in using Regex and can’t figure out why the following behaviour happens, especially if we take into account the difference ...
New
josevalim
Hi everyone, One of the features added to Elixir early on to help integration with Erlang code was the idea of overridable function defi...
New

We're in Beta

About us Mission Statement