mudasobwa

mudasobwa

Creator of Cure

ExPanda - full macro expansion for Elixir AST introspection

I’ve been heavily working with macros for more than 10 years already and I always used kinda ad-hoc code to expand/debug/test those when in trouble.

So yeah, it’s better to get a reputation of a slowpoke rather than to spend another 10 years fighting the ghosts.

Welcome ExPanda library that expands macros all the turtles down (short of defmodule and def/defp/defmacro/defmacrop structural forms.)

It’s time to take a look at what use GenServer does actually become in your code:

iex|🌢|1 ▶ "defmodule M, do: use GenServer"
          |> ExPanda.expand_to_string()
          |> elem(1)
          |> IO.puts() 

defmodule M do
  require GenServer
  opts = []
  @behaviour GenServer
  case :erlang.not(Module.has_attribute?(M, :doc)) do
    false ->
      nil

    true ->
      Module.__put_attribute__(
        M,
        :doc,
        {0,
         "Returns a specification to start this module under a supervisor.\n\nSee `Supervisor`.\n"},
        nil,
        []
      )
  end

  def child_spec(init_arg) do
    default = %{id: M, start: {M, :start_link, [init_arg]}}
    Supervisor.child_spec(default, unquote(Macro.escape(opts)))
  end

  defoverridable child_spec: 1
  @before_compile GenServer
  @doc false
  def handle_call(msg, _from, state) do
    proc =
      case Process.info(:erlang.self(), :registered_name) do
        {_, []} -> :erlang.self()
        {_, name} -> name
      end

    case :erlang.phash2(1, 1) do
      0 ->
        :erlang.error(
          RuntimeError.exception(
            <<"attempted to call GenServer ", String.Chars.to_string(inspect(proc))::binary,
              " but no handle_call/3 clause was provided">>
          ),
          :none,
          error_info: %{module: Exception}
        )

      1 ->
        {:stop, {:bad_call, msg}, state}
    end
  end

  @doc false
  def handle_info(msg, state) do
    proc =
      case Process.info(:erlang.self(), :registered_name) do
        {_, []} -> :erlang.self()
        {_, name} -> name
      end

    :logger.error(
      %{label: {GenServer, :no_handle_info}, report: %{module: M, message: msg, name: proc}},
      %{
        domain: [:otp, :elixir],
        error_logger: %{tag: :error_msg},
        report_cb: &:erlang./(GenServer.format_report(), 1)
      }
    )

    {:noreply, state}
  end

  @doc false
  def handle_cast(msg, state) do
    proc =
      case Process.info(:erlang.self(), :registered_name) do
        {_, []} -> :erlang.self()
        {_, name} -> name
      end

    case :erlang.phash2(1, 1) do
      0 ->
        :erlang.error(
          RuntimeError.exception(
            <<"attempted to cast GenServer ", String.Chars.to_string(inspect(proc))::binary,
              " but no handle_cast/2 clause was provided">>
          ),
          :none,
          error_info: %{module: Exception}
        )

      1 ->
        {:stop, {:bad_cast, msg}, state}
    end
  end

  @doc false
  def terminate(_reason, _state) do
    :ok
  end

  @doc false
  def code_change(_old, state, _extra) do
    {:ok, state}
  end

  defoverridable code_change: 3, terminate: 2, handle_info: 2, handle_cast: 2, handle_call: 3
end

https://github.com/am-kantox/ex_panda

Enjoy!

Most Liked

nulltree

nulltree

10/10 name.

mudasobwa

mudasobwa

Creator of Cure

I have plans to ping ExpertLSP team members after I have it tested thoroughly with my own Ragex.

cmo

cmo

Nice. I’ve been patiently waiting years for someone to integrate this sort of thing into the LSP for me.

Where Next?

Popular in Announcing Top

mspanc
I am pleased to announce an initial release of the Membrane Framework - an Elixir-based framework with special focus on processing multim...
New
seancribbs
Today I released a new dialyzer Mix task as the dialyzex package! At the time we started writing this task, the existing dialyzer integra...
New
gabrielpoca
Hello everyone! I want to share with you something that I’m really proud of: https://stillstatic.io/ Still is a static site builder for...
New
Crowdhailer
The latest release of Ace (0.10.0) includes serving content over HTTP/2. I have started writing a webserver to teach my self more about...
New
tmbb
I’ve been working on two packages (not on hex.pm yet) to build admin interfaces for phoenix apps: bureaucrat - which contains a bunch ...
New
maltoe
Hello! Came here to announce ChromicPDF, a pet project PDF generator I’ve been working on for the past few months. Why another PDF gener...
New
riverrun
I’ve just released version 3 of Comeonin, a password hashing library. The following small changes have been made: changes to the NIF c...
New
Eiji
ExApi is a library that I’m developing now and hope release soon This library will allow to: list all apis list all api implementation...
New
KronicDeth
Elixir plugin for JetBrain’s IntelliJ Platform (including Rubymine) This is a plugin that adds support for Elixir to JetBrains IntelliJ...
289 36432 110
New
woylie
Flop is an Elixir library that applies filtering, ordering and pagination parameters to your Ecto queries. offset-based pagination with...
New

Other popular topics Top

baxterw3b
Hi guys, i’m new in the Elixir world, and i have to say, that i love it! i’m having some problem to understand anonymous functions with ...
New
albydarned
Hello all! I am typing this post from my new MacBook Pro with the M1 chip. I’m loving it so far, and will probably use it as my daily dr...
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
chrismccord
This release brings a number of exciting features, including integration with the new Phoenix LiveDashboard and Phoenix LiveView. There h...
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
saif
Hello everyone, Long time lurker first time poster here. I’ve recently begun working on Elixir full-time again! :raised_hands: It’s been...
New
shijith.k
I am trying to start a new phoenix project with elixir 1.9, but mix phx.new does not work. It says that ** (Mix) The task "phx.new" could...
New
jaysoifer
Is there a way to rollback a specific migration and only that one (“skipping” all the other ones)? Would mix ecto.rollback -v 200809061...
New
sergio
Kind of like when jquery came out, it was super necessary. Existing drag and drop libraries have a bunch of baggage to support old browse...
New
lanycrost
Hi everyone! I need implement if…else if…else condition from my elixir code, and anymore of this control flow structures not work proper...
New

We're in Beta

About us Mission Statement