lok0613
Passing parameters into defmacros
Hello all,
I’m recently doing something similar to ExUnit, keeping a bunch of variables on “setup” block and then pass it to the next block which is “test” just like below.
defmodule MyTest do
use ExUnit.Case, async: true
setup do
{:ok, %{message: "hi"}}
end
test "my test title", %{message, msg} do
IO.puts(msg)
end
end
However, I didn’t managed to do this on my own.
defmodule XUnit do
defmacro __using__(_opts) do
quote do
import XUnit
@setups []
@tests []
@before_compile XUnit
def run() do
IO.puts("Running....")
run_setups()
run_displays()
end
end
end
defmacro setup(do: block) do
fn_name = String.to_atom("setup")
quote do
def unquote(fn_name)(), do: unquote(block)
@setups [unquote(fn_name) | @setups]
end
end
defmacro test(message, var, do: block) do
var = Macro.escape(var)
quote bind_quoted: [message: message, var: var, block: block] do
fn_name = String.to_atom("test " <> message)
def unquote(fn_name)(unquote(var)), do: unquote(block)
@tests [{fn_name, var} | @tests]
end
end
defmacro __before_compile__(_opts) do
quote do
def run_setups() do
@setups
|> Enum.each(fn setup_fn -> apply(__MODULE__, setup_fn, []) end)
end
def run_displays() do
@tests
|> Enum.each(fn {test_fn, params} ->
apply(__MODULE__, test_fn, [params])
end)
end
end
end
end
defmodule Test do
use XUnit
setup do
%{message: "hi"}
end
test "my test title", %{message: msg} do
IO.puts("print from test, #{msg}")
end
end
Test.run()
It turns out this error message.
warning: variable "msg" does not exist and is being expanded to "msg()", please use parentheses to remove the ambiguity or change the variable name
Main.exs:64: Test
** (CompileError) Main.exs:64: undefined function msg/0
(elixir) src/elixir_bitstring.erl:142: :elixir_bitstring.expand_expr/4
(elixir) src/elixir_bitstring.erl:27: :elixir_bitstring.expand/8
(elixir) src/elixir_bitstring.erl:20: :elixir_bitstring.expand/4
expanding macro: XUnit.test/3
I tried many ways but it still not really work as my expectation. This is my first question on elixir forum, so please could anyone give me some idea how to mimic the way that ex_unit was doing?
Thanks so much
Marked As Solved
Kabie
Ahh, I was overthinking, this should works already.
defmacro test(message, param, do: block) do
quote do
def unquote(:"test_#{message}")(unquote(param)) do
unquote(block)
end
end
end
But your problem is you didn’t pass results that setup returns to tests, something like:
def run_tests() do
setup_result = @setups
|> Enum.reduce(%{}, fn setup_fn, params
-> apply(__MODULE__, setup_fn, [params])
end)
@tests
|> Enum.each(fn test_fn ->
apply(__MODULE__, test_fn, [setup_result])
end)
end
1
Also Liked
kokolegorille
Hello and welcome,
You do have a syntax error,
It should be…
test "my test title", %{message: msg} do
2
Kabie
There is a trick:
defmacro test(message, param, do: block) do
quote do
def unquote(:"test_#{message}")(param) do
unquote(param) = param
unquote(block)
end
end
end
1
Last Post!
Popular in Questions
Hi!
In PHP: $_SERVER[‘SERVER_ADDR’] - in Elixir?
Searched the docs for ip address and the web, no good results.
Thanks!
New
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
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
There are pre-rolled solutions for other frameworks that do work. However, Phoenix does not seem to have these. Have people had good expe...
New
Good day to you all.
I have been struggling to get a query involving like and ilike to work.
Can anyone assist me on this, please?
pro...
New
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
I have a relationship of love and hate with Elixir. Lots of things are just absolutely right, but there are some things that are kind of ...
New
Other popular topics
Lets say I have map like this fetching from my database
%{"_id" => #BSON.ObjectId<58eb1a7a9ad169198c3dXXXX>, "email" => ...
New
Phoenix 1.4.0 released
Phoenix 1.4 is out! This release ships with exciting new features, most notably
with HTTP2 support, improved deve...
New
What is the idiomatic way of matching for not nil in Elixir?
E.g.,
First way:
defp halt_if_not_signed_in(conn, signed_in_account) when...
New
I asked this very same question on twitter and got some interesting feedback, but I thought it would be a good question to ask here as we...
New
What learn first? Rust or Elixir
Hi Elixir community!
I’m here because i want learn a new language. I’m a junior developer and mainly i ...
New
After calling mix ecto.create I get this error:
17:00:32.162 [error] GenServer #PID<0.412.0> terminating
** (Postgrex.Error) FATAL...
New
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #elixirconf-us
- #advent-of-code
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #hex










