Mix.install([
{:youtube, github: "brooklinjazz/youtube"},
{:hidden_cell, github: "brooklinjazz/hidden_cell"},
{:tested_cell, github: "brooklinjazz/tested_cell"},
{:utils, path: "#{__DIR__}/../utils"}
])
Ensure you type the ea
keyboard shortcut to evaluate all Elixir cells before starting. Alternatively you can evaluate the Elixir cells as you read.
Mix 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.
Create a hello_world
application in this course's projects
folder.
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 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.
defmodule HelloWorld do
@moduledoc """
Documentation for `HelloWorld`.
"""
@doc """
Hello world.
## Examples
iex> HelloWorld.hello()
:world
"""
def hello do
:world
end
end
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 shell environment.
Mix ignores .exs
files, so any modules in a .exs
file will not be available in the IEx shell.
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.
ExUnit 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.
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 section.
For now, know that you can execute all of your tests by running the following in the command line.
$ mix test
Run mix test
in your hello_world
project folder from the command line, and you
should see an output similar to the following.
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
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
.
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.
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
Modules can call functions from any other modules in .ex
files under the lib/
folder,
just as you have already seen in livebook cells.
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.
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
.
defmodule HelloWorld do
def hello do
"Hello, #{HelloWorld.Name.random()}."
end
end
Run your project in the IEx shell and ensure the HelloWorld.hello/0
function works as expected.
$ iex -S mix
iex> HelloWorld.hello()
"Hello, Peter."
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 _build/ebin/hello_world.app
.
This file is used under the hood to run the project. For more, you can see the Application module
on HexDocs.
Note the original contents of the application manifest build/ebin/hello_world.app
should be similar to:
{application,hello_world,
[{applications,[kernel,stdlib,elixir,logger]},
{description,"hello_world"},
{modules,['Elixir.HelloWorld']},
{registered,[]},
{vsn,"0.1.0"}]}.
Change the application/0
function to return an empty list.
def application do
[]
end
Run mix compile
.
The _build/ebin/hello_world.app
file will no longer have the logger
application.
{application,hello_world,
[{applications,[kernel,stdlib,elixir]},
{description,"hello_world"},
{modules,['Elixir.HelloWorld']},
{registered,[]},
{vsn,"0.1.0"}]}.
Mix provides an abstraction for building Elixir applications, so
we don't need to be concerned with these details. However, it's useful to be aware that nothing is magic. Changes to mix.exs
directly impact the compiled _build
folder.
defmodule HelloWorld.MixProject do
use Mix.Project
def project do
[
app: :hello_world,
version: "0.1.0",
elixir: "~> 1.13",
start_permanent: Mix.env() == :prod,
deps: deps()
]
end
# Run "mix help compile.app" to learn about applications.
def application do
[
extra_applications: [:logger]
]
end
# Run "mix help deps" to learn about dependencies.
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
end
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 to that you don't have to reinvent the wheel and solve already solved problems. The Hex.pm contains a list of available Elixir projects you may find useful. For a curated list, check out the 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.
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
Add the Faker project to your hello_world
application.
Faker provides functions for generating fake data, often useful for randomized test data.
It's often most reliable to check the Hex page of a project for the latest version.
Ensure you add :faker
with the latest version to the deps/0
function in mix.exs
.
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 module.
Use the Faker.Person.first_name/0
function in your HelloWorld.hello/0
function.
For more on how to use Faker, you can read the Faker Documentation.
def hello do
"Hello, #{Faker.Person.first_name()}."
end
Ensure your hello/0
function works in the IEx shell.
iex -S mix
iex> HelloWorld.hello()
"Hello, Salvador." # The name will be random each time.
Project Versions are generally represented by
Major.Minor.Patch
numbers.
When installing dependencies, we specify a version requirement.
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 below3.0.0
and above or equal to2.1.0
.~> 2.1.2
would allow any version below2.2.0
and above or equal to2.1.2
.
The Version documentation 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
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.
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.
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 for a quick guide on markdown syntax.
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.
$ 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.
For more on Mix, consider reading the following.
Run the following in your command line from the beta_curriculum folder to track and save your progress in a Git commit.
$ git add .
$ git commit -m "finish mix section"
Previous | Next |
---|---|
IEx | IO |