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_specificin case it helps, since I imagineindex_genericdoes 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
contextvariable cannot be used directly there? It is just an struct. I don’t understand whycontext.argsorcontext.namework, but notcontext.
== 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
Any idea?
Popular in Questions
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
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
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
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
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
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
Hello everybody,
usually, I use a 29" ultra-wide monitor for VSCode which can easily accomodate explorer (files panel) + file with code ...
New
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
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
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
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
TL;DR: I’ve just released an implementation of Microsoft’s IDE-independent Language Server Protocol for Elixir. It adds language support ...
New
can someone please explain to me how Enum.reduce works with maps
New
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
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
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
As promised, the first release candidate of Phoenix 1.3.0 is out! This release focuses on code generators with improved project structure...
New
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
To my knowledge, put_in, Map.update etc. all have the one limitation of not automatically creating intermediate keys when needed (for exa...
New
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







