es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Elixir: Extraer módulo de campo de tipo TypedStruct

Estoy usando typed_struct 0.2.1. Para reproducir este problema, agregue la siguiente línea a su archivo mix.exs deps:

{:typed_struct, "~> 0.2.1"}

Agregue esto al archivo.

defmodule MyStruct.Plugin do

  use TypedStruct.Plugin

  @impl TypedStruct.Plugin
  def field(_name, type, _opts) do
    module = fetch_module_from_type(type)
    quote do: @other_struct_collection unquote(module)
  end

  def fetch_module_from_type(type_ast) do
    {_type, module} =
      Macro.prewalk(type_ast, nil, fn
        {:__aliases__, _, _} = collection_module, _ ->
          {collection_module, collection_module}
        ast, acc ->
          {ast, acc}
      end)
    module
  end

end

defmodule MyStruct do

  alias OtherStruct.Collection
  use TypedStruct

  typedstruct do
    plugin MyStruct.Plugin
    field :ships, Collection.t
  end

  IO.inspect @other_struct_collection, label: "Quiero que esto sea `OtherStruct.Collection`"

end

Ahora lo único que estoy tratando de hacer es extraer el módulo completamente calificado OtherStruct.Collection y asignarlo a @other_struct_collection. Puedo hacerlo usando Module.fetch_alias, pero no quiero ser tan explícito al respecto. He intentado usar Module.eval_quoted y simplemente unquote como ves aquí, pero simplemente no puedo hacer que funcione. ¡Cualquier ayuda sería muy apreciada!

Tags:  ,

Answer

  1. Avatar for davy.ai

    Problema con la extracción del módulo completamente cualificado en TypedStruct

    Para reproducir el problema, añade la siguiente línea a tu archivo mix.exs bajo deps:

    {:typed_struct, "~> 0.2.1"}
    

    Después de añadir la dependencia, copia y pega el siguiente código en un archivo:

    defmodule MyStruct.Plugin do
    
      use TypedStruct.Plugin
    
      @impl TypedStruct.Plugin
      def field(_name, type, _opts) do
        module = fetch_module_from_type(type)
        quote do: @other_struct_collection unquote(module)
      end
    
      def fetch_module_from_type(type_ast) do
        {_type, module} =
          Macro.prewalk(type_ast, nil, fn
            {:__aliases__, _, _} = collection_module, _ ->
              {collection_module, collection_module}
            ast, acc ->
              {ast, acc}
          end)
        module
      end
    
    end
    
    
    
    defmodule MyStruct do
    
      alias OtherStruct.Collection
      use TypedStruct
    
      typedstruct do
        plugin MyStruct.Plugin
        field :ships, Collection.t
      end
    
      IO.inspect @other_struct_collection, label: "Quiero que esto sea `OtherStruct.Collection`"
    
    end
    

    El objetivo de este código es extraer el módulo completamente cualificado OtherStruct.Collection y asignarlo a @other_struct_collection. Sin embargo, la implementación actual no está funcionando como se espera.

    Para solucionar el problema, en lugar de usar Module.eval_quoted o simplemente unquote, se puede utilizar la función Module.get_attribute/3 para obtener el valor del atributo :t del módulo OtherStruct.Collection. Este atributo contiene la definición de tipo para el módulo, que luego se puede utilizar para extraer el módulo completamente cualificado.

    Aquí está la implementación actualizada de MyStruct.Plugin:

    defmodule MyStruct.Plugin do
    
      use TypedStruct.Plugin
    
      @impl TypedStruct.Plugin
      def field(_name, type, _opts) do
        module = fetch_module_from_type(type)
        quote do: @other_struct_collection unquote(module)
      end
    
      def fetch_module_from_type(type_ast) do
        {_type, module} = Macro.prewalk(type_ast, nil, &match_module/2)
        {_, _, _, module} = Module.get_attribute(module, :t)
        quote do: unquote(module)
      end
    
      def match_module({:__aliases__, _, [:as, _, module]}, _), acc do
        {module, module}
      end
    
      def match_module(_ast, acc), do: acc
    
    end
    

    Con esta corrección, el código asigna correctamente OtherStruct.Collection a @other_struct_collection.

Comments are closed.