trashyEx

trashyEx

Types in a decorator and accessing Context struct

Hello,

Probably related with macros (since I am learning them bit a bit), but let’s see if I can get some insight in what is going on.

I installed the decorator library (Elixir function decorators — decorator v1.4.0). Then, using a hello-world Phoenix project, I have a generic print decorator, but I would like to have a specific one for %Plug.Conn{}, and it does not work.

PageController:

  @decorate print_conn()
  def index_specific(%Plug.Conn{} = conn, _params) do
    IO.inspect(conn)
    render(conn, "index.html")
  end

  @decorate print()
  def index_generic(conn, _params) do
    IO.inspect(conn)
    render(conn, "index.html")
  end

The decorators from HwDecorator:

defmodule HwDecorator do
  use Decorator.Define, [print: 0, print_conn: 0]

  # at compile-time it does not know if is Plug.Conn
  # def print(body, %{args: [%Plug.Conn{} = conn, _params]} = context) do
  # so I assume we can work only with arity/2
  # alternative, to mark with print_conn
  def print(body, %{args: [conn, _params]} = context) do
    quote do
      IO.puts("Func Conn begin: #{Atom.to_string(unquote(context.name))}")
      unquote(body)
      IO.puts("Func Conn end: #{Atom.to_string(unquote(context.name))}")
    end
  end

  def print(body, context) do
    x = 3
    quote do
      #  IO.inspect(unquote(context), label: "context")  <---- WHY:2
      IO.puts("Func begin: #{unquote(x)} #{Atom.to_string(unquote(context.name))}")
      unquote(body)
      IO.puts("Func end: #{Atom.to_string(unquote(context.name))}")
    end
  end

  # This does not work:
  #  def print_conn(body, %{args: [%Plug.Conn{} = conn, _params]} = context) do. # WHY:1
  def print_conn(body, %{args: [conn, _params]} = context) do
    quote do
      IO.puts("Func Conn type begin: #{Atom.to_string(unquote(context.name))}")
      unquote(body)
      IO.puts("Func Conn type end: #{Atom.to_string(unquote(context.name))}")
    end
  end
end

The function receives:

  [{:=, [line: 8], [
      {:%, [line: 8], [
        {:__aliases__, [line: 8], [:Plug, :Conn]}, {:%{}, [line: 8], []}
      ]},
      {:conn, [line: 8], nil}
    ]},
    {:_params, [line: 8], nil}
  ]

So, I assume it is not matching since %Plug.Conn{} = conn is not the same as all those tuples from above.

I have 2 questions.

  • WHY:1: What can be done to achieve using types in the decorator functions? Like, for instance, matching Plug.Conn with the first param? I annotate the type in index_specific in case it helps, since I imagine index_generic does not know it is Plug.Conn at compile time (where I suspect the macros/decorators are being executed).
== Compilation error in file lib/hw_phoenix_web/controllers/page_controller.ex ==
** (FunctionClauseError) no function clause matching in HwDecorator.print_conn/2

    The following arguments were given to HwDecorator.print_conn/2:

        # 1
        {:__block__, [], [{{:., [line: 9], [{:__aliases__, [line: 9], [:IO]}, :inspect]}, [line: 9], [{:conn, [line: 9], nil}]}, {:render, [line: 10], [{:conn, [line: 10], nil}, "index.html"]}]}

        # 2
        %Decorator.Decorate.Context{args: [{:=, [line: 8], [{:%, [line: 8], [{:__aliases__, [line: 8], [:Plug, :Conn]}, {:%{}, [line: 8], []}]}, {:conn, [line: 8], nil}]}, {:_params, [line: 8], nil}], arity: 2, module: HwPhoenixWeb.PageController, name: :index}

    lib/hw_phoenix/decorator.ex:28: HwDecorator.print_conn/2
    (decorator 1.4.0) lib/decorator/decorate.ex:164: Decorator.Decorate.apply_decorator/3
    (elixir 1.13.4) lib/enum.ex:2396: Enum."-reduce/3-lists^foldl/2-0-"/3
    (decorator 1.4.0) lib/decorator/decorate.ex:128: Decorator.Decorate.decorate/4
    (elixir 1.13.4) lib/enum.ex:2396: Enum."-reduce/3-lists^foldl/2-0-"/3
    (decorator 1.4.0) expanding macro: Decorator.Decorate.before_compile/1
    lib/hw_phoenix_web/controllers/page_controller.ex:1: HwPhoenixWeb.PageController (module)
  • WHY:2: Why the context variable cannot be used directly there? It is just an struct. I don’t understand why context.args or context.name work, but not context.
== Compilation error in file lib/hw_phoenix_web/controllers/page_controller.ex ==
** (CompileError) lib/hw_phoenix_web/controllers/page_controller.ex: invalid quoted expression: %Decorator.Decorate.Context{args: [{:conn, [line: 14], nil}, {:_params, [line: 14], nil}], arity: 2, module: HwPhoenixWeb.PageController, name: :index_two}

Please make sure your quoted expressions are made of valid AST nodes. If you would like to introduce a value into the AST, such as a four-element tuple or a map, make sure to call Macro.escape/1 before

First Post!

trashyEx

trashyEx

Any idea?

Where Next?

Popular in Questions Top

_russellb
I want to try my hand at web scraping. What tools/libraries do I need to use. I’m hoping to turn this into something professional so don’...
New
quazar
How to set Jason to encode all fields in ecto schema, I don’t care about security and implementing only is taking long list of attributes...
New
Jim
As a follow up to my earlier question: I have the code compiling and running but not getting a successful login from the rest server. ...
New
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
New
qwerescape
Is there a way to get the call stack or stack trace at any point in the code? Not from exceptions, but an expression that returns how the...
New
shahryarjb
Hello, I have map which I want to convert it to string like this: the map: %{last_name: "tavakkoli", name: "shahryar"} the string I ne...
New
stefanluptak
Hello everybody, usually, I use a 29" ultra-wide monitor for VSCode which can easily accomodate explorer (files panel) + file with code ...
New
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
wernerlaude
In AR this is so simple @articles = current_user.articles How to do in Ecto? def index(conn, _params) do current_user = conn.assig...
New
skosch
To my knowledge, put_in, Map.update etc. all have the one limitation of not automatically creating intermediate keys when needed (for exa...
New

Other popular topics Top

Brian
What is the proper way to load a module from a file in to IEX? In the python world, doing something like this pretty standard: from ....
New
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
Tee
can someone please explain to me how Enum.reduce works with maps
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
vac
Hi, I'm quite new in Elixir and I'm trying to format a string to a PEM format. I have the certificate value like MIIDBTCCAe2...... and ...
New
chrismccord
As promised, the first release candidate of Phoenix 1.3.0 is out! This release focuses on code generators with improved project structure...
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
skosch
To my knowledge, put_in, Map.update etc. all have the one limitation of not automatically creating intermediate keys when needed (for exa...
New
aesmail
Hello guys, I have finally made it. I created an admin interface for a framework. It’s been on my todo list for years and with the curre...
New

We're in Beta

About us Mission Statement