Add a notebook about the unique features behind Elixir and Livebook (#314)

This commit is contained in:
José Valim 2021-06-03 15:47:33 +02:00 committed by GitHub
parent 91a9f62fb9
commit fcf53c4bf2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 152 additions and 118 deletions

View file

@ -55,6 +55,11 @@ defmodule Livebook.Notebook.Explore do
image_url: "/images/logo.png"
)
defnotebook(:elixir_and_livebook,
description: "Learn how to use some of Elixir and Livebook unique features together.",
image_url: "/images/live-elixir.png"
)
defnotebook(:intro_to_elixir,
description: "New to Elixir? Learn about the language and its core concepts.",
image_url: "/images/elixir.png"
@ -90,7 +95,8 @@ defmodule Livebook.Notebook.Explore do
@spec notebook_infos() :: list(notebook_info())
def notebook_infos() do
[
@intro_to_livebook
@intro_to_livebook,
@elixir_and_livebook
# @intro_to_elixir, @intro_to_nx, @intro_to_axon, @intro_to_vega_lite
]
end

View file

@ -0,0 +1,138 @@
# Elixir and Livebook
## Modules
You can use code cells to execute any Elixir code:
```elixir
IO.puts("hello world!")
```
But you can define modules inside cells too!
```elixir
defmodule Utils do
@doc """
Generates a random binary id.
"""
@spec random_id() :: binary()
def random_id() do
:crypto.strong_rand_bytes(20) |> Base.encode32(case: :lower)
end
end
```
If you're surprised by the above output, keep in mind that
every Elixir expression evaluates to some value and as so
does module compilation!
Having the module defined, let's take it for a spin.
```elixir
Utils.random_id()
```
## Autocompletion
Elixir code cells also support autocompletion by pressing
<kbd>Ctrl</kbd> + <kbd>Spacebar</kbd>. You can try it out by making sure the
module in the previous section has been defined and then
put the cursor after the `.` below and press <kbd>Ctrl</kbd> + <kbd>Spacebar</kbd>:
```elixir
Utils.
```
You can also press `Tab` to cycle across the different options.
## Imports
You can import modules as normally to make the imported functions visible
to all subsequent cells. Usually you want to keep `import`, `alias`, and
`require` in the first section, as part of the notebook setup.
For instance, you can import `IEx.Helpers` and bring all of the amazing
conveniences in Elixir's shell to your notebook:
```elixir
import IEx.Helpers
```
```elixir
h(Enum.map())
```
```elixir
# Sidenote: http://www.numbat.org.au/thenumbat
i("I ❤️ Numbats")
```
## Using packages
Sometimes you need a dependency or two and notebooks are no exception to this.
In Livebook, you can use [`Mix.install/2`](https://hexdocs.pm/mix/Mix.html#install/2)
to bring dependencies into your notebook! This approach is especially useful when
sharing notebooks because everyone will be able to get the same dependencies.
Let's try this out:
**Note:** compiling dependencies may use a reasonable amount of memory. If you are
hosting Livebook, make sure you have enough memory allocated to the Livebook
instance, otherwise the command below will fail.
```elixir
Mix.install([
{:jason, "~> 1.2"}
])
```
```elixir
%{elixir: "is awesome"}
|> Jason.encode!()
|> IO.puts()
```
It is a good idea to specify versions of the installed packages,
so that the notebook is easily reproducible later on.
Also keep in mind that `Mix.install/2` can be called only once
per runtime, so if you need to modify the dependencies, you should
go to the notebook runtime configuration and **reconnect** the current
runtime. Let's learn how to do that.
## Runtimes
Livebook has a concept of **runtime**, which in practice is an Elixir node responsible
for evaluating your code. You can choose the runtime by clicking the "Runtime" icon
on the sidebar (or by using the `rs` keyword shortcut).
By default, a new Elixir node is started (similarly to starting `iex`). You
can click reconnect whenever you want to discard the current node and start
a new one.
You can also choose to run inside a _Mix_ project (as you would with `iex -S mix`),
manually _attach_ to an existing distributed node, or run your Elixir notebook
_embedded_ within the Livebook source itself.
## Running tests
It is also possible to run tests directly from your notebooks.
The key is to disable `ExUnit`'s autorun feature and then explicitly
run the test suite after all test cases have been defined:
```elixir
ExUnit.start(autorun: false)
defmodule MyTest do
use ExUnit.Case, async: true
test "it works" do
assert true
end
end
ExUnit.run()
```
This helps you follow best practices and ensure the code you write
behaves as expected!

View file

@ -18,7 +18,7 @@ and run them locally.
Each notebook consists of a number of cells, which serve as primary building blocks.
There are **Markdown** cells (such as this one) that allow you to describe your work
and **Elixir** cells where the magic takes place!
and **Elixir** cells to run your code!
To insert a new cell move your cursor between cells and click one of the revealed buttons. 👇
@ -72,119 +72,6 @@ with just a few assumptions on how particular elements are represented. Thanks t
approach you can easily keep notebooks under version control and get readable diffs.
You can also easily preview those files, reuse for blog posts, and even edit in a text editor.
## Modules
As we have seen, Elixir cells can be used for working on tiny snippets,
but you may as well define a module!
```elixir
defmodule Utils do
@doc """
Generates a random binary id.
"""
@spec random_id() :: binary()
def random_id() do
:crypto.strong_rand_bytes(20) |> Base.encode32(case: :lower)
end
end
```
If you're surprised by the above output, keep in mind that
every Elixir expression evaluates to some value and as so does module compilation!
Having the module defined, let's take it for a spin.
```elixir
Utils.random_id()
```
## Imports
You can import modules as normally to make the imported functions visible
to all subsequent cells. Usually you want to keep `import`, `alias` and `require`
in the first section, as part of the notebook setup.
```elixir
import IEx.Helpers
```
```elixir
h(Enum.map())
```
```elixir
# Sidenote: http://www.numbat.org.au/thenumbat
i("I ❤️ Numbats")
```
## Runtimes
Livebook has a concept of **runtime**, which in practice is an Elixir node responsible
for evaluating your code.
By default, a new Elixir node is started (similarly to starting `iex`),
but you can also choose to run inside a Mix project (as you would with `iex -S mix`)
or even manually attach to an existing distributed node!
You can configure the runtime by clicking the "Runtime" icon on the sidebar.
## Using packages
Sometimes you need a dependency or two and notebooks are no exception to this.
One way to work with packages is to create a Mix project and configure the notebook
to run in its context (as pointed out above). This approach makes sense if you already have
a Mix project that you are working on, especially because this makes all project's
modules available as well.
But there are cases when you just want to play around with a new package
or quickly prototype some code that relies on such. Fortunately, Elixir v1.12+ ships with
[`Mix.install/2`](https://hexdocs.pm/mix/Mix.html#install/2) that allows you to install
dependencies into your Elixir runtime! This approach is especially useful when sharing notebooks
because everyone will be able to get the same dependencies. Let's try this out:
**Note:** compiling dependencies may use a reasonable amount of memory. If you are
hosting Livebook, make sure you have enough memory allocated to the Livebook
instance, otherwise the command below will fail.
```elixir
Mix.install([
{:jason, "~> 1.2"}
])
```
```elixir
%{elixir: "is awesome"}
|> Jason.encode!()
|> IO.puts()
```
It is a good idea to specify versions of the installed packages,
so that the notebook is easily reproducible later on.
Also keep in mind that `Mix.install/2` can be called only once
per runtime, so if you need to modify the dependencies, you should
go to the notebook runtime configuration and **reconnect** the current runtime.
## Running tests
It is also possible to run tests directly from your notebooks.
The key is to disable `ExUnit`'s autorun feature and then explicitly
run the test suite after all test cases have been defined:
```elixir
ExUnit.start(autorun: false)
defmodule MyTest do
use ExUnit.Case, async: true
test "it works" do
assert true
end
end
ExUnit.run()
```
## Math
Livebook uses $\\TeX$ syntax for math.
@ -204,10 +91,13 @@ to optimise how you move around. Livebook leverages the concept of
Make sure to check out the shortcuts by clicking the "Keyboard" icon in
the sidebar or by typing `?`.
## Final notes
## Next steps
Livebook is an open source project, so feel free to look into
[the repository](https://github.com/elixir-nx/livebook)
That's our quick your intro to Livebook! Now you are ready to learn
how Elixir integrates with Livebook in the ["Elixir and Livebook"](/explore/notebooks/elixir-and-livebook) notebook.
Finally, remember Livebook is an open source project, so feel free to look
into [the repository](https://github.com/elixir-nx/livebook)
to contribute, report bugs, suggest features or just skim over the codebase.
Now go ahead and build something cool! 🚢

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB