# 4. Importacao

### **📋 ÍNDICE**

1. Módulos em Elixir
2. Alias - Apelidando Módulos
3. Require - Carregando Macros
4. Import - Importando Funções
5. Use - Injeção de Código
6. Comparativo e Quando Usar
7. Multi Alias/Import/Require/Use
8. Módulos Aninhados e Escopo
9. Boas Práticas
10. Resumo Rápido

***

### 🔰 **1. MÓDULOS EM ELIXIR**

#### **1.1 O que são Módulos?**

```yaml
DEFINIÇÃO:
  Módulos em Elixir são contêineres para funções, macros, structs e outros
  módulos. Eles servem como namespace e mecanismo de organização de código.

CARACTERÍSTICAS:
  - Nomes de módulo começam com letra MAIÚSCULA
  - Usam convenção PascalCase (Ex: MeuModulo, Api.Cliente)
  - São representados como átomos em tempo de compilação
  - Podem ser aninhados (Ex: MeuApp.Submodulo)
  - Cada arquivo .ex ou .exs define (tipicamente) um módulo
```

#### **1.2 Sintaxe Básica**

```elixir
# Módulo simples
defmodule Matematica do
  def soma(a, b), do: a + b
  def multiplica(a, b), do: a * b
end

# Módulo com funções privadas
defmodule Banco do
  defp processar_transacao(conta, valor) do
    # função privada
    %{conta | saldo: conta.saldo + valor}
  end
  
  def depositar(conta, valor) when valor > 0 do
    processar_transacao(conta, valor)
  end
end

# Módulo aninhado
defmodule MeuApp do
  defmodule Banco do
    defmodule Conta do
      defstruct [:numero, :saldo]
      
      def criar(numero, saldo_inicial \\ 0) do
        %__MODULE__{numero: numero, saldo: saldo_inicial}
      end
    end
  end
end

# Acessando módulos aninhados
conta = MeuApp.Banco.Conta.criar("12345", 1000)
```

#### **1.3 Atributos de Módulo**

```elixir
defmodule Exemplo do
  # Atributo de módulo (constante em tempo de compilação)
  @versao "1.0.0"
  @autor "João Silva"
  
  # Usando atributo
  def versao, do: @versao
  
  # Acumulando valores
  @funcoes []
  defmacro defregistrar(nome) do
    @funcoes [nome | @funcoes]
  end
  
  # Documentação
  @moduledoc """
  Módulo de exemplo para demonstração de atributos.
  """
  
  @doc "Retorna a versão do módulo"
  def version, do: @versao
end

# Registro de callbacks (GenServer)
defmodule MeuServidor do
  use GenServer
  
  # Atributos de callback
  @impl GenServer
  def init(estado) do
    {:ok, estado}
  end
end
```

***

### 🔗 **2. ALIAS - APELIDANDO MÓDULOS**

#### **2.1 O que é Alias?**

```yaml
DEFINIÇÃO:
  Alias cria um atalho (apelido) para um módulo, permitindo referenciá-lo
  com um nome mais curto dentro do escopo atual.

SINTAXE:
  alias MeuModulo.Longo.Nome, as: Atalho
  alias MeuModulo.Longo.Nome  # as: Nome (última parte)
  
ESCOPO:
  - Lexical (apenas no bloco onde foi definido)
  - Pode ser usado dentro de funções
```

#### **2.2 Exemplos Práticos**

```elixir
# Alias básico - sem 'as'
defmodule MeuApp do
  alias MeuApp.Usuarios.Servico
  
  def listar_usuarios do
    Servico.listar()  # em vez de MeuApp.Usuarios.Servico.listar()
  end
end

# Alias com 'as' personalizado
defmodule MeuApp do
  alias MeuApp.Usuarios.Database, as: DB
  
  def buscar(id) do
    DB.buscar_por_id(id)
  end
end

# Alias com módulo externo
defmodule Processador do
  alias Jason, as: JSON  # Biblioteca externa
  
  def processar(dados) do
    dados
    |> JSON.encode!()
    |> IO.puts()
  end
end

# Alias dentro de função (escopo local)
defmodule Exemplo do
  def funcao_curta do
    alias Enum, as: E
    [1, 2, 3] |> E.map(&(&1 * 2))
  end
  
  def funcao_longa do
    # Alias não está mais disponível aqui
    Enum.map([1, 2, 3], &(&1 * 2))
  end
end
```

#### **2.3 Alias com Módulos Aninhados**

```elixir
defmodule MeuApp do
  # Alias para módulo no mesmo nível
  alias MeuApp.Banco.Conta, as: Conta
  
  # Alias para submódulo sem prefixo
  alias MeuApp.Banco.Transacao, as: Tx
  
  def criar_conta(numero, saldo) do
    Conta.criar(numero, saldo)
  end
  
  def registrar_transacao(conta, valor) do
    Tx.registrar(conta, valor)
  end
end

# Múltiplos aliases
defmodule Dashboard do
  alias MeuApp.{
    Usuarios.Servico,
    Pedidos.Repositorio,
    Produtos.Catalogo
  }
  
  def dados_completos do
    %{
      usuarios: Servico.listar(),
      pedidos: Repositorio.todos(),
      produtos: Catalogo.disponiveis()
    }
  end
end
```

***

### ⚙️ **3. REQUIRE - CARREGANDO MACROS**

#### **3.1 O que é Require?**

```yaml
DEFINIÇÃO:
  Require é usado para carregar macros de um módulo, tornando-os
  disponíveis para uso no escopo atual.

QUANDO USAR:
  - Você precisa usar MACROS definidas em outro módulo
  - Funções comuns NÃO precisam de require
  - Necessário para usar macros em guards

DIFERENÇA:
  - Funções públicas: disponíveis sem require
  - Macros: exigem require (ou import)
```

#### **3.2 Exemplos Práticos**

```elixir
# ❌ ERRO - Macro sem require
defmodule Exemplo do
  def par?(numero) do
    Integer.is_odd(numero)  # Macro requer require!
  end
end

# ✅ CORRETO - Com require
defmodule Exemplo do
  require Integer
  
  def par?(numero) do
    Integer.is_even(numero)  # Agora funciona!
  end
end

# Require com alias
defmodule Teste do
  require Integer, as: Int
  
  def metade(numero) do
    Int.is_even(numero)
  end
end

# Require para uso em guards
defmodule Validador do
  require Integer
  
  def maior_que_zero?(numero) when is_integer(numero) and numero > 0 do
    true
  end
  def maior_que_zero?(_), do: false
end
```

#### **3.3 Quando Require é Necessário?**

```elixir
# Módulo sem macros (não precisa de require)
defmodule Calculadora do
  def soma(a, b), do: a + b
end

defmodule Teste do
  # ❌ NÃO precisa de require
  alias Calculadora, as: Calc
  
  def testar do
    Calc.soma(1, 2)  # OK sem require
  end
end

# Módulo com macros (PRECISA de require)
defmodule MeuMacro do
  defmacro meu_macro do
    quote do
      IO.puts("Macro executada!")
    end
  end
end

defmodule TesteMacro do
  require MeuMacro
  
  def executar do
    MeuMacro.meu_macro()  # Requer require!
  end
end

# Macros built-in que exigem require
defmodule Exemplos do
  require Integer
  require Logger
  
  def testar do
    # Integer.is_odd/1 é uma macro
    Integer.is_odd(5)
    
    # Logger é um módulo com macros
    Logger.debug("Mensagem de debug")
  end
end
```

***

### 📥 **4. IMPORT - IMPORTANDO FUNÇÕES**

#### **4.1 O que é Import?**

```yaml
DEFINIÇÃO:
  Import traz funções e/ou macros de um módulo para o escopo atual,
  permitindo chamá-las sem o prefixo do módulo.

VANTAGENS:
  - Código mais conciso
  - Útil para DSLs e funções muito usadas

DESVANTAGENS:
  - Polui o namespace
  - Pode causar conflitos de nomes
  - Torna o código menos explícito (dificulta entender de onde vem a função)
```

#### **4.2 Exemplos Práticos**

```elixir
# Sem import (totalmente qualificado)
defmodule Exemplo do
  def processar(lista) do
    lista
    |> Enum.map(&(&1 * 2))
    |> Enum.filter(&(&1 > 5))
    |> Enum.sum()
  end
end

# Com import (mais conciso)
defmodule Exemplo do
  import Enum
  
  def processar(lista) do
    lista
    |> map(&(&1 * 2))
    |> filter(&(&1 > 5))
    |> sum()
  end
end

# Import com opções
defmodule Exemplo do
  # Importar apenas funções específicas
  import Enum, only: [map: 2, filter: 2, sum: 1]
  
  # Importar apenas macros específicas
  import Integer, only: [is_even: 1]
  
  # Importar tudo exceto algumas
  import Enum, except: [reduce: 3]
  
  def processar(lista) do
    lista
    |> map(&(&1 * 2))
    |> filter(&(&1 > 5))
    |> sum()
  end
end
```

#### **4.3 Import vs Alias**

```elixir
# Usando alias (explícito)
defmodule ExemploAlias do
  alias Enum, as: E
  
  def processar(lista) do
    lista
    |> E.map(&(&1 * 2))
    |> E.filter(&(&1 > 5))
    |> E.sum()
  end
end

# Usando import (implícito)
defmodule ExemploImport do
  import Enum
  
  def processar(lista) do
    lista
    |> map(&(&1 * 2))
    |> filter(&(&1 > 5))
    |> sum()
  end
end

# ⚠️ Problema com import: conflito de nomes
defmodule Conflito do
  import List, only: [duplicate: 2]
  
  def testar do
    # Qual duplicate? A de List ou do módulo atual?
    duplicate(:ok, 3)
  end
end

# ✅ Alias evita confusão
defmodule SemConflito do
  alias List, as: L
  
  def duplicate(valor, vezes) do
    # Função local
  end
  
  def testar do
    duplicate(:ok, 3)      # função local
    L.duplicate(:ok, 3)    # função do módulo List
  end
end
```

***

### 🚀 **5. USE - INJEÇÃO DE CÓDIGO**

#### **5.1 O que é Use?**

```yaml
DEFINIÇÃO:
  Use é um macro especial que chama o callback `__using__/1` do módulo,
  permitindo que ele injete código no módulo atual.

MECANISMO:
  use MeuModulo, opcoes  # Expande para:
  # require MeuModulo
  # MeuModulo.__using__(opcoes)

USO TÍPICO:
  - Frameworks (Phoenix, Ecto, GenServer)
  - Injeção de comportamento comum
  - Configuração de callbacks
```

#### **5.2 Mecanismo Interno**

```elixir
# Definindo um módulo que pode ser usado
defmodule MeuComportamento do
  defmacro __using__(opts) do
    quote do
      # Código injetado no módulo que usar
      import MeuComportamento
      @before_compile MeuComportamento
      
      # Atributo de módulo
      @meu_opcao Keyword.get(unquote(opts), :opcao, :padrao)
      
      # Define função
      def minha_funcao do
        IO.puts("Função injetada!")
      end
    end
  end
  
  defmacro __before_compile__(env) do
    quote do
      def funcao_gerada_antes do
        IO.puts("Gerada antes da compilação")
      end
    end
  end
end

# Usando o comportamento
defmodule MeuModulo do
  use MeuComportamento, opcao: :personalizado
  
  def funcao_local do
    minha_funcao()  # Função injetada!
  end
end

MeuModulo.minha_funcao()  # "Função injetada!"
MeuModulo.funcao_gerada_antes()  # "Gerada antes da compilação"
```

#### **5.3 Exemplos Comuns na Prática**

```elixir
# GenServer (comportamento OTP)
defmodule MeuServidor do
  use GenServer
  
  # Callbacks implementados
  def init(estado) do
    {:ok, estado}
  end
  
  def handle_call(:pegar, _from, estado) do
    {:reply, estado, estado}
  end
end

# Phoenix (Web Framework)
defmodule MeuWeb.Controller do
  use Phoenix.Controller
  
  def index(conn, _params) do
    render(conn, "index.html")
  end
end

# Ecto (ORM)
defmodule MeuApp.Usuario do
  use Ecto.Schema
  
  schema "usuarios" do
    field :nome, :string
    field :idade, :integer
    timestamps()
  end
end

# ExUnit (Testes)
defmodule MeuTeste do
  use ExUnit.Case, async: true
  
  test "a verdade" do
    assert 1 + 1 == 2
  end
end
```

#### **5.4 Opções no Use**

```elixir
# Definindo módulo com opções avançadas
defmodule Configuravel do
  defmacro __using__(opts) do
    nome = Keyword.get(opts, :as, __MODULE__)
    apenas = Keyword.get(opts, :apenas, [])
    
    quote do
      import unquote(__MODULE__), only: unquote(apenas)
      @nome_modulo unquote(nome)
      
      def nome_modulo, do: @nome_modulo
    end
  end
  
  def funcao1, do: :ok
  def funcao2, do: :ok
end

# Usando com opções
defmodule MeuModulo do
  use Configuravel, as: "Personalizado", apenas: [funcao1: 0]
  
  # funcao1/0 está disponível
  # funcao2/0 NÃO está disponível
end
```

***

### 📊 **6. COMPARATIVO E QUANDO USAR**

#### **6.1 Tabela de Decisão**

| Diretiva    | Efeito                   | Necessário para            | Impacto no namespace   | Uso típico                        |
| ----------- | ------------------------ | -------------------------- | ---------------------- | --------------------------------- |
| **alias**   | Atalho de nome (apelido) | Funções e macros           | Baixo                  | Encurtar nomes longos             |
| **require** | Carrega macros           | USAR macros                | Nenhum                 | Usar macros (ex: Integer.is\_odd) |
| **import**  | Traz funções/macros      | Funções/macros sem prefixo | Alto (polui namespace) | DSLs, funções muito usadas        |
| **use**     | Injeta código (macro)    | Callbacks e comportamentos | Médio                  | Frameworks (Phoenix, GenServer)   |

#### **6.2 Quando Usar Cada Um**

```yaml
PREFIRA alias QUANDO:
  - Módulos com nomes longos
  - Você quer deixar explícita a origem
  - Há risco de conflito de nomes
  - Trabalhando com código compartilhado (ex: bibliotecas)

PREFIRA require QUANDO:
  - Você precisa usar macros do módulo
  - Exemplo: Integer.is_odd/1, Logger.debug/1
  - A macro é usada como guard clause

PREFIRA import QUANDO:
  - Funções são usadas MUITO frequentemente
  - Exemplo: Enum.map, Enum.filter em pipelines
  - Você está criando uma DSL
  - O módulo é específico do domínio

PREFIRA use QUANDO:
  - Implementando comportamentos (GenServer, Supervisor)
  - Usando frameworks (Phoenix, Ecto)
  - Precisa de callbacks no módulo
  - Quer configurar o módulo através de opções
```

#### **6.3 Comparação Visual**

```elixir
# Exemplo sem diretivas (totalmente qualificado)
defmodule Exemplo do
  def processar(lista) do
    lista
    |> Enum.map(&(&1 * 2))
    |> Enum.filter(&Integer.is_odd(&1))
    |> Enum.sum()
  end
end

# Com alias
defmodule Exemplo do
  alias Enum, as: E
  require Integer
  
  def processar(lista) do
    lista
    |> E.map(&(&1 * 2))
    |> E.filter(&Integer.is_odd/1)
    |> E.sum()
  end
end

# Com import
defmodule Exemplo do
  import Enum
  require Integer
  
  def processar(lista) do
    lista
    |> map(&(&1 * 2))
    |> filter(&Integer.is_odd/1)
    |> sum()
  end
end

# Use (para comportamentos)
defmodule MeuServidor do
  use GenServer  # Injeta callbacks e funções
  import Enum    # Importa funções específicas
  alias MeuApp.Repo, as: Repo  # Atalho de nome
  
  def init(estado) do
    {:ok, estado}
  end
end
```

***

### 🔄 **7. MULTI ALIAS/IMPORT/REQUIRE/USE**

#### **7.1 Sintaxe Múltipla**

```elixir
# Múltiplos alias
defmodule MeuApp do
  alias MeuApp.{
    Usuarios.Servico,
    Pedidos.Repositorio,
    Produtos.Catalogo
  }
  
  # Agora disponível como: Servico, Repositorio, Catalogo
end

# Múltiplos import
defmodule Processador do
  import Enum, only: [map: 2, filter: 2, reduce: 3]
  import IO, only: [puts: 1, inspect: 1]
  
  def processar(dados) do
    dados
    |> map(&transformar/1)
    |> filter(&validar/1)
    |> reduce(0, &+/2)
    |> inspect()
    |> puts()
  end
end

# Múltiplos require
defmodule Validador do
  require Integer
  require Logger
  
  def validar(numero) do
    if Integer.is_odd(numero) do
      Logger.info("Número ímpar detectado")
      :impar
    else
      :par
    end
  end
end

# Múltiplos use (comum em Phoenix)
defmodule MeuWeb.Controller do
  use Phoenix.Controller, namespace: MeuWeb
  use MeuWeb, :controller
  use MeuApp.Auth, only: [:current_user]
end
```

#### **7.2 Dentro de Blocos**

```elixir
defmodule Exemplo do
  # Escopo global do módulo
  alias Enum, as: E
  
  def funcao1 do
    # Alias no nível de função
    alias Integer, as: Int
    
    [1, 2, 3]
    |> E.map(&(&1 * 2))
    |> E.filter(&Int.is_odd/1)
  end
  
  def funcao2 do
    # Alias não está disponível aqui!
    # Integer não está mais disponível
    E.map([1,2,3], &(&1 * 2))  # OK - Enum ainda disponível
  end
  
  # Escopo condicional
  if Mix.env() == :test do
    import ExUnit.Assertions
    
    def testar do
      assert 1 + 1 == 2  # assert funciona aqui
    end
  end
end
```

***

### 🏛️ **8. MÓDULOS ANINHADOS E ESCOPO**

#### **8.1 Nested Modules**

```elixir
# Forma de definir módulos nested
defmodule MeuApp do
  defmodule Banco do
    defmodule Conta do
      defstruct [:numero, :saldo]
    end
  end
end

# Acessando
conta = %MeuApp.Banco.Conta{numero: "123", saldo: 1000}

# Alias para módulo nested
defmodule Pagamento do
  alias MeuApp.Banco.Conta
  
  def processar(conta) do
    # Agora é necessário referenciar como Conta
    %Conta{} = conta
  end
end
```

#### **8.2 Escopo de Alias e Imports**

```elixir
defmodule Parent do
  defmodule Child do
  end
  
  # Alias funciona aqui
  alias Parent.Child, as: C
  
  # Import funciona aqui
  import IO, only: [puts: 1]
  
  def funcao1 do
    puts("Escopo do módulo")
    C.some_function()
  end
  
  def funcao2 do
    # Alias e import também funcionam dentro de funções
    alias Parent.Child, as: C
    
    C.some_function()
  end
end

# Escopo aninhado
defmodule A do
  defmodule B do
    # Alias apenas dentro de B
    alias A.C, as: C
  end
  
  defmodule C do
  end
end
```

***

### ✅ **9. BOAS PRÁTICAS**

#### **9.1 Recomendações**

```yaml
✅ PREFIRA ALIAS:
  - Para nomes de módulos longos
  - Para deixar explícita a origem da função
  - Em APIs públicas
  - Para evitar conflitos de nomes

✅ USE IMPORT COM MODERAÇÃO:
  - Apenas para módulos muito usados (ex: Enum)
  - Em contextos muito específicos (DSLs)
  - Use `only:` para explicitar o que está importando
  - Evite `import` em módulos grandes

✅ USE REQUIRE QUANDO NECESSÁRIO:
  - Apenas para módulos com macros que você usa
  - Exemplo: Integer, Logger

✅ USE PARA COMPORTAMENTOS:
  - GenServer, Supervisor, Phoenix
  - Frameworks e bibliotecas com callbacks
```

#### **9.2 Padrões Comuns em Projetos**

```elixir
# Padrão típico de módulo Phoenix
defmodule MeuWeb.PostsController do
  use MeuWeb, :controller
  use Phoenix.Controller
  alias MeuApp.Posts
  alias MeuApp.Repo
  import Ecto.Query
  
  def index(conn, _params) do
    posts = Posts
    |> Repo.all()
    |> Repo.preload([:user, :comments])
    
    render(conn, "index.html", posts: posts)
  end
end

# Padrão típico de módulo Ecto
defmodule MeuApp.Usuario do
  use Ecto.Schema
  import Ecto.Changeset
  
  schema "usuarios" do
    field :nome, :string
    field :email, :string
    timestamps()
  end
  
  def changeset(usuario, params) do
    usuario
    |> cast(params, [:nome, :email])
    |> validate_required([:nome, :email])
    |> unique_constraint(:email)
  end
end
```

***

### 📋 **10. RESUMO RÁPIDO**

#### **10.1 Tabela de Referência**

| Tarefa                              | Como fazer                             | Exemplo                                  |
| ----------------------------------- | -------------------------------------- | ---------------------------------------- |
| **Apelidar módulo**                 | `alias Meu.Modulo.Longo`               | `alias MeuApp.Repo`                      |
| **Apelidar com nome personalizado** | `alias Meu.Modulo, as: M`              | `alias Jason, as: JSON`                  |
| **Carregar macros**                 | `require Modulo`                       | `require Integer`                        |
| **Importar funções**                | `import Modulo`                        | `import Enum`                            |
| **Importar funções específicas**    | `import Modulo, only: [funcao: arity]` | `import Enum, only: [map: 2, filter: 2]` |
| **Importar macros**                 | `import Integer, only: [is_odd: 1]`    | `import Integer, only: [is_even: 1]`     |
| **Usar comportamento**              | `use Modulo`                           | `use GenServer`                          |

#### **10.2 Checklist de Boas Práticas**

```markdown
## ✅ ANTES DE USAR UMA DIRETIVA

- [ ] Este alias é realmente necessário? (o nome do módulo é muito longo?)
- [ ] O import vai poluir meu namespace?
- [ ] Usei `only:` para restringir o import?
- [ ] Existe risco de conflito com função local ou outro módulo?

## ✅ PARA REQUIRE

- [ ] O módulo possui macros que estou usando?
- [ ] Todos os módulos de macro estão com require?

## ✅ PARA USE

- [ ] Li a documentação do módulo sobre o que `use` injeta?
- [ ] Estou preparado para receber código injetado no meu módulo?
```

#### **10.3 Exemplo Integrado Final**

```elixir
defmodule MeuApp.Servico do
  # Use para comportamentos
  use GenServer
  
  # Alias para módulos do projeto
  alias MeuApp.{Repo, Usuario, Email}
  
  # Import de funções muito usadas
  import Ecto.Query
  
  # Require para macros
  require Logger
  
  # @impl para indicar callbacks
  @impl GenServer
  def init(opts) do
    Logger.info("Serviço iniciado com opções: #{inspect(opts)}")
    {:ok, opts}
  end
  
  # Função pública
  def listar_usuarios do
    # Query do Ecto
    query = from u in Usuario, select: u.name
    Repo.all(query)
    |> Enum.map(& &1.name)  # Import do Enum
    |> Enum.join(", ")
  end
  
  # Função privada
  defp enviar_email(usuario, assunto) do
    usuario
    |> Email.novo(assunto)
    |> Email.enviar()
  end
end
```

***

**🔐 Lembre-se: As diretivas de importação em Elixir são lexicamente escopadas e ferramentas poderosas. Use `alias` para clareza, `import` com moderação, `require` quando necessário e `use` para extensão de comportamento!**


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://0xmorte.gitbook.io/bibliadopentestbr/conceitos/programacao-e-linguagens/elixir/4.-importacao.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
