KoviRobi

KoviRobi

Debug function call macro

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?

iex(1)> require Debug; import Debug
Debug

iex(2)> inspect_call(round(2.3*4.5))
round(10.35) -> 10

iex(3)> inspect_call(inspect({:foo, 1+2}))
inspect({:foo, 3}) -> "{:foo, 3}"
"{:foo, 3}"

iex(4)> inspect_call(IO.inspect(1) + IO.inspect(2))
1
2
+(1, 2) -> 3
3

It’s hopefully a fairly easily understandable piece of macro, though only evaluating the arguments once did make it more complicated. The first pattern-matching is taken from the Macro.decompose_call/1 function.

defmodule Debug do
  defmacro inspect_call(block) do
    {name, args, rebuild} =
      case block do
        {:{}, _metadata_a, args} when is_list(args) ->
          raise CompileError,
            description: "Using inspect_call on a map literal is not supported",
            file: __CALLER__.file,
            line: __CALLER__.line

        {{:., metadata_a, [remote, function]}, metadata_b, args}
        when is_tuple(remote) or is_atom(remote) ->
          {
            Macro.to_string({{:., metadata_a, [remote, function]}, [no_parens: true], []}),
            args,
            fn new_args -> {{:., metadata_a, [remote, function]}, metadata_b, new_args} end
          }

        {name, metadata_a, args} when is_atom(name) and is_atom(args) ->
          {to_string(name), [], fn _new_args -> {name, metadata_a, args} end}

        {name, metadata_a, args} when is_atom(name) and is_list(args) ->
          {to_string(name), args, fn new_args -> {name, metadata_a, new_args} end}

        _ ->
          raise CompileError,
            description:
              "Cannot understand function call #{Macro.to_string(block)}",
            file: __CALLER__.file,
            line: __CALLER__.line
      end

    eval_args =
      for n <- 1..length(args) do
        Macro.unique_var(:"eval_arg_#{n}", __MODULE__)
      end

    return_value = Macro.unique_var(:return_value, __MODULE__)

    quote do
      unquote_splicing(
        for {e_a, a} <- Enum.zip(eval_args, args) do
          quote do
            unquote(e_a) = unquote(a)
          end
        end
      )

      IO.write(
        unquote(name) <>
          "(" <>
          (unquote(eval_args)
           |> Enum.map(&inspect/1)
           |> Enum.join(", ")) <>
          ")"
      )

      unquote(return_value) = unquote(rebuild.(eval_args))

      IO.puts(" -> " <> inspect(unquote(return_value)))

      unquote(return_value)
    end
  end
end

Most Liked

sabiwara

sabiwara

Elixir Core Team

Good news: starting from Elixir 1.15, prying for dbg in IEx becomes opt-in :tada:.

hauleth

hauleth

There is already such macro in Kernel

Where Next?

Popular in Guides/Tuts Top

OvermindDL1
Ran across this recently, it’s a set of cheatsheet inforgraphic things of the OTP behaviours on the BEAM: https://github.com/Telichkin/o...
New
kokolegorille
Hello dear alchemists, There was this question some days ago here about the deployment to a VPS. As I was in the process of deploying t...
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
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
nelsonic
When we were figuring out how to use Phoenix LiveView we got stuck a few times. So in order to save other people time, we created a comp...
New
njwest
In the process of developing a Phx-based multiplayer experience, I found myself with so many browser tabs open with Elixir gaming resourc...
New
cheerfulstoic
I spent quite a bit of time trying to find a good configuration to build / test my Elixir app in CircleCI and then push an image to Docke...
New
dmitriid
This is not a question, but a post for anyone who may need it in the future. Sometimes some browsers may mangle the filename if it’s non-...
New
caspg
Hi everyone, I recently implemented a real-time search feature in a Phoenix application using LiveView and Tailwind, and I wanted to sha...
New
yeshan333
vfox (version-fox) is a popular general version management tool write in Go, and the plug-in mechanism uses Lua to achieve extensibility....
New

Other popular topics Top

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
jononomo
I am trying to figure out how Mix knows whether the environment is test, dev, or prod – where is this set? Thanks.
New
ovidiubadita
Hey all, I discovered Elixir and I love it. I always wanted to learn a functional programming and I intended to go for Haskell, but afte...
New
stefanchrobot
What’s the safe way to decode a JSON string into a struct? I want to avoid calling String.to_atom. Jason.decode can give me a map with st...
New
dogweather
I wrote this comment on r/haskell, and it’s not popular there. :wink: But I think I’m on to something… Haskell reminds me of Java, and e...
New
fireproofsocks
Forgive me if this is obvious, but how does one delete a database record WITHOUT selecting it first? Ecto.Repo — Ecto v3.14.0 has exampl...
New
Nvim
Anybody knows a comprehensive comparison of Django and Phoenix, thanks for the help. Where are they similar? Where do they differ the m...
New
msaraiva
Surface is an experimental library built on top of Phoenix LiveView and its new LiveComponent API that aims to provide a more declarative...
564 43622 214
New
siddhant3030
Hi, I have to write a raw query for one of my project. But till now I have used ecto queries and don’t have much experience writing raw ...
New
TunkShif
This post is an instruction guide to help you setup your Neovim for Elixir development from scratch. It includes general information on h...
274 41539 114
New

We're in Beta

About us Mission Statement