Aprenda Elixir em um final de semana

Preview:

Citation preview

Elixir em um final de semana

Pergunte-me como!

@marcosbrizeno

Quem sou eu?@marcosbrizeno

brizeno.wordpress.com

Como?O Simples Hello World!

Testes com ExUnit

Pattern Matching com Fibonacci

Tail Recursion com Cálculo Fatorial

O Operador |> (pipe)

Próximos finais de semana

Por que Elixir?Porque sim Zequinha

Elixir e Erlang

Funcional BR HUE!

Divertida e performática

BEAM VM

Elixir <- Erlang

Hello World!

$> iexiex(1)> IO.puts("Hello World!")Hello World!:ok

$> iexiex(1)> IO.puts("Hello World!")Hello World!:ok

iex(1)> IO.puts("Hello World!")

Módulo IO

Função puts/1

Criando módulos

defmodule HelloWorld do def hello() do “Hello World” endend

hello_world.exs

defmodule HelloWorld do def hello() do “Hello World” endend

hello_world.exsdefmodule HelloWorld do

end

Módulo HelloWorld

defmodule HelloWorld do def hello() do “Hello World” endend

hello_world.exs

def hello() do “Hello World” end

Função hello/0

defmodule HelloWorld do def hello() do “Hello World” endend

hello_world.exs

$> iexiex(1)> Code.load_file(“hello_world.exs")iex(2)> HelloWorld.hello()"Hello World"

$> iexiex(1)> Code.load_file(“hello_world.exs")iex(2)> HelloWorld.hello()"Hello World"

iex(1)> Code.load_file(“hello_world.exs")iex(2)> HelloWorld.hello()

Carrega arquivo ”hello_world.exs”

Chama função hello/0

Modificando módulos com hot reload

defmodule HelloWorld do def hello() do “Hello World” end

def hello(name) do “Hello #{name}” endend

hello_world.exsdefmodule HelloWorld do

def hello(name) do “Hello #{name}” endend

defmodule HelloWorld do def hello(name) do “Hello #{name}” endend

hello_world.exs

$> iexiex(1)> Code.load_file(“hello_world.exs")iex(2)> HelloWorld.hello()"Hello World”iex(3)> HelloWorld.hello(“Lambda I/O“)** (UndefinedFunctionError)

$> iexiex(1)> Code.load_file(“hello_world.exs")iex(2)> HelloWorld.hello()"Hello World”iex(3)> HelloWorld.hello(“Lambda I/O“)** (UndefinedFunctionError)iex(4)> r(HelloWorld)iex(5)> HelloWorld.hello(“Lambda I/O“)"Hello Lambda I/O”

$> iexiex(1)> Code.load_file(“hello_world.exs")iex(2)> HelloWorld.hello()"Hello World”iex(3)> HelloWorld.hello(“Lambda I/O“)** (UndefinedFunctionError)iex(4)> r(HelloWorld)iex(5)> HelloWorld.hello(“Lambda I/O“)"Hello Lambda I/O”

iex(4)> r(HelloWorld)iex(5)> HelloWorld.hello(“Lambda I/O“)"Hello Lambda I/O”

r Recarrega o módulo HelloWorld

Agora podemos acessar hello/1

Testes com ExUnit

defmodule HelloWorld do def hello() do “Hello World” end

def hello(name) do “Hello #{name}” endend

hello_world.exs

hello_world_test.exsCode.load_file("hello_world.exs")

ExUnit.start

defmodule HelloWorldTest do use ExUnit.Case, async: true

test "returns Hello World" do assert HelloWorld.hello == "Hello World" endend

$> elixir hello_world_test.exs.

Finished in 0.1 seconds (0.1s on load, 0.00s on tests)1 test, 0 failures

Anatomia de um caso de test ExUnit

hello_world_test.exsCode.load_file("hello_world.exs")

ExUnit.start

defmodule HelloWorldTest do use ExUnit.Case, async: true

test "returns Hello World" do assert HelloWorld.hello == "Hello World" endend

Code.load_file("hello_world.exs")

hello_world_test.exsCode.load_file("hello_world.exs")

ExUnit.start

defmodule HelloWorldTest do use ExUnit.Case, async: true

test "returns Hello World" do assert HelloWorld.hello == "Hello World" endend

ExUnit.start

defmodule HelloWorldTest do use ExUnit.Case, async: true

end

hello_world_test.exsCode.load_file("hello_world.exs")

ExUnit.start

defmodule HelloWorldTest do use ExUnit.Case, async: true

test "returns Hello World" do assert HelloWorld.hello == "Hello World" endend

test "returns Hello World" do assert HelloWorld.hello == "Hello World" end

Saída em caso de falhas

$> elixir hello_world_test.exs1) test returns Hello World (HelloWorldTest) hello_world_test.exs:8 Assertion with == failed code: HelloWorld.hello() == "Hello not World" left: "Hello World" right: "Hello not World" stacktrace: hello_world_test.exs:9: (test)

Sequência Fibonacci com Pattern

Matching

fib_test.exsCode.load_file("fib.exs")

ExUnit.start

defmodule FibonacciTest do use ExUnit.Case, async: true

test "fibonacci 0 is 0" do assert Fibonacci.calculate(0) == 0 endend

fib.exsdefmodule Fibonacci do def calculate(number) do 0 endend

$> elixir fib_test.exs.

Finished in 0.1 seconds (0.1s on load, 0.00s on tests)1 test, 0 failures

fib_test.exstest "fibonacci 0 is 0" do assert Fibonacci.calculate(0) == 0end

test "fibonacci 1 is 1" do assert Fibonacci.calculate(1) == 1end

test "fibonacci 2 is 1" do assert Fibonacci.calculate(2) == 1end

fib.exsdef calculate(n) do cond do n <= 0 -> 0 n == 1 -> 1 true -> calculate(n-2) + calculate(n-1) endend

$> elixir fib_test.exs...

Finished in 0.1 seconds (0.1s on load, 0.00s on tests)3 test, 0 failures

Utilizando Pattern Matching

fib.exs

def calculate(n) do case n do 0 -> 0 1 -> 1 _ -> calculate(n-2) + calculate(n-1) endend

fib.exs

def calculate(n) do case n do 0 -> 0 1 -> 1 _ -> calculate(n-2) + calculate(n-1) endend

case n do 0 1 _ end

$> elixir fib_test.exs...

Finished in 0.1 seconds (0.1s on load, 0.00s on tests)3 test, 0 failures

Utilizando Pattern Matching nos argumentos

fib.exs

def calculate(0), do: 0

def calculate(1), do: 1

def calculate(n) do calculate(n-2) + calculate(n-1)end

$> elixir fib_test.exs...

Finished in 0.1 seconds (0.1s on load, 0.00s on tests)3 test, 0 failures

Guard Clause nos métodos

fib_test.exstest "raise ArgumentError" do assert_raise ArgumentError, fn -> Fibonacci.calculate(-1) endend

fib.exsdef calculate(0), do: 0

def calculate(1), do: 1

def calculate(n) when n < 0 do raise ArgumentErrorend

def calculate(n) do calculate(n-2) + calculate(n-1)end

def calculate(n) when n < 0 do raise ArgumentErrorend

Cálculo Fatorial com Tail Recursion

factorial_test.exsCode.load_file("factorial.exs")

ExUnit.start

defmodule FactorialTest do use ExUnit.Case, async: true

test "factorial of 0 is 1" do assert Factorial.of(0) == 1 endend

factorial.exsdefmodule Factorial do def of(0), do: 1end

factorial_test.exstest "factorial of 1 is 1" do assert Factorial.of(1) == 1end

factorial.exsdefmodule Factorial do def of(0), do: 1

def of(n) do of(n-1) * n endend

Otimizando com Tail recursion

factorial_test.exstest "factorial of 100000" do assert Factorial.of(100_000)end

@tag timeout: 600_000test "factorial of 500000" do assert Factorial.of(500_000)end

factorial.exsdefmodule Factorial do def of(n), do: of(n, 1)

defp of(0, accumulator), do: accumulator

defp of(n, accumulator) do of(n-1, accumulator*n) endend

factorial.exsdefmodule Factorial do def of(n), do: of(n, 1)

defp of(0, accumulator), do: accumulator

defp of(n, accumulator) do of(n-1, accumulator*n) endend

def of(n), do: of(n, 1)

of/1 of/2

factorial.exsdefmodule Factorial do def of(n), do: of(n, 1)

defp of(0, accumulator), do: accumulator

defp of(n, accumulator) do of(n-1, accumulator*n) endend

defp of(0, accumulator), do: accumulator

factorial.exsdefmodule Factorial do def of(n), do: of(n, 1)

defp of(0, accumulator), do: accumulator

defp of(n, accumulator) do of(n-1, accumulator*n) endend

defp of(n, accumulator) do of(n-1, accumulator*n) end

$> elixir factorial_test.exs....

Finished in 254.2 seconds (0.05s on load, 254.2s on tests)4 tests, 0 failures

Formando acrônimos e o operador |> (pipe)

acronym_test.exsdefmodule AcronymTest do use ExUnit.Case, async: true

test "it produces acronyms from title case" do assert Acronym.abbreviate("Portable Networks Graphic") === "PNG" endend

acronym.exsdefmodule Acronym do

def abbreviate(title) do separated_names = String.split(title, " ") capitalized_letters = capitalize_letters(separated_names) Enum.join(capitalized_letters) end

end

acronym.exsdefmodule Acronym do

defp capitalize_letters(names) do Enum.map(names, fn(name) -> first_letter = String.first(name) String.capitalize(first_letter) end)end

end

$> elixir acronym.exs.

Finished in 0.1 seconds (0.1s on load, 0.00s on tests)1 test, 0 failures

Refatorando com o |>

acronym.exsdefp capitalize_letters(names) do Enum.map(names, fn(name) -> String.capitalize(String.first(name)) endend

acronym.exsdefp capitalize_letters(names) do Enum.map(names, fn(name) -> String.capitalize(String.first(name)) endend

String.capitalize(String.first(name))

acronym.exsdefp capitalize_letters(names) do Enum.map(names, fn(name) -> String.first(name) |> String.capitalize() endend

acronym.exsdefp capitalize_letters(names) do Enum.map(names, fn(name) -> String.first(name) |> String.capitalize() endend

String.first(name) |> String.capitalize()

$> elixir acronym.exs.

Finished in 0.1 seconds (0.1s on load, 0.00s on tests)1 test, 0 failures

Refatorando com o |>, de novo

acronym.exsdefmodule Acronym do

def abbreviate(title) do separated_names = String.split(title, " ") capitalized_letters = capitalize_letters(separated_names) Enum.join(capitalized_letters) end

end

acronym.exsdef abbreviate(title) do String.split(title, " ") |> capitalize_letters() |> Enum.join()end

acronym.exsdef abbreviate(title) do String.split(title, " ") |> capitalize_letters() |> Enum.join()end

String.split(title, " ") |> capitalize_letters() |> Enum.join()

$> elixir acronym.exs.

Finished in 0.1 seconds (0.1s on load, 0.00s on tests)1 test, 0 failures

O que mais?Meu blog (https://brizeno.wordpress.com/tag/elixir/)

Elixir getting started (http://elixir-lang.org/getting-started/introduction.html)

Grok Podcast(http://www.grokpodcast.com/series/elixir/)

Elixir Koans(https://github.com/dojo-toulouse/elixir-koans)

exercism.io

Próximos passos

Manipulação de listas

Mix

Phoenix web framework

Obrigado!

@marcosbrizeno