Elixir: sexto asalto

Sexto asalto. En esta ocasión no veremos nada del lenguaje, si no del ecosistema de Elixir. Elixir viene acompañado de unas magníficas herramientas que complementan en lenguaje de programación en sí: mix, la herramienta de construcción de aplicaciones y herramientas de testing como ExUnit y DocTests. Además de estas herramientas, exploraremos también los sitios web donde los desarrolladores alojan la mayoría de las librerías y proyectos Elixir disponibles.

Sigo con la metodología de aprendizaje explicada en el primer post sobre Elixir:

Sixth

Imagen basada en More gladiators de Hans Splinter, algunos derechos reservados, licencia: CC BY 2.0

Aprender lo suficiente para comenzar

Elixir viene con la herramienta mix, la herramienta oficial de construcción de proyectos (creación, testeo, construcción, gestión de dependencias,…). En este asalto crearemos una aplicación que nos permitirá listar los últimos n issues de cualquier proyecto de GitHub.

mix help lista los comandos disponibles. Los más interesantes podrían ser: mix run para ejecutar el proyecto, mix test para ejecutar los tests o mix new para crear uno nuevo.

Crearemos un nuevo proyecto, llamado rct_issues:

$ mix new rct_issues

Listando los ficheros y directorios que ha creado el comando, encontramos los siguientes:

Transformación: parsear la línea de comandos

La aplicación de ejemplo tomará los parámetros de la línea de comandos. Las aplicaciones Elixir consisten en una serie de transformaciones, y la primera de ellas será la de parsear la línea de comandos.

En Elixir existen una serie de convenciones:

Los primeros tests

Elixir viene con un pequeño framework de testing llamado ExUnit.

En el fichero /test/cli_test.exs escribiremos los tests para el módulo que acabamos de escribir (echar un vistazo al fichero cli_test.exs)

Transformación: obtener datos de GitHub

La siguiente transformación sería obtener datos de GitHub. Para ello necesitaremos alguna librería externa. Hay varios lugares donde buscar:

  1. Librerías propias de Eixir, en http://elixir-lang.org/docs
  2. Librerías propias de Erlang (también distribuidas con Elixir), en http://erlang.org/docs
  3. Si todo esto falla, podemos buscar en el repositorio de Hex, el gestor de dependencias de Elixir
  4. Si aún así, todo falla, siempre nos quedará Google y GitHub

El autor recomienda usar HTTPoison como librería. Esta librería se encuentra en Hex, con lo que es muy fácil incluirla en nuestro proyecto. Simplemente hay que modificar el método deps dentro del fichero /mix.exs, indicando el nombre y la versión de la librería que queremos usar:

defp deps do
  [
    { :httpoison, "~> 0.4" }
  }
end

Con el comando mix deps podremos saber el estado de las dependencias del proyecto. Con mix deps.get podremos descargar las dependencias que no estén instaladas localmente. En caso de estar instaladas, lo estarán en el directorio /deps, como proyectos Elixir, con lo que podremos navegar a través de ellas.

Ahora ya podemos usarla. Lo haremos en un nuevo módulo, escrito en /lib/rct_issues/github_issues.ex. También modificaremos el método applications de mix.exs para indicar que la dependencia HTTPoison va a ser ejecutada como una subaplicación dentro de nuestro proyecto (hablará más adelante sobre ello en el libro).

Transformación: parsear la respuesta JSON

Para la siguiente transformación incluiremos una dependencia que proviene del mundo Erlang. mix es capaz de incluir dependencias de muy diversas fuentes, Erlan entre ellas. Se añade la librería jsx, como dependencia del proyecto. Añadir la línea { :jsx, "~> 2.0" } al fichero mix.exs y ejecutar el comando mix deps.get para instalarla localmente.

Modificaremos nuestro módulo que debe parsear la respuesta, lib/rct_issues/github_issues.ex:

def handle_response(%{status_code: 200, body: body}) do
  { :ok, :jsx.decode(body) }
end          

def handle_response(%{status_code:   _, body: body}) do
  { :error, :jsx.decode(body) }
end          

Configuración de la aplicación

Cuando creamos el proyecto con mix, éste crea un directorio de configuración, config/, con el fichero config.exs, donde podremos escribir ciertas configuraciones de nuestro proyecto. Cada línea de configuración suele ser un registro de clave valor, por ejemplo, para nuestro proyecto añadiríamos:

use Mix.Config
config :rct_issues, github_url: "https://api.github.com"

Más adelante, podremos usar este valor configurado gracias al módulo Application, así

# crea una variable de clase llamada github_url
@github_url Application.get_env(:rct_issues, :github_url)

Construir un ejecutable

Para ello es necesario modificar el fichero mix.exs, para configurar la herramienta escript y poder indicarle el módulo principal de la aplicación que se va a construir, el cual debe de tener un método llamado main.

Para construir, simplemente ejecutar el comando:

mix escript.build

Y tendremos un ejecutable que podremos ejecutar como cualquier otra aplicación de consola de Unix/Linux

Ejecutando los comentarios

¿Cómo? ¿Ejecutar los comentarios? No te preocupes, Elixir puede ejecutar ciertos comentarios como si fueran tests. En realidad, ejecuta comentarios escritos en cierta forma como si fueran sesiones de la herramienta iex. Esto sí que es documentación ejecutable. Simplemente, espectacular.

Un comentario del tipo:

@doc """   
Given a list of rows, where each row contains a keyed list
of columns, return a list containing lists of the data in
each column. The `headers` parameter contains the
list of columns to extract

## Example 

    iex> list = [Enum.into([{"a", "1"},{"b", "2"},{"c", "3"}], HashDict.new),
    ...>         Enum.into([{"a", "4"},{"b", "5"},{"c", "6"}], HashDict.new)]

    iex> Issues.TableFormatter.split_into_columns(list, [ "a", "b", "c" ])
    [ ["1", "4"], ["2", "5"], ["3", "6"] ]
"""        
def split_into_columns(rows, headers) do
# ...

Creamos un nuevo fichero de tests en test/doc_test.exs:

defmodule DocTest do
  use ExUnit.Case
  doctest Issues.TableFormatter
end  

Donde Issues.TableFormatter es el módulo donde hemos incluido el comentario ejecutable. Podemos lanzar los comentarios testeables con los comandos mix test test/doc_test.exs o simplemente mix test.

Para crear la documentación del proyecto, está la herramienta ExDoc, similar a JavaDoc. Para ello hay que añadirlo como dependencia del proyecto en el fichero mix.exs:

defp deps do
[
# ...
  { :ex_doc, github: "elixir-lang/ex_doc" },
# ...
]
end

Para generarlos, instalar la dependencia con mix deps.get, y generar la documentación con mix docs.

Experimentar, jugar, buscar puntos desconocidos, hacerse preguntas

Aprender lo suficiente para hacer algo de utilidad

Enseñar lo aprendido, y repetir desde el paso 7

Aquí está, este post, mis notas, mis pensamientos, mis dudas y mi código. Hasta el siguiente asalto.