# Mix
```elixir
Mix.install([
{:jason, "~> 1.4"},
{:kino, "~> 0.9", override: true},
{:youtube, github: "brooklinjazz/youtube"},
{:hidden_cell, github: "brooklinjazz/hidden_cell"}
])
```
## Navigation
<div style="display: flex; align-items: center; width: 100%; justify-content: space-between; font-size: 1rem; color: #61758a; background-color: #f0f5f9; height: 4rem; padding: 0 1rem; border-radius: 1rem;">
<div style="display: flex;">
<i class="ri-home-fill"></i>
<a style="display: flex; color: #61758a; margin-left: 1rem;" href="../start.livemd">Home</a>
</div>
<div style="display: flex;">
<i class="ri-bug-fill"></i>
<a style="display: flex; color: #61758a; margin-left: 1rem;" href="https://github.com/DockYard-Academy/curriculum/issues/new?assignees=&labels=&template=issue.md&title=Mix">Report An Issue</a>
</div>
<div style="display: flex;">
<i class="ri-arrow-left-fill"></i>
<a style="display: flex; color: #61758a; margin-left: 1rem;" href="../exercises/pascals_triangle.livemd">Pascal's Triangle</a>
</div>
<div style="display: flex;">
<a style="display: flex; color: #61758a; margin-right: 1rem;" href="../exercises/games.livemd">Games Project</a>
<i class="ri-arrow-right-fill"></i>
</div>
</div>
## Review Questions
Upon completing this lesson, a student should be able to answer the following questions.
* What is the purpose of Mix?
* Where should our application go inside of a mix project?
* How do we compile a mix project and explore it using the IEx shell?
## Mix
[Mix](https://hexdocs.pm/mix/Mix.html) is a build tool that ships with Elixir that automates tasks for creating, compiling, and testing your application.
We start a new Mix application by running the following in the command line.
```
mix new app_name
```
Where `app_name` is the name of the project.
<!-- livebook:{"break_markdown":true} -->
### Your Turn
Create a `hello_world` application.
You should notice that the command generated several files.
```
$ mix new hello_world
* creating README.md
* creating .formatter.exs
* creating .gitignore
* creating mix.exs
* creating lib
* creating lib/hello_world.ex
* creating test
* creating test/test_helper.exs
* creating test/hello_world_test.exs
Your Mix project was created successfully.
You can use "mix" to compile it, test it, and more:
cd hello_world
mix test
Run "mix help" for more commands.
```
Your project should have the following file and folder structure.
```
hello_world/
lib/
hello_world.ex
test/
hello_world_test.exs
test_helper.exs
.formatter.exs
.gitignore
mix.exs
README.md
```
We'll walk through the mix project structure and how you can build Elixir applications.
## The `lib` Folder
The `lib/` folder contains the files for the project. We start with a single module
named after the project. You should have a `HelloWorld` module in the `lib/hello_world.ex` file.
We use `@moduledoc` and `@doc` to document our code.
```elixir
defmodule HelloWorld do
@moduledoc """
Documentation for `HelloWorld`.
"""
@doc """
Hello world.
## Examples
iex> HelloWorld.hello()
:world
"""
def hello do
:world
end
end
```
## Running A Mix Project
To execute the Elixir code for our Mix project, you can load the project into the IEx Shell
by running the following command in the project folder.
```
iex -S mix
```
Now, all of the `.ex` files and modules under the `lib/` folder are available in the [IEx](https://hexdocs.pm/iex/IEx.html) shell environment.
[Mix](https://hexdocs.pm/mix/Mix.html) ignores `.exs` files, so any modules in a `.exs` file will not be available in the [IEx](https://hexdocs.pm/iex/IEx.html) shell.
### Your Turn
Load your project into the IEx Shell.
```
iex -S mix
```
Call the `hello/0` function.
```
iex> HelloWorld.hello()
:world
```
Notice that the `iex -S mix` command compiles your project into the `_build` folder. This folder contains `.beam` files which are executable files generated by the Erlang compiler.
You can also compile the project by running `mix compile` in the command line.
## Tests
[ExUnit](https://hexdocs.pm/ex_unit/ExUnit.html) is a built-in testing framework. Test files are under the `test/` folder in `.exs` files.
In your `hello_world` project, there should be an example test file `test/hello_world_test.exs` with
the following content.
<!-- livebook:{"force_markdown":true} -->
```elixir
defmodule HelloWorldTest do
use ExUnit.Case
doctest HelloWorld
test "greets the world" do
assert HelloWorld.hello() == :world
end
end
```
Test files generally correspond to another file in the `lib/` folder.
For example, a `lib/greeting/hola.ex` file might have a corresponding `test/greeting/hola_test.exs` file.
We will dive deeper into how to test Elixir projects in the [ExUnit](exunit.livemd) section.
For now, know that you can execute all of your tests by running the following in the command line.
<!-- livebook:{"force_markdown":true} -->
```elixir
$ mix test
```
### Your Turn
Run `mix test` in your `hello_world` project folder from the command line, and you
should see an output similar to the following.
<!-- livebook:{"force_markdown":true} -->
```elixir
Compiling 1 file (.ex)
Generated hello_world app
..
Finished in 0.02 seconds (0.00s async, 0.02s sync)
1 doctest, 1 test, 0 failures
Randomized with seed 768874
```
## File And Module Names
Mix compiles all `.ex` files under the `lib/` folder and bundles them together into a project.
Generally, Elixir projects organize modules under the main project namespace.
So all of the modules in the `HelloWorld` application would be grouped under the `HelloWorld` namespace.
For example, a new `Greeting` module would be defined under `HelloWorld.Greeting`.
```elixir
defmodule HelloWorld.Greeting do
def salutations(name) do
"Salutations, #{name}!"
end
end
```
Nested modules generally
relate to each other, often sub-modules deal with a more specific application of the higher-level module.
For example, a `Formal` module would be under the `Greeting` module.
```elixir
defmodule HelloWorld.Greeting.Formal do
def charmed() do
"Charmed, I'm sure."
end
end
```
While not enforced, module and file structure often follow a pattern, where the module name matches its folder and file.
For example, the `HelloWorld.Greeting.Formal` module would be in a `lib/greeting/formal.ex` file,
and the `HelloWorld.Greeting` will be in the `lib/greeting.ex` file.
```
lib/
greeting.ex
hello_world.ex
greeting/
formal.ex
```
### Your Turn
Modules can call functions from any other modules in `.ex` files under the `lib/` folder,
just as you have already seen in livebook cells.
```elixir
defmodule ModuleA do
def run do
"A"
end
end
defmodule ModuleB do
def run do
ModuleA.run() <> "B"
end
end
ModuleB.run()
```
In your `hello_world` application, create a new module, `HelloWorld.Name` in a `lib/name.ex` file, which will return a random name.
```elixir
defmodule HelloWorld.Name do
def random do
Enum.random(["Peter", "Bruce", "Tony"])
end
end
```
Then, call the `HelloWorld.Name.random/0` function from the `HelloWorld` module in `hello_world.ex`.
<!-- livebook:{"break_markdown":true} -->
<!-- livebook:{"force_markdown":true} -->
```elixir
defmodule HelloWorld do
def hello do
"Hello, #{HelloWorld.Name.random()}."
end
end
```
<!-- livebook:{"break_markdown":true} -->
Run your project in the [IEx](https://hexdocs.pm/iex/IEx.html) shell and ensure the `HelloWorld.hello/0` function works as expected.
<!-- livebook:{"force_markdown":true} -->
```elixir
$ iex -S mix
iex> HelloWorld.hello()
"Hello, Peter."
```
## Mix.exs
The `mix.exs` file's main responsibility is to configure the mix project.
It defines two public functions, `project/0` and `application/0`.
The `project/0` function returns project configuration such as the project name, current version, and installed dependencies. The `project/0` function relies on the private `deps/0` function to provide a list of dependencies.
The `application/0` function returns application configuration used to generate an application manifest file in the `_build` folder. This file is used under the hood to run the project. For more, you can see the [Application](https://hexdocs.pm/elixir/main/Application.html) module
on HexDocs. Sometimes removing the `_build` folder and recompiling a project can resolve compilation bugs.
## Dependencies
Other developers create open-source Elixir projects hosted on GitHub, which we can add as dependencies to our project.
There is a massive ecosystem of Elixir projects, which means you don't have to
reinvent the wheel and solve already solved problems. The [Hex.pm](https://hex.pm/) contains a list of available Elixir projects you may find useful. For a curated list, check out the [awesome-elixir](https://github.com/h4cc/awesome-elixir) project.
To install a dependency, include the name of the project and desired version in a tuple inside the `deps/0` function
in `mix.exs`. Notice that `mix.exs` includes comments on installing a dependency using the project version or GitHub URL.
<!-- livebook:{"force_markdown":true} -->
```elixir
defp deps do
[
# {:dep_from_hexpm, "~> 0.3.0"},
# {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"}
]
end
```
### Your Turn
Add the [Faker](https://hex.pm/packages/faker) project to your `hello_world` application.
[Faker](https://hexdocs.pm/faker/readme.html) provides functions for generating fake data, often useful for randomized test data.
It's often most reliable to check the [Hex page](https://hex.pm/packages/faker) of a project for the latest version.
Ensure you add `:faker` with the latest version to the `deps/0` function in `mix.exs`.
<!-- livebook:{"force_markdown":true} -->
```elixir
defp deps do
[
{:faker, "~> 0.17.0"}
]
end
```
Then run `mix deps.get` to update your project dependencies.
Once installed, you have access to the [Faker](https://hexdocs.pm/faker/readme.html) module.
Use the `Faker.Person.first_name/0` function in your `HelloWorld.hello/0` function.
For more on how to use [Faker](https://hexdocs.pm/faker/readme.html), you can read the [Faker Documentation](https://hexdocs.pm/faker/readme.html).
<!-- livebook:{"force_markdown":true} -->
```elixir
def hello do
"Hello, #{Faker.Person.first_name()}."
end
```
Ensure your `hello/0` function works in the IEx shell.
<!-- livebook:{"force_markdown":true} -->
```elixir
iex -S mix
iex> HelloWorld.hello()
"Hello, Salvador." # The name will be random each time.
```
<!-- livebook:{"break_markdown":true} -->
### Versions
Project [Versions](https://hexdocs.pm/elixir/Version.html) are generally represented by
`Major.Minor.Patch` numbers.
When installing dependencies, we specify a [version requirement](https://hexdocs.pm/elixir/Version.html#module-requirements).
We can even specify a version between two numbers using comparison operators. i.e. `>= 2.0.0 and < 2.1.0`,
The locally installed dependency may not exactly match the version requirement, but must belong in the range specified.
The `~>` symbol you see in dependencies means it will never go above its upper bound.
* `~> 2.1` would allow any version below `3.0.0` and above or equal to `2.1.0`.
* `~> 2.1.2` would allow any version below `2.2.0` and above or equal to `2.1.2`.
The [Version documentation](https://hexdocs.pm/elixir/Version.html) goes into further depth.
You can automatically update project versions by running the following in your command line.
```
mix deps.update example_dep
```
Or with the `--all` option to update all deps.
```
mix deps.update --all
```
## Formatting
The `.formatter.exs` file contains project configuration for how to format Elixir source code files automatically.
You can run `mix format` from the command line in the project folder to format elixir code.
### Your Turn
Indent the code in `hello_world.ex`. Then, run `mix format` and notice the code automatically
formats. If it does not, ensure that you do not have syntax errors that prevent code formatting.
## README.md
Most projects include a README.md file which contains basic information about the project written in markdown.
There is no universal README structure however it's common to include:
* The repository name.
* The project purpose.
* Setup instructions.
* Collaborators on the project.
GitHub pages display the README on the front of the repository page for the project.
When building your own projects,
you'll want to make sure you update the default README to include relevant information.
View the [Markdown cheat-sheet](https://www.markdownguide.org/cheat-sheet/) for a quick guide on markdown syntax.
## Mix Environments
Mix projects can run in different environments. The default environment is your development `:dev` environment.
Run your `hello_world` project in the IEx shell and call `Mix.env()` to see that `:dev` is the current environment.
<!-- livebook:{"force_markdown":true} -->
```elixir
$ iex -S mix
iex> Mix.env()
:dev
```
The project will use the `:test` environment when running tests and `:prod` when deployed to production.
We can change project behavior or configuration based on the current environment. For example,
if you had SMS (text) notifications in your project, you might want to disable them in the `:dev` and `:test`
environment to ensure that developers don't accidentally send out text messages to users.
## Further Reading
For more on [Mix](https://hexdocs.pm/mix/Mix.html), consider reading the following.
* [elixir-lang: Intro to Mix](https://elixir-lang.org/getting-started/mix-otp/introduction-to-mix.html)
* [HexDocs: Mix](https://hexdocs.pm/mix/Mix.html#content)
## Commit Your Progress
DockYard Academy now recommends you use the latest [Release](https://github.com/DockYard-Academy/curriculum/releases) rather than forking or cloning our repository.
Run `git status` to ensure there are no undesirable changes.
Then run the following in your command line from the `curriculum` folder to commit your progress.
```
$ git add .
$ git commit -m "finish Mix reading"
$ git push
```
We're proud to offer our open-source curriculum free of charge for anyone to learn from at their own pace.
We also offer a paid course where you can learn from an instructor alongside a cohort of your peers.
We will accept applications for the June-August 2023 cohort soon.
## Navigation
<div style="display: flex; align-items: center; width: 100%; justify-content: space-between; font-size: 1rem; color: #61758a; background-color: #f0f5f9; height: 4rem; padding: 0 1rem; border-radius: 1rem;">
<div style="display: flex;">
<i class="ri-home-fill"></i>
<a style="display: flex; color: #61758a; margin-left: 1rem;" href="../start.livemd">Home</a>
</div>
<div style="display: flex;">
<i class="ri-bug-fill"></i>
<a style="display: flex; color: #61758a; margin-left: 1rem;" href="https://github.com/DockYard-Academy/curriculum/issues/new?assignees=&labels=&template=issue.md&title=Mix">Report An Issue</a>
</div>
<div style="display: flex;">
<i class="ri-arrow-left-fill"></i>
<a style="display: flex; color: #61758a; margin-left: 1rem;" href="../exercises/pascals_triangle.livemd">Pascal's Triangle</a>
</div>
<div style="display: flex;">
<a style="display: flex; color: #61758a; margin-right: 1rem;" href="../exercises/games.livemd">Games Project</a>
<i class="ri-arrow-right-fill"></i>
</div>
</div>