Elixir - DailyTrip [001.3] Mix and Modules

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

你可能感兴趣的:(Elixir - DailyTrip [001.3] Mix and Modules)