domingo, 10 de septiembre de 2017

Empezando con Elixir 9


Composición

Ahora que sabemos cómo crear módulos y estructuras vamos a aprender cómo agregar la funcionalidad existente a ellos a través de la composición. Elixir nos proporciona una variedad de formas diferentes de interactuar con otros módulos.

alias

Nos permite alias nombres de módulo; utilizado con bastante frecuencia en código Elixir:

defmodule Sayings.Greetings do
  def basic(name), do: "Hi, #{name}"
end

defmodule Example do
  alias Sayings.Greetings

  def greeting(name), do: Greetings.basic(name)
end

# Without alias

defmodule Example do
  def greeting(name), do: Sayings.Greetings.basic(name)
end

Si hay un conflicto entre dos alias o simplemente deseamos alias a un nombre diferente por completo, podemos usar la opción: ":as"

defmodule Example do
  alias Sayings.Greetings, as: Hi

  def print_message(name), do: Hi.basic(name)
end

Incluso es posible alias múltiples módulos a la vez:

defmodule Example do
  alias Sayings.{Greetings, Farewells}
end

import

Si queremos importar funciones y macros en lugar de usar alias, podemos usar import/:

iex> last([1, 2, 3])
** (CompileError) iex:9: undefined function last/1
iex> import List
nil
iex> last([1, 2, 3])
3

Filtración

De forma predeterminada, todas las funciones y macros se importan, pero podemos filtrarlas mediante las opciones :only y :except.

Para importar funciones y macros específicas, debemos especificar los pares nombre de función y numero de parámetros a: only y :except. Comencemos importando sólo la función last/1 :

iex> import List, only: [last: 1]
iex> first([1, 2, 3])
** (CompileError) iex:13: undefined function first/1
iex> last([1, 2, 3])
3

Si importamos todo excepto last/1 e intentamos usar las mismas funciones que antes:

iex> import List, except: [last: 1]
nil
iex> first([1, 2, 3])
1
iex> last([1, 2, 3])
** (CompileError) iex:3: undefined function last/1

Hay dos átomos especiales, :functions y :macros, que importan sólo funciones y macros respectivamente:

import List, only: :functions
import List, only: :macros

require

Aunque se utiliza menos frecuentemente require/2 es importante. Requerir un módulo asegura que está compilado y cargado. Esto es muy útil cuando necesitamos acceder a las macros de un módulo:

defmodule Example do
  require SuperMacros

  SuperMacros.do_stuff
end

Si tratamos de llamar a una macro que aún no está cargada Elixir generará un error.

use

La macro "use" invoca una macro especial, llamada __using __/1, del módulo especificado. He aquí un ejemplo:

# lib/use_import_require/use_me.ex
defmodule UseImportRequire.UseMe do
  defmacro __using__(_) do
    quote do
      def use_test do
        IO.puts "use_test"
      end
    end
  end
end

y agregamos esta línea a UseImportRequire:

use UseImportRequire.UseMe

El uso de UseImportRequire.UseMe define una función use_test/0 mediante la invocación de la macro __using __/1.

Esto es todo lo que hace el uso. Sin embargo, es común que la macro __using__, a su vez, llame alias, require, o import. Esto a su vez creará alias o importaciones en el módulo de uso. Esto permite que el módulo que se utiliza para definir una política de cómo sus funciones y macros deben ser referenciados. Esto puede ser bastante flexible en que __using __/1 puede establecer referencias a otros módulos, especialmente submódulos.

El marco de Phoenix utiliza el use y __using __/1 para reducir la necesidad de alias repetitivas e import llamadas en módulos definidos por el usuario.

He aquí un ejemplo del módulo Ecto.Migration:

defmacro __using__(_) do
  quote location: :keep do
    import Ecto.Migration
    @disable_ddl_transaction false
    @before_compile Ecto.Migration
  end
end

La macro Ecto.Migration .__ using__/1 incluye una llamada de importación para que cuando utilice Ecto.Migration también importe Ecto.Migration. También configura una propiedad de módulo que asumimos que controla el comportamiento de Ecto.

Para recapitular: la macro de uso simplemente invoca la macro __using __/1 del módulo especificado. Para entender realmente qué es lo que necesita para leer la macro __using __/1.

Dejo link: https://elixirschool.com/en/lessons/basics/modules/