aprenda elixir em um final de semana
TRANSCRIPT
Elixir em um final de semana
Pergunte-me como!
@marcosbrizeno
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