in Review, tutorial

Building an Elixir CLI application

Elixir-lang is a dynamic, functional programming language which runs on top of the erlang VM. Running on beam(VM) it comes with all the goodies like low-latency and ease of building fault-tolerant distributed systems.

Elixir comes with excellent tooling and getting started with a new project is a breeze with mix. Mix is a build tool that ships with Elixir that provides tasks for creating, compiling, testing your application, managing its dependencies and much more.

Mix creates a new project with appropriate readme a gitignore the lib directory (all your source code would live here) and a test directory.

➜  mix new elixir_calc
* creating README.md
* creating .gitignore
* creating mix.exs
* creating config
* creating config/config.exs
* creating lib
* creating lib/elixir_calc.ex
* creating test
* creating test/test_helper.exs
* creating test/elixir_calc_test.exs

Your Mix project was created successfully.
You can use "mix" to compile it, test it, and more:

    cd elixir_calc
    mix test

Run "mix help" for more commands.

The directory structure should look more or less like below.

➜  tree
.
├── README.md
├── config
│   └── config.exs
├── lib
│   └── elixir_calc.ex
├── mix.exs
└── test
    ├── elixir_calc_test.exs
    └── test_helper.exs

3 directories, 6 files

mix.exs is the file that holds the metadata and dependency of the project. We use Escript to build an executable. Escript requires a module having a main function which will be the entry point of the application.

# mix.exs
defmodule ElixirCalc.Mixfile do
  use Mix.Project

  def project do
    [app: :elixir_calc,
     version: "0.1.0",
     elixir: "~> 1.3",
     build_embedded: Mix.env == :prod,
     start_permanent: Mix.env == :prod,
     escript: [main_module: ElixirCalc],
     deps: deps()]
  end
  ...
end

Let’s do the obligatory example of hello world but instead, we’ll print “Hello ” followed by the arguments.

# lib/elixir_calc.es
defmodule ElixirCalc do
    def main(args) do
        arg_string = Enum.join(args, " ")
        IO.puts "Hello #{arg_string}!"
    end
end

 

mix escript.build creates an executable binary

Now let’s do something interesting, well build a which calculates the nth Fibonacci number (complicated huh!).
We use OptionParser to parse the arguments. OptionParser is a nifty library for parsing switches and arguments.

# lib/elixir_calc.es
defmodule ElixirCalc do

  defmodule Parser do
    def parse(args) do
      {options, args, _} = OptionParser.parse(args)
      {options, args}
    end

    def parse_args({[fib: x], _}) do
      IO.puts x |> String.to_integer |> ElixirCalc.Calculator.fib
    end
  end

  def main(args) do
    args
    |> Parser.parse
    |> Parser.parse_args
  end
end

Next, we define the actual Calculator module which calculates Fibonacci sequence.
Below we use pattern matching a common pattern in functional programming to define the fib function.

# lib/calculator/calculator.ex
defmodule ElixirCalc.Calculator do
  def fib(0) do 0 end
  def fib(1) do 1 end
  def fib(n) do
    fib(n-1) + fib(n-2)
  end
end

Writing and running tests are pretty easy with mix and ExUnit. ExUnit is a test-unit based framework that ships with Elixir

# tests/elixir_calc_tests.exs
defmodule ElixirCalcTest do
  use ExUnit.Case
  doctest ElixirCalc

  test "fibonacci of 1 is 1" do
    assert ElixirCalc.Calculator.fib(1) == 1
  end

  test "fibonacci of 2 is 1" do
    assert ElixirCalc.Calculator.fib(2) == 1
  end

  test "fibonacci of 10 is 55" do
    assert ElixirCalc.Calculator.fib(10) == 55
  end
end

mix test runs the test suite

Elixir provides another way of defining tests with Doctests – a pretty cool way of writing documentation and test at the same time

All of the above code can be found on github

Write a Comment

Comment