12: HAML: Haml - LPC-Ltda/Ruby-on-Rails GitHub Wiki

HAML nos dio una gran forma en la que también se pueden hacer visitas. Se ve un poco críptico al principio, pero no dejes que te inquiete. Una vez has internalizado el significado de %, # y . todo estará bien (y usted ya sabe la mayoría de CSS)... Adicionalmente, no puedo dejar de tener respeto por un canadiense que se las arregla para jurar más de lo que hice durante mi diatriba de vendedor y beber cerveza al mismo tiempo. Un ejemplo perfecto de la diversidad en la comunidad Rails. Una parte muy importante de lo que nos hace espacial. -David hablando acerca de Haml y Hampton Catlin(http://david.heinemeierhansson/arc/2006_09.html)

Haml (http://haml.info) es un motor de templating de HTML "sensible a los espacios en blanco" que usa la indentación para determinar la jerarquía de un documento HTML. Haml fue creado porque su creador. Hampton Catlin, estaba cansado de tener que tipear markup y y deseo que toda la salida de su código estuviera hermosamente formateada. Lo que él inventó fue un nuevo motor de template que removió un montón de ruido repetitivo, tales como las llaves triangulares (de ERb), y terminó con la necesidad de cerrar los bloques y los tags HTML

Amamos Haml es verdaeramente mínimo, permitiéndole al desarrollador focalizarse simplemente en la estructura de la página y no en su contenido. Hoy día es común obtener vistas lógicas de sus templates, pero esa directiva ha sido el principio guía de Haml desde el comienzo. De acuerdo al Ruby Survey del 2012 (http://survey.hamptoncatlin.com/survey/stats) un 36.96% de los Rubistas prefieren Haml sobre ERb, y el 15.84% lo demanda en sus proyectos. Haml es un estándar en varias agencias de profesionales Ruby, tales como Hashrocket, Envy Labs, Remarkable Labs, y Astralis.

En este capítulo cubriremos los fundamentos de Haml, desde la creación de elementos HTML a usar filtros para crear otro tipo de contenido textual embuido en su docuemento.

##12.1 Partamos

Para comenzar a usar el lenguaje de template Haml en luar de ERb en su proyecto, primero agregue la gema haml-rails a su archivo Gamfile y corra bundle install.

# Gemfile
gem 'haml-rails'

El beneficio de usar haml-rails en lugar de sólo haml es que agrega soporte para características específicas de Rails. Por ejemplo, cuando usted usa un generador de controller o scaffold, haml-rails generará vistas Haml en lugar de usar el ERb de Rails por defecto. La gema haml-rails también configura templates Haml para trabajar con el lector de cache de Rails 4 en alto nivel.

##12.2 Lo básico

En este sección, cubriremos cómo crear elementos HTML y atributos usando Haml.

###12.2.1 Creando un elemento

Para crear un elemento HTML en Haml, uno simplemente necesita prefijar con un % el nombre del elemento. El nombre del elemento puede ser un string, permitiéndole usar los elementos recientemente agregados a HTML5, como un header.

Haml

%header

HTML

<header>content</header>

Haml manejará automáticamente la generación de la apertura y cierre del tag para el elemento en la compilación. Esto no sólo hace los templates más concisos y limpios, también elimina errores comunes como olvidar o no cerrar un tag HTML.

###12.2.2 Atributos

Los atributos en Haml son definidos usando dos estilos. El primer estilo involucra la definición de atributos entre llaves ({}). Estas "llaves" de atributos son como los hash de Ruby y son evaluados como tal. La razón de esto es que, las variables locales y la lógica Ruby puede ser usada cuando se definen atributos.

%a{ title: @article.title, href: article_path(@article) } Title

El segundo estilo sigue la forma más tradicional de definir atributos HTML usando parentesis, no te que los atributos están separados por espacios en blanco y no por comas.

%a([email protected] href=article_path(@article)) Title

Atributos multi-línea Los hashes de atributos pueden ser separados en múltiples líneas por legibilidad. Todas las líneas nuevas deben ser ubicadas después de la coma:

%a{ title: @article.title,
       href: article_path(@article) } Title

12.2.2.1 Atributos de data

Introducido en HTML5, los atributos de data nos permiten embuir data personalizada en un elemento HTML prefijando un atributo con data-. En lugar de llenar de basura el hash de atributos con múltiples llaves de atributos prefijadas con data-, uno puede definir todos sus atributos data en un hash anidado asociado con la clave :data, así:

Haml

%article{ data: { author_id: 1 } } Lorem Ipsum...

HTML

<article data-author-id='1'> Lorem Ipsum... </article>

Note que los underscores son automáticamente reemplazados por guiones. No es lo que usted deseaba, pero usted puede cambiar este comportamiento seteando la opción de configuración Haml hyphenate_data_attrs a false. (Las opciones de configuración de Haml son cubiertas después en este capítulo).

Es posible también anidar hash de data a más de un nivel para reducir la verborrea cuando los atributos comparten la misma raíz.

Haml

%article{ data: { author: { id: 1, name: "Kevin Wu" } } } Lorem Ipsum...

HTML

<article data-author-id='123' data-author-name="Kevin Wu"> Lorem Ipsum... </article>

12.2.2.2 Atributos booleanos

En HTML, existen ciertos atributos que no tienen un valor asociado como ellos, como un required.

<input type="text" required>

A ellos nos referimos como atributos booleanos en Haml, ya que su valor no importa -sólo si están o no presentes. Para representar estos atributos en la sintaxis de atributos estilo hash, setee el valor del atributo a true.

%input(type="text", required: true)

De otra forma, si usted está utilizando la sintaxis de atributo estilo HTML, un atributo booleano no debe ser seteado.

%input(type="text" required)

XHTML Si el formato de Haml es seteado a :xhtml, los atributos booleanos serán seteados a sus nombre. Para ilustrar, dado el ejemplo previo, Haml rendereará el sigueinte HTML:

<input type="text" required="required" />

###12.2.3 Clases e IDs

Haml fue diseñado para promover el principio DRY (no repetir código innecesariamente). Como tal, provee una sintaxis abreviada para agregar atributos de clase e ids a un elemento. Esta sintaxis es prestada de CSS, donde los ids son representados por un (#) y las clases por un (.). Ambos signos deben ser puestos inmediatamente después del elemento y antes del hash de atributos.

Haml

#content
  .entry.featured
    %h3.title Haml
    %p.body Lorem Ipsum

HTML

<div id='content'>
  <div class='entry featured'>
    <h3 class='title'> Haml</h3>
    <p class='body'>Lorem Ipsum...</p>
  </div>
</div>

Como el ejemplo previo muestra, pueden ser especificados múltiples nombres de clase similarmente a CSS al encadenar los nombres de clases con un punto. En un escenario un poco más complicado, las clases estilo CSS abreviado pueden ser combinadas con atributos. Ambos valores se mezclan juntos cuando se compilan hacia HTML.

Haml

%article.featured{ class: @article.visibility }

HTML

<article class='feature visible'>...</article>

Haml tiene algunos buenos trucos bajo la manga para tratar con clases e ids complejos. Por ejemplo, un arreglo de nombres de clase puede ser automáticamente joineado con un espacio.

Haml

%article{ class: [@article.visibility, @article.category] }

HTML

<article class='visible breakingnews'>...</article>

Un arreglo de ids será joineado con un underscore.

Haml

%article{ id: [@article.category, :article, @article.id] }

HTML

<article id='sports_article_1234'>...</article>

Note que el arreglo es aplanado y cualquier elemento que evalue como falso o nil será botado automáticamente. Esto le permite hacer trucos muy inteligentes al posible costo de la legibilidad y mentenibilidad.

%article{ class: [@article.visibility, @article.published_at < 4.hors.ago && 'breakingnews'] }

En el ejemplo, si el artículo fue publicado hace menos de cuatro horas, entonces breakingnews será agregado a una de las clases CSS de el elemento. Mientras estamos en el tema, recuerde que es aconsejable migrar este tipo de lógica dentro de sus clases Ruby. En este ejemplo particular, podemos dar a la class Article (una de sus clases presentadoras o decoradoras) un metodo breakingnews? en lugar de meter en la línea la lógica del negocio.

def breaking?
  published_at < 4.hours.ago
end

%article{ class: [@article.visibility, @article.breaking? && 'breakingnews'] }

Si breaking? retorna falso, entonces la expresión Ruby cortocicuitea a falso, y Haml ignora ese nombre de clase particular.

###12.2.4 Divs implícitos

Los elementos por defecto para Haml son los divs. Ya que ellos son usados frecuentemente en le markup, uno puede simplemente definir un div con una clase o id usando . o # respectivamente.

Haml

#container
  .content Lorem Ipsum

HTML

<div id="container">
  <div class="content">
    Lorem Ipsum...
  <div>
</div>

Creación implícita de divs: No tener que especificar tags divs explícitamente le ayuda a sus markup a ser más semánticos desde el principio, poniendo el foco en la intención del div en lugar de tratarlo como otro contenedor markup. Es también una de las principales razones por la que recomiendo Haml sobre ERb. Creemos que los templates Haml disminuyen la carga mental comnicando la estructura de su DOM en forma que mapea limpiamente al CSS que aplicaremos al documento.

###12.2.5 Tags vacíos

En HTML, hay ciertos elementos que no requieren yn tag de cierre, como br (http://www.colorglare.com/2014/02/03/to-close-or-not-to-close.html). Por defecto, Haml no agregará un tag de cierre a los siguientes tags:

  • area
  • base
  • br
  • col
  • hr
  • img
  • input
  • link
  • meta
  • param

Para ilustrar, considere el siguiente ejemplo:

%hr

rendereará en HTML

<hr>

o XHTML

<hr />

Agregar un slash hacia atrás (/) al fin de la definición del tag causa que Haml lo trate como un elemento vacío. La lista de tags vacíos que usa Haml puede ser sobre-escrita usando el seteo de configuración autoclose. Las opciones de configuración de Haml son cubiertas después en este capitulo.

##12.3 Doctype

Un doctype debe ser el primer item en cualquier documento HTML. Al inlcuir los caracteres !!! al comienzo del template, Haml generará automáticamente un doctype basado en la opción de configuración :format, seteado a :html5 por defecto. Al agregar !!! a un template resultará el siguiente HTML:

<!DOCTYPE html>

Haml también le permite especificar un doctype específico despues del !!!. Una completa lista de los doctypes soportados puede ser encontrada en el sitio web de referencia de Haml (http://haml.info/docs/yardoc/file.REFERENCE.html#doctype).

##12.4 Comentarios

Hay dos tipos de comentarios en Haml: los que aparecen rendereados en HTML y los que no.

###12.4.1 Comentarios HTML

Para dejar un comentario que sea rendereado por Haml, ponga un slash hacia adelante al comienzo de la línea que usted desea comentada. Caalquier cosa anidada bajo esa línea también será comentado.

/ Some comments

<!-- Some comment -->

Usted puede usar esta característica para producir comentarios condicionales de Internet Explorer poniendo el sufija a la condición en paréntesis cuadrados así:

/[if lt IE 9]

###12.4.2 Comentarios Haml

Junto a los comentarios condicionales para elegir Internet Explorer, los comentarios que usted deja en su markup se entienden como un mensaje a otros desarrolladores que trabajan con el template. Estos mensajes no pueden ser rendereados en el browser, porque son especificos para su equipo. En Haml, comenzar una línea con -# le asegura que el texto que sigue al signo # no será rendereado.

Haml

-# Some important comment
$h1 The Rails 4 Way

HTML

<h1>The Rails 4 Way</h1>

Si cualquier texto es anidado bajo este tipo de comentario en silencio, también será omitido.

##12.5 Evaluando código Ruby

Algo parecido a ERb, al usar un caracter igual (=) resulta en que Haml evalúa el código Ruby que sigue al caracter y pone el resultado dentro del documento.

Haml

%p= %w(foo bar).join(' ')

HTML

<p>foo bar</p>

Alternativamente, usando el caracter guión (-) evalúa el código pero no inserta el resultado en el documento resultante. Esto es comunmente usado en con las instrucciones if/else y loops.

- if flash.notice
  .notice= flash.notice 

Note que que los bloques ruby no necesitan ser explícitamente cerrados en Haml. Como vimos en el ejemplo previo, cualquier indentación bajo un comando de evaluación Ruby indica un bloque.

No use - para setear variables. Si usted se sorprende haciendo eso, es una indicación de que necesita crear algún objeto formulario o vista, como presentadores o decoradores.

Las líneas en el código Ruby pueden ser rotas en múltiples líneas siempre y cuando cada línea excepto la última termine en coma.

= image_tag post.image_url,
    class: 'featured_image'

###12.5.1 Interpolación

El código Ruby puede ser interpolado en dos formas en Haml: en la línea con texto plano usando #{} o usando interpolación de strings en combinación con =. Para ilustrar, las siguientes dos líneas de código Haml ejemplo son equivalentes:

%p By: #{post.author_name}
%p= "By #{post.author_name}"

###12.5.2 Escaping/Unescaping HTML

Para cumplir con el esquema de protección por defecto de Rails XSS, Haml sanitizará cualquier caracter sensitivo HTML de la salida de =. Esto resulta en que cualquier llamado = se comporta como &=.

Haml

&= "Cookies & Cream"

HTML

Cookies &amp Cream

Alternativamente, para unescape HTML con Haml, simplemente use != en lugar de =. Si la opción de configuración Haml escape_html esta seteada a false, entonces cualquier llamada a = se comportará como !=. (usted probablemente nunca deseará hacer esto.)

haml

!= "Remember the awful <blink> tag?

HTML

Remember the awful <blink> tag?

###12.5.3 Escaping el primer caracter de una línea

En raras ocasiones, usted puede partir una línea de su template con un caracter = que podría ser normalmente interpretado. Usted puede escapar este primer caracter de una línea usando un backslash.

Haml

%p
  \= equality for all =

HTML

<p>
  = equality for all =
</p>

###12.5.4 Declaraciones multilinea

Haml está pensado para ser usados para layouts y diseño. Aunque uno puede técnicamente escribir declaraciones multilinea dentro de un template, los creadores de Haml hicieron esto intencionalmente torpe para desalentar a la gente que lo hace.

Si usted por alguna razón necesita declaraciones que necesitan múltiples líneas en un template, lo puede hacer agregando multiples operadores | al final de cada línea.

#content
  %p= h(|
    "white possible to write" +              |
    "multiline Ruby code" +                  |
    "it is not the Haml way," +              |
    "as you should aliminate as much Ruby" + |
    "in your views as possible.")            |

Recomendamos sacar las declaraciones multilinea en helpers, decorators o presenters.

##12.6 Helpers

Haml provee una variedad de helpers que son útiles para el desarrollo día a día, como crear una lista de items para cada item en una colección y setear ids y clases CSS basados en un modelo o controlador.

###12.6.1 Referencia a objeto []

Dado un objeto, como una instancia Active Record, Haml puede producir como salida un elemento con los atributos id y class seteados para ese objeto vía el operador []. Por ejemplo, asumimos que @post es una instancia de una clase Post con un valir id de 1, entonces el código del template

%li[@post]
  %h4= @post.title
  = @post.excerp

renderea

<li class='post' id='post_1'>...</li>

Esto es similar a usar el helper de Rails div_for y content_tag_for, cubierto en el Capitulo 11, "Todo acerca de los Helpers".

###12.6.2 page_class

Retorna el nombre del controlador y acción actuales usados con el atributo class de un elemento HTML. Esto es comúnmente usado con el elemento body para permitir la fácil definición de estilos basados en un particular controlador-accion. Para ilustrar, asumamos que el controlador actual es PostController y la acción es index.

%body{ class: page_class }

renderea

<body class='posts index'>

###12.6.3 `list_of(enum, opts = {}) { |item| ... }

Dado un objeto Enumerable y un block, el método list_of iterará y producirá (yield) les resultados del block en elementos <li> secuenciales.

[Haml]

%ul
  = list_of [1, 2, 3] do |item|
    Number #{item}

[HTML]

<ul>
  <li>Number 1</li>
  <li>Number 2</li>
  <li>Number 3</li>
</ul>

##12.7 Filtros

Haml viene con una colección de filtros que le parmiten pasar bloques arbitrarios de cotenido de text como input a otro procesador, con la salida resultante insertada dentro del documento. La sintaxis para usar un filtro son dos puntos ":" seguidos por el nombre del filtro. Por ejemplo, para usar el filtro markdown,

:markdown
  # The Rails 4 Way

  Some awesome **Rails**-related content.

rendererea

<h1>The Rails 4 Way</h1>

<p>Some awesome <strong>Rails</strong>-related content.</p

Aquí hay una tabla de todos los filtros que Haml soporta por defecto:

[Tabla 12.1. Filtros Haml por defecto]

Filtro Haml Descripción
:cdata Rodea el texto filtrado con tags CDATA
:coffee Compila el texto filtrado a JavaScript usando CoffeeScript
:css Rodea el texto filtrado con tags "style"
:ERb Parsea el texto filtrado con ERb. Todo el código Ruby embuido es evaluado en el mismo contexto del template Haml
:escaped Escapa el texto filtrado
:javascript Rodea el texto filtrado con tags "script"
:less Compila el texto filtrado a CSS usando Less
:markdown Parsea el texto filtrado con Markdown
:plain No parsea el texto filtrado. Puede ser usado para insertar segmentos de HTML sin que pase por Haml
:preserve Inserta el texto filtrado preservando los espacios en blanco
:ruby Parsea el texto filtrado con el intérprete Ruby. El código Ruby es evaluado en el mismo contexto que el template Haml
:sass Compila el texto filtrado a CSS usando Sass
:scss Lo mismo que el filtro :sass, excepto que usa la sintaxis SCSS para producir la salida CSS

Algunos filtros requieren que gemas externas se agreguen a su Gemfile para poder funcionar. Por ejemplo, el filtro :markdown requiere una gema markdown, como redcarpet.

##12.8 Haml y el contenido

En el blog de Chris Eppstein posteo "Haml Sucks for Content" (http://chriseppstein.github.io/blog/2010/02/08/haml-sucks-for-content), él establece su opinión sobre por que uno no debe usar Haml para construir contenido:

El uso de Haml de la sintaxis CSS para nombres de IDs y clases puede ser muy clara: El markup que usted escribe en Haml puede tomar sus estilos de sus stylesheets. Por el contrario, el contenido no tiene usualmente un estilo específico -debe usar tags para ello.

Escencialmente lo que Chris intenta convenir es no usar la sintaxis nativa de Haml para crea otra cosa que no sea el markup HTML esqueleto (o estructura). Use los filtros para el contenido que se lee entrelíneas, así como este ejemplo usa el filtro :markdown.

%p
  Do
  %strong not
  use
  %a{ href: "http://haml.info" } Haml
  for content

es equivalente al siguiente markdown dentro de un filtro:

:markdown
  Do **not** use [Haml](http://haml.info) for content.

Nos gusta esta idea pero admitimos que su cuentakilómetros puede variar. Esto realmente depende del tipo de proyecto en que usted está trabajando y de las capacidadades de la persona que mantendrá las fuentes de templates Haml.

##12.9 Opciones de configuración

Haml provee varias opciones de configuración para controlar exactamente como el markup será rendereado. Las opciones pueden ser seteadas en al hash Haml::Template.options en el inicializador de Rails.

# config/initializers/haml.rb
Haml::Template.options[:format] = :html5

###12.9.1 autoclose

La opción autoclose acepta un arreglo de todos los tags que Haml debe auto-cerrar si no se presenta más contenido. Por defecto es ['meta', 'img', 'link', 'br', 'hr', 'input', 'area', 'param', 'col', 'base'].

###12.9.2 cdata

Determina si Haml incluirá secciones CDATA rodeando los bloques JavaScript y CSS cuando usemos los filtros :javascript y :css respectivamente.

Cuando el :format es seteado a :html por defecto es false. Si el :format es :xhtml, cdata siempre será seteado a true y no puede ser sobrescrito.

Esta opción también afecta los filtros * :sass, * :scss, * :less y * :coffeescript.

###12.9.3 compiler_class

Usamos compiler class cuando compilamos Haml a HTML, Por defecto es Haml::Compiler

###12.9.4 Encoding

El encoding por defecto para salida HTML es Encoding.default_internal. Si no es seteado, por defecto es el encoding del emplate Haml.

la opción encoding puede ser seteada a un string o a un objeto Encoding.

###12.9.5 scape_attrs

Es seteada a true por defecto, escapa todos os caracteres sensibles a HTML en los atributos.

###12.9.6 scape_html

Cuando Haml es usado con un proyecto Rails, la opción scape_html es automáticamente seteada a true para coincidir con el schema de protección XSS de Rails. Esto causa que = se comporte como &= en los templates de Haml.

###12.9.7 format

Especifica el formato de salida de un template Haml. Por defecto, es seteado a html5.

Otras opciones incluidas son:

  • :html4
  • xhtml. Lo cual causa que Haml automaticamente genere tags autocerrados y envuelva la salida de los filtros JavaScript y CSS dentro de CDATA.

###12.9.8 hyphenate_data_attrs

Haml convierte todos los underscores en todos los atributos de data a guiones por defecto. Para deshabilitar esta funcionalidad, setee hyphenate_attrs a false.

###12.9.9 mime_type

El tipo MIME con el cual son servidos los templates Haml. Si éste es seteado a text/xml, entonces el formato será sobrescrito a :xhtml, inlcuso si es seteado a :html4 o :html5.

###12.9.10 parser_class

La clase perser que usa. Por defecto es Haml::Parser.

###12.9.11 preserve

La opción preserve acepta que un arreglo de todos los tags pueda tener sus newlines preservadas usando el helper preserve. Por defecto es ['textarea', 'pre'].

###12.9.12 remove_whitespace

Seteandolo a true causa que todos los tags como si operadores Haml de remoción de espacios en blanco estuvieran presentes. Por defecto es false.

###12.9.13 ugly

Haml no intenta formatear o indentar la salida HTML de un template rendereado. Por defecto, ugly es seteado a false en todos los ambientes Rails excepto production. Esto lo habilita a ver el HTML rendereado en un formato agradable cuando usted está desarrollo pero produce un alto desempeño en producción.

⚠️ **GitHub.com Fallback** ⚠️