mix help
mix help new
mix new hello_world
cd hello_world
mix test
> $ tree
├── _build
│ └── test
│ └── lib
│ └── hello_world
│ ├── consolidated
│ │ ├── Elixir.Collectable.beam
│ │ ├── Elixir.Enumerable.beam
│ │ ├── Elixir.IEx.Info.beam
│ │ ├── Elixir.Inspect.beam
│ │ ├── Elixir.List.Chars.beam
│ │ └── Elixir.String.Chars.beam
│ └── ebin
│ ├── Elixir.HelloWorld.beam
│ └── hello_world.app
├── config
│ └── config.exs
├── lib
│ └── hello_world.ex
├── mix.exs
├── README.md
└── test
├── hello_world_test.exs
└── test_helper.exs
Let's look at the lib/hello_world.ex
file to check out our HelloWorld
module:
defmodule HelloWorld do
@moduledoc """
Documentation for HelloWorld.
"""
@doc """
Hello world.
## Examples
iex> HelloWorld.hello
:world
"""
def hello do
:world
end
end
Before we move on, let's run the REPL with our project loaded into it. Normally, if you just run iex
, you won't have these modules loaded. You can load your project by running:
iex -S mix
iex(1)> HelloWorld.hello()
:world
Let's create a division function:
defmodule HelloWorld do
# ...
def div(a, b) do
a / b
end
end
And we can use it:
iex -S mix
iex(1)> HelloWorld.div(1, 2)
0.5
Of course, this suffers from a bit of a problem:
iex(2)> HelloWorld.div(1, 0)
** (ArithmeticError) bad argument in arithmetic expression
(hello_world) lib/hello_world.ex:20: HelloWorld.div/2
defmodule HelloWorld do
# ...
def div(a, 0) do
:no_dice
end
def div(a, b) do
a / b
end
end
iex -S mix
iex(1)> HelloWorld.div(1, 0)
:no_dice
Let's change this a bit so we can pattern match on whether or not the function was successful:
defmodule HelloWorld do
def div(a, 0) do
{:error, "attempt at division by zero"}
end
def div(a, b) do
{:ok, a / b}
end
end
Now we can handle this result in a case statement. Let's do it in a test:
vim test/hello_world_test.exs
defmodule HelloWorldTest do
use ExUnit.Case
doctest HelloWorld
test "division" do
{:ok, result} = HelloWorld.div(2, 1)
assert result == 2.0
end
test "division by zero" do
{:error, err} = HelloWorld.div(1, 0)
assert err == "attempt at division by zero"
end
end
When you use a pipe, which looks like |>, you're really just moving the first argument to a function out of the function call, to the left of the pipe. We'll open an iex session to check it out:
iex -S mix
This:
iex(1)> HelloWorld.div(1, 2)
{:ok, 0.5}
is the same as this:
iex(2)> 1 |> HelloWorld.div(2)
{:ok, 0.5}
vim test/hello_world_test.exs
defmodule HelloWorldTest do
# ...
test "pipes and strings" do
# If we import the `String` module we can use its functions without
# qualifying them fully - so we get `upcase` instead of the more-verbose
# `String.upcase`
import String
val =
"josh"
|> reverse
|> capitalize
|> reverse
assert val == "josH"
end
end