# Introdução

Quando eu estava aprendendo Go, encontrei [Learn Go with Tests](https://quii.gitbook.io/learn-go-with-tests/) e achei interessante. A utilização de teste em programas já é algo comum e resolve/evita problemas de manutenção, organização e execução. Deixando o código mais claro e fácil de entender.

Seguindo a mesma ideia, criei esse livro para ensinar elixir utilizando testes.

{% hint style="info" %}
Este livro ainda está sendo escrito, logo, algumas mudanças podem vir a serem feitas sem aviso prévio. Também pode ser encontrado algumas sessões em branco que serão atualizadas com o tempo.
{% endhint %}

Espero que gostem :)

### Sobre o Conteúdo

Todo o livro é estruturado em cima de testes. Isso significa que você ganhará com essa leitura três pontos importantes para qualquer programador:

1. Aprenderá os fundamentos da linguagem elixir;
2. Aprenderá como testar suas implementações em elixir;
3. Aprenderá como pensar em forma de testes;

Esse tipo de pensamento nos possibilta sermos o primeiro a usar nosso próprio código, não sendo raro ver mudança de legibilidade e manutenabilidade devido a isso. Também nos ajuda com entendimento de tarefas e contextos, sendo que precisamos saber o que queremos fazer para criar os testes. Uma vez o teste criado, temos um guia para seguir e fica mais claro nosso objetivo com o mesmo.

Esse tipo de pensamente chegará a você por meio de "eurekas" enquanto você escreve seu código. Espero conseguir passar esse entendimento que tenho sobre desenvolvimento guiado a testes ([TDD](https://martinfowler.com/bliki/TestDrivenDevelopment.html)) e como ele me ajuda no dia-a-dia a resolver problemas complexos e evoluir rapidamente em minhas tarefas.

### Sobre Feedback

Estou abrindo um novo canal de feedback, esse mais efetivo para entendimento do conteúdo.&#x20;

Caso não tenha ficado claro a explicação ou exemplos, agora você pode abrir uma issue no link abaixo, explicando o que está acontecendo. Isso irá ajudará a refinar o conteúdo desse livro, obtendo uma melhor qualidade na didática.

{% embed url="<https://github.com/iago-effting/aprenda-elixir-utilizando-testes/issues>" %}

### Contato

Pode me encontrar no twitter [@iagoEffting](https://twitter.com/iagoEffting)

Tenho também uma newsletter chamada [Café com Elixir](https://semanal.cafecomelixir.com.br/)

E um canal no youtube: [Iago Effting](https://www.youtube.com/channel/UCa4Z9RYii3K-DHCAk8JWV-g/)

Email: <iago@neurocoder.dev>


# Sobre o autor

<div align="left"><figure><img src="https://202566226-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8vDHwBe0fv9dJZnZj1i0%2Fuploads%2FNyHYKUxO6okYrkpqJmuj%2Fimage.png?alt=media&amp;token=4fd128d6-cf45-4cf4-86b9-17877dd9f1dd" alt="" width="160"><figcaption></figcaption></figure></div>

[Iago Effting](https://twitter.com/iagoEffting) é desenvolvedor desde 2009. Atuou em projetos dentro e fora do Brasil utilizando a linguagem Elixir. Considerado um profissional generalista, trabalhou com DevOps (AWS, GCP), mobile (dart/flutter), front-end (JavaScript) e back-end (NodeJS, Go, Ruby, PHP e Elixir), tendo hoje foco em back-end, especificamente na construção de APIs.

Sua grande paixão é em integrações de API's e desenvolvimento guiado a testes.


# O valor desse livro

Não acho que viverei da escrita criativa e nem técnica, mas isso não me impediu de começar a me aventurar nesse mundo. É algo que gosto de fazer e tenho um carinho especial por frases bem elaboradas. Programar é algo próximo disso. Códigos bem elaborados que deixam a leitura fluida e funcionamento fácil é algo incrível. Quando comecei a escrever senti uma vontade de ver a página final, mas isso custa um alto preço em minha vida. Tempo. E é por isso que tenho que falar sobre o valor desse livro.

Chamo de valor propositalmente. O que venho pedir é que pense o quanto esse livro te ajudou ou vai ajudar. O que ele mudou na forma de pensar ou te empolgou em fazer um projeto. Esse é o valor que peço que analisem com carinho, não deve levar muito tempo.

Com base nessa análise, vou disponibilizar algumas formas de precificar. Sim, você leu direito. Quero que você precifique. Isso será meu norte para saber se escrevo outros ou não. Acho que é o jeito mais honesto de pedir isso. Não sou escritor profissional e não tenho um editor. Tudo aqui é feito por mim, em meio a tarefas do trabalho, tarefas como esposo e tarefas como pai. Não é algo fácil, mas me sinto motivado a seguir.

## Algumas formas que você pode me incentivar a continuar

### Me pagando um café

Preciso de energia para escrever, e você pode me pagar o café. Vou disponibilizar meu pix aqui para mandar qualquer valor que seu coração mandar. Pode ser R$ 5, R$ 10 ou qualquer valor que você quiser. Isso realmente me deixará feliz.

<div align="left"><figure><img src="https://202566226-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8vDHwBe0fv9dJZnZj1i0%2Fuploads%2FdgTF7p5U9B2lOJROHgW1%2Fimage.png?alt=media&amp;token=20caff6a-7d30-415a-a7d6-33fafd8dc7f8" alt="" width="217"><figcaption><p>Código QR</p></figcaption></figure></div>

Nome: Iago Effting\
Banco: Inter

### Seguindo minhas redes e compartilhando o conteúdo

Sei que muitos não possuem dinheiro para esbanjar dessa forma. Que temos famílias e sonhos a alcançar. Para vocês, peço apenas que compartilhem o conteúdo. Não só o livro como as redes que participo

{% embed url="<https://cafecomelixir.com.br>" %}

{% embed url="<https://dev.to/iagoeffting>" %}

{% embed url="<https://www.youtube.com/@IagoEffting>" %}

Também possuo uma newsletter semanal =D

{% embed url="<https://cafecomelixir.substack.com/>" %}


# Linguagem

ir é uma linguagem dinâmica e funcional. Ela foi projetada para a construção de aplicações escaláveis e de fácil manutenção, possuindo um cinto de utilidades moderno e uma base cientifica refinada.&#x20;

Dito isso, podemos ressaltar que foi criado pelo brasileiro [José Valim](https://twitter.com/josevalim) que está sempre atualizando o progresso da linguagem e fazendo lives na [twitch](https://t.co/8zKj1end4a), sendo um bom recurso de aprendizado.

Uma das principais aderências da linguagem é o seu suporte a concorrência. Veremos mais adiante nos tópicos avançados, o que isso significa e como podemos utiliza-la. Caso tenha curiosidade, fiz um video na prática de como podemos usar elixir para aumentar a performance em [importar uma grande quantidade de dados no banco de dados PostgresSQL](https://youtu.be/w_Z6BL9_59w). Você não precisa entender tudo do que foi feito ali ainda, você vai chegar la, mas é legal para dar uma ideia do que  o aguarda.

Também precisamos entender alguns conceitos da linguagem. Porém, pode se tornar complexo por tudo por aqui, então para simplificar as coisas, você pode seguir os estudos e quando sentir necessidade (ou eu avisar que será de extrema importância), vá ate a seção de [Conceitos](/conceitos/imutabilidade) do livro para se aprofundar mais nos detalhes.

O primeiro conceito (e que na maioria das vezes confundi quem vem de orientação a objetos) é a [imutabilidade](/conceitos/imutabilidade).  Escrevi ali de forma simples para se tornar mais fácil o entendimento e evoluirmos mais rapidamente.

Caso não entenda os conceitos, revisite sempre que quiser e sempre faça exemplos, pratique muito, mude as coisas, quebre as coisas e as arrume, so assim você vai entender como o elixir funciona. Não se limite a fazer o aplicativo perfeito, eu já desisti disso a muito tempo.

### Empresas que usam elixir em produção

<table data-view="cards"><thead><tr><th></th><th></th><th></th></tr></thead><tbody><tr><td><img src="https://202566226-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8vDHwBe0fv9dJZnZj1i0%2Fuploads%2FAzZAK975VmmABN5JwbdD%2Fimage.png?alt=media&amp;token=0f5e9d45-d108-447c-b29d-07a7902a8995" alt=""></td><td></td><td>embedded, nervers</td></tr><tr><td><img src="https://202566226-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8vDHwBe0fv9dJZnZj1i0%2Fuploads%2FjGQXhGUtWrA3F17a2k97%2Fimage.png?alt=media&amp;token=8328b2f2-ee1e-400b-9980-48a5fd2b11e2" alt=""></td><td></td><td>paas, phoenix</td></tr><tr><td><img src="https://202566226-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8vDHwBe0fv9dJZnZj1i0%2Fuploads%2FLXrgef9LGnxcX02ZUuuP%2Fimage.png?alt=media&amp;token=aada6737-70ba-4163-8210-2d575ec45d74" alt=""></td><td></td><td>real-time, genstage, otp</td></tr><tr><td><img src="https://202566226-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8vDHwBe0fv9dJZnZj1i0%2Fuploads%2F4qwe5xw22yaGAI5DGAUR%2Fimage.png?alt=media&amp;token=f028d422-4e26-4e9a-ac8a-a529b8cae9d8" alt=""></td><td></td><td>social, broadway</td></tr><tr><td><img src="https://202566226-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8vDHwBe0fv9dJZnZj1i0%2Fuploads%2FIREh43FDyPp0vNRqEPPC%2Fimage.png?alt=media&amp;token=e0d78fac-6dfc-42e1-a7b9-7c62c6ce1656" alt=""></td><td></td><td>collab, phoenix, otp</td></tr><tr><td><img src="https://202566226-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8vDHwBe0fv9dJZnZj1i0%2Fuploads%2FZF1v82TQBw48qVBgGZLK%2Fimage.png?alt=media&amp;token=3dc185b8-1eac-4b9e-b1b3-d592c910ca9b" alt=""></td><td></td><td>biz-intelligence, phoenix</td></tr></tbody></table>

Bons estudos.


# Instalação

Precisamos dela em nossa maquina, não é mesmo?

Existem algumas formas de fazer a instalação, dependendo do sistema operacional ou ferramenta que você está utilizando. Para a forma mais básica de instalação pode ser acessado o site onde possui um [guia de instalação](https://elixir-lang.org/install.html) bem simples.&#x20;

{% hint style="info" %}
**Na versão atual do livro estamos usando a versão 1.14 do elixir.**
{% endhint %}


# Ferramenta Mix

Linguagens modernas possuem um toolset que nos facilita a vida, possibilitando um ecossistema que nos ajuda na tarefa do dia-a-dia. A primeira ferramenta que você deve ter conhecimento é chamada [mix](https://hexdocs.pm/mix/Mix.html) e tem como principal propósito: gerenciar seu projeto.&#x20;

Ela tem o poder de:

* Criar projetos elixir;
* Gerenciar dependências;
* Rodar scripts elixir

Uma vez com a linguagem instalada ([já ensinado em etapas anteriores](/primeiros-passos-em-elixir/instalacao)), você tera acesso ao mix por linha de comando.

```shell
$ mix 

** (Mix) "mix" with no arguments must be executed in a directory with a mix.exs file

Usage: mix [task]

Examples:

    mix             - Invokes the default task (mix run) in a project
    mix new PATH    - Creates a new Elixir project at the given path
    mix help        - Lists all available tasks
    mix help TASK   - Prints documentation for a given task

The --help and --version options can be given instead of a task for usage and versioning information.
```

Com isso poderá criar projetos.

## Conclusão

FInalizamos a configuração do nosso ambiente elixir e tudo esta pronto para darmos início aos estudos. Espero que aproveitem cada tópico.


# Meu "Hello, world"

Todo começo precisa de uma apresentação

Toda linguagem tem seu tutorial relacionado ao **Olá, mundo**, vamos fazer isso aqui também. Mas vamos focar também em como o teste funciona, mas primeiro precisamos criar um projeto usando o **mix:**

```shell
mix new hello_world

* creating README.md
* creating .formatter.exs
* creating .gitignore
* creating mix.exs
* creating lib
* creating lib/hello_world.ex
* creating test
* creating test/test_helper.exs
* creating test/hello_world_test.exs

Your Mix project was created successfully.
You can use "mix" to compile it, test it, and more:

    cd hello_world
    mix test

Run "mix help" for more commands.
```

Uma vez criado, você terá a seguinte estrutura:

```
hello_world/
├─ lib/
│  ├─ hello_world.ex
├─ test/
│  ├─ hello_world_test.exs
│  ├─ test_helper.exs
├─ mix.exs
├─ README.md
```

O **mix.exs** é nosso manifesto, é ali que iremos definir tudo que será utilizado. Nome do projeto, versão, suas dependências e como será executado. A criação do projeto pelo mix nos facilita a etapa de configuração de projeto, saindo pronto para rodar, sem maiores complicações.

### Dependências

Todas as dependências vem de um local chamada [hex](https://hex.pm/), o que facilita a inserção e atualização de  bibliotecas no projeto. Elas são definidas dentro do arquivo **mix.exs** na função **deps**. Se algo estiver lá, sera gerido a dependencias de como foi configurada e adicionado ao projeto na pasta `deps` gerada na raiz do projeto, após rodar o comando para baixar as dependências. Para baixar as dependências basta rodar o comando `mix deps.get` .

```
mix deps.get

All dependencies are up to date
```

Nosso projeto ainda não possui nenhuma dependência, então a mensagem de "**All dependencies are up to date"** irá aparecer e podemos seguir.

### Testando

Nosso foco de validação vai ser na pasta `test` na raiz do projeto. Lá estarão todos os testes do projeto e helpers para nos ajudar nisso.

No arquivo `hello_world_test.exs` está nosso primeiro código:

{% code title="test/hello\_world\_test.exs" lineNumbers="true" %}

```elixir
defmodule HelloWorldTest do
  use ExUnit.Case

  test "greets the world" do
    assert HelloWorld.hello() == :world
  end
end
```

{% endcode %}

Por padrão, elixir traz o `ExUnit` como ferramenta de teste. Obtemos capacidades de teste quando adicionamos o código use `ExUnit.Case` em nosso arquivo, dando suporte a funções de `test`, `assert`, `describe` e outros.

O código é bem autoexplicativo, temos uma teste chamado *"greets the world"* nele temos uma afirmação onde a resposta de `HelloWorld.hello()` deve ser igual a `:world` caso isso não ocorra, um erro será disparado.

Para rodar esse teste, podemos executar o comando onde executa todos os testes de uma vez ou somente um arquivo especifico. Vamos executar todos de uma vez:

```shell
mix test

Compiling 1 file (.ex)
Generated hello_world app
..
Finished in 0.02 seconds (0.00s async, 0.02s sync)
1 test, 0 failures
```

Ao executar o comando teremos um relatório de resposta, O nosso nos diz que rodados 1 **doctest** e **1** **test** e não tivemos nenhuma falha.

Caso a resposta esteja diferente do esperado, você poderá ver o erro no relatório. Vamos alterar o teste para esperar `:new_world` e ver o que o relatório nos trás.

<pre class="language-elixir" data-title="test/hello_world_test.exs" data-line-numbers><code class="lang-elixir">defmodule HelloWorldTest do
  use ExUnit.Case

  test "greets the world" do
<strong>    assert HelloWorld.hello() == :new_world
</strong>  end
end
</code></pre>

Basta agora rodar o teste e verificar o relatório:

```shell
mix test
.

  1) test greets the world (HelloWorldTest)
     test/hello_world_test.exs:5
     Assertion with == failed
     code:  assert HelloWorld.hello() == :new_world
     left:  :world
     right: :new_world
     stacktrace:
       test/hello_world_test.exs:6: (test)


Finished in 0.03 seconds (0.00s async, 0.03s sync)
1 test, 1 failure
```

No seu terminal terá cores melhores, em vermelho e verde, mas aqui já da de ter noção da resposta e também o que está incorreto. Vamos voltar agora o teste para tudo voltar a funcionar.

Os testes em elixir funcionam assim. São de extrema importância e simples de serem usados.

### Conclusão

Teste é uma ferramentas importante no desenvolvimento de software, nos ajudando a garantir o comportamento de nossos códigos. Nós próximos capítulos iremos conhecer mais da linguagem por meio do teste, para já termos uma base boa de como as coisas funcionam. Espero ver vocês por lá.


# IEx

O iEx é um shell iterativo onde você pode executar comando elixir. Vamos abrir nosso terminal e executar o comando `iex`.

```elixir
iex
Erlang/OTP 25 [erts-13.1.4] [source] [64-bit] [smp:16:16] [ds:16:16:10] [async-threads:1] [jit:ns]

Interactive Elixir (1.14.3) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)>
```

Temos diversas informações interessantes sobre sua maquina, quando processos ela suporte, arquitetura e outras coisas. Mas vamos nos ater ao simples.&#x20;

Uma vez com o `iex` aberto podemos rodar qualquer tipo de comando elixir. Por exemplo, eu quero imprimir na tela o meu nome.

```
iex(1)> "Effting"
"Effting"
```

Ou quero inverter esse texto

{% hint style="info" %}
**Autocomplete**\
\
IEx tem função de autocomplete, podendo escrever pedaço da palavra e apertar em tab, ela irá dar as opções para você. Tanto as nativas do elixir quanto criadas por você.
{% endhint %}

```
iex(2)> String.reverse("̀Effting")
"gnitffe"
```

Você pode usar qualquer tipo de função que existe no elixir no iex, isso ajuda muito na hora de debugar o código.

{% hint style="info" %}
Caso tenha mais interesse em debugging tenho um vídeo no canal\
\
<https://www.youtube.com/watch?v=QL8gIwNI_7U>
{% endhint %}

### Executando iex em seu projeto

Uma vez que você já possui um projeto e queira usar os módulos que você criou nele, basta adicionar o mix de seu projeto junto. Para isso, temos um simples comando. Vá na pasta raiz de seu projeto (aquele lugar onde tem o `mix.ex` e execute o comando para abrir o iex junto com o `mix`

<pre class="language-sh" data-line-numbers><code class="lang-sh">iex -S mix
Erlang/OTP 25 [erts-13.1.4] [source] [64-bit] [smp:16:16] [ds:16:16:10] [async-threads:1] [jit:ns]

Compiling 4 files (.ex)

<strong>Generated hello_world app
</strong>Interactive Elixir (1.14.3) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)>
</code></pre>

Eu executei dentro do projeto [`hello_world`](/primeiros-passos-em-elixir/meu-hello-world) e como você pode ver ele foi compilado para dentro do terminal iterativo na linha 8.  Agora basta usar alguma função que você ja tenha criado.

### Arquivo .iex.exs

Uma das melhores coisas a se conhecer é o arquivo `.iex.exs`. De início você pode não precisar, mas quando o projeto começar a ficar maior ou os tipoes de dados mais complexas, você vai querer um solução que esse arquivo proporciona.

Quando inicamos uma sessão usitlizando `iex`, a ferramenta procura por um arquivo local chamado `.iex.exs`, normalmente criado no root do projeto, lado-a-lado do `mix.ex`. Então depois procura por um global localizado em `~/.iex.exs` carregando o primeiro que encontrar, dando sempre preferencia para o arquivo local do projeto.

Tudo que está dentro desse arquivo é carregado para o contexto do IEx. Tudo que for criado ali vai ser carregado na sessão. Seja uma [map](/basico/colecoes/mapas), uma [estrutura](/basico/colecoes/estruturas) ou um [modulo](/basico/modulos).&#x20;

Vamos criar um .iex.exs no root do projeto [Hello, world ](/primeiros-passos-em-elixir/meu-hello-world)criado no capítulo anterior. Adicionaremos lá uma variável simples

{% code title=".iex.exs" lineNumbers="true" %}

```elixir
my_first_variable = "awesome!"
```

{% endcode %}

Apenas isso. Agora vamos rodar o iex no root do projeto.

```sh
iex       
Erlang/OTP 25 [erts-13.1.4] [source] [64-bit] [smp:16:16] [ds:16:16:10] [async-threads:1] [jit:ns]

Interactive Elixir (1.14.3) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> my_first_variable
"awesome!"
```

Simples. Isso funciona para qualquer tipo de dado o que torna as coisas bem interessantes. Podendo criar ferramentas para ajudar o debug, por exemplo. Se bem pensado, esse arquivo pode lhe dar bons recursos para te ajudar no dia-a-dia.

### Conclusão

IEx é uma poderosa ferramenta que se bem utilizada pode te livrar de muito estresse. Crie funções de suporte que facilitem seu trabalho, não tenham medo de criar código por lá, isso pode te poupar muito tempo.

###


# Módulos

Precisamos de um lugar para nossas funções morarem, senão, elas podem se perder.

Módulos são onde nossas funções vivem. Elas não podem estar por ai sem um lugar para ficar, pois poderiam se perder e nunca mais ser utilizadas. Elixir obriga todas as funções estarem em módulos.

Para definir um modulo, utilizamos a palavra chave [`defmodule`](https://elixir-lang.org/getting-started/modules-and-functions.html) seguido do nome e da abertura de seu contexto usando `do`. No exemplo criado na seção `Meu "Hello, world"` podemos vê-lo no arquivo `hello_world.ex`

<pre class="language-elixir" data-title="lib/hello_world.ex" data-line-numbers><code class="lang-elixir"><strong>defmodule HelloWorld do # aqui está o nome do nosso módulo
</strong>  def hello do
    :world
  end
end
</code></pre>

Isso serve para quando chamarmos nossas funções. Ao invés de somente `hello`, temos `HelloWorld.hello` e facilmente sabemos quem ela é.

No arquivo de teste podemos ver como o código é executado utilizando a chamada do modulo e depois a função.

<pre class="language-elixir" data-title="test/hello_world_test.exs" data-line-numbers><code class="lang-elixir">defmodule HelloWorldTest do
  use ExUnit.Case
  doctest HelloWorld

  test "greets the world" do
<strong>    assert HelloWorld.hello() == :new_world # Chamada do modulo e função
</strong>  end
end
</code></pre>

Podemos definir diversas funções dentro de um modulo (mas não façam isso, precisamos de organização certo?). Alguns bons exemplos de módulos e funções:

* `Authentication.login(user, password)`
* `Authentication.logout(user)`
* `Article.save(content)`
* `Article.delete(id)`
* `Article.update(article, new_content)`

Percebem como as funções são organizadas dentro de módulos? Isso facilita a leitura e organização do código e deixa as coisas mais intuitivas.

Temos por regra:

* Todo módulo deve começar com letra maiúscula, no estilo [CamelCase](https://pt.wikipedia.org/wiki/CamelCase);
* O modulo deve conter apenas o que é necessário para sua execução;

Nome de módulos podem ter mais de uma nível de profundidade, exemplo `Project.Authentication.Meta.Token` e geralmente seguem a estrutura de pastas.&#x20;

```
lib/authenticatin/meta/token.ex
```

### Atributos de módulo

Podemos definir atributos no módulo. São um tipo de variáveis que vivem apenas dentro do módulo e nunca veem a luz do dia. Útil para utilização interna. Para declarar ela, utilizamos o arroba(@) seguido do nome do atributo e logo após o valor (sem sinal de igual). Exemplo `@attribute_name 10`

Vamos alterar nosso programa para concatenar o atributo de módulo em nossa resposta. Primeiro nosso teste:

<pre class="language-elixir" data-title="test/hello_world_test.exs" data-line-numbers><code class="lang-elixir">defmodule HelloWorldTest do
  use ExUnit.Case
  doctest HelloWorld

  test "greets the world" do
<strong>    assert HelloWorld.hello() == "Hello, new world"
</strong>  end
end
</code></pre>

Rode o programa e voce terá o relatório de erro

```shell
mix test
1) test greets the world (HelloWorldTest)
     test/hello_world_test.exs:5
     Assertion with == failed
     code:  assert HelloWorld.hello() == "Hello, new world"
     left:  :world
     right: "Hello, new world"
     stacktrace:
       test/hello_world_test.exs:6: (test)
```

Precisamos alterar nosso programa para atender a nova resposta e para isso, utilizaremos atributos de módulo, apenas para exemplificar

<pre class="language-elixir" data-title="lib/hello_world.ex" data-line-numbers><code class="lang-elixir">defmodule HelloWorld do
<strong>  @message "Hello, new world" # definição do atributo de módulo
</strong>  
  def hello do
<strong>    @message # Utilização do atributo de módulo
</strong>  end
end

</code></pre>

Basta rodar novamente o teste e tudo estará funcionando.

```shell
mix test
Compiling 1 file (.ex)
.
Finished in 0.01 seconds (0.00s async, 0.01s sync)
1 test, 0 failures
```

#### Para se manter atento

* Atributo de módulo não pode ser acessado do lado de fora do módulo.
* Suporta apenas tipos primitivos, então não poderá executar uma função para obter uma resposta diretamente nele.

### Conclusão

Módulos são formas de agregar funções a fim de deixa-las próximas por contexto, facilitando a utilização e criação da mesma.


# Funções

Funções são a base do desenvolvimento em Elixir. Ela que guiará seu programa ao sucesso e saber escreve-la bem é essencial para todo desenvolvedor. Existem dois tipos de funções

* [Funções nomeadas](/basico/funcoes/funcoes-nomeadas)
* [Funções anônimas](/basico/funcoes/funcoes-anonimas)
* [Funções nomeadas como anônimas](/basico/funcoes/funcoes-nomeadas-convertidas-para-anonima)

Vamos ver um pouco mais sobre elas.


# Funções nomeadas

A função é o principal elemento das linguagens funcionais (grande surpresa an?) e tem como objetivo realizar comportamentos.&#x20;

{% hint style="info" %}
**Aridade**\
\
De forma simples, a [aridade](/conceitos/aridade) é a quantidade de argumentos que uma função recebe.

Uma função `login` que recebe `user` e `password` por parâmetro tem aridade 2 e é representado com o nome da função, barra (/) e o número da aridade. Exemplo:\
\
`login(user, password) -> login/2`\
\
Veja mais no [capítulo de Aridade](/conceitos/aridade)
{% endhint %}

Funções nomeadas devem existir somente dentro de módulos e são declaradas com `def/2` e `defp/2` para funções privadas. Como por exemplo:

<pre class="language-elixir" data-line-numbers><code class="lang-elixir">defmodule Authenticate do
<strong>  def login(user, password) do
</strong>    # ...
  end
  
<strong>  defp create_session(user), do: # ...
</strong>end
</code></pre>

Vamos criar um novo teste em nosso projeto onde iremos fazer uma soma simples. Na pasta `test` crie um novo arquivo chamado `math_test.exs` e nele utilizaremos nosso primeiro `describe`, descrevendo o que está sendo testado.

{% hint style="info" %}
**Describe**

\
O `describe/2` descreve um grupo de testes que tem correlação. Assim podemos criar diversos cenários para uma mesma função que está sendo testada. Exemplo:<br>

* Quando a função x funciona
* Quando a função x não funciona devido a parâmetros errados<br>

Normalmente o describe recebe o `module + função sendo testada + aridade`&#x20;
{% endhint %}

Podemos tirar algumas vantagens quando utilizamos describe. Uma delas é servir de documentação. Então vamos pensar. Precisamos fazer uma soma (função) e essa soma irá somar dois valores x e y (parâmetros). Analisando isso, podemos presumir que o contrato de nossa função seja algo assim `Math.sum/2`. Vamos adicionar isso a nossa describe para facilitar o entendimento

<pre class="language-elixir" data-title="test/math_test.exs" data-line-numbers><code class="lang-elixir">defmodule MathTest do
  use ExUnit.Case

<strong>  describe "Math.sum/2" do
</strong>    # ...
  end
end

</code></pre>

Criaremos o primeiro bloco de teste  para quando passarmos os parâmetros corretos.&#x20;

{% hint style="info" %}
**Parâmetros**

\
Forma de injetar dados dentro de funções de forma a poder ser usada la dentro. A assinatura se da a criação da função usando `def/2`, definindo o nome da função e em seguida adicionando parênteses. Dentro dos parênteses adicionamos as variáveis posicionais. \
\
`def nome_da_funcao(parametro_1, parametro_2)`\
\
Assim você poderá passar dados para dentro da função e os usa-los lá.\
\
`nome_da_funcao(5, 10)`&#x20;
{% endhint %}

Vamos adicionar ao código o bloco de teste usando a função `test/2`

<pre class="language-elixir" data-title="test/math_test.exs" data-line-numbers><code class="lang-elixir">defmodule MathTest do
  use ExUnit.Case

  describe "Math.sum/2" do
<strong>    test "when successed return result" do
</strong>      
    end
  end
end

</code></pre>

Precisamos agora entender o que seria um teste bem sucedido aqui e para isso devemos seguir algumas etapas do TDD para se tornar mais simples

1. Configurar o teste
2. Executar a chamada
3. Criar afirmações

Para configurar o teste, precisamos da função a ser chamada e dos parâmetros que queremos passar, então executamos essa função com os parâmetros e guardados sua resposta, para podermos utilizarmos em nossas afirmações.

Pelo básico, Queremos a soma do valor `x = 1` e  `y = 7` e a resposta deve ser 8. Vamos converter isso para o código

{% code title="test/math\_test.exs" lineNumbers="true" %}

```elixir
defmodule MathTest do
  use ExUnit.Case

  describe "Math.sum/2" do
    test "when successed response the result" do
      # configurando
      x = 1
      y = 7
      
      # Executando a função
      result = Math.sum(x, y)
      
      # criando afirmações
      assert result == 8
    end
  end
end
```

{% endcode %}

Vamos rodar isso e ver o relatório

```shell
mix test
warning: Math.sum/2 is undefined (module Math is not available or is yet to be defined)
  test/math_test.exs:11: MathTest."test Math.sum/2 when successed response the result"/1

.

  1) test Math.sum/2 when successed response the result (MathTest)
     test/math_test.exs:5
     ** (UndefinedFunctionError) function Math.sum/2 is undefined (module Math is not available)
     code: result = Math.sum(x, y)
     stacktrace:
       Math.sum(1, 7)
       test/math_test.exs:11: (test)


Finished in 0.03 seconds (0.00s async, 0.03s sync)
2 tests, 1 failure
```

Possuímos nosso primeiro erro. Decidimos usar TDD e o teste vem antes do código a ser testado, então, não possuímos o código e o teste avisou isso para nós. `Math.sum/2 is undefined`. Vamos criar o módulo Math com a função sum com 2 de aridade.

{% hint style="info" %}
**TDD**

\
**Testing driven design** tem como regra guiar nosso código iniciando ele pelos testes. Uma vez que ele falhe temos um ponto de ação a fazer. Sempre focando no menor esforço a se fazer para o teste passar.\
\
[Leia mais sobre](https://martinfowler.com/bliki/TestDrivenDevelopment.html)
{% endhint %}

Crie o novo arquivo e adicione o mínimo necessários para seguirmos em frente.

{% code title="lib/math.ex" lineNumbers="true" %}

```elixir
defmodule Math do
  def sum(_x, _y) do

  end
end

```

{% endcode %}

{% hint style="info" %}
**Utilizando prefixo underline (\_)**

\
Quando temos parâmetros e não o utilizamos, o interpretador nos emite um aviso dizendo que a variável não está sendo utilizada.\
\
`warning: variable "y" is unused (if the variable is not meant to be used, prefix it with an underscore) lib/math.ex:2: Math.sum/2`

Para esse aviso sumir, podemos colocar como prefixo o underline (\_) e ele irá ignorar essa validação.

`def sum (_x, _y) do`  &#x20;
{% endhint %}

Salve o arquivo e vamos tentar rodar o teste mais uma vez

```shell
mix test
Compiling 1 file (.ex)
Generated hello_world app
.

  1) test Math.sum/2 when successed response the result (MathTest)
     test/math_test.exs:5
     Assertion with == failed
     code:  assert result == 8
     left:  nil
     right: 8
     stacktrace:
       test/math_test.exs:14: (test)


Finished in 0.02 seconds (0.00s async, 0.02s sync)
2 tests, 1 failure
```

Temos um erro diferente (progresso!). O relatório nos conta que o lado esquerdo de nossa assertion está `nil`, mas o lado direito esperava `8` . Nossa função não esta retornando nada. Podemos ler assim: o resultado da função esta nulo enquanto o esperado no teste é 8.&#x20;

Agora podemos implementar nosso código real. Vamos fazer a soma e retornar o valor.

<pre class="language-elixir" data-title="lib/math.ex" data-line-numbers><code class="lang-elixir">defmodule Math do
  def sum(x, y) do
<strong>    x + y
</strong>  end
end
</code></pre>

Não precisamos de nenhuma palavra chave para indicar que um valor vai ser retornado na função. Elixir faz isso na última linha da função.

Basta agora rodar o teste e ver tudo funcionar.

```shell
mix test
Compiling 1 file (.ex)
..
Finished in 0.01 seconds (0.00s async, 0.01s sync)
2 tests, 0 failures
```

## Conclusão

Vimos o básico de funções. Descobrimos que uma função é definida por seu nome e sua aridade. Que toda função nomeada deve estar dentro de um módulo e que podemos passar dados para dentro dela usando parâmetros posicionais.

Entendemos um pouco mais sobre TDD e criamos nosso primeiro teste do zero.


# Funções anônimas

Funções anônimas funcionam parecidos com as [funções nomeadas](/basico/funcoes/funcoes-nomeadas). Enquanto a função nomeada possui um nome próprio, a função anonima possui seu comportamento, podendo ser atribuido a qualquer variável, chamamos isso de "First class citizen". que significa que tratamos funções como valores.

Vamos criar um teste simples, um usando uma função nomeada, criado no capítulo [Funções nomeadas](/basico/funcoes/funcoes-nomeadas). Depois criaremos um segundo que faz a mesma coisa, porém, como uma função anônima e por ser first class citizen, colocaremos ela em uma variável pois variáveis recebem valores.

<pre class="language-elixir" data-title="" data-line-numbers><code class="lang-elixir">defmodule FunctionTest do
  use ExUnit.Case

  test "named function" do
<strong>    assert Math.sum(1, 5) == 6
</strong>  end

  test "success" do
    sum = fn x, y -> x + y end

<strong>    assert sum.(10) == 100
</strong>  end
end
</code></pre>

O que vale a penas ver aqui é a execução e definição. Enquanto a função nomeada chama um module + a função (`Math.sum/2`), a função anonima so tem o comportamento da função.&#x20;

Também podemos notar que a definição de uma função anonima começa com a palavra chave `fn` seguido dos parametros e um seta `->` para a direita, fechando entao com `end`, ficando assim:

```elixir
fn param_1 -> IO.inspect param_1 end
```

* Entre o `fn` e a seta `->` temos os parametros que funcionam igual o parametro de funções nomeadas.&#x20;
* Entre a seta `->` e o `end` temos o corpo da função, onde nossa logica é criada.

Se atribuirmos esse comportamente a uma variável, por exemplo x, para conseguir rodar ela, utilizando o código `x.()`. O ponto é uma peça fundamental para rodar funções anonimas. Caso você tire ele, um relatório de erro aparecerá. Vamos fazer esse teste

{% code title="" lineNumbers="true" %}

```elixir
defmodule FunctionTest do
  use ExUnit.Case

  # ...
  
  test "success" do
    sum = fn x, y -> x + y end

    assert sum(10) == 100
  end
end
```

{% endcode %}

```sh
mix test test/function_test.exs
warning: variable "sum" is unused (if the variable is not meant to be used, prefix it with an underscore)
  test/function_test.exs:9: FunctionTest."test success"/1


== Compilation error in file test/function_test.exs ==
** (CompileError) test/function_test.exs:11: undefined function sum/1 (expected FunctionTest to define such a function or for it to be imported, but none are available)
```

Ele avisa que a função `sum/1` não foi definida e ele está certo, o que temos é uma função anonima.

Existem diversos casos que a função anonima é mais apropriada. Como quando quisermos passar para dentro de uma função que espera como argumento uma outra função, mas não queremos nomear ela, pois já esta claro o suficiente sua intenção. Temos isso acontecendo em várias funções nativas do elixir. Um exemplo é a utilização de `Enum.map/2`.

{% hint style="info" %}
Não se importe agora com o que seja o Enum.map/2, veremos isso depois.
{% endhint %}

Aqui podemos ver novamente o **First Class Citizen** agindo. O segundo parâmetro de `Enum.map/2` espera um valor do tipo função. Podemos então colocar a função anonima diretamente, sem necessidade de passar por uma variável antes.

{% code lineNumbers="true" %}

```elixir
Enum.map([1, 2, 3], fn x -> x * 2 end
```

{% endcode %}

### Conclusão

Funções anônimas podem parecer estranhas em primeiro contato. Mas uma vez que você esteja lidando com problemas reais em seu programa, verá que ele se torna útil em diversas ocasiões.


# Funções nomeadas convertidas para anônima

Em alguns casos queremos utilizar uma função nomeada como parâmetro para alguma outra função. Por natureza não podemos fazer isso com funções nomeadas, somente com funções anônimas como foi exemplificado no capítulo de [funções anônimas](/basico/funcoes/funcoes-anonimas).

Mas quando precisamos fazer isso, o elixir nos deixa transformar uma função nomeada em função anônima. Para isso, podemos utilizar o operador de captura (&)

Sua estrutura começa com o operador de captura, seguido da chamada da função + a aridade da função.&#x20;

```elixir
&String.reverse/1
```

Com isso ela se torna uma função anônima, nos possibilitando coloca-la em uma variável ou passar por parâmetro.

Um exemplo de como podemos fazer isso

```elixir
# usando função anônima
Enum.map([1,2,3], fn x -> x * 2 end)
# [2, 4, 6]

# usando função nomeada
defmodule MyModule do
  def math(x), do: x * 2 
end

Enum.map([1,2,3], &MyModule.math/1)
# [2, 4, 6]
```


# Tipos


# String

Em Elixir, uma string é uma sequência de caracteres delimitada por aspas duplas (" ") ou aspas simples (' ').&#x20;

Vamos a um exemplo.

<pre class="language-elixir" data-title="test/my_name_test.exs" data-line-numbers><code class="lang-elixir">defmodule MyNameTest do
  use ExUnit.Case
  
  test "Write my name with the double quote" do
<strong>    my_name = "Iago"
</strong>    
    assert my_name == "Iago"
  end
end
</code></pre>

Criamos uma `string` no exemplo anterior, utilizando aspas duplas e esperamos que ela seja igual ao texto `"Iago"` também com aspas duplas. Vamos rodar esse teste:

```sh
mix test test/my_name_test.exs
.
Finished in 0.01 seconds (0.00s async, 0.01s sync)
1 test, 0 failures
```

Tudo funcionando. Comentei mais acima que também podemos criar strings utilizando aspas simples (' '). Vamos dar uma olhada nisso:

<pre class="language-elixir" data-title="test/my_name_test.exs" data-line-numbers><code class="lang-elixir">defmodule MyNameTest do
  use ExUnit.Case
  
  test "Write my name with the single quote" do
<strong>    my_name = 'Iago'
</strong>    
    assert my_name == 'Iago'
  end
end
</code></pre>

Se rodarmos o teste, ele passará.

```sh
mix test test/my_name_test.exs
..
Finished in 0.01 seconds (0.00s async, 0.01s sync)
2 tests, 0 failures
```

Tudo perfeito até então. Vamos agora comparar um texto com aspas simples com um texto de aspas duplas e ver o que acontece.

<pre class="language-elixir" data-title="test/my_name_test.exs" data-line-numbers><code class="lang-elixir">defmodule MyNameTest do
  use ExUnit.Case

  # ...

  test "Write my name with the single quote and compare with double quotes" do
<strong>    my_name = 'Iago'
</strong>
<strong>    assert my_name == "Iago"
</strong>  end
end

</code></pre>

```sh
mix test test/my_name_test.exs


  1) test Write my name with the single quote and compare with double quotes (MyNameTest)
     test/my_name_test.exs:16
     Assertion with == failed
     code:  assert my_name == "Iago"
     left:  'Iago'
     right: "Iago"
     stacktrace:
       test/my_name_test.exs:19: (test)

..
Finished in 0.02 seconds (0.00s async, 0.02s sync)
3 tests, 1 failure
```

A há! Te pegamos. Mesmo os dois sendo considerados textos, o tipo retornado é diferente.&#x20;

* Quando utilizamos aspas duplas (" ") o tipo retornado é um `binário`.&#x20;
* Enquanto que quando utilizado aspas simples (' ') temos um `charlist`

Vamos alterar o teste para garantir que string com aspas simples é diferente de aspas duplas:

<pre class="language-elixir" data-title="test/my_name_test.exs" data-line-numbers><code class="lang-elixir">defmodule MyNameTest do
  use ExUnit.Case

  # ...

  test "Write my name with the single quote and compare with double quotes" do
    my_name = 'Iago'

<strong>    assert my_name != "Iago"
</strong>  end
end

</code></pre>

Apenas alteramos a linha 9. Se rodarmos os testes, teremos mensagem de sucesso.

```sh
mix test test/my_name_test.exs
...
Finished in 0.02 seconds (0.00s async, 0.02s sync)
3 tests, 0 failures
```

Agora vamor provar que os tipos retornados são diferentes. Começando com aspas duplas. Vamos alterar o primeiro teste:

<pre class="language-elixir" data-title="test/my_name_test.exs" data-line-numbers><code class="lang-elixir">defmodule MyNameTest do
  use ExUnit.Case
  
  test "Write my name with the double quote" do
    my_name = "Iago"
    
    assert my_name == "Iago"
    
<strong>    assert is_binary(my_name) == true
</strong><strong>    assert is_list(my_name) == false
</strong>  end
end
</code></pre>

Adicionamos as validações `is_binary/1` onde esperamos que seja verdadeira e `is_list/1` onde esperamos que seja falso. Vamos rodar esse teste:

```sh
mix test test/my_name_test.exs
...
Finished in 0.02 seconds (0.00s async, 0.02s sync)
3 tests, 0 failures
```

Agora validaremos a `string` com aspas simples onde esperamos retornar um charlist. Em geral o charlist é uma lista. Então utilizaremos a função `is_list/1`.

<pre class="language-elixir" data-title="" data-line-numbers><code class="lang-elixir">defmodule MyNameTest do
  use ExUnit.Case

  # ...

  test "Write my name with the single quote" do
    my_name = 'Iago'

    assert my_name == 'Iago'
    
<strong>    assert is_binary(my_name) == false
</strong><strong>    assert is_list(my_name) == true
</strong>  end

  # ...
end

</code></pre>

```sh
mix test test/my_name_test.exs
...
Finished in 0.02 seconds (0.00s async, 0.02s sync)
3 tests, 0 failures
```

Isso se comprova verdadeiro.

* Aspas duplas -> Retorna o tipo de dado binário
* Aspas simples -> Retorna o tipo de dado lista

Isso acontece porque as aspas simples (' ') são usadas para representar uma lista de caracteres individuais. Cada elemento da lista é um caractere Unicode de 1 byte, portanto, uma lista de caracteres pode ser vista como uma sequência de inteiros, onde cada inteiro representa um caractere.

Por outro lado, as aspas duplas (" ") são usadas para criar uma `string`. Em Elixir, uma `string` é uma sequência de `bytes`, e cada caractere Unicode pode ser representado por vários bytes.

### Escolhendo um tipo de retorno

A escolha entre o uso de `charlists` ou `strings` em Elixir dependerá do contexto em que estamos trabalhando e das necessidades específicas do problema em questão. Aqui estão algumas diretrizes gerais que podem ajudar na escolha:

**Use `strings` quando:**

* A eficiência na manipulação de strings é importante e a concatenação não é um problema (por exemplo, quando as strings são pequenas e/ou há poucas concatenações);
* Você está trabalhando com operações que requerem o uso de funções de string específicas em Elixir, como `String.length/1`, `String.split/2`, `String.downcase/1`, entre outras;
* A interoperabilidade com outras linguagens não é um problema e o código está sendo escrito exclusivamente em Elixir.

**Use `charlists` quando:**

* A eficiência na concatenação de strings é importante e há muitas concatenações envolvidas;
* Você está trabalhando com código que usa `charlists` (por exemplo, se estiver interagindo com código escrito em Erlang);
* Você está trabalhando com caracteres Unicode complexos que requerem mais de um byte para serem codificados;
* Você precisa manipular listas de caracteres usando funções de lista em Elixir.

### Conclusão

Em resumo, `charlists` são mais adequadas para situações em que a eficiência na concatenação é importante e para lidar com caracteres Unicode complexos, enquanto `strings` são mais adequadas para operações gerais de manipulação de strings e interoperabilidade com outras linguagens.


# Integer

Em Elixir, `integer` é um tipo de dado que representa um número inteiro, ou seja, um número sem casas decimais. Em termos de programação, é um tipo de dado que pode ser usado para realizar operações matemáticas que não envolvem números fracionários.

Vamos criar um teste para entender melhor isso:

{% code title="test/integer\_test.exs" lineNumbers="true" %}

```elixir
defmodule IntegerTest do
  use ExUnit.Case

  test "defining an integer" do
    my_integer = 1652468751356775

    assert is_integer(my_integer) == true
  end
end

```

{% endcode %}

```sh
mix test test/integer_test.exs
.
Finished in 0.01 seconds (0.00s async, 0.01s sync)
1 test, 0 failures
```

Podemos também, realizar operações matemáticas:

{% code title="test/integer\_test.exs" lineNumbers="true" %}

```elixir
defmodule IntegerTest do
  use ExUnit.Case

  # ...
  
  test "math" do
    assert 1 - 1 == 0
    assert 1 + 3 == 4
    assert 1 * 5 == 5
  end
end

```

{% endcode %}

Dois valores inteiros quando somados, diminuidos ou multiplicados, tem como resposta um inteiro. Mas uma vez que dividimos esse valor e o valor venha com casas decimais, como por exemplo `5 / 2 = 2.5` temos um tipo de retorno de dado diferente.&#x20;

<pre class="language-elixir" data-title="test/integer_test.exs" data-line-numbers><code class="lang-elixir">defmodule IntegerTest do
  use ExUnit.Case

  # ...
  
  test "division" do
    x = 5
    y = 2
    
    assert is_integer(x) == true
    assert is_integer(y) == true
    
    result = x / y
    
<strong>    assert is_float(result) == true
</strong>  end
end

</code></pre>

O dada resultante da operação veio com casas decimais, sendo agora do tipo float.

### Conclusão

O tipo `integer` é uma representação flexível de inteiros, que pode ser usada para armazenar inteiros de qualquer tamanho e sinal. Como é implementado usando a biblioteca `erlang`, os inteiros são de tamanho variável, o que significa que o tamanho do inteiro é determinado automaticamente pelo valor que ele contém.


# Float

Em Elixir, o tipo de dado `float` representa números de ponto flutuante (ou números reais) que são usados para representar números fracionários ou valores decimais.

Um exemplo de uso de `float` seria o seguinte:

```elixir
a = 1.5
b = 2.75
c = a + b

IO.puts "c é igual a #{c}"
# c é igual a 4.25
```

Aqui estão alguns exemplos de testes de unidade para verificar se os valores `float` estão funcionando corretamente:

{% code title="test/float\_test.exs" lineNumbers="true" %}

```elixir
defmodule FloatTest do
  use ExUnit.Case

  test "adição de float" do
    assert 2.5 + 3.0 == 5.5
  end

  test "subtração de float" do
    assert 4.0 - 1.5 == 2.5
  end

  test "multiplicação de float" do
    assert 2.0 * 3.0 == 6.0
  end

  test "divisão de float" do
    assert 6.0 / 2.0 == 3.0
  end

  test "conversão de inteiro para float" do
    assert 5 + 2.5 == 7.5
  end
end
```

{% endcode %}

Em resumo, `float` é um tipo de dado usado para representar números de ponto flutuante (ou números reais) que são usados para representar números fracionários ou valores decimais. `float` é uma ferramenta importante para lidar com cálculos matemáticos precisos e é comumente usado em muitas linguagens de programação, incluindo Elixir.

Ao trabalhar com `float`, é importante ter em mente que os números de ponto flutuante são aproximados e não podem representar todos os números reais com precisão. Portanto, é importante estar ciente de problemas de arredondamento e imprecisão ao lidar com `float`.

### Problema de ponto flutuante

Os números de ponto flutuante podem apresentar problemas de imprecisão quando são usados em cálculos que envolvem números muito grandes ou muito pequenos. Isso ocorre porque os números de ponto flutuante têm uma precisão finita e não podem representar todos os números reais com exatidão.

Exemplo:

{% code lineNumbers="true" %}

```elixir
a = 1000000000.0
b = 0.000001
c = a + b

IO.puts "c é igual a #{c}"
# c é igual a 1000000000.0
```

{% endcode %}

O resultado é impreciso e não inclui o valor `0.000001`. Isso ocorre porque `b` é tão pequeno que sua representação em ponto flutuante não pode ser armazenada com precisão suficiente.

Para evitar problemas de imprecisão com números de ponto flutuante, é importante ter em mente suas limitações e usar técnicas para minimizar a perda de precisão, como o arredondamento ou o uso de bibliotecas de precisão arbitrária.

### Conclusão

Em conclusão, os números de ponto flutuante (ou `float`) são um tipo de dado importante em Elixir e em muitas outras linguagens de programação. Eles são usados para representar números reais e são necessários para lidar com cálculos matemáticos precisos.

Por fim, testes de unidade bem escritos são importantes para garantir que as operações matemáticas envolvendo números de ponto flutuante estejam funcionando corretamente em um programa em Elixir.


# Atoms

As constantes do elixir

Atoms são constantes onde seu valor é o próprio nome. Sua definição vem com um prefixo de dois pontos `:` seguido de um nome. Exemplo `:apple`.

Um ato é igual a outro atom com mesmo nome.

{% code title="test/atom\_test.exs" lineNumbers="true" %}

```elixir
defmodule AtomTest do
  use ExUnit.Case

  test "simple tests about atom" do
    apple = :apple

    assert apple == :apple
    assert :new_atom == :new_atom
  end
end
```

{% endcode %}

Rodando esse código teremos um relatório de sucesso.

```shell
mix test 
....
Finished in 0.02 seconds (0.00s async, 0.02s sync)
1 tests, 0 failures
```

Atoms podem ser definidos dinamicamente, para isso poder fazer de duas formas:

1. Utilizando interpolação
2. Utilizando conversão

#### 1. Interpolação

<pre class="language-elixir" data-title="test/atom_test.exs" data-line-numbers><code class="lang-elixir">defmodule AtomTest do
  use ExUnit.Case
  
  # ...

  test "interpolation" do
    value = "noise"
<strong>    new_atom = :"#{noise}"
</strong>
    assert new_atom == :noise
  end
end
</code></pre>

```shell
mix test 
.....
Finished in 0.02 seconds (0.00s async, 0.02s sync)
2 tests, 0 failures
```

#### 2. Conversão

<pre class="language-elixir" data-title="test/atom_test.exs" data-line-numbers><code class="lang-elixir">defmodule AtomTest do
  use ExUnit.Case
  
  # ...

  test "conversion" do
    value = "noise"
<strong>    new_atom = String.to_atom(value)
</strong>
    assert new_atom == :noise
  end
end
</code></pre>

```shell
mix test
......
Finished in 0.02 seconds (0.00s async, 0.02s sync)
3 tests, 0 failures
```

{% hint style="warning" %}

#### Atenção

Devemos tomar cuidado na criação de atoms dinamicamente em nossas aplicações. Quando atoms são criados eles se mantem na memória até que a aplicação reinicie.\
\
Isso quer dizer que, se tivermos uma forma de criar atoms dinamicamente exposta para o usuário, corremos o risco de usuários mal intencionados criarem N atoms, até que nossa aplicação não responda corretamente.
{% endhint %}

Temos algumas formas de evitar esse tipo de problema. Uma forma é a utilização do [`String.to_existing_atom/1`](https://hexdocs.pm/elixir/1.12/String.html#to_existing_atom/1) onde, um atom so será gerado, caso já tenha sido criado antes. Com isso podemos limitar o que pode e o que não pode ser criado.&#x20;

<pre class="language-elixir" data-title="lib/atom_test.exs" data-line-numbers><code class="lang-elixir">defmodule AtomTest do
  use ExUnit.Case

  test "to_existing_atom/1" do
    value = "atom_that_does_not_exist"
<strong>    new_atom = String.to_existing_atom(value)
</strong>
    assert new_atom == :atom_that_does_not_exist
  end
end

</code></pre>

```shell
mix test
1) test to_existing_atom/1 (AtomTest)
     test/atom_test.exs:25
     ** (ArgumentError) errors were found at the given arguments:
     
       * 1st argument: not an already existing atom
     
     code: new_atom = String.to_existing_atom("atom_that_does_not_exist")
     stacktrace:
       :erlang.binary_to_existing_atom("atom_that_does_not_exist", :utf8)
       test/atom_test.exs:27: (test)
```

E caso ele já tenha sido criado, não teremos problemas

<pre class="language-elixir" data-title="lib/atom_test.exs" data-line-numbers><code class="lang-elixir">defmodule AtomTest do
  use ExUnit.Case
  
  # ...

  test "atom that does exist" do
    _atom = :atom_that_does_exist
    
    value = "atom_that_does_exist"
<strong>    new_atom = String.to_existing_atom(value)
</strong>
    assert new_atom == :atom_that_does_exist
  end
end
</code></pre>

```shell
mix test
........
Finished in 0.02 seconds (0.00s async, 0.02s sync)
5 tests, 0 failures
```

### Conclusão

Atoms são muito utilizados no mundo elixir, são práticos e fáceis de usar. Vimos que precisamos tomar cuidado com a geração dinâmica e que podemos controlar o que pode ser criado. Mais a frente utilizaremos cada vez mais atoms para simplificar nosso código e estrutura-lo.


# Pattern Matching

### Pattern matching em variáveis

Toda linguagem de programação tem a capacidade de criar variáveis. Você define um nome (talvez um tipo, dependendo da linguagem) e assina um valor a ela.

Elixir é um pouco diferente, mesmo parecendo igual a primeira vista, seu conceito muda.

Vamos a um exemplo simples onde criaremos uma `map` chamado pessoa e dentro dele teremos o campo `name` e `genre`. Popularemos os valores do `map` com `My Name` e `:no_binary`.&#x20;

Vamos ao teste.

<pre class="language-elixir" data-title="test/person_test.exs" data-line-numbers><code class="lang-elixir">defmodule SimpleTest do
  use ExUnit.Case

  test "simple tests about pattern matching" do
<strong>    person = Person.create("My Name", :no_binary)
</strong>
    assert person.name == "My Name"
    assert person.genre == :no_binary
  end
end
</code></pre>

Rodando esse teste, obtemos o relatório de erro:

```shell
$ mix test
warning: Person.create/2 is undefined (module Person is not available or is yet to be defined)
  test/phrases_test.exs:6: SimpleTest."test simple tests about pattern matching"/1

.

  1) test simple tests about pattern matching (SimpleTest)
     test/phrases_test.exs:4
     ** (UndefinedFunctionError) function Person.create/2 is undefined (module Person is not available)
     code: person = Person.create("My Name", :no_binary)defmodule Document do
  def render(_id, _type) do
    "Rendering txt"
  end
end

     stacktrace:
       Person.create("My Name", :no_binary)
       test/phrases_test.exs:6: (test)

.
Finished in 0.04 seconds (0.00s async, 0.04s sync)
3 tests, 1 failure
```

Vamos criar nosso módulo para passar o teste

{% code title="lib/person.ex" lineNumbers="true" %}

```elixir
defmodule Person do
  def create(name, genre) do
    %{
      name: name,
      genre: genre
    }
  end
end
```

{% endcode %}

Essa função apenas retorna um map com os valores que enviamos.

Se rodarmos novamente, os testes terão passados.

```shell
mix test
...
Finished in 0.02 seconds (0.00s async, 0.02s sync)
3 tests, 0 failures
```

Analisando nosso teste, a definição de `person` parece uma assinatura comum de variável, certo? `chave = valor`. Mas por traz dos panos, elixir utiliza pattern matching para fazer isso. O valor a direita, apenas será adicionado a esquerda, caso de o match.&#x20;

Em nosso exemplo, o requisito para matching é: se possuir algo ao lado direito, ele conseguira ser atribuído a variável person. Ele é bem aberto e pode receber qualquer tipo de dado.

Sei que parece confuso. Mas vamos continuar, logo tudo fará sentido.

Imagine agora que voce precisa pegar apenas `name` e `genre` que estão dentro do map retornado da função e coloca-los em uma variável cada. Para poder fazer as confiramações isoladas.

Algo assim:

<pre class="language-elixir" data-line-numbers><code class="lang-elixir">  use ExUnit.Case

  test "simple tests about pattern matching" do
    # ...

<strong>    assert new_name == "My Name"
</strong><strong>    assert new_genre == :no_binary
</strong>  end
end
</code></pre>

Sem pattern matching, voce precisaria continuar com o valor `person.name` ou atribuir ele a uma nova variável `new_name = person.name`. O que por fim, daria na utilização do mesmo.

Com pattern matching é diferente, você pode obter diretamente o valor que quer, sem precisar de uma etapa intermediária.

<pre class="language-elixir" data-title="test/person_test.exs" data-line-numbers><code class="lang-elixir">defmodule PersonTest do
  use ExUnit.Case

  test "simple tests about pattern matching" do
<strong>    %{
</strong><strong>      name: new_name,
</strong><strong>      genre: new_genre
</strong><strong>    } = Person.create("My Name", :no_binary)
</strong>
<strong>    assert new_name == "My Name"
</strong><strong>    assert new_genre == :no_binary
</strong>  end
end
</code></pre>

O `new_name` e `new_genre` estão na posição onde está onde deveriam estar os valores certo? Ele é um espelho do que tem dentro da função, porem, no lugar dos valores, temos a definição de uma nova variável e é ai que o matching acontece. No nosso caso, estamos so dizendo que aceitamos qualquer valor que siga a estrutura de dentro do map, tendo `name` sendo chamado agora de `new_name` e a mesma coisa acontece com `new_genre`.&#x20;

Sendo assim, podemos utilizar diretamente a variável, porque após o matching, ela existe.

Se rodar o teste a cima, ele funcionará corretamente.

```shell
$ mix test
...
Finished in 0.02 seconds (0.00s async, 0.02s sync)
3 tests, 0 failures
```

Outros exemplo:

{% code lineNumbers="true" %}

```elixir
iex> 10 = 10
iex> x = 1
iex> %{y: value} = %{y: 100}
iex> %{person: %{name: person_name}} = %{person: %{name": "iago"}}
iex> IO.inspet(x) 
1
iex> IO.inspet(value) 
100
iex> IO.inspet(person_name) #
iago
```

{% endcode %}

{% hint style="info" %}
**IO.inspect**

\
Função do módulo IO para espionar o que tem dentro de algum elemento.\
\
[Mais sobre IO.inspect](https://hexdocs.pm/elixir/IO.html#inspect/2)
{% endhint %}

Quando um matching não é sucedido ele dispara uma exceção.

```shell
iex> {a, b, c} = {:hello, "world"}
** (MatchError) no match of right hand side value: {:hello, "world"}
```

### Pattern matching em funções

Na função funciona do mesmo jeito, porém, utilizado nos parâmetros. Vamos a um exemplo. Precisamos de uma função que exiba um tipo de documento dependendo do tipo pedido. Vamos chamar essa função de `render` e o módulo de `Document`. Nossa função precisará de um ID para identificar o documento e um atom pedindo o tipo apropriado, nesse exemplo `:txt`, `:pdf`. Vamos cuidar do `txt` primeiro:

{% code title="test/document\_test.exs" lineNumbers="true" %}

```elixir
defmodule DocumentTest do
  use ExUnit.Case

  describe "show/2" do
    test "render txt" do
      id = 12353
      type = :txt

      result = Document.render(id, type)

      assert result == "Rendering txt"
    end
  end
end
```

{% endcode %}

Rodando esse teste obteremos um relatório comum de erro.

```shell
mix test test/document_test.exs
warning: Document.render/2 is undefined (module Document is not available or is yet to be defined)
  test/document_test.exs:9: DocumentTest."test show/2 render txt"/1



  1) test show/2 render txt (DocumentTest)
     test/document_test.exs:5
     ** (UndefinedFunctionError) function Document.render/2 is undefined (module Document is not available)
     code: result = Document.render(id, type)
     stacktrace:
       Document.render(12353, :txt)
       test/document_test.exs:9: (test)


Finished in 0.02 seconds (0.00s async, 0.02s sync)
1 test, 1 failure
```

Nosso módulo ainda não existe. Vamos cria-lo:

{% code title="lib/document.ex" lineNumbers="true" %}

```elixir
defmodule Document do
  def render(_id, _type) do
    "Rendering txt"
  end
end
```

{% endcode %}

Rodando o teste agora, tudo vai estar funcionando.

```shell
mix test test/document_test.exs
Compiling 1 file (.ex)
.
Finished in 0.01 seconds (0.00s async, 0.01s sync)
1 test, 0 failures
```

Vamos lidar agora com o PDF.

{% code title="test/document\_test.exs" lineNumbers="true" %}

```elixir
defmodule DocumentTest do
  use ExUnit.Case

  describe "show/2" do
    # ...
    
    test "render pdf" do
      id = 12353
      type = :pdf

      result = Document.render(id, type)

      assert result == "Rendering pdf"
    end
  end
end
```

{% endcode %}

Se rodarmos novamente, teremos um relatório de erro.

```shell
mix test test/document_test.exs
.

  1) test show/2 render pdf (DocumentTest)
     test/document_test.exs:14
     Assertion with == failed
     code:  assert result == "Rendering pdf"
     left:  "Rendering txt"
     right: "Rendering pdf"
     stacktrace:
       test/document_test.exs:20: (test)


Finished in 0.02 seconds (0.00s async, 0.02s sync)
2 tests, 1 failure
```

Aqui as coisas começam a ficar interessantes. Estamos chamando a mesma função, mas com parâmetros diferente. Uma solução fácil para isso, é por um if dentro da função e retornar o valor que queremos. Algo assim:

{% code lineNumbers="true" %}

```elixir
defmodule Document do
  def render(_id, _type) do
    if type == :txt do
      "Rendering txt"
    else
      "Rendering pdf"
    end
  end
end
```

{% endcode %}

Isso funcionária, mas se tornaria uma bagunça se precisarmos colocar mais tipos de arquivos. Com pattern matching, podemos controlar o fluxo das chamadas de funções, colocando nos parâmetros a formula do padrão para executar uma função.&#x20;

<pre class="language-elixir" data-title="lib/document.ex" data-line-numbers><code class="lang-elixir">defmodule Document do
<strong>  def render(_id, :txt) do
</strong>    "Rendering txt"
  end

<strong>  def render(_id, :pdf) do
</strong>    "Rendering txt"
  end
end

</code></pre>

Na definição da função, no segundo parâmetro, ao invés de colocar uma variável, setamos diretamente o valor. Por regra do Pattern matching, o valor deve ser igual para ele ser realizado com sucesso e ai executar a função. A primeira função `render` so irá ser executada, quando o segundo parâmetro for `:txt` e a segunda função apenas quando for `:pdf`.

Se rodar o código, teremos um relatório positivo.

```shell
mix test test/document_test.exs
Compiling 1 file (.ex)
..
Finished in 0.01 seconds (0.00s async, 0.01s sync)
2 tests, 0 failures
```

Caso nenhuma dessas condições seja cumprida, uma exceção é lançada. Para evitar isso, podemos criar uma função para avisar que o tipo não é suportado:

<pre class="language-elixir" data-title="test/document_test.exs" data-line-numbers><code class="lang-elixir">defmodule DocumentTest do
  use ExUnit.Case

  describe "render/2" do
    # ...
    
    test "unsupported type" do
      id = 12353
<strong>      type = :unsupported
</strong>
      result = Document.render(id, type)

      assert result == "This type #{type} is not supported"
    end
  end
end

</code></pre>

executando o teste, temos o seguinte relatório:

```shell
mix test test/document_test.exs


  1) test show/2 unsupported type (DocumentTest)
     test/document_test.exs:23
     ** (FunctionClauseError) no function clause matching in Document.render/2

     The following arguments were given to Document.render/2:
     
         # 1
         12353
     
         # 2
         :unsupported
     
     Attempted function clauses (showing 2 out of 2):
     
         def render(_id, :txt)
         def render(_id, :pdf)
     
     code: result = Document.render(id, type)
     stacktrace:
       (hello_world 0.1.0) lib/document.ex:2: Document.render/2
       test/document_test.exs:27: (test)

..
Finished in 0.02 seconds (0.00s async, 0.02s sync)
3 tests, 1 failure
```

O próprio relatório nos da as opções válidas com `:txt` e `:pdf.` Vamos corrigir isso.

<pre class="language-elixir" data-title="lib/document.ex" data-line-numbers><code class="lang-elixir">defmodule Document do
  def render(_id, :txt) do
    "Rendering txt"
  end

  def render(_id, :pdf) do
    "Rendering pdf"
  end

<strong>  def render(_id, unsupported) do
</strong><strong>    "This type #{unsupported} is not supported"
</strong><strong>  end
</strong>end
</code></pre>

Na ultima função, troquei novamente o segundo parâmetro para variável, assim ele não espera um valor especifico e consegue executar a função. Tendo isso em mãos, criamos uma frase para avisar que o tipo informado não é válido.

Podemos rodar esse código e temos o relatório de sucesso:

```shell
mix test test/document_test.exs
...
Finished in 0.02 seconds (0.00s async, 0.02s sync)
3 tests, 0 failures
```

{% hint style="info" %}
**Ordem de execução**

A tentativa de execução de funções começa de cima para baixo. Quando uma função é atendida pelo pattern matching ela não vai para a próxima.<br>

`def render(_id, :txt), do: # ...`

`def render(_id, type), do: # Ela irá parar aqui`

`def render(_id, :pdf), do: # Nunca tentará fazer o pattern matching`
{% endhint %}

### Conclusão

Pattern matching é uma das principais funcionalidades do elixir. Versátil e fácil de usar, é uma excelente ferramenta para se aprender. Coisas complexas podem ser resolvidas de forma simples e elegante.


# Coleções

Em Elixir, uma **Collection** é uma estrutura de dados que armazena um conjunto de valores de maneira organizada e pode ser manipulada de várias formas. Por exemplo, uma [`lista`](/basico/colecoes/listas), um [`mapa`](/basico/colecoes/mapas), um `conjunto`, uma [`tupla`](/basico/colecoes/tuplas) ou um `bitstring` são todos exemplos de `coleções` em Elixir. As coleções podem ser usadas para armazenar dados e fornecer uma maneira conveniente de acessá-los e manipulá-los. Entre eles temos:

* [Lista](/basico/colecoes/listas)
* [Tuplas](/basico/colecoes/tuplas)
* [Mapas](/basico/colecoes/mapas)
* [Estruturas](/basico/colecoes/estruturas)

Cada tipo de coleção tem suas próprias propriedades e é adequado para diferentes tipos de problemas.

Ao usar as funções e módulos corretos para trabalhar com coleções em Elixir, você pode escrever código mais limpo e conciso.&#x20;

Além disso, Elixir também oferece recursos poderosos, como o protocolo [Enumerable](/conceitos/enumeraveis), que fornecem uma interface comum para trabalhar com coleções de dados. Isso permite que você trabalhe com diferentes tipos de coleções usando a mesma interface, economizando tempo e esforço.

Mas primeiro, vamos dar uma olhada sobre as coleções que possuímos.


# Tuplas

A tupla é uma estrutura de dados simples que aceita todos os tipos de dados. Diferente do map ela não aceita chave valor e sim, diretamente o valor. Iniciamos sua declaração com abrir chaves `{` e finalizamos com fechar chaves `}`.  Seus valores são separados por virgula.&#x20;

Exemplo :

<pre class="language-elixir" data-line-numbers><code class="lang-elixir">defmodule TupleTest do
  use ExUnit.Case

  test "simple tests about tuple" do
    int_value = 1
    atom_value = :ok
    map_value = %{name: "iago"}

<strong>    tuple = {int_value, atom_value, map_value, 10}
</strong>
<strong>    assert tuple == {1, :ok, %{name: "iago"}, 10}
</strong>  end
end

</code></pre>

```shell
mix test test/tuple_test.exs
.
Finished in 0.01 seconds (0.00s async, 0.01s sync)
1 test, 0 failures
```

Você verá muito pela comunidade elixir o padrão de utilização de tuplas para simbolizar sucesso de uma função, separando elas como `{:ok, data}` e `{:error, reason}`. Diversas bibliotecas utilizam esse mesmo padrão e é uma forma de aprender a lidar com os dados.

Ao lidar com tuplas, temos algumas funções para nos ajudar

* [`Tuple.insert_at/2`](https://hexdocs.pm/elixir/1.12/Tuple.html#insert_at/3) - Inserir valor ao final da tuple
* [`elem/2`](https://hexdocs.pm/elixir/1.12/Kernel.html#elem/2) - Acessar a tupla por um indice
* [`put_elem/3`](https://hexdocs.pm/elixir/1.12/Kernel.html#put_elem/3) - Substituir o valor de um elemento da tupla por um indice
* [`tuple_size/1`](https://hexdocs.pm/elixir/1.12/Kernel.html#tuple_size/1) - obter número de elementos na tupla

Outro exemplo simples:

{% code title="test/tuple\_test.exs" lineNumbers="true" %}

```elixir
defmodule TupleTest do
  use ExUnit.Case

  #...

  test "inserting elements" do
    data = {:initial}
    
    data = Tuple.insert_at(data, 1, :foo)
    data = Tuple.insert_at(data, 2, :bar)

    assert data == {:initial, :foo, :bar}
    assert tuple_size(data) == 3
    assert elem(data, 1) == :foo
  end
end
```

{% endcode %}

```shell
mix test test/tuple_test.exs
..
Finished in 0.01 seconds (0.00s async, 0.01s sync)
2 tests, 0 failures
```

Tuplas também podem ter valores complexos como `structures` ou `maps`.

### Utilização de tupla de `:ok` e `:error` em uma função

{% hint style="warning" %}
**Convenções**

Temos uma seção convenções da linguagem que é bem importante o entendimento. Tupla :ok/:error é uma delas. \
\
[Acesse aqui](/conceitos/convencoes)
{% endhint %}

Vamos supor que faremos uma operação de cadastro em um fornecedor. Após a operação precisamos informar se a operação foi bem sucedida ou não. Para facilitar chamarei esse modulo de `Vendor` e a função de `register`. No registro precisamos apenas de um ID e uam descrição. Então passaremos dois parâmetros para a função. Queremos como retorno, a utilização de tuplas com `:ok` e :`error` chamado de [error\_handling](https://elixirschool.com/pt/lessons/intermediate/error_handling) (ou, tratamento de erro).

{% code title="test/register\_test.exs" lineNumbers="true" %}

```elixir
defmodule VendorTest do
  use ExUnit.Case

  describe "register/2" do
    test "when params are valid" do
      id = 54853
      description = "Novo ponto de venda"

      {:ok, result} = Vendor.register(id, description)

      assert result == %{description: "Novo ponto de venda", id: 54853}
    end
  end
end

```

{% endcode %}

Conseguimos extrair o result utilizando `pattern matching`. O `:ok`  garante que so poderá ter um matching caso venha um `:ok` no primeiro elemento da tupla.&#x20;

Se rodarmos isso teremos os primeiros relatórios de erro

```shell
mix test test/vendor_test.exs
warning: Vendor.register/2 is undefined (module Vendor is not available or is yet to be defined)
  test/vendor_test.exs:8: VendorTest."test register/2"/1



  1) test register/2 (VendorTest)
     test/vendor_test.exs:4
     ** (UndefinedFunctionError) function Vendor.register/2 is undefined (module Vendor is not available)
     code: {:ok, result} = Vendor.register(id, description)
     stacktrace:
       Vendor.register(54853, "Novo ponto de venda")
       test/vendor_test.exs:8: (test)


Finished in 0.02 seconds (0.00s async, 0.02s sync)
1 test, 1 failure
```

Precisamos criar nosso módulo com nossa função

<pre class="language-elixir" data-title="lib/vendor.ex" data-line-numbers><code class="lang-elixir">defmodule Vendor do
  def register(id, description) do
    result = %{id: id, description: description}
<strong>    {:ok, result} # temos a tupla com o :ok simbolizando que tudo deu certo
</strong>  end
end
</code></pre>

```shell
mix test test/vendor_test.exs
Compiling 1 file (.ex)
.
Finished in 0.00 seconds (0.00s async, 0.00s sync)
1 test, 0 failures
```

O cenário feliz foi definido e tudo esta funcionando. Agora, precisamos também garantir o comportamento para a tupla com `:error`. Para isso iremos garantir que so possa ser enviado por parâmetro IDs do tipo inteiro.

{% code title="" lineNumbers="true" %}

```elixir
defmodule VendorTest do
  use ExUnit.Case

  describe "register/2" do
    # ...

    test "when params are not valid" do
      id = "invalid-id"
      description = "Novo ponto de venda"

      {:error, reason} = Vendor.register(id, description)

      assert reason == "Params are not valid"
    end
  end
end
```

{% endcode %}

Se rodarmos isso veremos que ele gera um novo erro para nós

```shell
mix test test/vendor_test.exs
Compiling 1 file (.ex)
.

  1) test register/2 when params are not valid (VendorTest)
     test/vendor_test.exs:14
     ** (FunctionClauseError) no function clause matching in Vendor.register/2

     The following arguments were given to Vendor.register/2:
     
         # 1
         "invalid-id"
     
         # 2
         "Novo ponto de venda"
     
     Attempted function clauses (showing 1 out of 1):
     
         def register(id, description) when is_integer(id)
     
     code: {:error, reason} = Vendor.register(id, description)
     stacktrace:
       (hello_world 0.1.0) lib/vendor.ex:2: Vendor.register/2
       test/vendor_test.exs:18: (test)


Finished in 0.01 seconds (0.00s async, 0.01s sync)
2 tests, 1 failure
```

Isso significa que nao foi encontrado uma função que atenda as espectativas dessa chamada. Devido a precisar ser inteiro e estarmos enviando String o código quebra.

Para resolver esse problema, precisamos criar uma nova função de mesmo nome que atenda a nova especificação. No nosso caso, criaremos uma apenas para informar que algo esta errado e retornar o `:error`.

<pre class="language-elixir" data-title="lib/vendor.ex" data-line-numbers><code class="lang-elixir">defmodule Vendor do
  # ...
  def register(_id, _description) do
<strong>    {:error, "Params are not valid"} # temos a tupla com :error, algo deu errado
</strong>  end
end
</code></pre>

Basta rodar e ver que agora temos o tratamento correto.

```shell
mix test test/vendor_test.exs
Compiling 1 file (.ex)
..
Finished in 0.01 seconds (0.00s async, 0.01s sync)
2 tests, 0 failures
```

{% hint style="warning" %}
**Tratamento de erro**\
\
Esta não é a melhor forma de tratar erros. Aqui foi simplificado para facilitar a explicação e exemplificar a utilização de tuplas. Mais a frente falaremos sobre tratemento de erros.\
\
[Veja mais  sobre isso aqui](https://elixirschool.com/pt/lessons/intermediate/error_handling)
{% endhint %}

### Conclusão

Tuplas são uma estrutura de dados simples onde guarda valores de todos os tipos. Vimos formas de utiliza-lo e algumas funções de apoio. Também demos uma olhada em um cenário comum que a tupla é utilizada.


# Mapas

`Map` são estruturas de dados no modelo chave valor (dicionário) que aceitam todos os tipos de dados. A definição dela segue o modelo `%{}` e os valores vão dentro das chaves.

Vamos criar uma estrutura simples:

{% code title="test/maps\_test.exs" lineNumbers="true" %}

```elixir
defmodule MapsTest do
  use ExUnit.Case

  test "maps" do
    data = %{
      name: "iago"
    }

    # utilizando pattern matching
    %{name: my_name_1} = data
    assert my_name == "iago"
    
    # Utilizando fech
    {:ok, my_name_2 } = Map.fetch(data, :name)
    assert my_name_2 == "iago"
    
    # Utilizando acesso por indice
    my_name_3 = data[:name]
    assert my_name_3 == "iago"
    
    # utilizando encadeamento
    my_name4 = data.name
    assert my_name4 == "iago"
    
    # Quando acessado por indice, o que acontece quando o elemento não existe
    my_name_5 = data[:not_exists_index]
    assert my_name_5 == nil
    
    # Quando acessado por encademamento, o que acontece quando o elemento não existe
    assert_raise KeyError, fn ->
      data = %{name: "iago"}
      data.nonexistent_element
    end
  end
end
```

{% endcode %}

Rodando esse código o test passará, mas dará um aviso que algo deu errado, no nosso caso, é a `linha 26`, que dispara um erro dizendo que não existe o elemento `nonexistent_element`.

A função [`assert_raise/2`](https://hexdocs.pm/ex_unit/ExUnit.Assertions.html#assert_raise/2) lida com expectativas de exceção do código, podendo fazer parte do teste para garantirmos o comportamento correto.

```shell
mix test test/maps_test.exs
warning: undefined field "not_exists_index" in expression:

    # test/maps_test.exs:26
    data.not_exists_index

expected one of the following fields: name

where "data" was given the type map() in:

    # test/maps_test.exs:25
    data = %{name: "iago"}

Conflict found at
  test/maps_test.exs:26: MapsTest."test maps"/1

.
Finished in 0.03 seconds (0.00s async, 0.03s sync)
1 test, 0 failures
```

Existem diversas formas de lidar com Map, bastante entender como fica melhor para você.

### Alterar valores

Tendo uma vez o Map criado, podemos também alterar os valores.&#x20;

{% code title="" lineNumbers="true" %}

```elixir
defmodule MapsTest do
  use ExUnit.Case
  
  # ...
  
  test "adding value in map" do
    data = %{
      name: "Iago"
    }

    new_data = %{data | name: "Elixir"}

    assert data.name == "Iago"
    assert new_data.name == "Elixir"
  end
end
```

{% endcode %}

```shell
mix test
..
Finished in 0.05 seconds (0.00s async, 0.05s sync)
2 tests, 0 failures
```

{% hint style="info" %}
**Imutabilidade**\
\
Elixir é uma linguagem que utiliza o [conceito de  imutabilidade](/conceitos/imutabilidade). Isso quer dizer que não podemos alterar valores ja definidos. Sempre que precisarmos fazer isso, devemos responder um novo elemento e re-assinar na estrutura de dados que estamos. Exemplo<br>

`data = %{ name: "Iago" }`

`new_data = %{data | name: "Elixir"}`

\
`a variáveldata` nunca será alterará, se quiser usar o valor novo, precisamos substituir o antigo pelo novo, onde perderemos tudo do valor inicial.&#x20;
{% endhint %}

### Conclusão

Existem diversas outras funções de apoio ao Map, voce poderá ver elas acessando [esse link](https://hexdocs.pm/elixir/1.12/Map.html#summary). Vimos aqui formas de criar, alterar e acessar dados de um Map. Também falamos um pouco sobre imutabilidade, conceito importante em linguagens funcionais.


# Estruturas

Estruturas em `elixir`, são implementados igual `Maps`. Os `Maps` podem ser lidos e gravados com eficiência, são imutáveis e as chaves podem ser qualquer termo, como `atoms`.

A estrutura é um map com uma chave já pré-definida chamada `__struct__`. Vamos criar uma estrutura.

{% code title="test/user\_test.exs" lineNumbers="true" %}

```elixir
defmodule StructTest do
  use ExUnit.Case

  test "create a simple struct" do
    new_struct = %User{id: 100, name: "Iago"}

    assert new_struct == %{__struct__: User, id: 100, name: "Iago"}
  end
end
```

{% endcode %}

```shell
mix test test/user_test.exs  

== Compilation error in file test/user_test.exs ==
** (CompileError) test/struct_test.exs:5: User.__struct__/1 is undefined, cannot expand struct User. Make sure the struct name is correct. If the struct name exists and is correct but it still cannot be found, you likely have cyclic module usage in your code
    expanding struct: User.__struct__/1
    test/struct_test.exs:5: AtomTest."test create a simple struct"/1
```

Você pode perceber, que ele já fala no próprio relatório de teste que `User.__struct__/1` não existe. Esse campo `__structure__` que define que um `map` é uma `struct`.

Claro, ainda não temos esse módulo e estrutura criados. Então vamos cria-los dentro do arquivo `user.ex.` Para isso precisamos utilizar uma função em nosso módulo chamada defstruct, ela por natureza utiliza o nome do modulo como nome da estrutura, injetando dentro de `__struct__` o nome completo do módulo, como o nosso so tem um nível, será apenas `User`

<pre class="language-elixir" data-title="lib/user.ex" data-line-numbers><code class="lang-elixir">defmodule User do
<strong>  defstruct [:id, :name]
</strong>end
</code></pre>

Feito isso, basta rodar o teste e tudo funcionará.

```shell
mix test test/user_test.exs
Compiling 1 file (.ex)
.
Finished in 0.00 seconds (0.00s async, 0.00s sync)
1 test, 0 failures
```

Se `Struct` na verdade é um map com uma chave `__struct__`, porque eu deveria usar ela e não `map` diretamente?

Diferente do Map, não podemos inserir valores na utilização da struct. Exemplo:

<pre class="language-elixir" data-title="test/user_test.exs" data-line-numbers><code class="lang-elixir">defmodule StructTest do
  use ExUnit.Case

  # ...

  test "error when create a simple struct" do
    assert_raise CompileError, fn ->
      %User{
        id: 100,
        name: "Iago",
<strong>        field_does_not_exist_in_structure: 255
</strong>      }
    end
  end
end

</code></pre>

Ao rodar esse teste, irá gerar um relatório de erro de compilação acusando que `field_does_not_exist_in_structure` não foi encontrado na estrutura `User.__struct__/1`.

```shell
mix test test/user_test.exs

== Compilation error in file test/struct_test.exs ==
** (KeyError) key :field_does_not_exist_in_structure not found
    (hello_world 0.1.0) expanding struct: User.__struct__/1
    test/struct_test.exs:16: StructTest."test error when create a simple struct"/1
```

Esse comportamento é semelhante ao tentar adicionar algum valor a uma chave que não existe no `map`:

```shell
iex> data = %{a: 1}
iex> %{data | z: 9}

** (KeyError) key :z not found in: %{a: 1}
    (stdlib 4.1.1) :maps.update(:z, 3, %{a: 1})
    (stdlib 4.1.1) erl_eval.erl:309: anonymous fn/2 in :erl_eval.expr/6
    (stdlib 4.1.1) lists.erl:1350: :lists.foldl/3
```

A diferença entre os dois é que no `map` temos um erro em tempo de execução (runtime) e na `struct` temos um erro de compilação (compile-time).

Utilizamos estrutura para definir dados bem definidos, que já temos conhecimento de seus campos, como por exemplo `User`, `Article` e outros. `Maps` são mais dinâmicos. Existem outras diferenças que veremos mais a frente.

## Conclusão

Estruturas são tratados como `Maps` e conseguimos ter um entendimento melhor assim. Porém temos algumas diferenças. Não podemos adicionar a nossa utilização de `estrutura` um campo que não está definido nela, isso causará um erro de compilação.&#x20;


# Listas

Vamos diretamente a um exemplo prático.

Foi decidido que precisamos de uma listagem de candidatos que foram aprovados no vestibular. Com ela, podemos realizar a operação de aprovar estudantes (adicionando o estudando a lista) e também desaprovar estudantes (removendo o estudando da lista.) Com esse levantamento temos três pontos a lidar:

1. Ter uma lista de estudando aprovados
2. Conseguir adicionar estudantes nessa lista
3. Remover estudantes da lista.

Vamos ao primeiro teste:

{% code title="test/students\_test.exs" lineNumbers="true" %}

```elixir
defmodule StudentsTest do
  use ExUnit.Case

  test "adding a new user on approved list" do
    current_list = ["Paulo", "João"]
    students = ["Iago"]
  
    assert Students.add_to_approved_list(current_list, students) == ["Paulo", "João", "Iago"]
  end
end
```

{% endcode %}

Criamos uma variável chamada `current_list` que vai conter nossa lista inicião de aprovados. Depois criamos uma variável chamada `students`, que é uma lista de usuário. Temo então na linha 8 a chamada `Students.add_to_approved_list/2`. Ele é nossa função que irá adicionar uma lista de usuário a uma lista ja existente. O retorno dessa função será uma nova lista com os estudantes adicionados. Com isso conseguimos criar nossa assertion dizendo que deve ser igual a nova lista.

Vamos rodar esse teste:

```sh
mix test test/students_test.exs
warning: Students.add_to_approved_list/2 is undefined (module Students is not available or is yet to be defined)
  test/students_test.exs:9: StudentsTest."test List of students approved adding a new user on approved list"/1



  1) test List of students approved adding a new user on approved list (StudentsTest)
     test/students_test.exs:5
     ** (UndefinedFunctionError) function Students.add_to_approved_list/2 is undefined (module Students is not available)
     code: assert Students.add_to_approved_list(current_list, students) == ["Paulo", "João", "Iago"]
     stacktrace:
       Students.add_to_approved_list(["Paulo", "João"], ["Iago"])
       test/students_test.exs:9: (test)


Finished in 0.02 seconds (0.00s async, 0.02s sync)
1 test, 1 failure
```

Com somente o teste criado, recebemos a mensagem de que a função `Students.add_to_approved_list/2` não existe. Próximo passo é cria-la.

{% code title="lib/students.ex" lineNumbers="true" %}

```elixir
defmodule Students do
  def add_to_approved_list(_, _) do
    []
  end
end

```

{% endcode %}

Criamos o módulo Students e dentro a função `add_to_approved/2`. Como já tinhamos falado, retornaremos uma lista.&#x20;

```sh
mix test test/students_test.exs
Compiling 1 file (.ex)


  1) test List of students approved adding a new user on approved list (StudentsTest)
     test/students_test.exs:5
     Assertion with == failed
     code:  assert Students.add_to_approved_list(current_list, students) == ["Paulo", "João", "Iago"]
     left:  []
     right: ["Paulo", "João", "Iago"]
     stacktrace:
       test/students_test.exs:9: (test)


Finished in 0.01 seconds (0.00s async, 0.01s sync)
1 test, 1 failure
```

No teste falhou novamente. Agora acusando que a nossa chamada esta retornando um `[]` e esperavamos `["Paulo", "João", "Iago"]`. Claro, não retornamos a lista enviada. Vamos fazer isso para seguir com a implementação. Vamos alterar `students.ex`. Ao chamar a função, o primeiro argumento que passamos é a lista atual e o segundo argumento é a lista de estudantes a serem adicionados. Vamos primeiro retornar apenas a primeira lista.

<pre class="language-elixir" data-title="lib/students.ex" data-line-numbers><code class="lang-elixir">defmodule Students do
  def add_to_approved_list(current_list, _) do
<strong>    current_list
</strong>  end
end

</code></pre>

Vamos executar novamente o teste:

```sh
mix test test/students_test.exs
Compiling 1 file (.ex)


  1) test List of students approved adding a new user on approved list (StudentsTest)
     test/students_test.exs:5
     Assertion with == failed
     code:  assert Students.add_to_approved_list(current_list, students) == ["Paulo", "João", "Iago"]
     left:  ["Paulo", "João"]
     right: ["Paulo", "João", "Iago"]
     stacktrace:
       test/students_test.exs:9: (test)


Finished in 0.01 seconds (0.00s async, 0.01s sync)
1 test, 1 failure
```

Estamos chegando perto! Agora acusou apenas que não temos o estudante Iago em nossa lista. Isso porque o primeiro parâmetro de nossa função esta passando apenas uma lista sem `Iago`. Já o segundo parâmetro está passando uma lista e nessa lista possuímos o nome `Iago`. Essa segunda lista são os estudantes que queremos adicionar na lista de estudantes que passaram. Precisamos unir essas duas listas. Para isso, podemos usar o operador `++/2` do elixir.

<pre class="language-elixir" data-title="lib/students.ex" data-line-numbers><code class="lang-elixir">defmodule Students do
<strong>  def add_to_approved_list(current_list, new_students) do
</strong><strong>    current_list ++ new_students
</strong>  end
end

</code></pre>

Alteramos o nome do segundo parâmetro de underline (`_`) para new\_students para podermos usar em nossa função. Tendo os novos estudantes  em mãos, adicionamos o operador `++/2` ao lado de `current_list` e colocamos ao final a lista que queremos fazer a união, no nosso casso `new_students`. Vamos rodar novamente nosso teste:

```sh
mix test test/students_test.exs
Compiling 1 file (.ex)
.
Finished in 0.01 seconds (0.00s async, 0.01s sync)
1 test, 0 failures
```

Agora temos uma nova lista retornada pela função `add_to_approved_list/2` contendo a união de duas listas. Com isso temos dois dos problemas resolvidos.&#x20;

1. ~~Ter uma lista de estudando aprovados~~
2. ~~Conseguir adicionar estudantes nessa lista~~
3. Remover estudantes da lista.

Precisamos agora remover os estudantes que foram desaprovados. Vamos ao teste:

{% code title="test/students\_test.exs" lineNumbers="true" %}

```elixir
defmodule StudentsTest do
  use ExUnit.Case

  test "removing a user on approved list" do
    current_list = ["Paulo", "João"]
    students = ["João"]

    assert Students.remove_from_approved_list(current_list, students) == ["Paulo"]
  end
end
```

{% endcode %}

```sh
mix test test/students_test.exs
Compiling 1 file (.ex)
warning: Students.remove_from_approved_list/2 is undefined or private
  test/students_test.exs:16: StudentsTest."test List of students approved removing an user on approved list"/1



  1) test List of students approved removing an user on approved list (StudentsTest)
     test/students_test.exs:12
     ** (UndefinedFunctionError) function Students.remove_from_approved_list/2 is undefined or private
     code: assert Students.remove_from_approved_list(current_list, students) == ["Paulo"]
     stacktrace:
       (hello_world 0.1.0) Students.remove_from_approved_list(["Paulo", "João"], ["João"])
       test/students_test.exs:16: (test)

.
Finished in 0.02 seconds (0.00s async, 0.02s sync)
2 tests, 1 failure
```

Agora vamos fazer o oposto do que fizemos anteriormente. Queremos remove elementos de uma lista. Choque com a informação, mas o oposot de `++/2` é `--/2`. Acredito que nem precisaria fazer essa implementação. Mas vou fazer para deixar aqui completo. Vamos a implementação:

{% code title="lib/students.ex" lineNumbers="true" %}

```elixir
defmodule Students do
  # ...

  def remove_from_approved_list(current_list, students_to_remove) do
    current_list -- students_to_remove
  end
end

```

{% endcode %}

Fizemos a mesma implementação, porem, utilizamos o operador `--/2`. Pode rodar os testes e ser feliz.

```sh
mix test test/students_test.exs
Compiling 1 file (.ex)
..
Finished in 0.01 seconds (0.00s async, 0.01s sync)
2 tests, 0 failures
```

E nosso escopo esta fechado:

1. ~~Ter uma lista de estudando aprovados~~
2. ~~Conseguir adicionar estudantes nessa lista~~
3. ~~Remover estudantes da lista.~~

Vamos adicionar mais uma tarefa. Queremos saber a quantidade de estudantes que passaram no vestibular. Vamos ao teste:

{% code title="test/students\_test.exs" lineNumbers="true" %}

```elixir
defmodule StudentsTest do
  use ExUnit.Case

  describe "List of students approved" do
    test "total approved" do
      current_list = ["Paulo", "João"]

      assert Students.total_approved(current_list) == 2
    end
  end
end

```

{% endcode %}

```sh
mix test test/students_test.exs
warning: Students.total_approved/1 is undefined or private. Did you mean:

      * add_to_approved_list/2

  test/students_test.exs:22: StudentsTest."test List of students approved total approved"/1

.

  1) test List of students approved total approved (StudentsTest)
     test/students_test.exs:19
     ** (UndefinedFunctionError) function Students.total_approved/1 is undefined or private. Did you mean:
     
           * add_to_approved_list/2
     
     code: assert Students.total_approved(current_list) == 2
     stacktrace:
       (hello_world 0.1.0) Students.total_approved(["Paulo", "João"])
       test/students_test.exs:22: (test)

.
Finished in 0.03 seconds (0.00s async, 0.03s sync)
3 tests, 1 failure
```

Não possuímos a função. Logo, temos um erro. Vamos resolver isso criando ela:

{% code title="lib/students.ex" lineNumbers="true" %}

```elixir
defmodule Students do
  # ...
  def total_approved(_current_list) do
    2
  end
end

```

{% endcode %}

Quando lidamos com totais, sempre esperamos um `integer`, para manter consistente retornamos dessa função apenas 2 para nosso teste passar. Vamos ver o que o teste nos diz.

```sh
mix test test/students_test.exs
Compiling 1 file (.ex)
...
Finished in 0.01 seconds (0.00s async, 0.01s sync)
3 tests, 0 failures
```

Vamos adicionar uma outra assertion para nosso teste, com uma quantidade diferente de itens na lista. Isso garante que ela funciona bem.

{% code title="test/students\_test.exs" lineNumbers="true" %}

```elixir
defmodule StudentsTest do
  use ExUnit.Case

  describe "List of students approved" do
    test "total approved" do
      current_list = ["Paulo", "João"]
      another_current_list = ["Carlos", "Cris", "Jill"]

      assert Students.total_approved(current_list) == 2
      assert Students.total_approved(another_current_list) == 3
    end
  end
end

```

{% endcode %}

Vamos rodar o teste com a nova assertion:

```sh
mix test test/students_test.exs
..

  1) test List of students approved total approved (StudentsTest)
     test/students_test.exs:19
     Assertion with == failed
     code:  assert Students.total_approved(another_current_list) == 3
     left:  2
     right: 3
     stacktrace:
       test/students_test.exs:24: (test)


Finished in 0.02 seconds (0.00s async, 0.02s sync)
3 tests, 1 failure
```

Algo deu errado. A quantidade esperada na segunda assertion é diferente de dois, que colocamos diretamente na implementação. Precisamos de algo mais dinâmico. Por sorte (uma brincadeira), temos a função nativa `length/1`, onde espera uma lista e nos retorna o total de elementos dessa lista. Vamos lá:

{% code title="" lineNumbers="true" %}

```elixir
defmodule Students do
  # ...
  def total_approved(current_list) do
    length(current_list)
  end
end
```

{% endcode %}

Simples não? Vamos rodar novamente os testes:

```sh
mix test test/students_test.exs
Compiling 1 file (.ex)
...
Finished in 0.02 seconds (0.00s async, 0.02s sync)
3 tests, 0 failures
```

Muito bem! Você está indo bem. Mas vamos pensar em alguma outra coisa. Você é um desses estudantes e quer saber se você passou. Como podemos fazer isso? Vamos ao teste:

{% code title="test/students\_test.exs" lineNumbers="true" %}

```elixir
defmodule StudentsTest do
  use ExUnit.Case

  describe "List of students approved" do
    test "was student approved?" do
      current_list = ["Iago", "Paulo","João"]

      assert Students.was_approved?(current_list, "Iago") == true
    end
  end
end

```

{% endcode %}

```sh
mix test test/students_test.exs
warning: Students.was_approved?/2 is undefined or private. Did you mean:

      * total_approved/1

  test/students_test.exs:30: StudentsTest."test List of students approved was student approved?"/1

...

  1) test List of students approved was student approved? (StudentsTest)
     test/students_test.exs:27
     ** (UndefinedFunctionError) function Students.was_approved?/2 is undefined or private. Did you mean:
     
           * total_approved/1
     
     code: assert Students.was_approved?(current_list, "Iago") == true
     stacktrace:
       (hello_world 0.1.0) Students.was_approved?(["Iago", "Paulo", "João"], "Iago")
       test/students_test.exs:30: (test)


Finished in 0.03 seconds (0.00s async, 0.03s sync)
4 tests, 1 failure
```

Criamos um teste que chama uma função `was_approved?/2`, onde o primeiro argumento é a lista de aprovados e o segundo argumento é uma `string` com o nome do estudante que queremos saber se foi aprovado.&#x20;

{% hint style="info" %}
O nome da função possui uma interrogação, dando a entender que queremos uma resposta de verdadeiro ou falso, isso é uma convenção que também adotamos no Elixir, você pode ver mais sobre isso no [capítulo de conveções](/conceitos/convencoes#funcao-com-interrogacao).
{% endhint %}

Vamos resolver esse teste:

{% code title="" lineNumbers="true" %}

```elixir
defmodule Students do
  # ...
  def was_approved?(_approved_list, _student) do
    true
  end
end

```

{% endcode %}

Criamos a função no módulo `Students` e retornamos uma valor estático `true`. Assim nosso teste passará.

```sh
mix test test/students_test.exs
Compiling 1 file (.ex)
....
Finished in 0.02 seconds (0.00s async, 0.02s sync)
4 tests, 0 failures
```

Vamos adicionar agora um caso de que o estudante que procuramos não passou.

<pre class="language-elixir" data-title="test/students_test.exs" data-line-numbers><code class="lang-elixir">defmodule StudentsTest do
  use ExUnit.Case

  describe "List of students approved" do
    test "was student approved?" do
      current_list = ["Iago", "Paulo","João"]

      assert Students.was_approved?(current_list, "Iago") == true
<strong>      assert Students.was_approved?(current_list, "Rui") == false
</strong>    end
  end
end

</code></pre>

Para isso, apenas adicionamos a linha 9 a nosso teste, procuranod por um estudante chamado Rui que não existe em nossa lista. Vamos rodar o teste:

```sh
mix test test/students_test.exs
..

  1) test List of students approved was student approved? (StudentsTest)
     test/students_test.exs:27
     Assertion with == failed
     code:  assert Students.was_approved?(current_list, "Rui") == false
     left:  true
     right: false
     stacktrace:
       test/students_test.exs:31: (test)

.
Finished in 0.03 seconds (0.00s async, 0.03s sync)
4 tests, 1 failure
```

A resposta para se Rui passou nos exames é true, mas na verdade esperavamos por false. Isso devido ao retorno de nossa função ser estático. Precisamos de algo mais dinâmico para nos salvar agora.

Temos um operador em elixir chamado `in/2`. Ele verificar se existe um elemento em nossa lista. A leitura desse operador fica muito interessante: `1 in [1,2,3]`. Vamos aplica-lo em nosso código:

<pre class="language-elixir" data-title="" data-line-numbers><code class="lang-elixir">defmodule Students do
  # ...
  def was_approved?(approved_list, student) do
<strong>    student in approved_list
</strong>  end
end

</code></pre>

Adicionamos o operador in na linha 4. Também removemos o underline (`_`) dos dois parâmetros da função, para podermos utiliza-las. vamos rodar o teste:

```sh
mix test test/students_test.exs
Compiling 1 file (.ex)
....
Finished in 0.02 seconds (0.00s async, 0.02s sync)
4 tests, 0 failures
```

Perfeito! As funções de lista para estudantes estão tomando forma e ficando claras em seus objetivos. Precisamos so de mais duas funcionalidades. Me ligaram ainda pouco pedindo que adicionacemos a possibilidade de saber o primeiro e ultimo estudante de nossa lista. Falei que não seria um problema, que você já estava dominando a listagem. Vamos escopar isso

Desafio final

1. Obter primeiro estudante da lista
2. Obter último estudante da lista

Vamos começar do primeiro. Criaremos seu teste:

{% code title="test/students\_test.exs" lineNumbers="true" %}

```elixir
defmodule StudentsTest do
  use ExUnit.Case

  describe "List of students approved" do
    # ...
    test "first the list" do
      current_list = ["Iago", "Paulo", "João"]

      assert Students.first(current_list) == "Iago"
    end
  end
end

```

{% endcode %}

```sh
mix test test/students_test.exs
warning: Students.first/1 is undefined or private
  test/students_test.exs:37: StudentsTest."test List of students approved first the list"/1

.

  1) test List of students approved first the list (StudentsTest)
     test/students_test.exs:34
     ** (UndefinedFunctionError) function Students.first/1 is undefined or private
     code: assert Students.first(current_list) == "Iago"
     stacktrace:
       (hello_world 0.1.0) Students.first(["Iago", "Paulo", "João"])
       test/students_test.exs:37: (test)

...
Finished in 0.03 seconds (0.00s async, 0.03s sync)
5 tests, 1 failure
```

Vamos implementar a função `first/1`, onde recebe a lista que queremos obter o primeiro. Elixir tem um módulo de List que nos ajuda a listar com algumas coisas relacionadas a lista. Para resolver nosso problema aqui, temos a função `List.first/1`, onde o argumento passado é a lista e a resposta é o elemento da lista, exatamente o que precisamos.

{% code title="lib/students.ex" lineNumbers="true" %}

```elixir
defmodule Students do
  # ...
  def first(current_list) do
    List.first(current_list)
  end
end

```

{% endcode %}

```sh
mix test test/students_test.exs
Compiling 1 file (.ex)
.....
Finished in 0.02 seconds (0.00s async, 0.02s sync)
5 tests, 0 failures
```

Simples não? Agora precisamos lidar com o útilmo da lista. Te desafio a pensar qual função usaremos para resolver isso. Enquanto pensa, vamos para o teste:

{% code title="test/students\_test.exs" lineNumbers="true" %}

```elixir
defmodule StudentsTest do
  use ExUnit.Case

  describe "List of students approved" do
    # ...
    test "last in the list" do
      current_list = ["Iago", "Paulo", "João"]

      assert Students.last(current_list) == "João"
    end
  end
end

```

{% endcode %}

```sh
mix test test/students_test.exs
warning: Students.last/1 is undefined or private
  test/students_test.exs:43: StudentsTest."test List of students approved last in the list"/1

...

  1) test List of students approved last in the list (StudentsTest)
     test/students_test.exs:40
     ** (UndefinedFunctionError) function Students.last/1 is undefined or private
     code: assert Students.last(current_list) == "João"
     stacktrace:
       (hello_world 0.1.0) Students.last(["Iago", "Paulo", "João"])
       test/students_test.exs:43: (test)

..
Finished in 0.03 seconds (0.00s async, 0.03s sync)
6 tests, 1 failure
```

Vamos implementar a função que não existe. Pensou na função que usariamos para ser oposto a `List.first/1`? É isso mesmo, `List.last/1`. Vamos implementar nosso código.

{% code title="lib/students.ex" lineNumbers="true" %}

```elixir
defmodule Students do
  # ...
  def last(current_list) do
    List.last(current_list)
  end
end

```

{% endcode %}

```sh
mix test test/students_test.exs
Compiling 1 file (.ex)
......
Finished in 0.02 seconds (0.00s async, 0.02s sync)
6 tests, 0 failures
```

### Conclusão

Ótimo! Agora temos muitas ferramentas para lidar com listas. Listas são simples, mas podemos tirar grandes vantagens dela ao dia-a-dia de trabalho. Ela sempre estará presente e muitas vezes podem se tornar bem complexa. O domínio de operações e funções de auxílio ira te ajudar na jornada.

Você deve ter ficado com a impressão de faltar algo. Sim, temos um buraco aqui. Que tipo de aprendizado de lista não ensina como a percorremos. Por isso o próximo capítulo falará sobre estruturas de repetição.&#x20;


# Estruturas de repetição


# Recursão

Um assunto interessante em programação funcional é a recursão. Um recurso usado para lidar com a impossibilidade de manter estado falado no capítulo sobre [imutabilidade](/conceitos/imutabilidade).

Ele se classifica em uma forma de passar por itens de uma lista, um por um.

O básico de uma recursão é: Uma função que se chama, criando um looping onde vai até sair fora dessa chamada. Vamos a um exemplo real.

{% hint style="info" %}
[capture\_log](https://hexdocs.pm/ex_unit/1.13.4/ExUnit.CaptureLog.html) como o próprio nome diz, captura o log tendo o objetivo de ser usado em testes.
{% endhint %}

Primeiro o teste:

{% code title="test/recursion\_test.exs" lineNumbers="true" %}

```elixir
defmodule RecursionTest do
  use ExUnit.Case

  import ExUnit.CaptureLog

  describe "print_loop/1" do
    test "Print x until x = 0" do
      x = 5

      execution = capture_log(fn ->
        Recursion.print_loop(x)
      end)

      assert capture_log(execution) =~ "Printed number 5"
      assert capture_log(execution) =~ "Printed number 4"
      assert capture_log(execution) =~ "Printed number 3"
      assert capture_log(execution) =~ "Printed number 2"
      assert capture_log(execution) =~ "Printed number 1"
    end
  end
end

```

{% endcode %}

Queremos registrar 5 vezes uma mensagem para entender que fez um loop de 5 vezes, onde o único dado alterado é o x onde vai de 5 a 1. Para isso utilizaremos o [capture\_log](https://hexdocs.pm/ex_unit/1.13.4/ExUnit.CaptureLog.html) que serve para capturar logs feitos na aplicação.

Vamos rodar esse código

```sh
mix test test/recursion_test.exs
warning: Recursion.print_loop/1 is undefined (module Recursion is not available or is yet to be defined)
  test/recursion_test.exs:11: RecursionTest."test print_loop/1 Print x until x = 0"/1



  1) test print_loop/1 Print x until x = 0 (RecursionTest)
     test/recursion_test.exs:7
     ** (UndefinedFunctionError) function Recursion.print_loop/1 is undefined (module Recursion is not available)
     code: execution = capture_log(fn ->
     stacktrace:
       Recursion.print_loop(5)
       (ex_unit 1.14.3) lib/ex_unit/capture_log.ex:108: ExUnit.CaptureLog.with_log/2
       (ex_unit 1.14.3) lib/ex_unit/capture_log.ex:77: ExUnit.CaptureLog.capture_log/2
       test/recursion_test.exs:10: (test)


Finished in 0.04 seconds (0.00s async, 0.04s sync)
1 test, 1 failure
```

Obtivemos o relatório de erro por não termos o módulo nem a função criados. Vamos cria-las.

<pre class="language-elixir" data-title="lib/recursion.ex" data-line-numbers><code class="lang-elixir">defmodule Recursion do
  require Logger

<strong>  def print_loop(x) do
</strong>    Logger.info("Printed number #{x}")

<strong>    print_loop(x - 1)
</strong>  end
end

</code></pre>

Como podemos ver, na linha 7 temos a chamada para a mesma função que definimos na linha 4. Isso é a recursão, algo chamando a si mesmo, criando um laço de repetição. Porém, se rodarmos esse código, teremos um loop infinito, pois não temos um condição de parada. Caso execute esse código teremos o terminal congelado esperando a operação finalziar, mas isso não irá acontecer, então precisamos apertar CTRL + C e abortar a operação.

```sh
mix test test/recursion_test.exs
^C
BREAK: (a)bort (A)bort with dump (c)ontinue (p)roc info (i)nfo
       (l)oaded (v)ersion (k)ill (D)b-tables (d)istribution
^C%
```

Para isso não acontecer, precisamos de uma condição de parada, sendo a primeira coisa que definimos em nossa recursão. Nesse exemplo queremos que o X seja maior que 0. Essa é nossa condição. Para por isso em nossa função utilizaremos os [guards](/basico/controle-de-fluxo/guards). Vamos alterar nossa implementação.

<pre class="language-elixir" data-title="lib/recursions.ex" data-line-numbers><code class="lang-elixir">defmodule Recursion do
  require Logger

<strong>  def print_loop(x) when x > 0 do
</strong>    Logger.info("Printed number #{x}")

    print_loop(x - 1)
  end
end

</code></pre>

Na linha 4, ao lado da definição da função temos a palavra chave when seguida de uma condição. Ele garantirá que nosso x seja maior que 0. Caso não seja, ele não ta match com esse função, procurando uma outra definição para seguir o processo do programa. Caso não encontre, extoura uma exceção. Vamos rodar esse teste.

```sh
mix test test/recursion_test.exs
Compiling 1 file (.ex)


  1) test print_loop/1 Print x until x = 0 (RecursionTest)
     test/recursion_test.exs:7
     ** (FunctionClauseError) no function clause matching in Recursion.print_loop/1

     The following arguments were given to Recursion.print_loop/1:
     
         # 1
         0
     
     Attempted function clauses (showing 1 out of 1):
     
         def print_loop(x) when x > 0
     
     code: assert capture_log(execution) =~ "Printed number 5"
     stacktrace:
       (hello_world 0.1.0) Recursion.print_loop/1
       (ex_unit 1.14.3) lib/ex_unit/capture_log.ex:108: ExUnit.CaptureLog.with_log/2
       (ex_unit 1.14.3) lib/ex_unit/capture_log.ex:77: ExUnit.CaptureLog.capture_log/2
       (ex_unit 1.14.3) lib/ex_unit/capture_log.ex:108: ExUnit.CaptureLog.with_log/2
       (ex_unit 1.14.3) lib/ex_unit/capture_log.ex:77: ExUnit.CaptureLog.capture_log/2
       test/recursion_test.exs:14: (test)


Finished in 0.02 seconds (0.00s async, 0.02s sync)
1 test, 1 failure
```

Uma vez que o `x` chegou a `0`, nossa função não se apresentava mais como um match e ganhamos com isso uma `FunctionClauseError` que significa que que a clausura para acessar essa função não foi atendida.

O que esta correto, não queremos a recursão de valores abaixo de 1. Queremos apenas maiores que 0. O que precisamos fazer agora é silenciar essa exceção. Para isso, podemos criar uma função de mesmo nome abaixo da criada anteriormente, fazer com que aceite valores abaixo de 1 e retornar algum valor como por exemplo `nil`. Vamos alterar nossa implementação:

<pre class="language-elixir" data-title="lib/recursion_test.exs" data-line-numbers><code class="lang-elixir">defmodule Recursion do
  require Logger

  def print_loop(x) when x > 0 do
    Logger.info("Printed number #{x}")

    print_loop(x - 1)
  end

<strong>  def print_loop(_x), do: nil
</strong>end

</code></pre>

Na linha 10, adicionamos uma nova definição da função `print_loop/1`, onde apenas espera receber um valor qualquer e retorna um `nil`. Não temos nenhuma condição em relação a isso porque esse é um cenário onde esperamos parar o looping. Então, quando chegamos a x = 0, a primeira fução que cotém o codicionameto `x >0` não será mais atendido e irá para a proxima função de mesmo nome. Nessa nova função da linha 10 espera um valor qualquer, sem qualquer regra ou condição, logo, nosso `x = 0` será atendido e iremos executar essa função. Executando essa função, a unica coisa que ele faz é retornar `nil`. Ela não executa novamente a própria função, isso causa a parada da repetição e a finalização da recursão.

Vamos rodar esse teste:

```sh
mix test test/recursion_test.exs
Compiling 1 file (.ex)
.
Finished in 0.08 seconds (0.00s async, 0.08s sync)
1 test, 0 failures
```

Nosso relatório de teste nos trouxe sucesso. Tivemos então um looping em cima da função `print_loop/1`. Finalizando a recursão utilizando [guards](/basico/controle-de-fluxo/guards).

### Utilizando head | tail

Entendo uma vez o conceito de recursão, temos algumas facilidades que o elixir nos proporciona. Chamamos de `head | tail` (cabeça e cauda). Ele diz respseito ao processamento de listas, como por exemplo `[1,2,3,4,5]`. O número 1 seria a cabeça (primeiro elemento da lista) enquanto o restante `[2, 3, 4, 5]` seria a cauda. Isso pode ser utilizado para saber qual os proximos elementos de uma recursão. Vamos a um exemplo.

Precisamos processar números de uma lista que vai do 1 até o 10. Cada iteração utilizaremos o Logger para falar que passamos por lá, muito parecido com o exemplo anterior. Mas nesse caso estamos lidando com uma lista.

Primeiro, vamos o teste de parada, para não termos um loop infinito:

{% code title="test/my\_list\_test.exs" lineNumbers="true" %}

```elixir
defmodule MyListTest do
  use ExUnit.Case

  import ExUnit.CaptureLog

  describe "process/1" do
    test "the list are empty" do
      elements = []

      execution = fn ->
        capture_log(fn -> MyList.process(elements) end)
      end
      
      assert capture_log(execution) =~ "the list are empty"
    end
  end
end

```

{% endcode %}

Simplesmente queremos que um looping seja feito e que seja impresso uma vez cada elemento da lista. Vamos rodar para ter nosso erro

```sh
mix test test/my_list_test.exs
Compiling 1 file (.ex)
warning: MyList.process/1 is undefined or private
  test/my_list_test.exs:11: MyListTest."test process/1 the list are empty"/1



  1) test process/1 the list are empty (MyListTest)
     test/my_list_test.exs:7
     ** (UndefinedFunctionError) function MyList.process/1 is undefined or private
     code: assert capture_log(execution) =~ "the list are empty"
     stacktrace:
       (hello_world 0.1.0) MyList.process([])
       (ex_unit 1.14.3) lib/ex_unit/capture_log.ex:108: ExUnit.CaptureLog.with_log/2
       (ex_unit 1.14.3) lib/ex_unit/capture_log.ex:77: ExUnit.CaptureLog.capture_log/2
       (ex_unit 1.14.3) lib/ex_unit/capture_log.ex:108: ExUnit.CaptureLog.with_log/2
       (ex_unit 1.14.3) lib/ex_unit/capture_log.ex:77: ExUnit.CaptureLog.capture_log/2
       test/my_list_test.exs:14: (test)


Finished in 0.02 seconds (0.00s async, 0.02s sync)
1 test, 1 failure
```

Como esperado, o relatório nos avisou que `MyList.process/1` não foi definido. Vamos a implementação. Primeiramente precisamos decidir o critério de parada. O conceito de recursão continua o mesmo, a função vai se chamar, até que por algum motivo o parâmetro que inserimos na função faça com que outra função de mesmo nome seja invocada e faça a parada da recursão.

Utilizaremos o conceito de `head|tail`. Sendo `head` o primeiro elemento, e `tail` o restante. Com isso podemos entender que ao chamar a propria função na recursão enviaremos o `tail` para a proxima iteração, seguindo até o final onde teremos uma lista vazia e isso causará a parada da recursão.

Vamos implementar primeiro a condição de parada:

{% code title="lib/my\_list.ex" lineNumbers="true" %}

```elixir
defmodule MyList do
  require Logger

  def process([]) do
    Logger.info("the list are empty")
  end
end

```

{% endcode %}

Utilizamos pattern matching para dizer que, ao receber uma lista vazia por parâmetro, não chamaremos a função process dentro dela mesmo. Isso causará a parada da recursão. Também logamos o registro `the list are empty`, para garantirmos que estamos corretos. Vamos rodar o teste novamente

```sh
mix test test/my_list_test.exs
Compiling 1 file (.ex)
.
Finished in 0.02 seconds (0.00s async, 0.02s sync)
1 test, 0 failures
```

Perfeito! Temos a parada, agora precisamos fazer a recursão utilizando `head|tail`. vamos começar pelo teste:

{% code title="lib/my\_list.ex" lineNumbers="true" %}

```elixir
defmodule MyListTest do
  use ExUnit.Case

  import ExUnit.CaptureLog

  describe "process/1" do
    # ...
    test "print all elements" do
      elements = [1,2,3,4,5]

      execution = fn ->
        capture_log(fn -> MyList.process(elements) end)
      end

      assert capture_log(execution) =~ "head is 1 and tail is [2, 3, 4, 5]"
      assert capture_log(execution) =~ "head is 2 and tail is [3, 4, 5]"
      assert capture_log(execution) =~ "head is 3 and tail is [4, 5]"
      assert capture_log(execution) =~ "head is 4 and tail is [5]"
      assert capture_log(execution) =~ "head is 5 and tail is []"
      assert capture_log(execution) =~ "the list are empty"
    end
  end
end

```

{% endcode %}

De forma simples, queremos apenas que cada iteração faz um log do valor de head e tail para exemplificar como o looping se comporta. Novamente `head` é o primeiro valor da lista, sem ser uma lista e `tail` é o restante sendo uma lista. Se tivermos `[1,2,3]` o `head` é o número `1` e `tail` é a lista `[2,3]`.

{% hint style="info" %}
**Interpolação**.

\
Podemos inserir valores em uma string utilizando a interpolação. Dentro de uma string definida qualquer texto que tem envolta aspas duplas. Para demarcar o local utilizamos jogo da velha abrir chaves, a variável a ser impressa e fechar chaves.&#x20;
{% endhint %}

{% hint style="info" %}
**inspect**\
\
Para imprimir um valor complexo como listas e mapas como texto, precisamos utilizar a função `inspect/1` onde converterá os dados para texto.
{% endhint %}

Vamos a implementação

<pre class="language-elixir" data-title="lib/my_list.ex" data-line-numbers><code class="lang-elixir">defmodule MyList do
  require Logger

  def process([]) do
    Logger.info("the list are empty")
  end

<strong>  def process([head | tail]) do
</strong>    Logger.info("head is #{head} and tail is #{inspect(tail)}")

    process(tail)
  end
end

</code></pre>

Criamos uma nova função embaixo da criada como critério de parada com o mesmo nome. Utilizamos então o `head | tail` na entrada do parâmetro com a notação padrão `[head | tail]`, conseguindo nosso `head` e nosso `tail` de forma fácil. Agora precisamos nos ater a duas coisas

1. `head` é o valor atual, não sendo uma lista. Esse valor usaremos para realizar algo nessa iteração. Nesse nosso exemplo, logaremos `"Printed number #{head}"`.
2. `tail` é uma lista dos elementos restantes que deve ser passada para a proxima iteração.

Podemos rodar o teste novamente e ver o que acontece:

```sh
mix test test/my_list_test.exs
..
Finished in 0.03 seconds (0.00s async, 0.03s sync)
2 tests, 0 failures
```

O relatório de sucesso é imprimido, isso quer dizer que nossa recursão utilizando `head | tail` foi um sucesso! Esse conteúdo pode ser um pouco estanho quando vemos pela primeira vez, mas com o tempo e prática vai se tornar claro.

### Conclusão

A utilização de recursão é altamente utilizado em programações funcionais. Elixir não é diferente. Ele possibilidade diversas funções. No próximo capítulo utilizaremos funções nativas do Elixir que se beneficiam da recursão.


# Controle de fluxo


# Pipes

A tradução direta de `pipes` é `canos`.  Você pode pensar sobre`Canos` como os canos de sua casa.  Eles funcionam para passar água de um lugar para outro. No meio dessa passagem podemos por algumas coisas como, válvulas e filtros, até chegar em nossa torneira pronta para uso.&#x20;

A água seria nossos dados. As válvulas e filtros os redutores e a torneira seria nosso transformador.  A ideia aqui é passar dados a fim de realizar operações sequenciais para termos uma resposta final que precisamos.  `dados -> função 1 -> função 2 -> função N -> dados transformados pronto para uso.`

Normalmente utilizamos funções dessa forma

```elixir
funcao(argumento1)
```

Com pipe, é um pouco diferente.&#x20;

```elixir
argumento_1
|> funcao()
```

A troca da sequência, onde colocamos o parâmetro antes da função nos possibilita encadear várias funções.

```elixir
arumento_1
|> funcao_1()
|> funcao_2()
|> funcao_3()
```

No exemplo acima, a `funcao_1` recebe o `argumento_1,` a `funcao_2` recebe a resposta da `funcao_1` e a `funcao_3` recebe a resposta da `funcao_2`.&#x20;

{% hint style="info" %}
**Aridade em funções**<br>

Se a aridade de uma função for maior do que `1`, Utilize parênteses. Elixir não se importa com isso, mas, é importante para outros programadores, pois podem interpretar mal o seu código. <br>

`foo # Isso é uma função ou variável?`

`bar() # Aaah, isso é uma função.`
{% endhint %}

Podemos utilizar pipes

* Com funções nativas;
* Em um linha só;

```shell
iex(1)> "Iago Effting" |> String.downcase() |> IO.inspect()
"iago effting"
```

* Com condicionais (mesmo não sendo tão legal de ler)

```shell
iex(1)> 100 \
...(1)> |> case do
...(1)>   100 -> "It's 100"
...(1)>   _ -> "it's something else"
...(1)> end

"It's 100"
```

Podemos utilizar basicamente qualquer função no pipe, seguindo a regra do primeiro parâmetro vir antes.

### Exemplo

Vamos fazer algo então. Precisamos fazer uma sequencia de operações para atender a uma regra.&#x20;

1. Dado um valor vamos
2. **Somar** o valor de entrada por 10;
3. **Multiplicar** o valor por 2;
4. **Diminuir** por 5

Vamos começar sem a utilização de `pipes`. Para isso adicionarei um parâmetro extra em nossa função, onde poderemos colocar  e cair na função que não utiliza pipes ou apenas passando um valor e cairá na função com `pipe`. Vamos sem `pipes` primeiro.

<pre class="language-elixir" data-title="test/pipes_test.exs" data-line-numbers><code class="lang-elixir">defmodule CalculatorTest do
  use ExUnit.Case

  test "Not using pipes" do
    value = 5
    
<strong>    assert Calculator.crazy_rule(value, :without_pipe) == 25
</strong>  end
end
</code></pre>

```shell
mix test test/calculator_test.exs
warning: Calculator.crazy_rule/1 is undefined (module Calculation is not available or is yet to be defined)
  test/pipes_test.exs:7: PipesTest."test Not using pipes"/1



  1) test Not using pipes (PipesTest)
     test/pipes_test.exs:4
     ** (UndefinedFunctionError) function Calculator.crazy_rule/1 is undefined (module Calculation is not available)
     code: assert Calculator.crazy_rule(value) == 25
     stacktrace:
       Calculator.crazy_rule(5)
       test/calculator_test.exs:7: (test)


Finished in 0.04 seconds (0.00s async, 0.04s sync)
1 test, 1 failure
```

Não temos criado o modulo, vamos cria-lo.

{% code title="lib/calculator.ex" lineNumbers="true" %}

```elixir
defmodule Calculator do
  def crazy_rule(value, :not_using_pipes) do

  end
end
```

{% endcode %}

```shell
mix test test/calculator_test.exs


  1) test Not using pipes (PipesTest)
     test/calculator_test.exs:4
     Assertion with == failed
     code:  assert Calculator.crazy_rule(value) == 25
     left:  nil
     right: 25
     stacktrace:
       test/calculator_test.exs:7: (test)


Finished in 0.02 seconds (0.00s async, 0.02s sync)
1 test, 1 failure
```

Agora podemos seguir.

Precisamos resolver esse modulo usando funções e elas ficam bem claras quais são. Basta pegar os passos que devem ser feitos `somar`, `diminuir` e `multiplicar`.

Podemos resolver isso, assim:

{% code title="" lineNumbers="true" %}

```elixir
defmodule Calculator do
  def crazy_rule(value, :without_pipes) do
    value = sum(value, 10)
    value = multiple(value, 2)
    value = decrease(value, 5)
    
    value # Retorna o valor final
  end
  
  defp sum(current_value, value), do: current + value
  defp multiple(current_value, value), do: current_value * value
  defp decrease(current_value, value), do: current_value - value
end
```

{% endcode %}

Criamos as funções referente a regra e juntamos tudo na função publica `crazy_rule`. Vamos rodar isso.

```shell
mix test test/calculator_test.exs
Compiling 1 file (.ex)
.
Finished in 0.01 seconds (0.00s async, 0.01s sync)
1 test, 0 failures
```

Tudo funcionando bem e nosso teste passando.

Vamos agora criar utilizando pipes.

<pre class="language-elixir" data-title="test/calculator_test.exs" data-line-numbers><code class="lang-elixir">defmodule PipesTest do
  use ExUnit.Case
  
  # ...

  test "Using pipes" do
    value = 5
    
<strong>    assert Calculator.crazy_rule(value, :with_pipes) == 25
</strong>  end
end
</code></pre>

Adicionando a função utilizando `pipes`:

<pre class="language-elixir" data-title="lib/calculator.ex" data-line-numbers><code class="lang-elixir">defmodule Calculator do
  def crazy_rule(value, :without_pipes) do
    value = sum(value, 10)
    value = multiple(value, 2)
    value = decrease(value, 5)

    value # Retorna o valor
  end
  
<strong>  def crazy_rule(value, :with_pipes) do
</strong><strong>    value
</strong><strong>    |> sum(10)
</strong><strong>    |> multiple(2)
</strong><strong>    |> decrease(5)
</strong><strong>  end
</strong>  
  defp sum(current_value, value), do: current_value + value
  defp multiple(current_value, value), do: current_value * value
  defp decrease(current_value, value), do: current_value - value
end
</code></pre>

Execute os testes novamente

```shell
mix test test/calculator_test.exs
..
Finished in 0.01 seconds (0.00s async, 0.01s sync)
2 tests, 0 failures
```

A utilização de pipes deixa o código mais elegante a fácil de entender. A leitura se torna mais fluída e colocar uma nova função no meio dele fica bem simples, enquanto sem pipes se torna repetitiva e verbosa.

{% hint style="warning" %}
**Pipes**

As funções no pipe deve seguir uma ordem lógica. Quando a ordem é alterada, o resultado tende a se alterar também. Existem formas de programar pipes, onde isso não será um problema, mas em nosso exemplo, é. Tenha isso em mente.
{% endhint %}

### Conclusão

A utilização pipes se torna simples em colocar funções em uma sequência lógica para atender um requisito, mesmo que estranho. É amplamente utilizado no elixir e recomendado. Devemos sempre seguir a regra de, o primeiro argumento deve vir antes da chamada da função&#x20;

```elixir
argumento_1
|> funcao(argumento_2) # funcao/2
|> outra(argumento_2) # outra/1
```

Pense bem ao utilizar pipes, podem ser uma boa forma de melhorar a legibilidade de seu código.


# With

Eu realmente acho interessante a declaração `with`. Ele deixa as coisas mais claras e podemos também controlar o fluxo do código. Ela é baseada na utilização de funções encadeadas que podemos controlar em caso de sucesso e em caso de algo der errado.&#x20;

Diferente dos [pipes](/basico/controle-de-fluxo/pipes), com `with` podemos ter um maior controle na mesma camada de onde ele está sendo implementado. Podemos definir o que esperamos de cada função por meio de pattern matching e como iremos usar a resposta nas funções subsequentes. Também podemos definir qual o fluxo ele vai tomar em caso de um erro especifico ou genérico.

A estrutura é simples:

* Declaração `with`

```elixir
with
```

* Execução de funções separadas por `,` (virgula). Prestando atenção que temos os valores retornados e isso é de extrema importância. Aqui podemos criar um controle de como será executado, a ordem de execução e critérios de aceite.

```elixir
with valor_1 <- funcao_1(),
     valor_2 <- funcao_2()
```

* Declaração `do`, onde abrimos escopo para quando tudo der certo, ele fará. Muito usado para definir a resposta de uma função onde o `with` esta sendo composto.

```elixir
with valor_1 <- funcao_1(),
     valor_2 <- funcao_2() do
  # caso tudo funciona
end
```

* Declaração `else`, para quando algo sair errado. Aqui podemos usar a regra do `pattern matching` para conseguir a resposta do erro.

```elixir
with valor_1 <- funcao_1(),
     valor_2 <- funcao_2() do
  # caso tudo funciona
else
  # caso algo de errado
  error -> IO.inspect(error)
end
```

A `funcao_1` e `funcao_2` são funções que estao compondo uma funcionalidade. Podemos utilizar várias funções para compor uma funcionalidade, mas lembrando que nem sempre ter muitas facilita o entendimento.

{% hint style="warning" %}
**Composição**\
Quando falamos de composição aqui, estamos falando sobre juntar várias funções com o intuito de fazer uma funcionalidade completa. Por exemplo, salvar usuário ou renderizar arquivos, onde precisamos passar por validações e outras operações até chegar ao resultado estimado.&#x20;
{% endhint %}

### Exemplo

Nada como um exemplo real para entender coisas complexas. Vamos imaginar que precisamos criar um usuário. Para essa funcionalidade precisamos:

* Validar se os dados estão corretos;
* Salvar no banco de dados
* Atualizar usuário para ativo
* Responder que tudo deu certo

São vários passos. Você pode perceber que temos bem definido uma sequencia de operações até finalizar a funcionalidade. Vamos começar escrevendo o nosso teste.

{% code title="test/users\_test.exs" lineNumbers="true" %}

```elixir
defmodule WithTest do
  use ExUnit.Case

  describe "create/1" do
    test "create an user and active him when params are valid" do
       params = %{name: "iago"}

       {:ok, result} = Users.create(params)

       assert result.name == params.name
    end
  end
end
```

{% endcode %}

```shell
mix test test/users_test.exs
warning: Users.create/1 is undefined (module Users is not available or is yet to be defined)
  test/users_test.exs:8: WithTest."test create/1 create an user and active him when params are valid"/1



  1) test create/1 create an user and active him when params are valid (WithTest)
     test/users_test.exs:5
     ** (UndefinedFunctionError) function Users.create/1 is undefined (module Users is not available)
     code: result = Users.create(params)
     stacktrace:
       Users.create(%{name: "iago"})
       test/users_test.exs:8: (test)


Finished in 0.03 seconds (0.00s async, 0.03s sync)
1 test, 1 failure
```

Precisamos criar o modulo e a função. Começamos simples:

{% code title="lib/users.ex" lineNumbers="true" %}

```elixir
defmodule Users do
  def create(params) do
    data = %{
      name: params.name,
    }
    
    {:ok, data}
  end
end
```

{% endcode %}

```shell
mix test test/users_test.exs
Compiling 1 file (.ex)
Generated hello_world app
.
Finished in 0.01 seconds (0.00s async, 0.01s sync)
1 test, 0 failures
```

Primeira iteração passando, vamos lidar a primeira etapa, com a validação. Ela será simples, precisamos ter somente o elemento name dentro de nosso map. Criaremos um teste para isso

{% code title="test/users\_test.exs" lineNumbers="true" %}

```elixir
defmodule WithTest do
  use ExUnit.Case

  describe "create/1" do
    # ...

    test "show an error when params are invalid" do
      invalid_params = %{name: "iago"}

      {:error, reason} = Users.create(invalid_params)

      assertreason == "The field name is required"
    end
  end
end
```

{% endcode %}

```shell
mix test test/users_test.exs


  1) test create/1 show an error when params are invalid (WithTest)
     test/users_test.exs:14
     ** (MatchError) no match of right hand side value: {:ok, %{is_actived: true, name: "iago"}}
     code: {:error, reason} = Users.create(invalid_params)
     stacktrace:
       test/users_test.exs:17: (test)

.
Finished in 0.03 seconds (0.00s async, 0.03s sync)
2 tests, 1 failure
```

Ao rodar o teste, vemos que nosso pattern matching não funcionou. Nosso teste esta esperando um `{:error, reason}` e recebemos um `{:ok, data}`. Claramente por que estamos passando um dado estático. Vamos arrumar isso.

Criamos uma função dentro de `users.ex` para validar se os dados estão corretos.&#x20;

{% hint style="info" %}
Temos apenas uma função, ainda não temos a necessidade de utilizar a declaração `with`, não ganhamos nada com isso.
{% endhint %}

Vamos atualizar o arquivo `lib/users.ex`

Aqui precisamos de dois tipos de resposta para nosso `create/1`. Quando temos sucesso e voltamos um `{:ok, data}` e quando de erro um `{:error, reason`} para assim podemos fazer o teste passar.

Temos algumas declarações condicionais boas para isso. Iremos utilizar `case` para facilitar o entendimento.

{% code title="lib/users.ex" lineNumbers="true" %}

```elixir
defmodule Users do
  def create(params) do
    case validate(params) do
      {:ok, validated_user} ->
        {:ok,
         %{
           name: validated_user.name,
         }}

      error ->
        error
    end
  end

  defp validate(user_params) when not is_nil(user_params.name), do: {:ok, user_params}
  defp validate(_user_params), do: {:error, "The field name is required"}
end
```

{% endcode %}

Se rodar isso, teremos um bom resultado.

```shell
mix test test/users_test.exs
Compiling 1 file (.ex)
..
Finished in 0.02 seconds (0.00s async, 0.02s sync)
2 tests, 0 failures
```

Aqui precisamos de uma pausa para uma reflexão. Se você analisar o código, está  bagunçado. Temos indentações demais, que dificultam a leitura. Vamos refatorar.

{% hint style="info" %}
**Refatoração**

Processo de modificar um sistema de software para melhorar a estrutura interna do código sem alterar seu comportamento externo.

[Mais sobre](https://pt.wikipedia.org/wiki/Refatora%C3%A7%C3%A3o)
{% endhint %}

Uma boa regra da refatoração é nunca mudar o comportamento do que se refatora. Isso faz com que nossos testes criados até então, sirvam de checkpoint para saber se tudo esta funcionando como deveria após a alteração.

**Vamos fazer o seguinte:**

Onde adicionamos o dado `name` vamos por para dentro de uma função chamada `build/1` onde receberá o usuário que queremos construir. Ele Irá montar o campo e retornar o novo valor do `map.`

Vamos lá

{% code title="lib/users.ex" lineNumbers="true" %}

```elixir
defmodule Users do
  def create(params) do
    case validate(params) do
      {:ok, validated_user} ->
        {:ok, build(validated_user)}

      error ->
        error
    end
  end

  defp build(user) do
     %{
       name: user.name,
     }
  end

  defp validate(user_params) when not is_nil(user_params.name), do: {:ok, user_params}
  defp validate(_user_params), do: {:error, "The field name is required"}
end

```

{% endcode %}

```shell
mix test test/users_test.exs
Compiling 1 file (.ex)
..
Finished in 0.01 seconds (0.00s async, 0.01s sync)
2 tests, 0 failures
```

Ficou melhor de ler. Ainda temos alguns problemas ali, mas vamos seguir e esperar doer mais um pouco para entender o que esta acontecendo.

Em nossa lista o próximo seria salvar o usuário no banco.

* ~~Validar se os dados estão corretos;~~
* Salvar no banco de dados
* Atualizar usuário para ativo
* Responder que tudo deu certo

Não utilizaremos banco de dados aqui, mas iremos criar uma função para simular. Para isso vamos atualizar nosso primeiro teste, aquele que esperamos sucesso e agora adicionaremos uma nova afirmação, onde um novo campo chamada `is_inserted` irá ser adicionado ao nosso `map`, apenas para exemplificar que foi inserido em nosso banco de dados que não existe. Vamos ao teste:

<pre class="language-elixir" data-title="test/users_test.exs" data-line-numbers><code class="lang-elixir">defmodule WithTest do
  use ExUnit.Case

  describe "create/1" do
    test "create an user and active him when params are valid" do
       params = %{name: "iago"}

       {:ok, result} = Users.create(params)

       assert result.name == params.name
<strong>       assert result.is_inserted == true
</strong>    end
  end
end
</code></pre>

Se rodarmos esse teste, teremos um erro

```shell
mix test test/users_test.exs


  1) test create/1 create an user and active him when params are valid (WithTest)
     test/users_test.exs:5
     ** (KeyError) key :is_inserted not found in: %{is_actived: true, name: "iago"}
     code: assert result.is_inserted == true
     stacktrace:
       test/users_test.exs:12: (test)

.
Finished in 0.03 seconds (0.00s async, 0.03s sync)
2 tests, 1 failure
```

Precisamos criar um novo comportamento onde simulará salvar no banco de dados adicionando ao map a chave `inserted_at: true`.&#x20;

Porém, temos um problema. Onde iremos colocar esse código? Teremos que tratar caso algum erro aconteça. Poderíamos utilizar o `case` e encadear mais `case`. Ficando algo assim:

```elixir
defmodule Users do
  def create(params) do
    case validate(params) do
      {:ok, validated_user} ->
        case save(validated_user) do
          {:ok, user_saved} -> {:ok, user_saved}
          {:error, reason} -> {:error, reason}
        end

      error ->
        error
    end
  end

  defp validate(user_params) when not is_nil(user_params.name), do: {:ok, user_params}
  defp validate(_user_params), do: {:error, "The field name is required"}
end

```

Isso até pode funcionar, mas temos grandes perdas como ilegibilidade e este arquivo se tornará gigante até finalizarmos todas as etapas que queremos, logo, a manutenção será penosa. Podemos também usar pipes, estudamos sobre eles, porém, temos os problemas com os errors. Teríamos que tratar dentro de cada função o erro anterior e isso traria muitas indireções.

Para a nossa felicidade, temos uma declaração chamada with, que trabalha como um pipe, porem, cuidando de algumas coisas que ele não consegue fazer. Vamos usar ele e aprender como ele funciona.

Primeiro, um refactoring do que temos até agora.

{% code title="lib/users.ex" lineNumbers="true" %}

```elixir
defmodule Users do
  def create(params) do
    with {:ok, validated_user} <- validate(params) do
      {:ok, validated_user}
    else
      error ->
        error
    end
  end

  defp validate(user_params) when not is_nil(user_params.name), do: {:ok, user_params}
  defp validate(_user_params), do: {:error, "The field name is required"}
end
```

{% endcode %}

A resposta que esperamos da primeira função é `{:ok, validated_user}` caso não seja atendida a execução cairá no else e lá temos um tratamento simples de so passar o erro para frente.

Caso o erro de validação ocorra, ele cairá no else e no error tera o valor de `{:error, "The field name is required"}`. O legal da utilização do with é que qualquer coisa que não seja esperada como resultado nas função de composição, sera direcionadas para o else, onde podemos fazer tratamento ou so retornar seu erro de forma genérica. Logo isso ficará mais claro.

Continuando. Precisamos agora salvar em nosso banco de dados falso e retornar o dado com a chave `is_saved: true`. As coisas se tornam mais simples daqui para frente. Precisamos criar uma função para salvar, chamarei de save/1 onde recebe o usuário que precisamos salvar e adicionaremos na composição de funções do `with`.

<pre class="language-elixir" data-title="lib/user.ex" data-line-numbers><code class="lang-elixir">defmodule Users do
  def create(params) do
    with {:ok, validated_user} &#x3C;- validate(params),
<strong>         {:ok, saved_user} &#x3C;- save(validated_user) do
</strong><strong>      {:ok, saved_user}
</strong>    else
      error ->
        error
    end
  end

  # ...

<strong>  defp save(user) do
</strong><strong>    data = %{
</strong><strong>      name: user.name,
</strong><strong>      is_saved: true
</strong><strong>    }
</strong><strong>
</strong><strong>    {:ok, data}
</strong><strong>  end
</strong>end
</code></pre>

Na função `save/1` retorno apenas como sucesso, mas se você realmente quiser por isso em um banco, e queira retornar um `{:error, reason}` também irá funcionar, o with cuidará do retorno do error.

Rodando isso, temos sucesso.

```shell
mix test test/users_test.exs
..
Finished in 0.02 seconds (0.00s async, 0.02s sync)
2 tests, 0 failures
```

Mais uma etapa concluída, vamos agora ativar o usuário:

* ~~Validar se os dados estão corretos;~~
* ~~Salvar no banco de dados~~
* Atualizar usuário para ativo
* Responder que tudo deu certo

Começamos pelo teste, adicionado a afirmação em nosso teste de sucesso que esperamos agora um campo `is_activated: true`.

<pre class="language-elixir" data-title="test/users_test.exs" data-line-numbers><code class="lang-elixir">defmodule WithTest do
  use ExUnit.Case

  describe "create/1" do
    test "create an user and active him when params are valid" do
       params = %{name: "iago"}

       {:ok, result} = Users.create(params)

       assert result.name == params.name
       assert result.is_saved == true
<strong>       assert result.is_activated == true
</strong>    end

    # ...
  end
end
</code></pre>

```shell
mix test test/users_test.exs


  1) test create/1 create an user and active him when params are valid (WithTest)
     test/users_test.exs:5
     ** (KeyError) key :is_activated not found in: %{is_saved: true, name: "iago"}. Did you mean:
     
           * :is_saved
     
     code: assert result.is_activated == true
     stacktrace:
       test/users_test.exs:12: (test)

.
Finished in 0.03 seconds (0.00s async, 0.03s sync)
2 tests, 1 failure
```

Vamos implementar esse comportamento. Precisamos de uma função semelhante ao save. Iremos criar a função `activate/1` passando o usuário que queremos ativar e então adicionaremos o campo e retornaremos o novo valor.

{% code title="lib/users.ex" lineNumbers="true" %}

```elixir
defmodule Users do
  def create(params) do
    with {:ok, validated_user} <- validate(params),
         {:ok, saved_user} <- save(validated_user),
         {:ok, activated_user} <- activate(saved_user) do
      {:ok, activated_user}
    else
      error ->
        error
    end
  end

  # ...

  defp activate(user) do
    data = %{
      name: user.name,
      is_saved: user.is_saved,
      is_activated: true
    }

    {:ok, data}
  end
end
```

{% endcode %}

```shell
mix test test/users_test.exs
Compiling 1 file (.ex)
..
Finished in 0.02 seconds (0.00s async, 0.02s sync)
2 tests, 0 failures
```

Perceba como ficou simples adicionar novas funções a funcionalidade. É fácil de ler, fácil dar manutenção e fácil remover. Era isso que estávamos procurando.

E por fim, a última etapa. Responder que tudo deu certo.

* ~~Validar se os dados estão corretos;~~
* ~~Salvar no banco de dados~~
* ~~Atualizar usuário para ativo~~
* Responder que tudo deu certo

Na verdade, já fazemos isso. Quando utilizamos with, precisamos já ter o que responder. Podemos transformar dados ou chamar outras funções, isso depende de cada cenário. Mas sabemos que, ao entrar no bloco de execução do, todas as etapas anteriores foram feitas com sucesso e podemos ir sem medo para a próxima.

O código final de nossa implementação ficou assim:

{% code title="lib/users\_test.exs" lineNumbers="true" %}

```elixir
defmodule Users do
  def create(params) do
    with {:ok, validated_user} <- validate(params),
         {:ok, saved_user} <- save(validated_user),
         {:ok, activated_user} <- activate(saved_user) do
      {:ok, activated_user}
    else
      error ->
        error
    end
  end

  defp validate(user_params) when not is_nil(user_params.name), do: {:ok, user_params}
  defp validate(_user_params), do: {:error, "The field name is required"}

  defp save(user) do
    data = %{
      name: user.name,
      is_saved: true
    }

    {:ok, data}
  end

  defp activate(user) do
    data = %{
      name: user.name,
      is_saved: user.is_saved,
      is_activated: true
    }

    {:ok, data}
  end
end
```

{% endcode %}

## Conclusão

A declaração `with` é poderosa, podemos usar para compor uma funcionalidade completa. Isso nos ajuda na legibilidade e manutenibilidade. Também nos força a pensar de forma funcional, uma vez que só podemos usar ela como função.

Existem mais sobre `with` que podemos aprender, mas acredito que esse capitulo ficou grande o suficiente.&#x20;


# Condicionais

Condicionais nos ajudam a controlar o fluxo da aplicação. Elas permitem execuções condicionais de blocos de código e elixir temos três formas básicas de fazer isso

* [If/2](/basico/controle-de-fluxo/condicionais/if)
* [cond/1](/basico/controle-de-fluxo/condicionais/cond)
* [case/2](/basico/controle-de-fluxo/condicionais/case)

Vamos dar uma olhada neles.

###


# if

O mais popular no mundo do desenvolvimento é o `if/else`. Definido com `if/2` ele espera uma expressão e um bloco de execução inicado com `do`.

```elixir
if some_expression do
  # se a expressão for verdadeira, rodar contexto de if
end
```

Só será executado o contexto de `if` caso a expressão seja verdadeira. Vamos a um exemplo

Precisamos de uma função que retorna se uma pessoa é maior de idade. Então expressão seria: `idade >= 18`. caso seja verdadeira, retorna `true`, case não, retorna `false`.

Para estruturar nossa solução, iremos utiliza maps (caso não saiba o que é, de uma olhada no [capitulo de maps](/basico/colecoes/mapas)). Teremos no map o atributo `name` e o atributo `age`.&#x20;

Vamos ao nosso teste:

{% code title="test/person\_test.exs" lineNumbers="true" %}

```elixir
defmodule PersonTest do
  use ExUnit.Case

  describe "is_adult/1" do
    test "Person is an adult" do
      person = %{name: "Iago", age: 30}
      result = Person.is_adult?(person)
  
      assert result == true
    end
  end
end
```

{% endcode %}

Rodando o teste, teremos o primeiro relatório de erro

```shell
mix test test/person_test.exs
warning: Person.is_adult?/1 is undefined or private
  test/person_test.exs:6: PersonTest."test Person is an adult"/1



  1) test Person is an adult (PersonTest)
     test/person_test.exs:4
     ** (UndefinedFunctionError) function Person.is_adult?/1 is undefined or private
     code: result = Person.is_adult?(person)
     stacktrace:
       (hello_world 0.1.0) Person.is_adult?(%{age: 30, name: "Iago"})
       test/person_test.exs:6: (test)


Finished in 0.02 seconds (0.00s async, 0.02s sync)
1 test, 1 failure
```

Ainda não possuimos o modulo nem a função criada, mas ja temos uma ideia do que precisamos. Vamos lá. Criaremos agora o arquivo `person.ex` e escreveremos a menor logica para o teste passar:

{% code title="lib/person.ex" lineNumbers="true" %}

```elixir
defmodule Person do
  def is_adult(_person) do
    true
  end
end
```

{% endcode %}

Se rodarmos o teste novamente, teremos sucesso.

```elixir
mix test test/person_test.exs
Compiling 1 file (.ex)
.
Finished in 0.01 seconds (0.00s async, 0.01s sync)
1 test, 0 failures
```

Caso de verdadeiro cobrido, agora precisamos do caso falso, quando não se é maior de idade. Vamos ao teste

{% code title="test/person\_test.exs" lineNumbers="true" %}

```elixir
defmodule PersonTest do
  use ExUnit.Case

  describe "is_adult/1" do
    # ...
    test "Person isn't an adult" do
      person = %{name: "Edgar", age: 2}
      result = Person.is_adult?(person)
  
      assert result == false
    end
  end
end
```

{% endcode %}

A utilização de interrogação no nome da função é uma convenção. Você pode entender melhor dela no capítulo de [conveções](/conceitos/convencoes#funcao-com-interrogacao).

```shell
mix test test/person_test.exs
.

  1) test is_adult/1 Person isn't an adult (PersonTest)
     test/person_test.exs:12
     Assertion with == failed
     code:  assert result == false
     left:  true
     right: false
     stacktrace:
       test/person_test.exs:16: (test)


Finished in 0.02 seconds (0.00s async, 0.02s sync)
2 tests, 1 failure
```

Obviamente, a resposta da função `is_adult?/1` sempre será true, já que fixamos um valor estatico para ela. Como podemos resoltar esse problema? Condicionais foram criados para esse tipo de tratamento.&#x20;

Todas as expressões `if` que não são verdadeiras, caem no contexto `else`, caso definido. Podemos escrever o códio if de duas formas, normal ou encurtada:

{% code lineNumbers="true" %}

```elixir
# Normal
if true do
  # contexto caso expressão do if for verdadeiro
else
  # contexto caso expressão do if nao for verdadeiro
end

# Encurtado
if(5 > 1, do: true, else: false)
```

{% endcode %}

As expressoes lidam com `operadores de comparação`, algum deles são:

* `==` igual
* `===` identico
* `!=` diferente
* `>` maior
* `<` menor
* `>=` maior igual
* `<=` menor igual

#### Exemplos simples

{% code lineNumbers="true" %}

```elixir
if(5 > 1, do: true, else: false) # true
if(5 < 1, do: true, else: false) # false
if(1 >= 1, do: true, else: false) # true
if(0 <= 1, do: true, else: false) # true

if(5 == 5, do: true, else: false) # true
if(2 === 5, do: true, else: false) # true
if(2.0 === 2.0, do: true, else: false) # false

if(5 != 5, do: true, else: false) # false
```

{% endcode %}

Vamos alterar nosso código e fazer o teste passar.

Precisamos de nossa regra que a idade seja `maior a 17 anos` ou `maior e igual a 18`.&#x20;

{% code title="lib/person.ex" lineNumbers="true" %}

```elixir
defmodule Person do
  def is_adult?(person) do
    if person.age >= 18 do
      true
    else
      false
    end
  end
end
```

{% endcode %}

```shell
mix test test/person_test.exs
Compiling 1 file (.ex)
..
Finished in 0.01 seconds (0.00s async, 0.01s sync)
2 tests, 0 failures
```

Podemos também alterar para inline.&#x20;

{% hint style="warning" %}
**Códigos inline**

São codigos que podem ser executado em uma linha só. Server para simplificar a escreita e se tornar mais fácil entendimento. Porém, deve ser tomado cuidado em não deixar as coisas mais complexas com isso, sempre pense nisso antes de seguir essa estrategia.
{% endhint %}

{% code title="lib/person.ex" lineNumbers="true" %}

```elixir
defmodule Person do
  def is_adult?(person) do
    if person.age >= 18, do: true, else: false
  end
end
```

{% endcode %}

```shell
mix test test/person_test.exs
Compiling 1 file (.ex)
..
Finished in 0.01 seconds (0.00s async, 0.01s sync)
2 tests, 0 failures
```

If é largamente utilizado em outras linguagens. Mesmo elixir possuindo `if`, não é tão utilizado devido ao [`pattern matching`](/basico/pattern-matching). Porém, existem diversos cenários que são importantes.


# cond

Diferente de `case/2` que verificamos o valor e escolhemos o caso especifico para ela, `cond/1`  **verificamos a condição**, como feito no `if/2` com o adicional de termos várias condições alinhadas onde retornamos a primeira que for verdadeira.

A definição dele segue a palavra chave `cond` seguido de `do`. Todo o controle de fluxo é tido dentro dele, exemplo:

{% code lineNumbers="true" %}

```elixir
x = 3 # declaração de váriavel que será usada no cond

cond do
  x == 5 -> 
   "Isso não é verdadeiro" # não entrará nesse escopo
   
  (x + 8) > 10 ->
    "Nem isso" # nem nesse
    
  x == 3 ->
    "Mas isso será" # Essa condição é verdadeira pois x é igual a 3 então esse bloco será executado.
    
  true ->
    "Nunca virá aqui, pois a clausura anterior é verdadeira"
end
```

{% endcode %}

Vamos a um exemplo mais útil. Você é um cientista em uma grande empresa farmacêutico. Temos vários níveis de acesso que vão de 1 a 3, sendo 1 o nível de visitantes e 3 o nível de acesso a armas biológicas.&#x20;

Precisamos então dar permissão a cada área de acordo com seu nível de acesso.&#x20;

{% hint style="danger" %}
**Lembrando que estamos falando de autorização e não autenticação.**&#x20;
{% endhint %}

Nossos critérios de aceite serão:

* Quando usuário tiver acesso 1, exibir mensagem "***Bem vindo {nome}, sinta-se*****&#x20;à vontade&#x20;*****em nossas estruturas!*****"**
* Quando usuário tiver acesso 2, mostrar ultima pendência no setor da saúde junto com o nome do usuário ***"Bem vindo João, o Ibuprofeno x42 esta nas fases finais"***
* Quando o usuário tiver acesso 3, mostrar ultimo status do nemesis. **"Sr. Iago, já mandamos nemesis para Raccoon city"**

Vamos começar criando nosso teste:

{% code title="tests/authorization\_test.exs" lineNumbers="true" %}

```elixir
defmodule AuthorizationTest do
  use ExUnit.Case
  
  describe "access/1" do
    test "User is a guest" do
      person = %{name: "Paulo", level: 1}
      result = Authorization.access(person)
  
      assert result == "Bem vindo #{person.name}, sinta-se à vontade em nossas estruturas!"
    end
  end
end
```

{% endcode %}

```shell
mix test test/authorization_test.exs
warning: Authorization.access/1 is undefined (module Authorization is not available or is yet to be defined)
  test/authorization_test.exs:7: AuthorizationTest."test access/1 User is a guest"/1



  1) test access/1 User is a guest (AuthorizationTest)
     test/authorization_test.exs:5
     ** (UndefinedFunctionError) function Authorization.access/1 is undefined (module Authorization is not available)
     code: result = Authorization.access(person)
     stacktrace:
       Authorization.access(%{level: 1, name: "Iago"})
       test/authorization_test.exs:7: (test)


Finished in 0.03 seconds (0.00s async, 0.03s sync)
1 test, 1 failure
```

Recebemos um relatório dizendo que Authorization.access não está disponível. Claramente, por que não possuímos esse modulo. Criaremos ele

{% code title="lib/authorization.ex" lineNumbers="true" %}

```elixir
defmodule Authorization do
  def access(_user) do

  end
end
```

{% endcode %}

Criamos o modulo de `Authorization` com uma função chamada `access/1` que contém um variável `_user`. Se rodarmos o teste conseguiremos outro erro.

```elixir
mix test test/authorization_test.exs
Compiling 1 file (.ex)
Generated hello_world app


  1) test access/1 User is a guest (AuthorizationTest)
     test/authorization_test.exs:5
     Assertion with == failed
     code:  assert result == "Bem vindo #{person.name}, sinta-se à vontade em nossas estruturas!"
     left:  nil
     right: "Bem vindo Paulo, sinta-se à vontade em nossas estruturas!"
     stacktrace:
       test/authorization_test.exs:9: (test)


Finished in 0.02 seconds (0.00s async, 0.02s sync)
1 test, 1 failure
```

Recebemos agora outro erro, dizendo que precisamos de um texto, mas o que recebemos foi um `nil`. Isso por que não estamos retornando nada da função chamada. Vamos fazer o mínimo para passar esse teste, retornaremos da função, o texto completo.

<pre class="language-elixir" data-title="lib/authorization.ex" data-line-numbers><code class="lang-elixir">defmodule Authorization do
  def access(_user) do
<strong>    "Bem vindo Paulo, sinta-se à vontade em nossas estruturas!"
</strong>  end
end
</code></pre>

Se rodarmos agora, os testes irão passar.

```shell
mix test test/authorization_test.exs
.
Finished in 0.02 seconds (0.00s async, 0.02s sync)
1 test, 0 failures
```

Uma vez os testes passando podemos refatorar. O primeiro passo, é deixa-lo dinamico. Vou adicionar uma nova validação junto no mesmo teste, apenas para comprovar que está correto. Vamos alterar nosso teste:

<pre class="language-elixir"><code class="lang-elixir">defmodule AuthorizationTest do
  use ExUnit.Case

  describe "access/1" do
    test "User is a guest" do
<strong>      person1 = %{name: "Paulo", level: 1}
</strong><strong>      person2 = %{name: "José", level: 1}
</strong>
<strong>      result1 = Authorization.access(person1)
</strong><strong>      result2 = Authorization.access(person2)
</strong>
<strong>      assert result1 == "Bem vindo #{person1.name}, sinta-se à vontade em nossas estruturas!"
</strong><strong>      assert result2 == "Bem vindo #{person2.name}, sinta-se à vontade em nossas estruturas!"
</strong>    end
  end
end
</code></pre>

Se rodarmos o teste assim ele acusará um erro

```shell
mix test test/authorization_test.exs


  1) test access/1 User is a guest (AuthorizationTest)
     test/authorization_test.exs:5
     Assertion with == failed
     code:  assert result2 == "Bem vindo #{person2.name}, sinta-se à vontade em nossas estruturas!"
     left:  "Bem vindo Paulo, sinta-se à vontade em nossas estruturas!"
     right: "Bem vindo José, sinta-se à vontade em nossas estruturas!"
     stacktrace:
       test/authorization_test.exs:13: (test)


Finished in 0.02 seconds (0.00s async, 0.02s sync)
1 test, 1 failureshe
```

Isso por que, em nossa implementação não utilizamos a variável que mandamos por parâmetro. Logo, ela está fixado como Paulo. Vamos arrumar isso.

<pre class="language-elixir" data-title="lib/authorization.ex" data-line-numbers><code class="lang-elixir">defmodule Authorization do
  def access(user) do
<strong>    "Bem vindo #{user.name}, sinta-se à vontade em nossas estruturas!"
</strong>  end
end
</code></pre>

Removemos o underline (\_) de user e utilizamos na interpolação da linha 3. Se rodarmos agora esse teste, teremos sucesso.

```shell
mix test test/authorization_test.exs
Compiling 1 file (.ex)
.
Finished in 0.01 seconds (0.00s async, 0.01s sync)
1 test, 0 failures
```

Agora possuímos apenas mais um ponto para ver. O que acontece caso mandamos um map incorreto para dentro da função `access`? Por exemplo `Authorization.access("lalala")`.

Vamos validar isso no terminal iterativo do elixir. Para isso queremos que esse projeto que estamos mexendo compile junto para que possamos usar o modulo `Authorization`. Para isso, basta executar na pasta raiz de seu projeto `iex -S mix` e o terminal iterativo será aberto:

```shell
iex -S mix
Erlang/OTP 25 [erts-13.1.4] [source] [64-bit] [smp:16:16] [ds:16:16:10] [async-threads:1] [jit:ns]

Interactive Elixir (1.14.3) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> 
```

Caso não saiba o que é isso, vá para a sessão [iEX](/primeiros-passos-em-elixir/iex) do livro.&#x20;

Vamos executar a função Authorization.access/1 utilizando como parâmetro algo incorreto, como "lalala"

```shell
iex(1)> Authorization.access("lalala")
** (KeyError) key :name not found in: "lalala". If you are using the dot syntax, such as map.field, make sure the left-hand side of the dot is a map
    (hello_world 0.1.0) lib/authorization.ex:3: Authorization.access/1
```

Isso acontece porque na função `access/1` tentamos acessar um elemento chamado `name` dentro do map `user`. Já que user agora é "lalala", uma string, ele não possui esse elemento. Ele nem é um map, logo, não temos como acessa-lo. Temos várias formas de resolver esse problema.&#x20;

Primeira coisa que iremos fazer é criar um teste para entender o que precisamos que seja retornado caso seja invalido. Criaremos um teste chamado `invalid_params` e adicionaremos o cenário de falha ali.

{% code title="test/authorization\_test.exs" lineNumbers="true" %}

```elixir
defmodule AuthorizationTest do
  use ExUnit.Case

  describe "access/1" do
    test "invalid params" do
      invalid_params = "lalala"
      {:error, reason} = Authorization.access(invalid_params)
      
      assert reason == "invalid_params"
    end
    
    # ...
  end
end
```

{% endcode %}

Criamos um teste simples para garantir o comportamento. Se você analisar o código, verá que agora adicionamos a convenção de [:ok/:error](/conceitos/convencoes#tupla-ok-result-e-error-reason) para conseguirmos facilmente identificar quando algo da certo e quando algo da errado.

Se rodarmos o teste, vamos ver que conseguimos reproduzir o erro no teste, o que é um ótimo sinal.

```shell
mix test test/authorization_test.exs


  1) test access/1 invalid params (AuthorizationTest)
     test/authorization_test.exs:5
     ** (KeyError) key :name not found in: "lalala". If you are using the dot syntax, such as map.field, make sure the left-hand side of the dot is a map
     code: {:error, reason} = Authorization.access(invalid_params)
     stacktrace:
       (hello_world 0.1.0) lib/authorization.ex:3: Authorization.access/1
       test/authorization_test.exs:7: (test)

.
Finished in 0.03 seconds (0.00s async, 0.03s sync)
2 tests, 1 failure
```

Agora precisamos lidar com ele. Para isso, utilizaremos a validação de tipo usando uma estrutura que ja possuímos no projeto. A estrutura `User`. Nela já possuímos o `name`.&#x20;

{% hint style="info" %}
Utilizo uma estrutura ja criada para mostrar a reutilização de módulos e também como seria um fluxo de atualização do mesmo, chegando mais perto do mundo real.
{% endhint %}

Caso você não a tenha por algum motivo, vou colocar aqui para facilitar

{% code title="lib/user.ex" lineNumbers="true" %}

```elixir
defmodule User do
  defstruct [:id, :name]
end
```

{% endcode %}

Tendo a estrutura, precisamos garantir que nossa função `access` aceite receber apenas ela. Vamos atualizar nosso código.

{% code title="lib/authorization.ex" lineNumbers="true" %}

```elixir
defmodule Authorization do
  def access(user = %User{}) do
    "Bem vindo #{user.name}, sinta-se à vontade em nossas estruturas!"
  end
end
```

{% endcode %}

Se rodar novamente o erro, teremos um relatório diferente

```shell
mix test test/authorization_test.exs
Compiling 1 file (.ex)


  1) test access/1 User is a guest (AuthorizationTest)
     test/authorization_test.exs:12
     ** (FunctionClauseError) no function clause matching in Authorization.access/1

     The following arguments were given to Authorization.access/1:
     
         # 1
         %{level: 1, name: "Paulo"}
     
     Attempted function clauses (showing 1 out of 1):
     
         def access(user = %User{})
     
     code: result1 = Authorization.access(person1)
     stacktrace:
       (hello_world 0.1.0) lib/authorization.ex:2: Authorization.access/1
       test/authorization_test.exs:16: (test)



  2) test access/1 invalid params (AuthorizationTest)
     test/authorization_test.exs:5
     ** (FunctionClauseError) no function clause matching in Authorization.access/1

     The following arguments were given to Authorization.access/1:
     
         # 1
         "lalala"
     
     Attempted function clauses (showing 1 out of 1):
     
         def access(user = %User{})
     
     code: {:error, reason} = Authorization.access(invalid_params)
     stacktrace:
       (hello_world 0.1.0) lib/authorization.ex:2: Authorization.access/1
       test/authorization_test.exs:7: (test)


Finished in 0.02 seconds (0.00s async, 0.02s sync)
2 tests, 2 failuresshel
```

Recebemos dois erros, vamos focar no primeiro agora. Já que nossa função access permite apenas receber a estrutura `User` agora, precisamos alterar nossos dados de testes para enviar o `User` para `access`.

<pre class="language-elixir" data-title="test/authorization_test.exs" data-line-numbers><code class="lang-elixir">defmodule AuthorizationTest do
  use ExUnit.Case

  describe "access/1" do
    test "User is a guest" do
<strong>      person1 = %User{name: "Paulo", level: 1}
</strong><strong>      person2 = %User{name: "José", level: 1}
</strong>
      result1 = Authorization.access(person1)
      result2 = Authorization.access(person2)

      assert result1 == "Bem vindo #{person1.name}, sinta-se à vontade em nossas estruturas!"
      assert result2 == "Bem vindo #{person2.name}, sinta-se à vontade em nossas estruturas!"
    end
  end
end
</code></pre>

```shell
mix test test/authorization_test.exs

== Compilation error in file test/authorization_test.exs ==
** (KeyError) key :level not found
    (hello_world 0.1.0) expanding struct: User.__struct__/1
    test/authorization_test.exs:13: AuthorizationTest."test access/1 User is a guest"/1
```

Recebemos um outro erro, dizendo que a `key :level not found`. Quando utilizamos structure, precisamos utilizar apenas a estrutura de dados criada nele. Em user não possuímos um campo :level e isso faz com que a compilação falhe.&#x20;

{% hint style="danger" %}
A utilização de estrutura engessa os dados nele, garantindo que a estrutura seja sempre a mesma. Isso é um bom ganho quando tratamos com dados.
{% endhint %}

Precisamos adicionar `:level` em `User`. É uma simples mudança

{% code title="lib/user.ex" lineNumbers="true" %}

```elixir
defmodule User do
  defstruct [:id, :name, level: 1]
end
```

{% endcode %}

Para garantir consistência e segurança em nosso projeto, podemos configurar que, caso não passado o `level`, ele será automaticamente 1, que significa que ele é visitante.

Podemos agora rodar os testes&#x20;

```shell
mix test test/authorization_test.exs


  1) test access/1 invalid params (AuthorizationTest)
     test/authorization_test.exs:5
     ** (FunctionClauseError) no function clause matching in Authorization.access/1

     The following arguments were given to Authorization.access/1:
     
         # 1
         "lalala"
     
     Attempted function clauses (showing 1 out of 1):
     
         def access(user = %User{})
     
     code: {:error, reason} = Authorization.access(invalid_params)
     stacktrace:
       (hello_world 0.1.0) lib/authorization.ex:2: Authorization.access/1
       test/authorization_test.exs:7: (test)

.
Finished in 0.02 seconds (0.00s async, 0.02s sync)
2 tests, 1 failure
```

Resolvemos o primeiro erro. Agora vamos para o proximo tratamento. Esse aqui esta falando que "lalala" não é uma estrutura User e ele esta certo. Agora precisamos fazer com que o erro seja retornado. Já possuímos o texto que precisamos no teste criado em `authorization_test.exs`.

Se você analisar, estamos usando pattern matching no parâmetro da função e devido não ter sido correspondido ele não entrou na primeira função access. Podemos então criar uma nova função de mesmo nome, fazer dar matching e então retornar a mensagem de erro. Vamos lá

{% code title="lib/authorization.ex" lineNumbers="true" %}

```elixir
defmodule Authorization do
  def access(user = %User{}) do
    "Bem vindo #{user.name}, sinta-se à vontade em nossas estruturas!"
  end

  def access(_user) do
    {:error, "invalid_params"}
  end
end
```

{% endcode %}

Se rodarmos o teste agora, teremos sucesso.

```shell
mix test test/authorization_test.exs
..
Finished in 0.03 seconds (0.00s async, 0.03s sync)
2 tests, 0 failures
```

Tudo finalizado no primeiro caso, porém, temos um inconsistência. Quando temos sucesso, recebemos a `message`, mas quando temos um erro temos uma estrutura diferente `{:error, reason}`. Devemos deixar elas similares e como estamos usando o padrão de [tuplas de ok/error](/conceitos/convencoes#tupla-ok-result-e-error-reason), devemos alterar a resposta de sucesso para recebermos `{:ok, result}`. Mudança simples, apenas alterar primeiro os testes e depois a implementação.

<pre class="language-elixir" data-title="test/authorization_test.exs" data-line-numbers><code class="lang-elixir">defmodule AuthorizationTest do
  use ExUnit.Case

  describe "access/1" do
    # ...
    test "User is a guest" do
      person1 = %User{name: "Paulo", level: 1}
      person2 = %User{name: "José", level: 1}

<strong>      {:ok, result1} = Authorization.access(person1)
</strong><strong>      {:ok, result2} = Authorization.access(person2)
</strong>
      assert result1 == "Bem vindo #{person1.name}, sinta-se à vontade em nossas estruturas!"
      assert result2 == "Bem vindo #{person2.name}, sinta-se à vontade em nossas estruturas!"
    end
  end
end
</code></pre>

<pre class="language-elixir" data-title="lib/authorization.ex" data-line-numbers><code class="lang-elixir">defmodule Authorization do
  def access(user = %User{}) do
<strong>    {:ok, "Bem vindo #{user.name}, sinta-se à vontade em nossas estruturas!"}
</strong>  end

  # ...
end
</code></pre>

Feito isso, so rodar os testes para garantir que esta tudo certo.

```shell
mix test test/authorization_test.exs
Compiling 1 file (.ex)
..
Finished in 0.02 seconds (0.00s async, 0.02s sync)
2 tests, 0 failures
```

{% hint style="danger" %}
**Uma pausa rápida**\
\
Sei que não vimos nada sobre `cond/0` até então, mas isso foi um bom exercício para pensar em como desenvolver em elixir. Espero que me perdoem por essa volta, mas as vezes o atalho tem mais perigos que a longa jornada.\
\
Seguimos
{% endhint %}

Conseguimos finalizar o primeiro ponto, vamos seguir para o ponto dois.

* ~~Quando usuário tiver acesso 1, exibir mensagem "***Bem vindo {nome}, sinta-se*****&#x20;****à vontade****&#x20;*****em nossas estruturas!*****"**~~
* Quando usuário tiver acesso 2, mostrar ultima pendência no setor da saúde junto com o nome do usuário ***"Bem vindo João, o Ibuprofeno x42 esta nas fases finais"***
* Quando o usuário tiver acesso 3, mostrar ultimo status do nemesis. **"Sr. Iago, já mandamos nemesis para Raccoon city"**

Vamos agora para o nível 2, a autorização de um funcionário. Vamos agora criar um teste para lidar com esse cenário.

{% code title="test/authorization\_teste.exs" lineNumbers="true" %}

```elixir
defmodule AuthorizationTest do
  use ExUnit.Case

  describe "access/1" do
    # ...
    test "User is an employee" do
      person = %User{name: "Carlos", level: 2}

      {:ok, result} = Authorization.access(person)


      assert result == "Bem vindo #{person.name}, o Ibuprofeno x42 esta nas fases finais"
    end
  end
end
```

{% endcode %}

O teste agora quer garantir que usuários com nível 2 de acesso, tenham informação sobre seu dia de trabalho, pois nível dois se da a funcionários. Se rodarmos esse teste, teremos um relatório de erro.

```shell
mix test test/authorization_test.exs


  1) test access/1 User is an employee (AuthorizationTest)
     test/authorization_test.exs:5
     Assertion with == failed
     code:  assert result == "Bem vindo #{person.name}, o Ibuprofeno x42 esta nas fases finais"
     left:  "Bem vindo Carlos, sinta-se à vontade em nossas estruturas!"
     right: "Bem vindo Carlos, o Ibuprofeno x42 esta nas fases finais"
     stacktrace:
       test/authorization_test.exs:11: (test)

..
Finished in 0.04 seconds (0.00s async, 0.04s sync)
3 tests, 1 failure
```

A mensagem que esperavamos não foi entregue. Isso devido a função access so esta implementado para devolver uma mensagem de primeiro nível. Vamos alterar utilizando cond/0 para tomar a decisão de fluxo que queremos.

{% hint style="info" %}
Relembrando que

\
\* nivel 1 -> mensagem para visitantes\
\* nivel 2 -> mensagem de funcionarios base\
\* nivel 3 -> mensagem de postos altos
{% endhint %}

Vamos alterar nosso código

{% code title="lib/authorization.ex" lineNumbers="true" %}

```elixir
defmodule Authorization do
  def access(user = %User{}) do
    cond do
      user.level == 1 ->
        {:ok, "Bem vindo #{user.name}, sinta-se à vontade em nossas estruturas!"}

      user.level == 2 ->
        {:ok, "Bem vindo #{user.name}, o Ibuprofeno x42 esta nas fases finais"}
    end
  end

  def access(_user) do
    {:error, "invalid_params"}
  end
end
```

{% endcode %}

Adicionamos a condicional `cond/0` onde ela lida com o `level` de acesso do usuário. Percebe como fica simples adicionar novos desvios de fluxo?&#x20;

```shell
mix test test/authorization_test.exs
Compiling 1 file (.ex)
...
Finished in 0.02 seconds (0.00s async, 0.02s sync)
3 tests, 0 failures
```

Simples assim, fechamos mais um critério de aceite.<br>

* ~~Quando usuário tiver acesso 1, exibir mensagem "***Bem vindo {nome}, sinta-se*****&#x20;****à vontade****&#x20;*****em nossas estruturas!*****"**~~
* ~~Quando usuário tiver acesso 2, mostrar ultima pendência no setor da saúde junto com o nome do usuário ***"Bem vindo João, o Ibuprofeno x42 esta nas fases finais"***~~
* Quando o usuário tiver acesso 3, mostrar ultimo status do nemesis. **"Sr. Iago, já mandamos nemesis para Raccoon city"**

{% hint style="info" %}
**Desafio**\
\
Tente adicionar o level 3 para dar matching na frase: **Sr. {nome}, já mandamos Nemesis para Raccoon city.**\
\
Você deve:\
\
1\. Escrever o teste em authorizatin\_test.exs\
2\. Implementar a solução em authorization.ex
{% endhint %}

Espero que tenha feito o desafio, essas ações que fazem internalizarmos o conteúdo. Não irei implementar ele. Esse é o desafio.&#x20;

Existe apenas mais uma coisa a se fazer. Vamos dizer que eu coloque o nível de acesso 10. O que aconteceria? Vamos abrir novamente nosso terminal iterativo `iex -S mix` e executaremos a chamada da função usando o level 10.

```shell
iex(1)> Authorization.access(%User{name: "iago", level: 10})
** (CondClauseError) no cond clause evaluated to a truthy value
    (hello_world 0.1.0) lib/authorization.ex:7: Authorization.access/1
```

Recebemos um relatório de erro. A parte importante é `no cond clause evaluated to a truthy value`. Nenhuma condição foi saciada no cond, sem opção do que fazer, ele quebra. Temos que ter pelo menos uma condição que verdadeira para não causar problemas a nos. Fora que precisamos avisar ao usuário que é melhor ele se retirar antes que chame a segurança. Vamos primeiro criar nosso teste.

```elixir
defmodule AuthorizationTest do
  use ExUnit.Case

  describe "access/1" do
    test "You are supposed to not be here" do
      person = %User{name: "Eduardo", level: 10}

      {:error, reason} = Authorization.access(person)

      assert reason == "#{person.name}, você não deveria estar aqui. Peço que se retire"
    end

    # ...
  end
end
```

Execute esse código e verá que conseguimos reproduzir o problema que enfrentamos no terminal iterativo.&#x20;

```shell
mix test test/authorization_test.exs
Compiling 1 file (.ex)
...

  1) test access/1 You are supposed to not be here (AuthorizationTest)
     test/authorization_test.exs:5
     ** (CondClauseError) no cond clause evaluated to a truthy value
     code: {:error, reason} = Authorization.access(person)
     stacktrace:
       (hello_world 0.1.0) lib/authorization.ex:7: Authorization.access/1
       test/authorization_test.exs:8: (test)
```

Precisamos cuidar disso agora, mas seremos defensivos. Ao invez de fazer alguma regra, deixaremos uma clausura true no final de cond, onde, se nenhuma clausura for saciada, a ultima sera e uma mensagem de erro aparecerá.

<pre class="language-elixir" data-title="lib/authorization.ex" data-line-numbers><code class="lang-elixir">defmodule Authorization do
  def access(user = %User{}) do
    cond do
      user.level == 1 ->
        {:ok, "Bem vindo #{user.name}, sinta-se à vontade em nossas estruturas!"}

      user.level == 2 ->
        {:ok, "Bem vindo #{user.name}, o Ibuprofeno x42 esta nas fases finais"}

<strong>      true ->
</strong><strong>        {:error, "#{user.name}, você não deveria estar aqui. Peço que se retire"}
</strong>    end
  end

  def access(_user) do
    {:error, "invalid_params"}
  end
end
</code></pre>

Adiconamos uma condição que será sempre `true`, caso nenhuma condição acima seja `true`, ele caira nessa última e a mensagem de erro vai ser gerada. Uma solução simples, que funciona bem para nós aqui.&#x20;

### Conclusão

Nesse capítulo, seguimos um fluxo de desenvolvimento comum em elixir, onde criar e refatoramos uma implementação. Também entendemos a utilidade da condicional `cond/0` e fizemos um desafio. Lembrem-se, sempre existe outras formas de atender a uma expectativa, podendo muitas vezes, utilizar os mesmos recursos. Tente e re-tente criar de formas diferentes para conseguir extrair os melhores resultados.&#x20;


# case

O `case/2` nos ajuda a **condicionar um valor de acordo com diferentes valores de entrada**. Ele cairá no caso especificado pelo valor esperado. Normalmente utilizando [pattern matching](/basico/pattern-matching). \
\
Um exemplo real:

<pre class="language-elixir" data-line-numbers><code class="lang-elixir"><strong>case HTTPoison.get("http://.../user/1") do
</strong>  {:ok, %HTTPoison.Response{body: body, status: 200}} -> Jason.decode(body)
  {:ok, %HTTPoison.Response{body: body, status: 404}} -> {:error, :not_found}
  {:ok, %HTTPoison.Response{body: body, status: 401}} -> {:error, :unauthorized}
  {:error, reason} -> {:error, reason}
end
</code></pre>

{% hint style="warning" %}

```
HTTPoison.get/1

HTTPoison é um biblioteca escrita em elixir para realizar requisições HTTP externas.
Caso queira, você pode ver mais sobre ela na página de biblioteca

https://github.com/edgurgel/httpoison
```

{% endhint %}

Temos no exemplo uma chamada a um endpoint para resgatar um usuário com o id 1. No mundo real temos vários casos de resposta utilizando [pattern matching](/basico/pattern-matching) para cada caso.

* **status: 200** -> Deu tudo certo e o usuário foi retornado no boddy
* **status: 404** -> O usuário com id 1 não foi encontrado
* **status: 401** -> Você não possui autorização para acessar esse endpoint
* **:error** -> Algo deu errado na chamada do endpoint mas não possuimos tratamento para isso, logo, vou apenas retornar a razão do erro junto com a [tupla de error](/conceitos/convencoes#tupla-ok-result-e-error-reason).<br>

Case se torna um bom recurso para conseguirmos lidar com todos os casos dessa requisição e facilmente trata-las a fim de avisar o usuário ou tentar uma ação corretiva. No nosso caso, apenas alertamos que algo não saiu como o esperado.

### Criando nosso código

Vamos a um código mais simples para aplicarmos o conceito.

Utilizaremos o código de autorização feita no estudo de [cond/1](/basico/controle-de-fluxo/condicionais/cond) . Precisamos obter os dados de um recurso, que vamos chamar aqui de `articles.` Pra isso o usuário deve estar autorizado a receber a informação. Qualquer nível de funcionário conseguirá realizar essa operação.

{% code title="test/article\_test.exs" lineNumbers="true" %}

```elixir
defmodule ArticlesTest do
  use ExUnit

  test "success: user has the authorization to get articles" do
    user = %User{id: 156, name: "Iago", level: 1}

    assert {:ok, _articles} = Articles.all()
  end
end
```

{% endcode %}

```
mix test test/articles_test.exs
warning: Articles.all/1 is undefined (module Articles is not available or is yet to be defined)
  test/articles_test.exs:7: ArticlesTest."test success: user has authorization to get articles"/1



  1) test success: user has the authorization to get articles (ArticlesTest)
     test/articles_test.exs:4
     ** (UndefinedFunctionError) function Articles.all/1 is undefined (module Articles is not available)
     code: assert {:ok, _articles} = Articles.all(user)
     stacktrace:
       Articles.all(%User{id: 156, name: "Iago", level: 2})
       test/articles_test.exs:7: (test)


Finished in 0.03 seconds (0.00s async, 0.03s sync)
1 test, 1 failure
```

Teste falhou por que não temos ainda o módulo `Articles.` Vamos cria-lo e já adicionar a logica utilizando o `Authorizatin.access/1`. Vamos fazer esse teste passar o mais simples possível.

<pre class="language-elixir" data-title="lib/articles.ex" data-line-numbers><code class="lang-elixir">defmodule Articles do
  def all(_user) do
    articles = [%{title: "This is an example"}]

<strong>    {:ok, articles}
</strong>  end
end
</code></pre>

```sh
mix test test/articles_test.exs
Compiling 1 file (.ex)

.
Finished in 0.01 seconds (0.00s async, 0.01s sync)
1 test, 0 failures
```

Primeira etapa finalizada. Vamos para o segundo problema. Caso você não tenha um nível de acesso acima de 1, você não pode acessar os dados.

{% code title="test/articles\_test.exs" lineNumbers="true" %}

```elixir
defmodule ArticlesTest do
  use ExUnit.Case

  # ...

  test "fail: user has not authorization to get articles" do
    user = %User{id: 156, name: "Iago", level: 1}

    assert {:error, _reason} = Articles.all(user)
  end
end
```

{% endcode %}

Rodando o teste, teremos um relatório de erro.

```elixir
mix test test/articles_test.exs
Compiling 1 file (.ex)


  1) test fail: user has not authorization to get articles (ArticlesTest)
     test/articles_test.exs:10
     match (=) failed
     code:  assert {:error, _reason} = Articles.all(user)
     left:  {:error, _reason}
     right: {:ok, [%{title: "This is an example"}]}
     stacktrace:
       test/articles_test.exs:13: (test)

.
Finished in 0.02 seconds (0.00s async, 0.02s sync)
2 tests, 1 failure
```

Temos agora um cenário novo. Quando o seu nível de acesso é baixo, ele não deveria deixar passar. Mas como esta agora voce consegue acessar os artigos normalmente.&#x20;

Vamos adicionar a checagem de autorização. A autorização responde de duas formas:

* {:ok, data} => quando algo tem sucesso
* {:error, reason}  => quando algo está errado.

Já que possuimos esses dois cenários e ambos podem ser pegos por pattern matching podemos utilizar case/2 para resolver o problema.

1. Utilizaremos case/2 com o primeiro argumento a chamada a função Authorization.access/1
2. Utilizaremos o bloco do para realizar os matchs dos cenários
3. Retornaremos o valor dependendo do caso.

{% code title="lib/articles.ex" lineNumbers="true" %}

```elixir
defmodule Articles do
  def all(user) do
    articles = [%{title: "This is an example"}]

    case Authorization.access(user)
      {:ok, articles} -> {:ok, articles}
      {:error, reason} -> {:error, reason}
    end
  end
end
```

{% endcode %}

Dentro do segundo argumento do `case/2` temos a chamada do escopo  `do` onde isola o contexto de `case`. Cada linha dentro do escopo `do` é um possível cenário a ser coberto. Sendo o lado esquerdo a resposta de `Authorization.access` (o que foi chamado no primeiro argumento do `case/2`). Para acessar um caso especifico o pattern matching deve ser válido. Caso não seja ele passa para o proximo match. Caso não encontra nenhum que seja valido ele dispara uma exceção.

Vamos rodar o teste novamente

```sh
mix test test/articles_test.exs
..
Finished in 0.02 seconds (0.00s async, 0.02s sync)
2 tests, 0 failures
```

Tudo funcionando novamente. Com isso você pode criar diversos casos dentro desse case em articles. Como por exemplo:

* Somente usuários com permissões de level 2 conseguem pegar determinados artigos
* Quando tivermos level 0 pode ser apenas dito que nada foi encontrado.

Assim você consegue expandir os casos de uma funcionalidade.

### Conclusão

Case é uma poderosa ferramenta para ter em sua caixa de ferramentas. Várias bibliotecas a utilizam. Também conseguimos tirar maior proveitos da [conveção de tuplas](/conceitos/convencoes#tupla-ok-result-e-error-reason), sendo assim, mais fácil a sua utilização.


# Guards

Os guards ajudam a aumentar a força na utilização de pattern matching em funções. Eles podem servir de controle de fluxo para uma determinada função ou até garantir que um tipo especifico esta passando.

Vamos supor que precisamos imprimir o dado que é passado como argumento da função, mas temos uma peculiaridade. Podemos passar tanto número inteiro, string e até map. A forma como esses três devem ser imprimidos é diferente. Vamos a um teste simples:

{% code title="test/printer\_test.exs" lineNumbers="true" %}

```elixir
defmodule PrinterTest do
  use ExUnit.Case

  test "print/1" do
    assert Printer.print(1) == "Number: 1"
    assert Printer.print("Hello") == "Text: Hello"
    assert Printer.print(%{name: "iago"}) == "Map with name: iago"
  end
end

```

{% endcode %}

Vamos rodar-lo:

```sh
mix test test/printer_test.exs
Compiling 1 file (.ex)
Generated hello_world app
warning: Printer.print/1 is undefined (module Printer is not available or is yet to be defined)
Invalid call found at 3 locations:
  test/printer_test.exs:5: PrinterTest."test print/1"/1
  test/printer_test.exs:6: PrinterTest."test print/1"/1
  test/printer_test.exs:7: PrinterTest."test print/1"/1



  1) test print/1 (PrinterTest)
     test/printer_test.exs:4
     ** (UndefinedFunctionError) function Printer.print/1 is undefined (module Printer is not available)
     code: assert Printer.print(1) == "Number: 1"
     stacktrace:
       Printer.print(1)
       test/printer_test.exs:5: (test)


Finished in 0.02 seconds (0.00s async, 0.02s sync)
1 test, 1 failure
```

Recebemos relatório de erro por não possuir o módulo e função utilizados. Vamos cria-los. Para reoslver esse problema, poderiamos usar cond facilmente:

{% code title="lib/printer.ex" lineNumbers="true" %}

```elixir
defmodule Printer do
  def print(arg) do
    cond do
      is_integer(arg) -> "Number: #{arg}"
      is_bitstring(arg) -> "Text: #{arg}"
      is_map(arg) -> "Map with name: #{arg.name}"
      true -> "Noops"
    end
  end
end

```

{% endcode %}

```sh
mix test test/printer_test.exs
Compiling 1 file (.ex)
Generated hello_world app
.
Finished in 0.01 seconds (0.00s async, 0.01s sync)
1 test, 0 failures
```

Isso parece bom. Resolve nosso problema de forma elegante, acredito. Mas estamos lidando com um problema que resolvemos basicamente uma linha por tipo. Mas e se tivermos que fazer uma operação maior. Começa a se formar uma bagunça. Vamos adicionar uma operação superficial para simular isso. Vamos alterar o primeiro teste para saber se um número é par ou impar.

<pre class="language-elixir" data-title="test/printer_test.exs" data-line-numbers><code class="lang-elixir">defmodule PrinterTest do
  use ExUnit.Case

  test "print/1" do
<strong>    assert Printer.print(2) == "Number 2 is even"
</strong><strong>    assert Printer.print(1) == "Number 1 is odd"
</strong>    assert Printer.print("Hello") == "Text: Hello"
    assert Printer.print(%{name: "iago"}) == "Map with name: iago"
  end
end

</code></pre>

Vamos alterar nossa implementação, utilizando ainda o `cond/2`.

<pre class="language-elixir" data-title="lib/printer.ex" data-line-numbers><code class="lang-elixir">defmodule Printer do
  require Integer

  def print(arg) do
    cond do
<strong>      is_integer(arg) ->
</strong><strong>        if (Integer.is_even(arg) == true) do
</strong><strong>          "Number #{arg} is even"
</strong><strong>        else
</strong><strong>          "Number #{arg} is odd"
</strong><strong>        end
</strong>
      is_bitstring(arg)
        -> "Text: #{arg}"

      is_map(arg)
        -> "Map with name: #{arg.name}"
      true -> "Noops"
    end
  end
end

</code></pre>

A leitura começou a ficar um pouco bagunçada, nao? Isso foi uma mudança pequena. Você pode me dizer que poderiamos usar uma função ali. E você está certo em relação a isso. Mas ao invez disso, porque não isolamos a função `print/1` para cada tipo de dado de entrar? Podemos fazer isso utilizando clauses. Elas são definidas ao lado da definição da função iniciando com a palavra chave `when` e uma operação a seguir. Vamos la:

<pre class="language-elixir" data-title="lib/printer.ex" data-line-numbers><code class="lang-elixir">defmodule Printer do
  require Integer

<strong>  def print(arg) when is_integer(arg) do
</strong>    if (Integer.is_even(arg) == true) do
      "Number #{arg} is even"
    else
      "Number #{arg} is odd"
    end
  end

<strong>  def print(arg) when is_bitstring(arg), do: "Text: #{arg}"
</strong><strong>  def print(arg) when is_map(arg), do: "Map with name: #{arg.name}"
</strong>end

</code></pre>

Não preciso falar o quanto a leitura melhorou nesse exemplo certo? Temos diversas outras vantagens como, facilidade de extração e adição de novos tipos. Você pode perceber que as funções são controladas pelas funções seguidas do `when`. É ali que os guards moram.

Rodamos os teste e pronto:

```sh
mix test test/printer_test.exs
Compiling 1 file (.ex)
.
Finished in 0.02 seconds (0.00s async, 0.02s sync)
1 test, 0 failures
```

### Limitações

Podemos pensar que guards podem ser usados até em operações complexas. Mas existe uma regras de utilização dos guards. Não podemos adicionar módulos nosso em nossas condicionais. Precisamos utilizar somente o básico da linguage. Foi uma decisão deliberada pela linguagem para evitar certos problemas e complexidades em cima dos `guards`.

[Aqui uma lista do que é permitido.](https://hexdocs.pm/elixir/guards.html#list-of-allowed-expressions)


# Manipulação de dados

Os dados em Elixir são representados por diferentes tipos de valores, como `números`, `strings`, `booleanos`, [`listas`](/basico/colecoes/listas), [`mapas`](/basico/colecoes/mapas), [`tuplas`](/basico/colecoes/tuplas), conjuntos, e outros. Cada tipo de dado tem suas próprias características e propriedades que podem ser utilizadas para resolver problemas específicos.

Para trabalhar com dados, existem diversas funções e módulos disponíveis, como o módulo `Enum`, o módulo `Stream`, e outros. Esses recursos fornecem ferramentas para manipular e transformar dados de maneira eficiente e concisa. Eles estão associados ao protocolo Enumerable dando a eles super poder de lidar com certos tipos de coleções. Veja mais sobre o conceito de coleções [enumeráveis](/conceitos/enumeraveis).

Em resumo, a manipulação de dados é uma parte essencial do desenvolvimento de software em Elixir. Com uma ampla gama de recursos e ferramentas disponíveis, você pode trabalhar com dados de várias formas e resolver problemas específicos de maneira eficiente e concisa.

Olharemos agora duas formas de manipular dados:

* [Enum](/conceitos/enumeraveis)
* [Stream](/basico/manipulacao-de-dados/stream)

Vamos nessa!


# Enum

Algumas funções nativas no Elixir utilizam recursão estão disponíveis para utilizarmos com uma API  limpa. O módulo [`Enum`](https://hexdocs.pm/elixir/1.12/Enum.html) é um deles. Para entender melhor o que é um Enum, leia o [conceito de Enumeráveis](broken://pages/2ZadBlkYxEfwNtpTzAXt).

Vamos a um exemplo real com base em algumas funções que Enum tem.

### Enum.each/2

Supomos que precisamos percorrer todos os itens de uma lista mandando um email para cada email da lista.&#x20;

Utilizaremos para esse looping onde só precisamos percorrer a lista a função `Enum.each/2` (caso não esteja familiado com o conceito de aridade, recomendo o capítulo sobre [Aridade](/conceitos/aridade))

Para rodar o `Enum.each/2` precisamos um primeiro argumento onde será nossa lista e o segundo argumento uma função anonima com apenas um argumento (que será cada item da nossa lista, passada no primeiro argumento).

Vamos criar um teste para isso

{% code title="test/send\_email\_test.exs" lineNumbers="true" %}

```elixir
defmodule EnumTest do
  use ExUnit.Case

  describe "Enum.each/2" do
    test "simple tests about Enum.each" do
      my_list = ["test@example.com", "another_test@example.com"]

      Enum.each(my_list, fn email ->
        assert "Email sent to #{email}" == Email.send(email)
      end)
    end
  end
end

```

{% endcode %}

```sh
mix test test/enum_test.exs    
warning: Sender.email/1 is undefined (module Sender is not available or is yet to be defined)
  test/sender_test.exs:8: EnumTest."test simple tests about Enum.each"/1



  1) test simple tests about Enum.each (SenderTest)
     test/enum_test.exs:4
     ** (UndefinedFunctionError) function Sender.email/1 is undefined (module Sender is not available)
     code: Enum.each(my_list, fn email ->
     stacktrace:
       Sender.email("test@example.com")
       test/enum_test.exs:8: anonymous fn/1 in SenderTest."test simple tests about Enum.each"/1
       (elixir 1.14.3) lib/enum.ex:975: Enum."-each/2-lists^foreach/1-0-"/2
       test/enum_test.exs:7: (test)


Finished in 0.08 seconds (0.00s async, 0.08s sync)
1 test, 1 failure
```

Não possuímos o módulo Email nem a função send. Vamos cria-los.

```elixir
defmodule Sender do
  def email(email), do: "Email sent to #{email}"
end

```

Fizemos uma função inline, somente para exemplificar o looping. Basta rodar os testes e tudo estará bem.

```sh
mix test test/enum_test.exs
Compiling 1 file (.ex)
Generated hello_world app
.
Finished in 0.04 seconds (0.00s async, 0.04s sync)
1 test, 0 failures
```

### Enum.map/2

Agora supomos que precisamos alterar a lista para, ao invez de enviar o email, gere links para clicarmos e sermos redirecionados a um cliente de email. Uma vez que precisamos alterar os dados, utilizaremos Enum.map/2 que tem como ideia mapear novamente os dados dentro dele.

Vamos ao teste

{% code title="" lineNumbers="true" %}

```elixir
defmodule EnumTest do
  use ExUnit.Case

  describe "Enum.map/2" do
    test "simple tests about Enum.each" do
      my_list = ["test@example.com", "another_test@example.com"]
      expected_list = ["mailto:test@example.com", "mailto:another_test@example.com"]

      new_list = Enum.map(my_list, fn email ->
        "mailto:#{email}"
      end)

      assert new_list == expected_list
    end
  end
end

```

{% endcode %}

Perceba que criamos uma nova variável e assinamos o retorno da função map/2 lá. Como Elixir é uma linguagem funcional, nada se muta, precisamos sempre re-assinar um valor para que a variável tenha um outro valor. (Veja mais sobre imutabilidade no capítulo de [Imutabilidade](/conceitos/imutabilidade))

A função map serve para alterar o valor que vem de uma lista, sem precisarmos abrir um por um, ja possuindo uma estrutura de repetição onde você passa a lista e o que quer que faça com cada elemento da lista, retornando para seu próprio valor.

Depois disso, apenas comparamos a um valor experado que definimos. Basta rodar o testes e verá a mágica acontecer.

```sh
mix test test/enum_test.exs
..
Finished in 0.04 seconds (0.00s async, 0.04s sync)
2 tests, 0 failures
```


# Stream

Falamos sobre enumeráveis (ou enumerables), onde é uma característica do que é enumerável ou qualidade daquilo que se consegue enumerar. Em nosso contexto, algo que podemos iterar, passando um por um. Fizemos exemplos de iteração no capítulo sobre [Enum](/basico/manipulacao-de-dados/enum).&#x20;

Stream está nessa mesma categoria, com uma diferença importante. Streams são composições de enumeração preguiçosa.&#x20;

Isso quer dizer, diferente de listas que ao criamos são executadas, `Streams` não são. Eles contém tudo que precisamos para executar, mas só irão ser executados quando for necessário. Logo, preguiçoso.&#x20;

Vamos a um exemplo simples:

Precisamos agendar 5 eventos, porém, não queremos ter o resultado agora, porque só será processado semana que vem.&#x20;

Vamos ao teste:

<pre class="language-elixir" data-title="test/schedule_test.exs" data-line-numbers><code class="lang-elixir">defmodule EventTest do
  use ExUnit.Case

  describe "schedule/1" do
    test "Create a lazy list and execute later" do
      range = 1..5

<strong>      stream = Stream.map(range, &#x26;Event.schedule/1)
</strong><strong>      assert %Stream{enum: 1..5, funs: [_function_1]} = stream
</strong>    end
  end
end

</code></pre>

O teste parece complexo por nao ser tão comum utilizarmos Stream desa forma, mas, vamos tentar entende-lo.&#x20;

Na linha 8 utilizamos o `Stream.map/2` passando no primeiro argumento um enumerable (no nosso caso foi um range, mas poderia ser uma lista também). No segundo paramentro, passamos a função que queremos que execute para cada elemento de nosso enumerable. Isso quer dizer que esse função será executada para cada item dentro do campo enum.&#x20;

Na linha 9 garantimos que criamos nosso `enum` com o valor de range (1 até 5) e em `funs`, que temos uma função para ser executada para cada interação. No teste de mesa seria:

```elixir
Event.schedule(1)
Event.schedule(2)
Event.schedule(3)
Event.schedule(4)
Event.schedule(5)
```

Porém, estamos usando `Stream` e esse código ainda não foi executado. Vamos rodar o teste para ver o que temos:

```sh
mix test test/event_test.exs
warning: Event.schedule/1 is undefined (module Event is not available or is yet to be defined)
  test/event_test.exs:8: EventTest."test schedule/1Create a lazy list and execute later"/1

.
Finished in 0.03 seconds (0.00s async, 0.03s sync)
1 test, 0 failures
```

Estranho não? O teste passou, mesmo acusando em um `warning` que não possuimos `Event.schedule/1`. Isso quer dizer que a função não foi executada, como já esperavamos. Lembrando que `Stream` é um carregamento preguiçoso, ele só será executado quando realmente precisar. Vamos seguir até falhar. Precisamos agora fazer ele executar. Vamos atualizar nosso teste.

<pre class="language-elixir" data-title="test/event_test.exs" data-line-numbers><code class="lang-elixir">defmodule EventTest do
  use ExUnit.Case

  describe "schedule/1" do
    test "Create a lazy list and execute later" do
      range = 1..5

      stream = Stream.map(range, &#x26;Event.schedule/1)
      assert %Stream{enum: 1..5, funs: [_function_1]} = stream

<strong>      Stream.run(stream)
</strong>    end
  end
end

</code></pre>

A linha 12 roda o streaming para mim e nessa hora ele tenta executar a função passada. Vamos rodar o teste:

```sh
mix test test/event_test.exs
warning: variable "response" is unused (if the variable is not meant to be used, prefix it with an underscore)
  test/event_test.exs:11: EventTest."test schedule/1 Create a lazy list and execute later"/1

warning: Event.schedule/1 is undefined (module Event is not available or is yet to be defined)
  test/event_test.exs:8: EventTest."test schedule/1 Create a lazy list and execute later"/1



  1) test schedule/1 Create a lazy list and execute later (EventTest)
     test/event_test.exs:5
     ** (UndefinedFunctionError) function Event.schedule/1 is undefined (module Event is not available)
     code: response = Stream.run(stream)
     stacktrace:
       Event.schedule(1)
       (elixir 1.14.3) lib/stream.ex:612: anonymous fn/4 in Stream.map/2
       (elixir 1.14.3) lib/range.ex:392: Enumerable.Range.reduce/5
       (elixir 1.14.3) lib/stream.ex:1811: Enumerable.Stream.do_each/4
       (elixir 1.14.3) lib/stream.ex:689: Stream.run/1
       test/event_test.exs:11: (test)


Finished in 0.04 seconds (0.00s async, 0.04s sync)
1 test, 1 failure
```

Agora temos nosso primeiro erro. Ele esta avisando que não possuímos a função `Event.schedule/1`. O mais interessante é que agora ele falou que na linha 8 também não foi encontrado a função. Esse é um dos diferenciais de utilizar `Stream`. Ele deixa tudo pronto para ser executado e quando realmente precisar, ele vai realizar a computação e dar o resultado.

Imagina um cenário onde temos milhoes de dados. Esses dados precisam ser computados na hora, podemos fazer isso aos poucos e com `Stream` podemos criar uma lógica onde isso seja possível. Deixando o processamento mais rápido e não gastando recursos de máquina a toa.

Vamos resolver o problema do teste e criar nossa implementação. Você vai perceber que agora se tornou uma função comum, como fizemos no [capítulo sobre Enum](/basico/manipulacao-de-dados/enum). Vamos criar a função apenas para passar os testes até então:

{% code title="lib/event.ex" lineNumbers="true" %}

```elixir
defmodule Event do
  def schedule(_x), do: nil
end

```

{% endcode %}

```sh
mix test test/event_test.exs
.
Finished in 0.02 seconds (0.00s async, 0.02s sync)
1 test, 0 failures
```

Perfeito, estamos conseguindo executar `Event.schedule/1`, porém, ele não faz nada. Vamos alterar nosso teste para que ele diga que o evento x foi agendado.&#x20;

{% code title="test/event\_test.exs" lineNumbers="true" %}

```elixir
defmodule EventTest do
  use ExUnit.Case

  describe "schedule/1" do
    test "Create a lazy list and execute later" do
      range = 1..5

      stream = Stream.map(range, &Event.schedule/1)
      assert %Stream{enum: 1..5, funs: [_function_1]} = stream

      response = Stream.run(stream)
      
      assert response == [
        "event 1 was scheduled",
        "event 2 was scheduled",
        "event 3 was scheduled",
        "event 4 was scheduled",
        "event 5 was scheduled"
      ]
    end
  end
end

```

{% endcode %}

Vamos rodar esse teste:

```sh
mix test test/event_test.exs


  1) test schedule/1 Create a lazy list and execute later (EventTest)
     test/event_test.exs:5
     Assertion with == failed
     code:  assert response == [
              "event 1 was scheduled",
              "event 2 was scheduled",
              "event 3 was scheduled",
              "event 4 was scheduled",
              "event 5 was scheduled"
            ]
     left:  :ok
     right: ["event 1 was scheduled", "event 2 was scheduled", "event 3 was scheduled", "event 4 was scheduled", "event 5 was scheduled"]
     stacktrace:
       test/event_test.exs:13: (test)


Finished in 0.03 seconds (0.00s async, 0.03s sync)
1 test, 1 failure
```

Algo estranho aconteceu. A resposta para [`Stream.run/1`](https://hexdocs.pm/elixir/1.12/Stream.html#run/1) foi `:ok`. Isso causou o problema que não estavamos esperando. Queriamos a lista de eventos agendados. Vamos entender isso.

A função [`Stream.run/1`](https://hexdocs.pm/elixir/1.12/Stream.html#run/1) mesmo executando nosso `Stream` não retorna o valor processado. Ele é normalmente utilizado para iniciar um processo que não precisamos de uma resposta. Logo, essa função não serve para nós obtermos uma resposta do processamento. Para isso precisamos usar uma outra. &#x20;

Para resolver isso, utilizaremos uma função simples do módulo `Enum` chamada `to_list`. Quando utilizamos ela, a própria função entende quando estamos utilizando `Stream` e faz a conversão, executando o `Stream` e pegando a resposta, convertendo para uma lista e devolvendo para nos como uma lista simples. Vamos a implementação:

<pre class="language-elixir" data-title="lib/event.ex" data-line-numbers><code class="lang-elixir">defmodule EventTest do
  use ExUnit.Case

  describe "schedule/1" do
    test "Create a lazy list and execute later" do
      range = 1..5

      stream = Stream.map(range, &#x26;Event.schedule/1)
      assert %Stream{enum: 1..5, funs: [_function_1]} = stream

<strong>      response = Enum.to_list(stream) # apenas alteramos aqui
</strong>
      assert response == [
        "event 1 was scheduled",
        "event 2 was scheduled",
        "event 3 was scheduled",
        "event 4 was scheduled",
        "event 5 was scheduled"
      ]
    end
  end
end

</code></pre>

Apenas alteramos a linha 11 para faze a conversão do `Stream` para uma `lista`. Isso faz todo o processamento e nos devolve a lista que queremos. vamos rodar o teste e ver o que acontece:

```sh
mix test test/event_test.exs
.
Finished in 0.03 seconds (0.00s async, 0.03s sync)
1 test, 0 failures
```

Perfeito! Fizemos nosso primeiro processamento de `Stream` e tudo ocorreu bem.&#x20;

### Conclusão

Stream é uma lista de carregamento preguiçoso que só será executado quando realmente precisar. ele serve para evitar processamente sem necessidades, como quando não precisamos executar todos os dados de uma vez em uma lista de milhares de dados. Isso nós ajuda a salvar processamento.

Esse foi um exemlpo simples para entendermos o conceito de Stream. Fiz um vídeo mais avançado sobre processamento de grande quantidade de dados. Você pode dar uma olhada nele [nesse link](https://www.youtube.com/watch?v=w_Z6BL9_59w).


# Compreensão (for)

Vamos começar um pouco diferente nesse capítulo. Vamos direto para o exemplo e ver a necessidade aparecer com o tempo e assim, explicar melhor o conceito de compreensão.&#x20;

### Exemplo

Precisamos filtrar uma lista de números e obter apenas os números pares. Vamos ao teste. Ele deve seguir as regras

* Enviamos uma lista de inteiros para a função
* Essa função nos retorna uma lista de apenas números pares
* Também queremos apenas os numeros entre 0 e 10&#x20;

Vamos crianos nosso teste primeiro:

<pre class="language-elixir" data-title="test/comprehensions_test.exs" data-line-numbers><code class="lang-elixir">defmodule ComprehensionsTest do
  use ExUnit.Case

  test "just pair please" do
    numbers = 1..10
    
    result = Numbers.just_pair_please(numbers)

<strong>    assert is_list(result)
</strong>    assert result == [2,4,6,8,10]  
  end
end

</code></pre>

Na linha 9 adicionamos uma confirmação de que teremos de resultado da operação `for` uma lista. Se assemelhando ao [Enum.map](https://aprenda.cafecomelixir.com.br/basico/pages/gkM78dEsP8e5YGqQTjbm#enum.map-2). Vamos rodar esse teste:

```sh
mix test test/numbers_test.exs       
warning: Numbers.just_pair_please/1 is undefined (module Numbers is not available or is yet to be defined)
  test/numbers_test.exs:7: NumbersTest."test just pair please"/1



  1) test just pair please (NumbersTest)
     test/numbers_test.exs:4
     ** (UndefinedFunctionError) function Numbers.just_pair_please/1 is undefined (module Numbers is not available)
     code: result = Numbers.just_pair_please(numbers)
     stacktrace:
       Numbers.just_pair_please(1..10)
       test/numbers_test.exs:7: (test)


Finished in 0.03 seconds (0.00s async, 0.03s sync)
1 test, 1 failure
```

Como esperado, o relatório de erro nos trouxe que a função não existe. Vamos criar ela. Sua definição é `Numbers.`just\_pair\_please`/1`. Vamos replicar isso em nosso código

{% code title="lib/numbers.ex" lineNumbers="true" %}

```elixir
defmodule Numbers do
  def just_pair_please(_number_list) do
    [2,4,6,8,10]
  end
end

```

{% endcode %}

Criado a função, retornamos os valores que precisamos para fazer o teste passar:

```sh
mix test test/numbers_test.exs
Compiling 1 file (.ex)
.
Finished in 0.02 seconds (0.00s async, 0.02s sync)
1 test, 0 failures
```

Certo, teste passando. Vamos adicionar uma nova lista, para garantir que tudo funciona. Vamos ao teste:

<pre class="language-elixir" data-title="test/numbers_test.exs" data-line-numbers><code class="lang-elixir">defmodule NumbersTest do
  use ExUnit.Case

  test "just pair please" do
    numbers = 1..10
    
    result = Numbers.just_pair_please(numbers)

    assert is_list(result)
    assert result == [2,4,6,8,10]
    
<strong>    result2 = Numbers.just_pair_please(1..5)
</strong><strong>    assert result2 == [2,4]
</strong>  end
end

</code></pre>

Fizemos uma nova chamada a função passando uma lista diferente que vai de 1 a 5. O restultado esperado é 2 e 4, os únicos pares da lista. Vamos rodar isso para ver se tudo funciona com deveria.

```sh
mix test test/numbers_test.exs


  1) test just pair please (NumbersTest)
     test/numbers_test.exs:4
     Assertion with == failed
     code:  assert result == [2, 4]
     left:  [2, 4, 6, 8, 10]
     right: [2, 4]
     stacktrace:
       test/numbers_test.exs:13: (test)


Finished in 0.02 seconds (0.00s async, 0.02s sync)
1 test, 1 failure
```

Temos uma resposta diferente do esperado, isso porque estamos com valores estáticos na resposta da função. Precisamos agora deixar mais dinâmica as coisas. Precisamos percorrer a lista e retornar somente valores pares. Podemos fazer isso utilizando um `Enum.filter/2`. Vamos tentar:

<pre class="language-elixir" data-title="lib/numbers.ex" data-line-numbers><code class="lang-elixir">defmodule Numbers do
  def just_pair_please(numbers_list) do
<strong>    Enum.filter(numbers_list, fn number -> rem(number, 2) == 0 end)
</strong>  end
end

</code></pre>

Utilizamos `Enum.filter/2` para conseguir fazer essa operação. Seguinda ideia de que um número par deve ter como resto de divisão por 2 o valor 0. A função `rem/2` pega o resto da operação (casas decimais) e converte para `integer`. Uma vez que for 0 o valor é par. Em `Enum.filter/2` uma vez que seja true o valor, o elemento ficará na lista, quando for falso, será removido. Vamos rodar o teste:

```sh
mix test test/numbers_test.exs
Compiling 1 file (.ex)
.
Finished in 0.02 seconds (0.00s async, 0.02s sync)
1 test, 0 failures
```

Perfeito! As coisas estão melhorando.&#x20;

* ~~Enviamos uma lista de inteiros para a função~~
* ~~Essa função nos retorna uma lista de apenas números pares~~
* Também queremos apenas os numeros entre 0 e 10&#x20;

Dois pontos foram resolvidos. Precisamos agora permitir que o range de nosso filtro seja apenas para números até o número 10. Vamos criar uma teste para isso:

{% code title="test/numbers\_test.exs" lineNumbers="true" %}

```elixir
defmodule NumbersTest do
  use ExUnit.Case

  # ...
  test "just pair please, until 10" do
    result = Numbers.just_pair_please(1..40)

    assert is_list(result)
    assert result == [2,4,6,8,10]
  end
end

```

{% endcode %}

Um teste praticamente igual ao anterior, porém, com o range maior, indo de 1 a 10. Nossa nova regra é, os números devem apenas ir até 10. Vamos rodar o teste":

```sh
mix test test/numbers_test.exs
Compiling 1 file (.ex)


  1) test just pair please, until 10 (NumbersTest)
     test/numbers_test.exs:16
     Assertion with == failed
     code:  assert result == [2, 4, 6, 8, 10]
     left:  [2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40]
     right: [2, 4, 6, 8, 10]
     stacktrace:
       test/numbers_test.exs:20: (test)

.
Finished in 0.03 seconds (0.00s async, 0.03s sync)
2 tests, 1 failure
```

Queriamos os números até 10. Mas temos a resposta dos pares com valores até 40. Então um relatório de erro foi mostrado. Vamos arrumar isso.

<pre class="language-elixir" data-title="lib/numbers.ex" data-line-numbers><code class="lang-elixir">defmodule Numbers do
  def just_pair_please(numbers_list) do
    Enum.filter(numbers_list, fn number ->
<strong>      if number > 10, do: false, else: rem(number, 2) == 0
</strong>    end)
  end
end

</code></pre>

Adicionamos uma nova validação em nosso filtro. Uma condição if em que o número que for maior que 10, deve voltar `false` e com isso, não entrar na lista.

Vamos rodar o teste:

```sh
mix test test/numbers_test.exs
Compiling 1 file (.ex)
..
Finished in 0.02 seconds (0.00s async, 0.02s sync)
2 tests, 0 failures
```

Funcionou perfeitamente. Agora vamos adicionar um novo comportamento. Os dados que restaram em nosso filtro devem ser multiplicados por 3.

* ~~Enviamos uma lista de inteiros para a função~~
* ~~Essa função nos retorna uma lista de apenas números pares~~
* ~~Também queremos apenas os numeros entre 0 e 10~~
* Valores restantes na lista devem ser multiplicados por 3

Vamos alterar nossos testes:

```elixir
defmodule NumbersTest do
  use ExUnit.Case

  test "just pair please" do
    result = Numbers.just_pair_please(1..10)

    assert is_list(result)
    assert result == [6,12,18,24,30]

    result2 = Numbers.just_pair_please(1..5)

    assert is_list(result2)
    assert result2 == [6,12]
  end

  test "just pair please, until 10" do
    result = Numbers.just_pair_please(1..40)

    assert is_list(result)
    assert result == [6,12,18,24,30]
  end
end

```

Vamos rodar o teste:

```sh
mix test test/numbers_test.exs


  1) test just pair please (NumbersTest)
     test/numbers_test.exs:4
     Assertion with == failed
     code:  assert result == [6, 12, 18, 24, 30]
     left:  [2, 4, 6, 8, 10]
     right: [6, 12, 18, 24, 30]
     stacktrace:
       test/numbers_test.exs:8: (test)



  2) test just pair please, until 10 (NumbersTest)
     test/numbers_test.exs:16
     Assertion with == failed
     code:  assert result == [6, 12, 18, 24, 30]
     left:  [2, 4, 6, 8, 10]
     right: [6, 12, 18, 24, 30]
     stacktrace:
       test/numbers_test.exs:20: (test)


Finished in 0.03 seconds (0.00s async, 0.03s sync)
2 tests, 2 failures
```

Duas falhas. Nosso teste esta pedindo que os valores retornados sejam multiplicado por e. com isso precisamos realizar uma transformação em nossa lista. Mas `Enum.filter/2` não serve para isso, ele serve apenas para filtrar. Quem faz transformações de um [enumerável](/conceitos/enumeraveis) é o [`Enum.map`](https://aprenda.cafecomelixir.com.br/basico/pages/gkM78dEsP8e5YGqQTjbm#enum.map-2)`/2`. Vamos ter que obter o resultado do `Enum.filter/2`, para conseguir usar em um [`Enum.map/2`](https://aprenda.cafecomelixir.com.br/basico/pages/gkM78dEsP8e5YGqQTjbm#enum.map-2). Vamos implementar:

{% code title="lib/numbers.ex" lineNumbers="true" %}

```elixir
defmodule Numbers do
  def just_pair_please(numbers_list) do
    list_filtered = Enum.filter(numbers_list, fn number ->
      if number > 10, do: false, else: rem(number, 2) == 0
    end)
    
    Enum.map(list_filtered, fn number -> 
      number * 3
    end)
  end
end

```

{% endcode %}

Colocamos a lista filtrada em uma variável chamada `list_filtered`. Depois utilizamos o `Enum.map/2` para realizar a transformação, passando `list_filtered` como primeiro argumento e o segundo a função de transformação, obtendo o valor de um número e multiplicando por 3.&#x20;

Vamos executar o teste para ver como estamos:

```sh
mix test test/numbers_test.exs
Compiling 1 file (.ex)
..
Finished in 0.03 seconds (0.00s async, 0.03s sync)
2 tests, 0 failures
```

Conseguimos realizar todas as regras de negócio que precisamos.

* ~~Enviamos uma lista de inteiros para a função~~
* ~~Essa função nos retorna uma lista de apenas números pares~~
* ~~Também queremos apenas os numeros entre 0 e 10~~
* ~~Valores restantes na lista devem ser multiplicados por 3~~

Mas em um problema relativamente simples, temos um código maior. Não é necessariamente um problema, o código é claro e fácil de entender após lermos com atenção. Porém, existe uma forma de resumir isso caso você queira. Chamamos isso de sintaxy sugar.

Em elixir temos a syntax sugar chamada `Comprehension` que é criado em três partes: filtro, transformação e coleção. Justamente o que precisamos agora. Uma explicação rápida:

### Compreensão

Compreensões em Elixir são uma forma concisa e expressiva de criar, filtrar, transformar e combinar coleções em uma única linha de código. As compreensões em Elixir são inspiradas nas compreensões de listas em Python e nas expressões de conjunto em matemática.

Uma compreensão é composta por três partes principais:

* A cláusula `for`: que especifica uma ou mais variáveis e as expressões que geram os valores para essas variáveis.

```elixir
for n <- 1..10
```

* A cláusula `do`: que define as transformações a serem aplicadas a cada valor gerado pela cláusula `for`.

```elixir
for n <- 1..10, do: n*n
```

* Opcionalmente, cláusulas adicionais, como `if` ou `unless`, que filtram os valores gerados pela cláusula `for`.

```elixir
for n <- 1..10, rem(n, 2), do: n*n # usando if
for n <- 1..10, unless rem(n, 2) == 0, do: n # usando unless
```

Vamos voltar ao exemplo

### Refatorando

Não precisamos mais tocar no teste, uma vez que toda a regra de negócio está refletida lá. O que precisamos agora é deixar nosso implementação melhor, vamos lá:

<pre class="language-elixir"><code class="lang-elixir">defmodule Numbers do
  def just_pair_please(numbers_list) do
<strong>    for number &#x3C;- numbers_list, rem(number, 2) == 0 &#x26;&#x26; number &#x3C;= 10  do
</strong><strong>      number * 3
</strong><strong>    end
</strong>  end
end

</code></pre>

O que vocês acham da nova implementação? Bem mais clara, não acham? Vamos rodar os testes:

```sh
mix test test/numbers_test.exs
Compiling 1 file (.ex)
..
Finished in 0.02 seconds (0.00s async, 0.02s sync)
2 tests, 0 failures
```

Perfeito, refatoramos de forma a ficar mais claro e fácil de entender. Mantivemos todos os testes passando o que garante o funcionamento de nossa implementação.&#x20;

### Conclusão

Compreensão pode ser útil para diminuir o tamanho de nosso código. Porém isso pode causar problemas de legibilidade, então, minha dica é: entendam o que vocês precisam no momento e tomem uma decisão conciente. Tanto um quanto o outro estão corretos.


# Imutabilidade

{% hint style="warning" %}
**Aviso sobre esse capítulo**

Abordarei apenas o básico para seguirmos nos estudos. Imutabilidade é um assunto complexo. Entender as vantagens e desvantagens pode consumir tempo e também confundir quem está começando em linguagens funcionais. Por hora, irei somente abordar o básico para entendimento da linguagem e para darmos continuidade nos estudos.
{% endhint %}

Como o próprio nome diz, imutabilidade significa imutável, algo constante, que não muda. Isso quer dizer, toda definição uma vez feita, nunca mudará. Para termos valores diferente, por exemplo, em uma variável, nós precisaremos sobrepor ela, jogando fora todo o valor antigo e adotando o novo valor.

Vamos a um exemplo simples:

* Criaremos um [`map`](/basico/colecoes/mapas) de user onde terá o atributo `name`&#x20;
* Alteraremos o `name` para `Cafe com elixir`

Vamos criar nosso teste para isso

<pre class="language-elixir" data-title="test/imutability_test.exs" data-line-numbers><code class="lang-elixir">defmodule ImmutabilityTest do
  use ExUnit.Case

  test "trying immutability" do
    user = %{name: "iago"}
<strong>    updated_user = %{user | name: "iago updated"}
</strong>
    assert user.name == "iago"
    assert updated_user.name == "iago updated"
  end
end
</code></pre>

```shell
mix test test/imutability_test.exs
.
Finished in 0.02 seconds (0.00s async, 0.02s sync)
1 test, 0 failures
```

**Duas coisas para notar aqui:**

1. Mesmo atualizando `user` para o novo nome, o valor de `user` não se alterou;&#x20;
2. Após a atualização, é retornado o valor atualizado do map. Esse novo valor nós adicionamos dentro de `updated_user` e essa variável tem a atualização do `user`.

Caso você queira continuar com a mesma variável, porém, com o novo valor, você vai precisar sobrepor o valor da variável anterior.

{% code title="" lineNumbers="true" %}

```elixir
defmodule ImmutabilityTest do
  use ExUnit.Case

  # ...
  test "override variable" do
    user = %{name: "iago"}
    user = %{user | name: "iago updated"}

    assert user.name == "iago updated"
  end
end
```

{% endcode %}

```shell
mix test test/imutability_test.exs
..
Finished in 0.02 seconds (0.00s async, 0.02s sync)
2 tests, 0 failures
```

Tudo no elixir é imutável, mantenha isso em mente é um conceito importante.

### Conclusão

Abordamos o básico de imutabilidade. É um ponto importante no estudo de linguagens funcionais. Ela nos ajuda a evitar diversos problemas na utilização da concorrência, nos dando uma boa vantagem em relações a linguagens mutáveis.

Lembrando, toda vez que realizarmos uma mudança de dados, o dado original nunca será alterado, você terá que cuidar dessa re-assinatura ou sobreposição de valores.


# Aridade

Normalmente você verá as funções com essa representação `map/2` ou `Enum.map/2`. Esse número após a barra se chama aridade. Ela vem da matemática onde significa o número de argumentos ou de operandos que uma função ou operação requer.

Ele tem o mesmo significado no Elixir. Ele indica quantos argumentos essa função necessita para ser executada. No exemplo acima temos o `Enum.map/2`. Leia-se que a função `map` do módulo `Enum` precisa de dois argumentos para poder ser utilizado.

Isso serve para as funções que você cria também. Vamos a um exemplo. Teremos uma função simples chamada `multiple` do módulo `Math` que multiplica 2 números `x` e `y`.&#x20;

Podemos representar isso dessa forma `Math.multiple/2`. Uma vez que você passe isso para alguém que entenda de aridade, ele entenderá o que é necessário para essa função.

Vamos ao teste

{% code title="test/math\_test.exs" lineNumbers="true" %}

```elixir
defmodule MathTest do
  use ExUnit.Case
  
  describe "multiple/2" do
    test "success: return the result" do
      assert Math.multiple(3, 5) == 15
    end
  end
end
```

{% endcode %}

Rodando isso teremos um relatório de erro pois não possuímos a função.

```sh
mix test test/math_test.exs    
warning: Math.multiple/2 is undefined or private
  test/math_test.exs:6: MathTest."test multiple/2 success: return the result"/1



  1) test multiple/2 success: return the result (MathTest)
     test/math_test.exs:5
     ** (UndefinedFunctionError) function Math.multiple/2 is undefined or private
     code: assert Math.multiple(3, 5) == 15
     stacktrace:
       (hello_world 0.1.0) Math.multiple(3, 5)
       test/math_test.exs:6: (test)


Finished in 0.02 seconds (0.00s async, 0.02s sync)
1 test, 1 failure
```

Agora que possuímos a representação e o teste de nossa função, vamos criar a implementação dela.

<pre class="language-elixir" data-title="lib/math.ex" data-line-numbers><code class="lang-elixir">defmodule Math do
<strong>  def multiple(x, y) do
</strong>    x * y
  end
end
</code></pre>

```elixir
mix test test/math_test.exs
Compiling 1 file (.ex)
.
Finished in 0.01 seconds (0.00s async, 0.01s sync)
1 test, 0 failures
```

Tudo funcionando. Mas, sabendo que nossa função é dois de aridade, o que acontece quando mandamos apenas um argumento? Vamos criar um teste para isso

{% code title="test/math\_test.exs" lineNumbers="true" %}

```elixir
defmodule MathTest do
  use ExUnit.Case
  
  describe "multiple/2" do
    # ...
    
    test "fail: Insufficient Arguments" do
      Math.multiple(3)
    end
  end
end
```

{% endcode %}

<pre class="language-sh"><code class="lang-sh">test test/math_test.exs
<strong>warning: Math.multiple/1 is undefined or private. Did you mean:
</strong>
<strong>      * multiple/2
</strong>
  test/math_test.exs:10: MathTest."test multiple/2 fail: Insufficient Arguments"/1



  1) test multiple/2 fail: Insufficient Arguments (MathTest)
     test/math_test.exs:9
<strong>     ** (UndefinedFunctionError) function Math.multiple/1 is undefined or private. Did you mean:
</strong>     
           * multiple/2
     
     code: assert Math.multiple(3) == nil
     stacktrace:
       (hello_world 0.1.0) Math.multiple(3)
       test/math_test.exs:10: (test)

.
Finished in 0.02 seconds (0.00s async, 0.02s sync)
2 tests, 1 failure
</code></pre>

Quando não encontra uma função com a especificação enviada, recebemos uma exceção dizendo que função não foi definida. Também recebemos uma sugestão de que talvez o que queremos seja a função `multiple/2` e não `multiple/1`.

Podemos fazer esse teste passar dizendo que esperamos que falhe quando isso aconteça. Vamos alterar nosso teste para esperar por iso.

<pre class="language-elixir" data-title="test/math_test.exs" data-line-numbers><code class="lang-elixir">defmodule MathTest do
  use ExUnit.Case
  
  describe "multiple/2" do
    # ...
    
    test "fail: Insufficient Arguments" do
<strong>      expected = "function Math.multiple/1 is undefined or private"
</strong>      assert_raise UndefinedFunctionError, expected, fn ->
        Math.multiple(3)
      end
    end
  end
end
</code></pre>

{% hint style="warning" %}
[**assert\_raise**](https://hexdocs.pm/ex_unit/ExUnit.Assertions.html#assert_raise/2)&#x20;

Ele é uma função auxiliadora do `ExUnit` que captura uma exceção, assim podemos criar testes que esperamos que uma implementação falhe quando algo sai do esperado. Algumas vezes esse caso é necessário.
{% endhint %}

Executando isso, teremos sucesso nos testes

```sh
mix test test/math_test.exs
..
Finished in 0.03 seconds (0.00s async, 0.03s sync)
2 tests, 0 failures
```

Também podemos usar a aridade para escolher a função a ser rodada de mesmo nome. Vamos fazer outro teste.

{% code title="" lineNumbers="true" %}

```elixir
defmodule PersonhTest do
  use ExUnit.Case
  
  describe "say_my_name/2" do
    test "success: when passing two arguments" do
      assert Person.say_my_name("Iago", "Effting") == "Seu nome completo é Iago Effting"
    end
  end
end
```

{% endcode %}

Você pode rodar e ver que o módulo e função não foram definidas. Vamos cria-la.

{% code title="lib/person.ex" lineNumbers="true" %}

```elixir
defmodule Person do
  def say_my_name(first_name, last_name) do
    "Seu nome completo é #{first_name} #{last_name}"
  end
end
```

{% endcode %}

```sh
mix test test/person_test.exs
Compiling 1 file (.ex)

...
Finished in 0.01 seconds (0.00s async, 0.01s sync)
1 tests, 0 failures
```

Agora vamos supor que só mande o primeiro nome.

{% code title="test/person\_test.exs" lineNumbers="true" %}

```elixir
defmodule PersonhTest do
  use ExUnit.Case
  
  describe "say_my_name/2" do
    # ...
    
    test "success: when passing one argument" do
      assert Person.say_my_name("Iago") == "Seu primeiro nome é Iago Effting"
    end
  end
end
```

{% endcode %}

```sh
mix test test/person_test.exs
warning: Person.say_my_name/1 is undefined or private. Did you mean:

      * say_my_name/2

  test/person_test.exs:10: PersonTest."test say_my_name/2 success: when passing one argument"/1

..

  1) test say_my_name/2 success: when passing one argument (PersonTest)
     test/person_test.exs:9
     ** (UndefinedFunctionError) function Person.say_my_name/1 is undefined or private. Did you mean:
     
           * say_my_name/2
     
     code: assert Person.say_my_name("Iago") == "Seu primeiro nome é Iago"
     stacktrace:
       (hello_world 0.1.0) Person.say_my_name("Iago")
       test/person_test.exs:10: (test)

.
Finished in 0.02 seconds (0.00s async, 0.02s sync)
2 tests, 1 failure
```

O relatório de erro avisa que não temos uma função say\_my\_name de aridade 1 (`say_my_name/1`) e sugestiona a outra que criamos no exemplo anterior `say_my_name/1`. Para fazer esse teste passar, precisamos criar uma nova função `say_my_name` que suporte receber apenas um argumento.

{% hint style="info" %}
Diferente de algumas linguagem de programação, Elixir suporte multiplas definições de uma mesma função.
{% endhint %}

Vamos criar essa nova função

{% code title="lib/person.ex" lineNumbers="true" %}

```elixir
defmodule Person do
  # ...
  def say_my_name(first_name) do
    "Seu primeiro nome é #{first_name}"
  end
end
```

{% endcode %}

Rodando o teste agora, você terá um relatório de sucesso.

```sh
mix test test/person_test.exs
Compiling 1 file (.ex)
....
Finished in 0.01 seconds (0.00s async, 0.01s sync)
2 tests, 0 failures
```

Quando chamamos uma função que tem mais de uma definição ela irá começar da primeira definição a que esta mais ao topo do aqruivo para baixo, parando na primeira oportunidade.&#x20;

{% code lineNumbers="true" %}

```elixir
defmodule Sample do
  def function_1(), do: IO.inspect("Declaração 1")
  def function_1(_arg), do: IO.inspect("Declaração 2")
  def function_1(_arg), do: IO.inspect("Declaração 3")
end

# ...

Sample.functin_1("hello")
# Declaração 2
```

{% endcode %}

Então, devemos levar em consideração a posição que a função é declarada.

### Conclusão

Aridade é uma representação matemática que utilizamos para definir o número de argumentos que uma função necessidade para ser executada.&#x20;


# Convenções

Em primeira vista, as convenções podem parecer apenas uma escolha feita por um time de desenvolvimento. Mas ela é muito mais do que isso. É a definição de como algo deve ser feito, porém, criado por uma comunidade que está imerso no código da linguagem, sabendo que se isso não for respeitado, podemos ter grandes problemas no futuro.

**Ganhamos algumas coias ao utilizar convenções:**

1. Padronização de código;
2. Facilidade de membros de fora do projeto, conseguirem entender o que esta acontecendo;
3. Várias bibliotecas seguem o mesmo padrão, então você tera o entendimento mais rápido e de forma fácil, conseguirá adicionar ao seu código sem mudar a estrategia ou organização.

Vamos a algumas convenções

### Tupla `{:ok, result}` e `{:error, reason}`

Podemos facilmente entender que uma função não foi executada com sucesso, quando em seu retorno, temos essa estrutura `{:error, "Something went wrong"}`. Ou que tudo deu certo `{:ok, %{...}}`. Essa é uma convenção adotada pela comunidade elixir para facilitar a identificação de erros e sucessos, podendo tomar alguma ação com base nisso.

A definição de resposta funciona de duas formas.&#x20;

1. Em caso de sucesso retornamos uma [tupla](/basico/colecoes/tuplas) de `:ok`, junto com o `result`.&#x20;

```elixir
{:ok, result} = Authentication.login(email, password)
```

Podemos facilmente obter o resultado, garantindo que ele esteja funcionando devido ao pattern matching. Caso tenhamos uma resposta diferente de `{:ok, result}` o pattern matching falhará e saberemos que algo esta errado.

2\. Para definir um erro, seguimos na mesma ideia, porém, utilizando o atom de `:error` e a `reason`.

```elixir
{:error, reason} = Authentication.login(email, password)
```

Isso nos proporciona maior controle e também facilita a leitura do código.

O `result` e a `reason` são variáveis que criamos no pattern matching (para entender melhor isso, vá para a seção de [Pattern Matching ](/basico/pattern-matching)no livro.

Vou listar algumas bibliotecas famosas que utilizam dessa convenção:&#x20;

* [Ecto](https://hexdocs.pm/ecto/Ecto.Repo.html#c:insert/2-examples)
* [HTTPoison](https://hexdocs.pm/httpoison/HTTPoison.html#get/3)

Uma das grandes vantagens na utilização da tupla de `:ok/:error` é a utilização do [`with`](/basico/controle-de-fluxo/with) onde podemos controlar por meio de pattern matching os resultados esperados. De uma olhada na seção [with](/basico/controle-de-fluxo/with) do livro, para se aprofundar mais.

Um exemplo simples:

<pre class="language-elixir" data-line-numbers><code class="lang-elixir">def do_something() do
<strong>  with {:ok, function_result} &#x3C;- Module.function(), # tupla :ok
</strong><strong>       {:ok, another_result} &#x3C;-Module.another() do # tupla :ok
</strong>    IO.inspect("All good")
  else
<strong>    {:error, reason} -> IO.inspect("Something went worg: #{reason}") # tupla :error
</strong>  end
end
</code></pre>

### Função com bang (`!`)

Pode também ser notado que em alguns casos você pode adicionar um ponto de exclamação (`!`), chamada comumente de bang. Vimos isso nesse exemplo da lib HTTPoison `HTTPoison.get!/2`. Por convenção, essa invocação remove a tupla `:ok/:error` e retorna apenas o valor.&#x20;

Isso faz com que não tenhamos o poder de saber se algo deu certo por pattern matching. Dependendo o caso, é o melhor a se fazer.

**Um exemplo**

{% code lineNumbers="true" %}

```shell
iex> HTTPoison.get(url)
# {:ok, %HTTPoison.Response{...}}

iex> HTTPoison.get!(url)
# %HTTPoison.Response{...}
```

{% endcode %}

### Função com interrogação (`?`)

Quando queremos uma resposta de sim ou não para alguém, fazemos perguntas. Em elixir não é diferente. Quando queremos que o tipo do dado seja booleano (que aceite true ou false) utilizamos em seu nome o ponto de interrogação. Quando você ver isso em alguma função você saberá que retorna-rá um boleano.

{% code lineNumbers="true" %}

```sh
File.dir?("./test")
# true

Enum.any?([false, true, false])
# true
```

{% endcode %}

### Conclusão

Sempre que tiver criando funções, tenha em mente que ela pode falhar, e caso isso aconteça, precisamos saber que isso aconteceu.

Quando uma função segue de um ponto de exclamação `!`, a convenção nos diz que a resposta dessa função não trará a tupla com `:ok` ou `:error` e sim o resultado diretamente. Exemplo


# Enumeráveis

Os `Enumerables` são módulos em Elixir que fornecem uma série de funções para manipular [coleções](broken://pages/2ZadBlkYxEfwNtpTzAXt). As funções do módulo `Enumerables` permitem que você faça coisas como `filtrar`, `mapear`, `reduzir` e `classificar` [coleções](broken://pages/2ZadBlkYxEfwNtpTzAXt) de maneira eficiente. Essas funções são projetadas para trabalhar com qualquer tipo de coleção que implemente o protocolo `Enumerable`, que é implementado por muitas coleções em Elixir.

Ao usar as funções do módulo `Enumerables`, você pode escrever código mais conciso e legível do que ao manipular coleções manualmente usando loops. Por exemplo, em vez de escrever um loop para percorrer uma lista e executar uma determinada operação em cada elemento, você pode usar a função `Enum.map` para aplicar uma função a cada elemento da lista.

Alguns exemplos de funções do módulo `Enumerables` incluem:

* `map`: aplica uma função a cada elemento de uma coleção e retorna uma nova coleção com os resultados.
* `filter`: retorna uma nova coleção contendo apenas os elementos que atendem a uma determinada condição.
* `reduce`: aplica uma função a cada elemento de uma coleção para acumular um resultado único.
* `sort`: classifica uma coleção com base em uma determinada ordem.

Essas são apenas algumas das muitas funções disponíveis no módulo `Enumerables` em Elixir. Usando essas funções, você pode manipular coleções de maneira fácil e expressiva em seus programas Elixir.

Alguns dos módulos mais comuns que utilizam o protocolo Enumerable:

* [Enum](/basico/manipulacao-de-dados/enum)
* [Stream](/basico/manipulacao-de-dados/stream)
* [List](/basico/colecoes/listas)
* Range
* MapSet

Ao aprender a trabalhar com o protocolo Enumerable em Elixir, você poderá trabalhar com esses e outros módulos de forma mais eficiente e com menos código.

### Conclusão

Em resumo, o protocolo Enumerable é um recurso fundamental em Elixir que permite que você trabalhe com coleções de dados de maneira eficiente, fácil e consistente. Ao dominar o protocolo Enumerable, você pode escrever código mais robusto e conciso, tornando-se um programador mais eficaz em Elixir.


