#272 Markdown with Redcarpet
- Download:
- source codeProject Files in Zip (204 KB)
- mp4Full Size H.264 Video (12.4 MB)
- m4vSmaller H.264 Video (7.75 MB)
- webmFull Size VP8 Video (8.32 MB)
- ogvFull Size Theora Video (19.8 MB)
Hace un par de meses GitHub presentó una nueva gema de Ruby llamada Redcarpet. Esta gema sirve para interpretar código Markdown e internamente Github la utiliza con la librería Upskirt para permitir escribir el marcado de los documentos de forma sencilla. Redcarpet es fácil de utilizar y en este episodio la usaremos en una aplicación Rails para mostrar cómo se puede adaptar y cómo podemos añadir resaltado sintáctico a bloques de código.
Trabajaremos con la sencilla aplicación de blog que se muestra debajo. El contenido introducido para el artículo se muestra directamente como HTML por lo que aunque hemos introducido dos párrafos separados se muestra en un único bloque.
El contenido no se interpreta de ninguna manera. Vamos a cambiar la aplicación para pasar dicho contenido a través de Markdown, de esta forma cualquiera que cree o edite un artículo tendrá más flexibilidad a la hora de controlar el formato.
Instalación
Como es de esperar el primer paso para todo esto pasa por instalar la gema Redcarpet. Esto se hace de la manera habitual, añadiendo una referencia a la gema en el fichero Gemfile
y luego ejecutando bundle
para instalarla.
source 'http://rubygems.org' gem 'rails', '3.0.9' gem 'sqlite3' gem 'nifty-generators' gem 'redcarpet'
A continuación iremos a la página show
de ArticleController
y añadiremos Redcarpet a la línea de código que muestra el contenido del artículo. Para esto creamos un nuevo objeto Redcarpet
, le pasamos el contenido que queremos transformar, e invocamos to_html
sobre la cadena devuelta:
<% title @article.name %> <%= Redcarpet.new(@article.content).to_html %> <p> <%= link_to "Edit", edit_article_path(@article) %> | <%= link_to "Destroy", @article, :confirm => 'Are you sure?', :method => :delete %> | <%= link_to "View All", articles_path %> </p>
Pero si recargamos la página no sale exactamente lo que queríamos.
Rails 3 ha escapado automáticamente el HTML por lo que en la página lo que vemos son las etiquetas que ha añadido Redcarpet. La forma rápida de corregir esto es rodear la salida con raw
.
<% title @article.name %> <%= raw Redcarpet.new(@article.content).to_html %> <p> <%= link_to "Edit", edit_article_path(@article) %> | <%= link_to "Destroy", @article, :confirm => 'Are you sure?', :method => :delete %> | <%= link_to "View All", articles_path %> </p>
Si ahora recargamos la página ya sale como queremos.
Por supuesto hacer esto cada vez que queremos mostrar código Markdown es un pequeño fastidio, por lo que crearemos un método helper llamado markdown
que nos hará la vida más fácil.
module ApplicationHelper def markdown(text) Redcarpet.new(text).to_html.html_safe end end
Recordemos que cuando un método helper devuelve contenido HTML en lugar de raw
hay que usar html_safe
. Con esto ya podemos usar el método en la página del artículo:
<% title @article.name %> <%= markdown @article.content %> <p> <%= link_to "Edit", edit_article_path(@article) %> | <%= link_to "Destroy", @article, :confirm => 'Are you sure?', :method => :delete %> | <%= link_to "View All", articles_path %> </p>
Personalización de Redcarpet
Veamos cómo se configura Redcarpet. Una de las cosas que por defecto no hace es gestionar los saltos de línea; hace falta poner una línea en blanco para definir el comienzo de un nuevo párrafo. Si introducimos un nuevo texto sólo con un único salto de linea como este:
give me a break
Aparecerá en la salida como una única línea de texto.
Sería mejor si el texto introducido de esa manera generase una etiqueta de salto de línea en el HTML generado. Si miramos la documentación de Redcarpet veremos una lista de opciones y una de ellas es hard_wrap que hace exactamente esto.
Podemos pasarle estas opciones como símbolos al constructor de Redcarpet así:
module ApplicationHelper def markdown(text) Redcarpet.new(text, :hard_wrap).to_html.html_safe end end
Si ahora recargamos el artículo la línea “Give me a break” aparecerá como queríamos en dos líneas.
Podemos usar aquí otras opciones útiles. La opción filter_html
sirve para evitar que se genere HTML en crudo. También podemos añadir autolink
para convertir a enlaces las URLs que se detecten en el código. Como estamos planeando mostrar ejemplos de código en los artículos podemos usar no_intraemphasis
para evitar que los guiones bajos entre palabras se traten como el inicio o el fin de bloques de énfasis (lo que nos pasará mucho con los métodos y variables de Ruby) Finalmente para ayudar en la visualización de los ejemplos de código en los artículos de nuestro blog podemos añadir dos opciones más: fenced_code
(que usaremos en breve) y gh_blockcode
.
Ya tenemos muchas opciones, así que las sacaremos a un array.
module ApplicationHelper def markdown(text) options = [:hard_wrap, :filter_html, :autolink, :no_intraemphasis, :fenced_code, :gh_blockcode] Redcarpet.new(text, *options).to_html.html_safe end end
Con estas opciones ya podemos añadir bloques de código en nuestros artículos igual que podríamos hacer con Github. Estos bloques empiezan y terminan con una línea que contiene tres tildes seguidas del lenguaje. Editemos nuestro artícuo para añadirle un bloque de código Ruby.
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. ``` ruby puts "Hello, world!"
<p>Esto se muestra de la siguiente manera, con el fragmento de código incrustado en un elemento <code>pre</code> con el atributo <code>lang</code> apropiado.</p> <div class="imageWrapper"> <img src="http://railscasts.com/static/episodes/asciicasts/E272I06.png" width="802" height="428" alt="Ya salen los bloques de código ."/> </div> <p>También podemos utilizar la forma más tradicional de definir bloques de código utilizando virgulillas en lugar de tildes.</p> ``` html Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. ~~~ruby puts "Hello, world!" ~~~
Esto se mostrará igual que si usásemos tildes.
Resaltado sintáctico
Ahora que ya podemos añadir fragmentos de código a nuestros artículos, ¿cómo añadir el resaltado sintáctico? Github lo hace con una combinación de la librería en Python Pygments y la gema Albino, así que nosotros haremos igual.
Añadiremos Albino a nuestro Gemfile
. También pondremos Nokogiri para poder interpretar el HTML generado por Redcarpet.
source 'http://rubygems.org' gem 'rails', '3.0.9' gem 'sqlite3' gem 'nifty-generators' gem 'redcarpet' gem 'albino' gem 'nokogiri'
Igual que antes tenemos que ejecutar bundle
para instalarlo todo.
También tenemos que instalar Pygments. Como ya tenemos Python instalado en nuestra máquina podemos instalarlo ejecutando:
$ sudo easy_install pygments
En nuestro ApplicationHelper
añadiremos un método que llamaremos syntax_highlighter
alrededor de la línea de código que convierte el código Redcarpet a HTML. Este método utilizará Nokogiri para rastrear el documento en busca de elementos pre
con el atributo lang
, que es como Redcarpet genera los bloques de código. Luego reemplazaremos el contenido de estos elementos por el código coloreado.
module ApplicationHelper def markdown(text) options = [:hard_wrap, :filter_html, :autolink, :no_intraemphasis, :fenced_code, :gh_blockcode] syntax_highlighter(Redcarpet.new(text, *options).to_html).html_safe end def syntax_highlighter(html) doc = Nokogiri::HTML(html) doc.search("//pre[@lang]").each do |pre| pre.replace Albino.colorize(pre.text.rstrip, pre[:lang]) end doc.to_s end end
Este código está basado en la gema rack-pygmentize, merece la pena la echarle un vistazo a para entender cómo funciona. Con este método es muy fácil cambiar la librería de resaltado sintáctico, por ejemplo podríamos usar Coderay si quisiéramos
Hemos añadido una hoja de estilo como ejemplo de resaltado sintáctico que se puede encontrar en Github. Si recargamos la página el código aparecerá con los estilos aplicados.
Con esto terminamos nuestro repaso a Redcarpet. Podemos encontrar más información en la página Github del proyecto.