shahryarjb

shahryarjb

Need help to create nested struct macro (A.B.C)

Hello, I am developing a macro to create nested struct in a module or (module → module …), I took the original code from this repo, because it had been abandoned and I want many options for validation etc, I move it inside my project, you can see it in this link.

The problem:

To create a nested struct, I create a new module in one module. For example (A.B.C) is made. Since struct B cannot be called in A at compile time, I just want to create a field named module in its parent struct.
But it seems that the parent has already been compiled and does not allow me to do this.

Please see this part of code:
https://github.com/mishka-group/mishka_developer_tools/blob/master/lib/macros/guarded_struct.ex#L303-L318

in this part I create another module, but how can define a filed which struct type with options

defmodule A do
  defstruct name: "", :b 
  
  defmodule B do
    defstruct name: ""
  end
end

I tried to use @before_compile {__CALLER__.module, :add_parent_field_of_sub_field} to add module attribute like using this

https://github.com/mishka-group/mishka_developer_tools/blob/master/lib/macros/guarded_struct.ex#L296-L300

== Compilation error in file lib/macros/guarded_struct.ex ==
** (ArgumentError) cannot set attribute @before_compile inside function/macro

Even I use this macro inside sub_field macro, to define a field, but it has no effect on my code

Example code I want finally:

  defmodule TestNestedStruct do
    use GuardedStruct

    guardedstruct do
      field(:title, String.t())
      field(:subject, String.t())

      sub_field(:oop, struct(), enforce: true) do
        field(:title, String.t())
        field(:fam, String.t())

        sub_field(:soos, struct(), enforce: true) do
          field(:fam, String.t())
        end

        field(:site, String.t())
      end

      field(:site, String.t())
    end
  end

If I create a field has same name with module name, I can check it inside my builder function.

I have no idea how can do it, thank you in advance

First Post!

shahryarjb

shahryarjb

I think it works for me, but I need more test, if my idea is good for this problem?

  defmacro sub_field(name, type, opts \\ [], do: block) do
    ast = register_struct(block, opts)
    type = Macro.escape(type)

    converted_name =
      name
      |> Atom.to_string()
      |> Macro.camelize()
      |> String.to_atom()
      |> then(&Module.concat(__CALLER__.module, &1))

    quote do
      GuardedStruct.__field__(unquote(name), unquote(type), unquote(opts), __ENV__)

      defmodule unquote(converted_name) do
        unquote(ast)
      end
    end
  end

Output

%MishkaDeveloperToolsTest.GuardedStructTest.TestNestedStruct{
  site: nil,
  oop: nil,
  subject: nil,
  title: nil
}
[:site, :oop, :subject, :title]
[
  __struct__: 0,
  __struct__: 1,
  builder: 1,
  enforce_keys: 0,
  enforce_keys: 1,
  keys: 0,
  keys: 1
]
--------------------------------
%MishkaDeveloperToolsTest.GuardedStructTest.TestNestedStruct.Oop{
  site: nil,
  soos: nil,
  fam: nil,
  title: nil
}
[:site, :soos, :fam, :title]
[
  __struct__: 0,
  __struct__: 1,
  builder: 1,
  enforce_keys: 0,
  enforce_keys: 1,
  keys: 0,
  keys: 1
]
--------------------------------
%MishkaDeveloperToolsTest.GuardedStructTest.TestNestedStruct.Oop.Soos{fam: nil}
[:fam]
[
  __struct__: 0,
  __struct__: 1,
  builder: 1,
  enforce_keys: 0,
  enforce_keys: 1,
  keys: 0,
  keys: 1
]

If you see I just create a field in parent struct and I will check it inside builder function, there is no way I think to load and call the B struct inside A struct field, I think, am I right?

Where Next?

Popular in Questions Top

lastday4you
I wanted to check elixir version in phoenix because i found that my elixir is 1.5 but when i use Enum.chunk_by it said the function is un...
New
aadeshere1
I have a another noob question about loop. Since elixir is immutable, while loop is not directly possible. total = 10 while total != 0 ...
New
gshaw
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
sen
Hi All, I set a environment variables in dev.exs , like below code. when i start server, how can i set the ${enable} value? thanks. d...
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
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
fireproofsocks
I’m working on defining a simple Ecto schema for a table (in PostGres), but I don’t see where I can define a column as NOT NULL. Conside...
New
vrod
I am using the Starship cross-shell prompt – it seems pretty nice, but I get some errors: [WARN] - (starship::utils): Executing command ...
New
joaquinalcerro
Hi there, I am working with Ecto-Postgresql and I need to call all of the records from a specific table but the table has 40,000 records...
New
PeterCarter
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

Other popular topics Top

9mm
I am constructing a JSON object (map) and I need to conditionally set a field. I’m trying to write proper elixir-way code… and I’m at a l...
New
danschultzer
None of the current solutions worked well for me, so I went ahead and built a user management system from scratch. This project took far...
548 29703 241
New
sen
Hi All, I set a environment variables in dev.exs , like below code. when i start server, how can i set the ${enable} value? thanks. d...
New
JeremM34
Hello, how can I check the Phoenix version ? Thanks !
New
Fl4m3Ph03n1x
About me? ( if you have nothing better to do than reading about some random guy in the internet :stuck_out_tongue: ) Hello all, this is ...
New
vrod
I am using the Starship cross-shell prompt – it seems pretty nice, but I get some errors: [WARN] - (starship::utils): Executing command ...
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
RisingFromAshes
I’ve read in another post that it may be possible with a router helper - but I couldn’t find an appropriate one, and tbh, I’m still just ...
New
sergio_101
I am VERY much an elixir newbie. I have taken one elixir course and one phoenix course on Udemy. During that course, I saw the instructor...
New
bsollish-terakeet
Credo is smart enough to check for (something like) this: assert length(the_list) == 0 with this response: Checking if an enum is empt...
New

We're in Beta

About us Mission Statement