Home Programming Elixir Cookbook

Elixir Cookbook

By Paulo Pereira
books-svg-icon Book
eBook $28.99
Print $48.99
Subscription $15.99
$10 p/m for first 3 months. $15.99 p/m after that. Cancel Anytime!
What do you get with a Packt Subscription?
This book & 7000+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with a Packt Subscription?
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with eBook + Subscription?
Download this book in EPUB and PDF formats, plus a monthly download credit
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with a Packt Subscription?
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with eBook?
Download this book in EPUB and PDF formats
Access this title in our online reader
DRM FREE - Read whenever, wherever and however you want
Online reader with customised display settings for better reading experience
What do you get with video?
Download this video in MP4 format
Access this title in our online reader
DRM FREE - Watch whenever, wherever and however you want
Online reader with customised display settings for better learning experience
What do you get with video?
Stream this video
Access this title in our online reader
DRM FREE - Watch whenever, wherever and however you want
Online reader with customised display settings for better learning experience
What do you get with Audiobook?
Download a zip folder consisting of audio files (in MP3 Format) along with supplementary PDF
What do you get with Exam Trainer?
Flashcards, Mock exams, Exam Tips, Practice Questions
Access these resources with our interactive certification platform
Mobile compatible-Practice whenever, wherever, however you want
BUY NOW $10 p/m for first 3 months. $15.99 p/m after that. Cancel Anytime!
eBook $28.99
Print $48.99
Subscription $15.99
What do you get with a Packt Subscription?
This book & 7000+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with a Packt Subscription?
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with eBook + Subscription?
Download this book in EPUB and PDF formats, plus a monthly download credit
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with a Packt Subscription?
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with eBook?
Download this book in EPUB and PDF formats
Access this title in our online reader
DRM FREE - Read whenever, wherever and however you want
Online reader with customised display settings for better reading experience
What do you get with video?
Download this video in MP4 format
Access this title in our online reader
DRM FREE - Watch whenever, wherever and however you want
Online reader with customised display settings for better learning experience
What do you get with video?
Stream this video
Access this title in our online reader
DRM FREE - Watch whenever, wherever and however you want
Online reader with customised display settings for better learning experience
What do you get with Audiobook?
Download a zip folder consisting of audio files (in MP3 Format) along with supplementary PDF
What do you get with Exam Trainer?
Flashcards, Mock exams, Exam Tips, Practice Questions
Access these resources with our interactive certification platform
Mobile compatible-Practice whenever, wherever, however you want
  1. Free Chapter
    Command Line
About this book
Publication date:
February 2015
Publisher
Packt
Pages
236
ISBN
9781784397517

 

Chapter 1. Command Line

This chapter will cover the following recipes:

  • Interactive Elixir (IEx):

    • Using the terminal to prototype and test ideas

    • Loading and compiling modules

    • Getting help and accessing documentation within IEx

    • Using Erlang from Elixir

    • Inspecting your system in IEx

    • Inspecting your system with Observer

  • Mix:

    • Creating a simple application

    • Managing dependencies

    • Generating a supervised application

    • Generating umbrella applications

    • Managing application configuration

    • Creating custom Mix tasks

 

Introduction


The command line is the preferred way to create and interact with Elixir applications, inspect running systems, and prototype ideas.

Interactive Elixir (IEx) allows immediate evaluation of any expression, and it is also possible to define modules directly without saving them previously on a file. Similar tools exist in other programming languages; Ruby's IRB or Clojure's REPL are some examples.

Mix is a build tool that provides several tasks to create, compile, and test projects, and handle dependencies. It is also possible to define custom tasks with Mix. In the Creating custom Mix tasks recipe, we will create a task to display the memory usage. It is common for some applications to define their own tasks. Phoenix framework (which will be covered in Chapter 7, Cowboy and Phoenix) is just one example of this.

 

Using the terminal to prototype and test ideas


The Elixir default installation provides an REPL (short for read-eval-print-loop) named IEx. IEx is a programming environment that takes user expressions, evaluates them, and returns the result to the user. This allows the user to test code and even create entire modules, without having to compile a source file.

To start prototyping or testing some ideas, all we need to do is use IEx via our command line.

Getting ready

To get started, we need to have Elixir installed. Instructions on how to install Elixir can be found at http://elixir-lang.org/install.html. This page covers installation on OSX, Unix and Unix-like systems, and Windows. It also gives some instructions on how to install Erlang, which is the only prerequisite to run Elixir.

How to do it…

To prototype and test the ideas using IEx, follow these steps:

  1. Start IEx by typing iex in your command line.

  2. Type some expressions and have them evaluated:

    iex(1)> a = 2 + 2
    4
    iex(2)> b = a * a
    16
    iex(3)> a + b
    20
    iex(4)>
    
  3. Define an anonymous function to add two numbers:

    iex(5)> sum = fn(a, b) -> a + b end
    Function<12.90072148/2 in :erl_eval.expr/5>
    
  4. Invoke the function to add two numbers:

    iex(6)> sum.(1,2)
    3
    
  5. Quit from IEx by pressing Ctrl + C twice.

How it works…

IEx evaluates expressions as they are typed, allowing us to get instant feedback. This allows and encourages experimenting ideas without the overhead of editing a source file and compiling it in order to see any changes made.

Note

In this recipe, we used the = operator. Unlike other languages, = is not an assignment operator but a pattern matching operator. We will get into more detail on pattern matching in the Using pattern matching and Pattern matching an HTTPoison response recipes in Chapter 2, Data Types and Structures.

In step 3, we used a dot (.) in the sum function right before the arguments, like this: sum.(1,2). The dot is used to call the anonymous function.

There's more…

It is possible to define modules inside an IEx session.

 

Loading and compiling modules


It is possible to load code from source files into an IEx session. Multiple modules may be loaded and used, allowing us to incorporate existing code into our prototyping or idea testing session.

Getting ready

In this recipe, we will be importing two files that define the Greeter and Echoer modules into our IEx session.

In the following lines, we will list the contents of these modules:

code\greeter.ex
defmodule Greeter do

  def greet(name \\ "you") do
    "Hello #{name} !"
  end

end

code/echoer.ex
defmodule Echoer do

  def echo(msg) do
    IO.puts "#{msg} ... #{msg} ...... #{msg}"
  end

end

Tip

Downloading the example code

You can download the example code files from your account at http://www.packtpub.com for all the Packt Publishing books you have purchased. If you purchased this book elsewhere, you can visit http://www.packtpub.com/support and register to have the files e-mailed directly to you.

How to do it…

We will follow these steps to load and compile the modules:

  1. Start IEx:

    iex
    
  2. Load the Greeter module defined in greeter.ex:

    iex(1)> c("greeter.ex")
    [Greeter]
    
  3. Load the Echoer module defined in echoer.ex:

    iex(2)> c("echoer.ex")
    [Echoer]
    
  4. Use the greet function defined in the Greeter module:

    iex(3)> Greeter.greet("Me")
    "Hello Me !"
    
  5. Use the echo function defined in the Echoer module:

    iex(4)> Echoer.echo("hello")
    hello ... hello ...... hello
    :ok
    
  6. Combine the functions defined in both modules:

    iex(7)> Greeter.greet("Me") |> Echoer.echo
    Hello Me ! ... Hello Me ! ...... Hello Me !
    :ok
    

Note

Some functions may have default values. They are denoted by the use of \\. In the Greeter module, the greet function is defined as def greet(name \\ "you"), which means that if we omit the argument passed to the function, it will default to you.

How it works…

When c("file_name.ex") is invoked from IEx, the file is loaded and compiled (a corresponding file with the .beam extension will be created).

The module (or modules) defined on each imported file become available. It is possible to invoke functions on these modules using the ModuleName.function_name(args) syntax.

If a module_name.beam file exists for a given module, then every time you import that module into an IEx session, you will see the following warning:

module_name.ex:1: warning: redefining module ModuleName

The warning means that a new compiled .beam file is being created, potentially redefining the module. If no changes were made to the source code, the code will be the same, although the warning is still issued.

In step 6, the pipe operator (|>) is used to simplify the code. This operator means that the output of the left operation will be fed as the first argument to the right operation.

This is equivalent to writing the following:

Echoer.echo(Greeter.greet("Me"))

There's more…

In steps 2 and 3, the greeter.ex and echoer.ex files are imported without indicating the path because they are under the same directory from where the IEx session was started.

It is possible to use relative or full paths when loading files:

  • We can use relative paths like this:

    iex(1)> c("../greeter.ex")
    
  • We can use full paths like this:

    iex(2)> c("/home/user/echoer.ex")
    

    Note

    Note that the c IEx function accepts a string as an argument.

 

Getting help and accessing documentation within IEx


Documentation is a first-class citizen in the Elixir ecosystem, so it comes as no surprise that IEx provides convenient ways to access documentation and get help without the need to leave an IEx session.

This recipe exemplifies the use of the defined help functions.

How to do it…

We will follow these steps to get help and access documentation in an IEx session:

  1. Enter h inside a running IEx session to see the help options related to the use of IEx helpers, as shown in this screenshot:

  2. If we wish, for instance, to get information regarding the c/2 function, we type h(c/2), as shown in the following screenshot:

  3. Accessing a module documentation is done by invoking h(ModuleName). In the next screenshot, we access documentation related to Enum:

  4. Getting information about a specific function inside a module is also possible by invoking h(ModuleName.function_name). The following screenshot shows the documentation for Enum.map:

How it works…

When we define modules, it is possible to use the @moduledoc and @doc annotations to define documentation related to the whole module or to a specific function in that module.

IEx parses the documentation defined with these annotations and makes it available in a convenient way so that there's no need to leave the session when help or some more information is needed.

IEx itself has several helper functions defined (refer to the first screenshot of this recipe), and among them, we find h/0 and h/1.

Note

It is common to refer to functions by their name followed by / and a number indicating the number of arguments that function takes. Therefore, h/0 is a function named h that takes 0 arguments, and h/1 is the same h function but with 1 argument.

There's more…

There are several defined functions that allow accessing information on function specifications and types (if defined). To learn more, you can use s/1 and t/1.

As an example, to get information on the types defined for the Enum module, we would use t(Enum), and to get information on the specifications, we would use s(Enum).

 

Using Erlang from Elixir


Elixir code runs in the Erlang VM. The ability to invoke Erlang code from within Elixir allows the use of resources from the entire Erlang ecosystem, and since Elixir code is compiled to the same byte code as Erlang code, there is no performance penalty.

It is also possible to include in an Elixir application the Erlang code that is already compiled.

If you take a closer look, the files we compile in IEx sessions have the .beam extension, and that's exactly the same format Erlang's compiled code gets transformed into.

Getting ready

To use Erlang code in Elixir, we start a new IEx session.

How to do it…

These are some examples of how to invoke Erlang code from Elixir:

  1. Erlang's Application module defines a function named which_applications. This function returns a list of applications being executed in an Erlang VM. This is the way to use this function from Elixir:

    iex(1)> :application.which_applications
    

    Note

    The Erlang code would be application:which_applications().

  2. To get information on any Erlang module, there is a function named module_info. To know more about the erlang module, we enter this:

    iex(2)> :erlang.module_info
    

    Note

    The Erlang code would be erlang:module_info().

How it works…

In Elixir, Erlang modules are represented as atoms. Functions in these modules are invoked in the same way as any Elixir function.

Note

In Elixir, the atom type is used as an identifier for a given value. In Ruby, the equivalent of the atom is known as the symbol.

There's more…

Existing Erlang libraries can be included in Elixir applications, widening the available options. It is also possible to choose an Erlang implementation of a module over Elixir's.

The Elixir standard library has a List module defined. The Erlang counterpart is lists.

If we wish to get the last element of a list, we could use both modules:

  • We can use Elixir's List module like this:

    List.last([1,2,3])
    
  • We can use Erlang's lists module in this manner:

    :lists.last([1,2,3])
    

    Note

    The Erlang code for this operation is lists:last([1,2,3]).

 

Inspecting your system in IEx


Sometimes, we need to take a look at what is going on in a running VM. It is useful to see which applications are open and any information about memory usage.

We will use some Erlang modules to inspect a VM instance.

Getting ready

Start a new IEx session.

How to do it…

We will follow these steps to get information on our running system:

  1. To get the currently running applications, type this:

    iex(1)> :application.which_applications
    [
      {:logger, 'logger', '0.15.1'},
      {:iex, 'iex', '0.15.1'},
      {:elixir, 'elixir', '0.15.1'}, 
      {:syntax_tools, 'Syntax tools', '1.6.15'},
      {:compiler, 'ERTS  CXC 138 10', '5.0.1'}, 
      {:crypto, 'CRYPTO', '3.4'},
      {:stdlib, 'ERTS  CXC 138 10', '2.1'}, 
      {:kernel, 'ERTS  CXC 138 10', '3.0.1'}
    ]
    

    The list that is returned contains three-element tuples. The first element is an atom identifying the application, the second element is the application description, and the third is the application version.

  2. We get information on the memory usage by running the following commands:

    iex(2)> :erlang.memory
    [total: 15474240, processes: 4958016, processes_used: 4957056, system: 10516224,
     atom: 256313, atom_used: 234423, binary: 15352, code: 6071692, ets: 399560]
    
  3. It is also possible to get memory usage for atoms, ets tables, binaries, and so on:

    iex(3)> :erlang.memory(:atom)
    256313
    

How it works…

As we saw in the previous recipe, Using Erlang from Elixir, it is possible to seamlessly call Erlang code from Elixir. Even though there is no specific Elixir code to perform these inspections, it is easy to get these abilities via Erlang libraries.

See also

  • When a GUI environment is available, there's a tool called Observer that helps to get information on an Erlang VM. Take a look at the next recipe, Inspecting your system with Observer.

 

Inspecting your system with Observer


The command line isn't the only way to get information on an Erlang VM. There is a GUI tool named Observer that allows access to information in a more convenient way.

If a GUI-enabled system is available, Observer allows us to open multiple windows with information on the whole system's statistics or even an individual process of that running system.

Getting ready

Start an IEx session.

How to do it…

To use the Observer GUI application, we will follow these steps:

  1. Start the Observer application:

    iex(1)> :observer.start
    :ok
    
  2. A new window with a tabbed interface will open, and the first information displayed shows CPU information, memory usage, system information, and statistics, as shown in the following screenshot:

  3. Select the Load Charts tab to see graphical representation of memory usage, IO, and scheduler utilization over time, as shown here:

  4. Under the Applications tab, by selecting the kernel application, it is possible to see a representation of an application process's hierarchy, as shown in this screenshot:

  5. Double-click on any of the nodes, for example, code_server. A new window will be opened with information for the specific process, as shown in the following screenshot:

 

Creating a simple application


In this recipe, we will be using Mix to create a new application.

How to do it…

To create a new Elixir application, follow these steps:

  1. In a command-line session, enter mix help to see a list of available tasks:

    > mix help
    

    Here is what the screen will look like:

  2. To generate a new application, type mix new simple_app:

    > mix new simple_app
    

    What happens next is shown in the following screenshot:

  3. Inside the simple_app directory, the generated application is ready to be started. Run iex –S mix to start the application and verify that everything is working:

    > iex -S mix
    Erlang/OTP 17 [erts-6.1] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]
    Interactive Elixir (0.15.1) - press Ctrl+C to exit (type h() ENTER for help)
    iex(1)>  
    
  4. Nothing happened. So is it working? The absence of messages in the IEx session is a good thing. This generated application behaves more like a library; there's no main function like in Java or C. To be sure that the application is responding, edit the lib/simple_app.ex file by inserting the following code:

    defmodule SimpleApp do
      def greet do
        IO.puts "Hello from Simple App!"
      end
    end
  5. Restart the application by pressing Ctrl + C twice and entering iex –S mix again.

  6. In the IEx session, enter SimpleApp.greet.

  7. You will see the following output from the application:

    iex(1)> SimpleApp.greet
    Hello from Simple App!
    :ok
    iex(2)>
    

The Elixir application is ready to be used either on your local machine or, if a node is started, it could even be used from another machine.

How it works…

The Elixir installation provides a command-line tool called Mix. Mix is a build tool. With this tool, it is possible to invoke several tasks to create applications, manage their dependencies, run them, and more.

Mix even allows the creation of custom tasks.

See also

  • To generate an OTP application with a supervisor, see the Generating a supervised application recipe.

 

Managing dependencies


One of the advantages of OTP (more information on OTP may be found in Chapter 6, OTP – Open Telecom Platform) is modularity, and it is very common to have several applications running as dependencies of one application. An application is a way to achieve modularity; in this context, we call an application something that is known in other programming languages as a library. In this recipe, we will integrate an HTTP client with a new application. We will be using the Hex package manager (http://hex.pm).

Getting ready

  1. Generate a new application with mix new manage_deps:

    > mix new manage_deps
    

    The output is shown in the following screenshot:

  2. Visit https://hex.pm/packages?search=http.

  3. We will choose HTTPoison (https://hex.pm/packages/httpoison).

How to do it…

To add a dependency to our application, we will follow these steps:

  1. Inside the manage_deps application, open mix.exs and edit the file to include HTTPoison as a dependency:

    defp deps do
        [{:httpoison, "~> 0.4"}]
    end
  2. HTTPoison must be started with our system. Add this to the started applications list by including it inside the application function:

    def application do
        [applications: [:logger, :httpoison]]
    end
  3. Save mix.exs and run mix deps.get to fetch the declared dependencies, as shown in this screenshot:

  4. Compile the dependencies by executing mix deps.compile, as shown in the following screenshot:

    Note

    Sometimes, some of the dependencies are Erlang projects, so you may get a prompt asking you to install rebar (rebar is a tool similar to Mix used in Erlang projects). Once you accept to download it, it will be available in your system and you won't have to worry about it anymore.

  5. Start your application with iex –S mix.

  6. Inside the IEx session, check whether HTTPoison is running:

    iex(1)> :application.which_applications
    [{:manage_deps, 'manage_deps', '0.0.1'},
     {:httpoison, '  Yet Another HTTP client for Elixir powered by hackney\n',
      '0.4.2'}, {:hackney, 'simple HTTP client', '0.13.1'}(…)]
    
  7. Get Google's main page using HTTPoison:

    iex(5)> HTTPoison.get("http://www.google.com")
    %HTTPoison.Response{body: "<HTML><HEAD><meta http-equiv=\"content-type\" content=\"text/html;charset=utf-8\">\n<TITLE>302 Moved</TITLE></HEAD><BODY>\n<H1>302 Moved</H1>\nThe document has moved\n<A HREF=\"http://www.google.pt/?gfe_rd=cr&amp;ei=WFAOVLvQFJSs8wfehYJg\">here</A>.\r\n</BODY></HTML>\r\n",
     headers: %{"Alternate-Protocol" => "80:quic", "Cache-Control" => "private",
       "Content-Length" => "256", "Content-Type" => "text/html; charset=UTF-8",
       "Date" => "Tue, 09 Sep 2014 00:56:56 GMT",
       "Location" => "http://www.google.pt/?gfe_rd=cr&ei=WFAOVLvQFJSs8wfehYJg",
       "Server" => "GFE/2.0"}, status_code: 302}
    

How it works…

Dependencies are preferably added using hex.pm (https://hex.pm/).

Tip

If an application doesn't yet exist in Hex, it is also possible to use a GitHub repository as a source.

To fetch a dependency from GitHub, instead of declaring the dependency with the {:httpoison, "~> 0.4"} format, the following format is used:

{:httpoison, github: " edgurgel/httpoison "} 

The local filesystem may also be configured as a source for dependencies, as follows:

 {:httpotion, path: "path/to/httpotion"}

Once the dependencies are declared inside the mix.exs file, there are Mix tasks to get, compile, and clean them. The dependencies are then fetched, and if these dependencies have more dependencies on themselves, Mix is smart enough to fetch them.

When compiling dependencies, Mix is also capable of figuring out whether any dependent application has its own dependencies and whether they need to be compiled.

Starting IEx with the –S Mix loads the Mix environment inside IEx, and the application becomes accessible.

As shown in the Inspecting your system recipe, it is possible to get a list of running applications and check whether our dependency (and its own dependencies) are running. In the particular case of HTTPoison, automatic start is ensured by adding the atom representing the application name to the list under applications ([applications: [:logger, :httpoison]]).

See also

 

Generating a supervised application


An application may be generated with a supervision tree to monitor processes. The supervision tree must be started and stopped with the application, and to do so, an application module callback must also be implemented. Mix provides a simple way to generate this type of application.

How to do it…

To generate an application with a supervision tree and an application module callback, we run mix new supervised_app –-sup in the command line. This is shown in the following screenshot:

How it works…

When mix new task is invoked with the –-sup option, although the generated application appears to be identical to the application created in the Creating a simple application recipe, a few things change, which are as follows:

supervised_app/mix.exs
def application do
  [applications: [:logger],
  mod: {SupervisedApp, []}]
end

An application module callback is added like this:

supervised_app/lib/supervised_app.ex
defmodule SupervisedApp do
  use Application
  def start(_type, _args) do
    import Supervisor.Spec, warn: false
    children = [
      # Define workers and child supervisors to be supervised
      # worker(SupervisedApp.Worker, [arg1, arg2, arg3])
    ]
    opts = [strategy: :one_for_one, name: SupervisedApp.Supervisor]
    Supervisor.start_link(children, opts)
  end
end

The Application module behavior is declared, and a start function must be defined to comply with this behavior. Inside the start function, a list of children (usually worker processes) is declared, and so are the supervision options (opts). The supervisor is then started, passing the list of processes to be supervised and the options.

See also

 

Generating umbrella applications


The "Erlang way" is to name each self-contained unit of code as an app. Sometimes, an app may be what is referred to as a library in other languages. This is a great way to achieve code reusability and modularity, but sometimes, it is convenient to treat all the apps in a project as a single entity, committing them as a whole to version control, to allow running tests, and so on. Think of an umbrella application as a container used to hold one or more applications and to make them behave as a single application.

This recipe shows how to create umbrella applications with Mix.

How to do it…

  1. Generate an umbrella application to contain other applications:

    mix new --umbrella container
    

    What happens next is shown in the following screenshot:

  2. Generate application_one and application_two inside the container/apps directory:

    > cd container/apps
    > mix new application_one
    > mix new application_two
    
  3. Modify the tests in the applications as follows:

    • Change the test in container/apps/application_one/application_one_test.exs like this:

      test "the truth on application one" do
        IO.puts "Running Application One tests"
        assert 1 + 1 == 2
      end
    • Change the test in container/apps/application_two/application_two_test.exs as shown here:

      test "the truth on application two" do
        IO.puts "Running Application Two tests"
        assert 2 - 1 == 1
      end
  4. Run the tests in all applications (inside the container directory):

    > mix test
    

    The result of these tests is shown here:

  5. Now run the tests individually. Firstly, run them for application_one as follows:

    > cd apps/application_one
    > mix test
    

    The outcome of these tests is shown in the following screenshot:

    For application_two , run them like this:

    > cd ../application_two
    > mix test
    

    The result of these tests is shown in this screenshot:

How it works…

By generating this structure of the application with subprojects under the apps directory, Elixir makes dependency management, compilation, and testing easier. It is possible to perform these tasks at the umbrella application level, affecting all the subprojects, or at each subproject level, allowing a high level of granularity.

See also

  • The Elixir Getting Started guide on dependencies and umbrella projects is available at http://elixir-lang.org/getting_started/mix_otp/7.html. It says the following:

    Remember that the runtime and the Elixir ecosystem already provide the concept of applications. As such, we expect you to frequently break your code into applications that can be organized logically, even within a single project. However, if you push every application as a separate project to a Git repository, your projects can become very hard to maintain, because now you will have to spend a lot of time managing those Git repositories rather than writing your code.

    For this reason, Mix supports "umbrella projects." Umbrella projects allow you to create one project that hosts many applications and push all of them to a single Git repository. That is exactly the style we are going to explore in the next sections.

 

Managing application configuration


Mix tasks run in a specific environment. The predefined environments are production, development, and test (prod, dev, and test). The default environment is dev. In this recipe, we will configure an application with different values for each environment. Invoking the same function will result in a different output based on the configuration.

How to do it…

To manage an application configuration, we follow these steps:

  1. Create a new application:

    > mix new config_example
    
  2. Go to the generated application directory and open config/config.exs.

  3. Replace all of the file's content with the following code:

    use Mix.Config
    
    config :config_example,
      message_one: "This is a shared message!"
    
    import_config "#{Mix.env}.exs"
  4. Create three more files under the config directory with the following code:

    • In config/dev.exs, add the following:

      use Mix.Config
      
      config :config_example,
        message_two: "I'm a development environment message!"
    • In config/prod.exs, add this code:

      use Mix.Config
      
      config :config_example,
        message_two: "I'm a production environment message!"
    • In config/test.exs, add the following:

      use Mix.Config
      
      config :config_example,
        message_two: "I'm a test environment message!"
  5. Define two module attributes in lib/config_example.ex to hold the values of message_one and message_two, as follows:

    @message_one Application.get_env(:config_example, :message_one)
    @message_two Application.get_env(:config_example, :message_two)
  6. Create a show_messages function in lib/config_example.ex, like this:

    def show_messages do
      IO.puts "Message one is: #{@message_one}"
      IO.puts "Message two is: #{@message_two}"
    end
  7. Start the application in the three different environments and see the output of the show_messages function:

    • For the development environment, start the application as follows:

      > MIX_ENV=dev iex –S mix
      iex(1)> ConfigExample.show_messages
      Message one is: This is a shared message!
      Message two is: I'm a development environment message!
      :ok
      iex(2)>
      
    • For the production environment, start the application like this:

      > MIX_ENV=prod iex –S mix
      iex(1)> ConfigExample.show_messages
      Message one is: This is a shared message!
      Message two is: I'm a production environment message!
      :ok
      iex(2)>
      
    • For the test environment, start the application as follows:

      > MIX_ENV=test iex –S mix
      iex(1)> ConfigExample.show_messages
      Message one is: This is a shared message!
      Message two is: I'm a test environment message!
      :ok
      iex(2)>
      

How it works…

When we include the last line in config.exs (import_config "#{Mix.env}.exs"), the Mix configuration is loaded from the files, in this case with the Mix environment as its name and .exs as its extension.

The configuration from the imported files will override any existing configuration (with the same key) in the config.exs file. In fact, Configuration values are merged recursively. See the example at https://github.com/alco/mix-config-example.

To access configuration values, we use Application.get_env(:app, :key).

 

Creating custom Mix tasks


Sometimes, the existing Mix tasks just aren't enough. Fortunately, Mix allows the creation of customized tasks that integrate as if they were shipped with Mix itself. In this recipe, we will create a custom Mix task that will print the Erlang VM memory status.

How to do it…

The steps required to create a custom task are as follows:

  1. Create a new file, meminfo.ex, that defines the Meminfo module inside Mix.Tasks:

    defmodule Mix.Tasks.Meminfo do
      use Mix.Task
    end
  2. Add the new task description to be displayed when mix help is invoked:

    @shortdoc "Get Erlang VM memory usage information"
  3. Add the new task module documentation:

    @moduledoc """
      A mix custom task that outputs some information regarding 
      the Erlang VM memory usage
      """
  4. Create a run/1 function:

    def run(_) do
      meminfo = :erlang.memory
      IO.puts """
      Total            #{meminfo[:total]}
      Processes        #{meminfo[:processes]}
      Processes (used) #{meminfo[:processes_used]}
      System           #{meminfo[:system]}
      Atom             #{meminfo[:atom]}
      Atom (used)      #{meminfo[:atom_used]}
      Binary           #{meminfo[:binary]}
      Code             #{meminfo[:code]}
      ETS              #{meminfo[:ets]}
      """
    end
  5. Compile the code using the Elixir compiler, elixirc:

    elixirc meminfo.ex
    

    No message should appear but a file named Elixir.Mix.Tasks.Meminfo.beam is created.

  6. Run mix help to see the new task listed and its short description:

    > mix help
    mix               # Run the default task (current: mix run)
    mix archive       # List all archives
    (…)
    mix meminfo     # Get Erlang VM memory usage information
    mix new           # Create a new Elixir project
    mix run           # Run the given file or expression
    mix test          # Run a project's tests
    iex -S mix        # Start IEx and run the default task
    
  7. Execute the custom task:

    > mix meminfo
    Total            17692216
    Processes        4778984
    Processes (used) 4777656
    System           12913232
    Atom             339441
    Atom (used)      321302
    Binary           14152
    Code             8136817
    ETS              452832
    

How it works…

Mix tasks are just modules that are declared as Mix.Tasks.<MODULENAME> with a run function defined.

In meminfo.ex, we use the Mix.Task module by declaring use Mix.Task. The use directive allows us to use a given module in the current context.

The @shortdoc attribute allows us to define a short description to display when some help on Mix or the mix.task is displayed.

The run/1 function is the place where all of the task's work is done. In this particular case, we use an Erlang function to return a keyword list with several entries, and print them for the user in a formatted way.

About the Author
  • Paulo Pereira

    Paulo A Pereira is a journalist and senior software engineer with a background in Grails and Rails. He fell in love with Elixir and has a passion for exploring new technologies and keeping himself up to date with the industry's developments. Paulo previously worked as a consultant and lead developer for Mediadigital, implementing Grails and Rails solutions, and he is currently working at Onfido Background Checks, a London-based tech start-up that is proving to be a key player in the background checking industry.

    Browse publications by this author
Latest Reviews (3 reviews total)
En comparación a otros libros del mismo tema, es el más complejo de entender y el menos estructurado. Muy mal.
Aprendi muy rapido, y muy bien explicado.
Elixir Cookbook
Unlock this book and the full library FREE for 7 days
Start now