Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adds composition lesson translation to spanish
- Loading branch information
1 parent
9794004
commit 561ae1b
Showing
1 changed file
with
239 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,239 @@ | ||
--- | ||
layout: page | ||
title: Composición | ||
category: basics | ||
order: 8 | ||
lang: es | ||
--- | ||
|
||
Sabemos por experiencia que es revoltoso tener nuestras funciones en el mismo archivo y alcance. En esta sección cubriremos cómo agrupar funciones y definir un mapa especializado conocido como estructura (struct), con el propósito de organizar nuestro código de manera eficiente. | ||
|
||
## Tabla de contenidos | ||
|
||
- [Módulos](#modules) | ||
- [Atributos de módulo](#module-attributes) | ||
- [Estructuras](#structs) | ||
- [Composición](#composition) | ||
- [`alias`](#alias) | ||
- [`import`](#import) | ||
- [`require`](#require) | ||
- [`use`](#use) | ||
|
||
## Modulos | ||
|
||
Los módulos son la mejor manera de organizar funciones en un namespace. En adición a las funciones agrupativas, los módulos nos permiten definir funciones nombradas y privadas, las cuales cubrimos en la lección pasada | ||
|
||
Démosle un vistazo a un ejemplo básico: | ||
|
||
``` elixir | ||
defmodule Example do | ||
def greeting(name) do | ||
~s(Hello #{name}.) | ||
end | ||
end | ||
|
||
iex> Example.greeting "Sean" | ||
"Hello Sean." | ||
``` | ||
|
||
Es posible anidar módulos en Elixir, permitiendonos ser explícitos nombrando nuestra funcionalidad. | ||
|
||
|
||
```elixir | ||
defmodule Example.Greetings do | ||
def morning(name) do | ||
"Good morning #{name}." | ||
end | ||
|
||
def evening(name) do | ||
"Good night #{name}." | ||
end | ||
end | ||
|
||
iex> Example.Greetings.morning "Sean" | ||
"Good morning Sean." | ||
``` | ||
|
||
### Atributos de un Módulo | ||
|
||
Los atributos de un módulo son comúnmente usados como constantes en Elixir. | ||
Démosle un vistazo al siguiente ejemplo: | ||
|
||
```elixir | ||
defmodule Example do | ||
@greeting "Hello" | ||
|
||
def greeting(name) do | ||
~s(#{@greeting} #{name}.) | ||
end | ||
end | ||
``` | ||
|
||
Es importante notar que hay atributos reservados en Elixir. Los tres más comunes son: | ||
|
||
|
||
+ `moduledoc` — Documenta el módulo actual. | ||
+ `doc` — Documentación para funciones y macros. | ||
+ `behaviour` — Usa OTP o comportamiento definido por el usuario. | ||
|
||
## Estructuras | ||
|
||
Las estructuras son mapas especiales con un conjunto definido de llaves y valores default. Deben ser definidas dentro de un módulo, y tomarán su nombre. Es común que una estructura sea definida únicamente dentro de un módulo. | ||
|
||
Para definir una estructura utilizamos `defstruct` junto con una lista de llaves y valores por defecto: | ||
|
||
```elixir | ||
defmodule Example.User do | ||
defstruct name: "Sean", roles: [] | ||
end | ||
``` | ||
|
||
Ahora, creemos estructuras: | ||
|
||
```elixir | ||
iex> %Example.User{} | ||
%Example.User{name: "Sean", roles: []} | ||
|
||
iex> %Example.User{name: "Steve"} | ||
%Example.User{name: "Steve", roles: []} | ||
|
||
iex> %Example.User{name: "Steve", roles: [:admin, :owner]} | ||
%Example.User{name: "Steve", roles: [:admin, :owner]} | ||
``` | ||
|
||
Podemos actualizar una estructura justo como lo hacemos con un mapa: | ||
|
||
```elixir | ||
iex> steve = %Example.User{name: "Steve", roles: [:admin, :owner]} | ||
%Example.User{name: "Steve", roles: [:admin, :owner]} | ||
iex> sean = %{steve | name: "Sean"} | ||
%Example.User{name: "Sean", roles: [:admin, :owner]} | ||
``` | ||
|
||
Algo muy importante es que podemos hacer match entre estructuras y mapas: | ||
|
||
```elixir | ||
iex> %{name: "Sean"} = sean | ||
%Example.User{name: "Sean", roles: [:admin, :owner]} | ||
``` | ||
|
||
## Composición | ||
|
||
Ahora que sabemos cómo crear módulos y estrucutras, aprendamos cómo incluir funcionalidad existente dentro de ellos con composición. | ||
Elixir nos provee una variedad de diferentes formas para interactuar con otros módulos, démosle un vistazo a lo que tenemos disponible: | ||
|
||
### `alias` | ||
|
||
Nos permite darle un alias a los módulos, que son usados frecuentemente en Elixir. | ||
|
||
```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: Saying.Greetings.basic(name) | ||
end | ||
``` | ||
|
||
Si hay un conflicto entre dos alias o quieres que los alias tomen un nombre diferente, podemos utilizar la opción `:as` | ||
|
||
```elixir | ||
defmodule Example do | ||
alias Sayings.Greetings, as: Hi | ||
|
||
def print_message(name), do: Hi.basic(name) | ||
end | ||
``` | ||
|
||
Es posible dar multiples alias a un módulo a la vez: | ||
|
||
```elixir | ||
defmodule Example do | ||
alias Sayings.{Greetings, Farewells} | ||
end | ||
``` | ||
|
||
### `import` | ||
|
||
Si queremos importar las funciones y macros de un módulo, más que sólo darle un alias, podemos utilizar `import/` | ||
|
||
```elixir | ||
iex> last([1, 2, 3]) | ||
** (CompileError) iex:9: undefined function last/1 | ||
iex> import List | ||
nil | ||
iex> last([1, 2, 3]) | ||
3 | ||
``` | ||
|
||
### Filtrado | ||
|
||
Por default, todas las funciones y macros son importadas, pero podemos filtarlas utilizando las opciones `:only` y `:except` | ||
Empecemos por importar únicamente la función `last/1` | ||
|
||
```elixir | ||
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 utilizar la misma función: | ||
|
||
```elixir | ||
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 | ||
``` | ||
|
||
En adición a los pares nombre/aridad, hay dos atomos especiales, `:functions` y `:macros`, las cuales importan únicamente funciones y macros, respectivamente: | ||
|
||
```elixir | ||
import List, only: :functions | ||
import List, only: :macros | ||
``` | ||
|
||
### `require` | ||
|
||
Aunque `require/2` no es usado frecuentemente, es bastante importante. Haciendo `require` de un módulo asegura que está compilado y cargado. Esto es muy útil cuando necesitamos acceso a las macros de un módulo: | ||
|
||
```elixir | ||
defmodule Example do | ||
require SuperMacros | ||
|
||
SuperMacros.do_stuff | ||
end | ||
``` | ||
|
||
Si intentamos hacer un llamado a una macro que no está cargada aún, Elixir arrojará un error. | ||
|
||
### `use` | ||
|
||
Utiliza el módulo en el contexto actual. Esto es particularmente utilizado cuando un módulo necesita realizar algún setup. Llamando `use`, invocamos el hook `__using__` dentro del módulo, dándole al módulo una oportunidad para modificar nuestro contexto actual. | ||
|
||
```elixir | ||
defmodule MyModule do | ||
defmacro __using__(opts) do | ||
quote do | ||
import MyModule.Foo | ||
import MyModule.Bar | ||
import MyModule.Baz | ||
|
||
alias MyModule.Repo | ||
end | ||
end | ||
end | ||
``` |