-
-
Save reginadiana/a9be5229a9aaa94bc4906eba78db0664 to your computer and use it in GitHub Desktop.
O Elixir é uma linguagem de programação funcional brasileira criada por José Valin que roda na máquina virtual do Erlang.
-
String.length("diana")
-
Para remover caracteres especiais e espaços em branco de uma string, podemos usar
String.trim/1
-
Todo valor é verdadeiro com exceção de
false
enil
-
Átomos são equivalentes a simbolos
:example
-
iex
entra no modo interativo -
No Elixir não existem classes ou heranças, assim como declarações sem retorno de valor. Tudo é feito em funções.
-
Para fazer um ternário:
if condicao, do: alguma_coisa, else: se_nao_outra_coisa
-
Para pegar o primeiro elemento de um array, podemos usar tanto
array |> elem(1)
, como[primeiro_elemento] = array
Para poder acessar os registros associados que os macros belongs_to
, has_many
e has_one
nos expoem, precisamos pré-carregar os esquemas associados.
Um exemplo é quando queremos acessar os atores de um filme:
movie = Repo.get(Movie, 1)
movie.actors
%Ecto.Association.NotLoaded<association :actors is not loaded>
Não podemos acessar esses atores associados, a menos que os pré-carreguemos. Existem algumas maneiras diferentes de pré-carregar registros com o Ecto, e uma delas é com o preload
.
Phoenix é um framework escrito em Elixir para o desenvolvimento de aplicações WEB.
📚 Doc
PostgreeSQL é o banco de dados padrão do Phoenix. Para configurar um banco diferente, basta usar a flag --database
. Também podemos usar --no-ecto
para não configurar nenhum banco.
mix ecto.create
cria o banco
mix ecto.migrate
roda as migrations
mix phx.routes
lista todas as rotas geradas em lib/
mix phx.serve
roda o servidor
mix phx.new <name_project>
cria um novo projeto
mix deps.get
instala as dependencias do projeto
MIX_ENV=test
roda no ambiente de teste
📁 build contém todos os artefatos para compilação.
📁 assets contém tudo o que é relacionado ao javascript e css.
📁 config/config.exs é o arquivo responsável por configurar a aplicação.
📁 deps é um diretorio com todas as dependencias listadas em mix.exs.
📁 lib é um diretório que vai cuidar do MVC.
📁 lib/name_app é um diretório responsável pela parte de model, ou seja, visa tratar das regras de negocio.
📁 lib/name_app_web é um diretório responsável pela parte de view e controller, ou seja, contém tudo o que é necessário para expor as informações.
O logger irá mostrar as mensagens apenas nos metodos configurados em config/.exs.
Os tokens podem ser gerados e verificados para serem usados nos channels e endpoints como dados identificadores. É recomendado que eles expirem em 1 dia e o atributo namespace deve ser o mesmo para a função que gera e verifica o token.
elixir{:ok, :valid}
A configuração pepiline :browser
permite lidar com requisições html.
O método Repo.get(Model, id)
busca, por padrão, a partir do id
. Se quisermos buscar por outro parametro, temos que user Repo.get_by(Model, other_param: value)
.
O operador pipe |>
passa o resultado de uma expressão para outra.
Podemos usar o |> json(%{:ok, :valid})
como uma simples resposta a uma requisição.
O i18n do Phoenix é feito através do gettext, que já vem por padrão.
@moduledoc serve para documentar o metodo defmodule SomeModule
@doc serve para documentar os métodos def SomeSimpleModule
aridade em linguagens funcionais correspondem ao número de argumentos que uma função recebe. Por isso, é possível declarar funções com mesmo nome, mas que recebem número de parametros diferentes como my_function/1
que recebe um argumento e my_function/2
que recebe dois argumentos.
execução paralela: significa que duas ou mais tarefas são livres para serem executadas ao mesmo tempo.
execução concorrente: significa que o processador está trocando o foco entre as tarefas de maneira muito rápida.
Os métodos utilizados com File
podem ser usados com o bang (!), permitindo que a função seja executada e o retorno seja seu prório conteúdo. Já quando não a utilizamos, a função será executada e o retorno será o math {:ok, "return function content"}
ou {:error, :reason}
File.cd/1
Define o diretório de trabalho
File.cd!/1
Define o diretório de trabalho, mas retorna File.Error caso algo de errado
File.cd!/2
Muda o diretório de trabalho, então deve receber o diretório atual e o novo
Para declarar uma constante, fazemos:
defmodule MyModule do
@my_favorite_number 13
end
O then é algo nativo do elixir que serve para capturarmos o valor retornado na pipe, sem precisarmos adicionar uma variável e só assim manupulá-la, exemplo:
string # " diana \n"
|> String.trim() # "diana"
|> String.first() # "d"
|> String.upcase() # "D"
|> then(& &1 <> ".") # &1 é referente ao "D", então podemos fazer um join, retornando "D."
Primeiro de tudo, saiba que se voce não rodou a migrate, basta excluir o arquivo que foi gerado pela migration e é isso :)
Para dar rollback na ultima migration, basta executar:
mix ecto.rollback
É possível ainda dar rollback em uma migration especifica:
mix ecto.rollback -v [timestamp]
Depois, exclua o arquivo da ultima migration e execute a migrate novamente com:
mix ecto.migrate
Caso tenha algum erro de migration ao rodar os testes, tente dar um reset nesse ambiente:
Ex: Postgrex.Error 42P07 (duplicate_table): relation “users” already exists
MIX_ENV=test mix ecto.reset
Exemplos:
function_variable = fn param -> param + 1 end
function_variable.(1) # 2
variable = &(&1 + 1)
variable.(1) # 2
Chamando uma função anonima dentro de outra
recursive_function_variable = &(variable.(&1))
recursive_function_variable.(1) # 2
Outro caso em que faço isso:
def secret_combine(secret_function1, secret_function2) do
fn arg -> secret_function2.(secret_function1.(arg)) end
end
def secret_add(secret) do
# arg_func é o param da função add e secret é o param da função secret_add
fn arg_func -> arg_func + secret end
end
add = Secrets.secret_add(6)
add.(9) # 15
Uma forma de devolver essa função de maneira mais enchuta, seria:
def secret_add(secret) do
&(&1 + secret)
end
Quando criamos um mapa com chaves duplicadas, será retornado uma das chaves e a duplicação será removida com o seu respectivo valor:
iex(4)> %{3 => :two, 3 => "four"}
warning: key 3 will be overridden in map
iex:4
%{3 => "four"}
Considere o seguinte mapa:
map = %{a: 1, b: 2}
Quando a chave/key existe
Map.fetch(map, :a) # {:ok, 1}
Map.get(map, :a) # 1
map.a # 1
map[:b] # 1
Quando a chave/key NÃO existe
Map.fetch(map, :not_existing) # {:error}
Map.get(map, :not_existing) # nil
map.not_existing # ** (KeyError) key :not_existing not found in: %{a: 1, b: 2}
map[:not_existing] # nil
Para o caso do get, podemos definir um valor padrão para caso uma chave não exista
Map.get(map, :not_existing, "Valor alternativo") # "Valor alternativo"
O uso de map[key]
é recomendado quando o mapa é criado dinamicamente e portanto, pode conter qualquer chave, seja ela de qualquer tipo. Já o map.key
é usando quando temos bem definido quais são as chaves, criadas por intermédido do defstruct
por exemplo.
As chaves também podem ser usadas dentro de variáveis, mas ao serem usadas em patter matchers, devem usar um prefixo:
iex(23)> id = 123
123
iex(24)> %{id => 123} = %{id => 123, 2 => :two, 3 => :three}
** (CompileError) iex:24: cannot use variable id as map key inside a pattern. Map keys in patterns can only be literals (such as atoms, strings, tuples, and the like) or an existing variable matched with the pin operator (such as ^some_var)
(stdlib 3.13.2) lists.erl:1267: :lists.foldl/3
iex(24)> %{^id => 123} = %{id => 123, 2 => :two, 3 => :three}
%{2 => :two, 3 => :three, 123 => 123}
map = %{one: 1, two: 2}
map |> Map.delete(:one) # %{two: 2}
map |> Map.delete(:not_exist) # %{one: 1, two: 2}
O método delete
vai retornar o mapa com a chave-valor deletados quando a chave existir, e retornar o próprio mapa quando a chave passada não existir, mas repare que, de qualquer forma, o mapa só tem a chave-valor deletada dentro daquela interação, então para deixá-la de fato deletada precisamos adicioná-la a uma variável.
map = %{one: 1, tree: 3, two: 2}
map |> Map.drop([:two, :tree]) # %{one: 1}
map |> Map.drop([:two, :four]) # %{one: 1, tree: 3}
map |> Map.drop([]) # %{one: 1, tree: 3, two: 2}
O método drop
vai eliminar uma série de chaves-valores de uma mapa. Na primeira interação as chaves :two
e :four
foram passadas, então elas foram deletadas, restando apenas a chave :one
. Na segunda interação as chaves :two
e :four
foram passadas, porém a chave :four
não existe, fazendo com que apenas :two
fosse deletada, restanto as chaves :one
e :tree
. Já na terceira interação, nenhuma chave foi passada, fazendo com que não houvesse alteração.
map_a = %{a: 1, b: 2}
map_b = %{a: 1, b: 2}
map_c = %{c: 1, b: 2}
map_a == map_b # true
map_a == map_c # false
Map.equal?(map_a, map_b) # true
Map.equal?(map_a, map_c) # false
O método equal?
verifica se os 2 mapas passados possuem as mesmas chaves com os mesmos valores. Porém, o resultado é similar ao usar ==
. Na verdade, existe uma diferença entre usar essas duas abordagens. Veja o caso de quando os valores possuem tipos diferentes:
Map.equal?(%{a: 1.0}, %{a: 1}) # false
%{a: 1.0} === %{a: 1} # false
%{a: 1.0} == %{a: 1} # true
MIX_ENV=test mix ecto.reset