joe di castrohttp://joedicastro.comTue, 05 Jul 2011 23:02:00 +0200Pelican - Repositoriohttp://joedicastro.com/pelican-repositorio.html<p>Como complemento a la <a href="http://joedicastro.com/tag/pelican.html">serie de artículos</a> que he publicado sobre <a href="http://docs.notmyidea.org/alexis/pelican/">Pelican</a>, el software que genera este blog, añado el repositorio, <a href="http://joedicastro.com/pelican-configuracion-y-personalizacion.html">como había prometido</a>, del contenido del mismo. El repositorio empleaba el sistema de control de versiones <a href="http://mercurial.selenic.com/">Mercurial</a> y estába alojado en <a href="https://bitbucket.org/">Bitbucket</a>.</p> <p>Las ventajas de disponer del contenido del blog en un repositorio son las de poder enmendar un error con suma facilidad y en muy poco tiempo, además de la de poder trabajar con distintas versiones del mismo (pruebas y producción). Además el repositorio en Bitbucket me proporcionaba una copia de seguridad adicional del sitio sin esfuerzo alguno. Y si alguien está interesado en crear su propio blog con Pelican y quiere saber como he realizado el mio, ahí tiene las claves. Salvo el propio Pelican (que no tendría mucho sentido) todo el material empleado para generarlo está en el. Y disponiendo del fichero <strong>fabric</strong>, se pueden descargar Pelican e instalar el entorno virtual en un minuto. </p> <p>Para automatizar todas las tareas, incluso las más comunes del repositorio, he añadido al fichero fabric <em>fabfile.py</em> dos tareas más:</p> <div class="codehilite"><pre><span class="k">def</span> <span class="nf">commit</span><span class="p">(</span><span class="n">message</span><span class="p">):</span> <span class="sd">&quot;&quot;&quot;Make a commit to the local mercurial repository.&quot;&quot;&quot;</span> <span class="n">local</span><span class="p">(</span><span class="s">&quot;hg add&quot;</span><span class="p">)</span> <span class="n">local</span><span class="p">(</span><span class="s">&quot;hg commit -m &#39;{0}&#39;&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">message</span><span class="p">))</span> <span class="k">def</span> <span class="nf">push</span><span class="p">():</span> <span class="sd">&quot;&quot;&quot;Make a push to the remote mercurial repository.&quot;&quot;&quot;</span> <span class="n">local</span><span class="p">(</span><span class="s">&quot;hg push ssh://hg@bitbucket.org/joedicastro/joedicastro.com&quot;</span><span class="p">)</span> </pre></div> <p>Con estas puedo hacer un <code>commit</code> y un <code>push</code> a Bitbucket en un solo paso, por ejemplo:</p> <div class="codehilite"><pre><span class="go">fab commit:&quot;Añadido articulo: Pelican - Repositorio&quot; push</span> </pre></div> <p>También he cambiado la página que generaba los archivos del blog, ya que no me gustaba el formato anterior: una fecha, un articulo. He pasado de esto:</p> <div class="codehilite"><pre><span class="cp">{%</span> <span class="k">extends</span> <span class="s2">&quot;base.html&quot;</span> <span class="cp">%}</span><span class="x"></span> <span class="cp">{%</span> <span class="k">block</span> <span class="nv">content</span> <span class="cp">%}</span><span class="x"></span> <span class="x">&lt;section id=&quot;content&quot; class=&quot;body&quot;&gt;</span> <span class="x">&lt;h1&gt;Archivos de </span><span class="cp">{{</span> <span class="nv">SITENAME</span> <span class="cp">}}</span><span class="x">&lt;/h1&gt;</span> <span class="x">&lt;dl&gt;</span> <span class="cp">{%</span> <span class="k">for</span> <span class="nv">article</span> <span class="k">in</span> <span class="nv">dates</span> <span class="cp">%}</span><span class="x"></span> <span class="x"> &lt;dt&gt;</span><span class="cp">{{</span> <span class="nv">article.locale_date</span> <span class="cp">}}</span><span class="x">&lt;/dt&gt;</span> <span class="x"> &lt;dd&gt;&lt;a href=&#39;</span><span class="cp">{{</span> <span class="nv">article.url</span> <span class="cp">}}</span><span class="x">&#39;&gt;</span><span class="cp">{{</span> <span class="nv">article.title</span> <span class="cp">}}</span><span class="x">&lt;/a&gt;&lt;/dd&gt;</span> <span class="cp">{%</span> <span class="k">endfor</span> <span class="cp">%}</span><span class="x"></span> <span class="x">&lt;/dl&gt;</span> <span class="x">&lt;/section&gt;</span> <span class="cp">{%</span> <span class="k">endblock</span> <span class="cp">%}</span><span class="x"></span> </pre></div> <p>a esto:</p> <div class="codehilite"><pre><span class="cp">{%</span> <span class="k">extends</span> <span class="s2">&quot;base.html&quot;</span> <span class="cp">%}</span><span class="x"></span> <span class="cp">{%</span> <span class="k">block</span> <span class="nv">content</span> <span class="cp">%}</span><span class="x"></span> <span class="x">&lt;section id=&quot;content&quot; class=&quot;body&quot;&gt;</span> <span class="x">&lt;h1&gt;Archivos de </span><span class="cp">{{</span> <span class="nv">SITENAME</span> <span class="cp">}}</span><span class="x">&lt;/h1&gt;</span> <span class="cp">{%</span>- <span class="k">set</span> <span class="nv">years_month</span> <span class="o">=</span> <span class="o">{}</span> -<span class="cp">%}</span><span class="x"></span> <span class="cp">{%</span>- <span class="k">set</span> <span class="nv">months</span> <span class="o">=</span> <span class="o">{</span><span class="m">1</span><span class="s1">:&#39;Enero&#39;</span><span class="o">,</span> <span class="m">2</span><span class="s1">:&#39;Febrero&#39;</span><span class="o">,</span> <span class="m">3</span><span class="s1">:&#39;Marzo&#39;</span><span class="o">,</span> <span class="m">4</span><span class="s1">:&#39;Abril&#39;</span><span class="o">,</span> <span class="m">5</span><span class="s1">:&#39;Mayo&#39;</span><span class="o">,</span> <span class="m">6</span><span class="s1">:&#39;Junio&#39;</span><span class="o">,</span> <span class="m">7</span><span class="s1">:&#39;Julio&#39;</span><span class="o">,</span> <span class="m">8</span><span class="s1">:&#39;Agosto&#39;</span><span class="o">,</span> <span class="m">9</span><span class="s1">:&#39;Septiembre&#39;</span><span class="o">,</span> <span class="m">10</span><span class="s1">:&#39;Octubre&#39;</span><span class="o">,</span> <span class="m">11</span><span class="s1">:&#39;Noviembre&#39;</span><span class="o">,</span> <span class="m">12</span><span class="s1">:&#39;Diciembre&#39;</span><span class="o">}</span> -<span class="cp">%}</span><span class="x"> </span> <span class="cp">{%</span>- <span class="k">for</span> <span class="nv">article</span> <span class="k">in</span> <span class="nv">dates</span> -<span class="cp">%}</span><span class="x"></span> <span class="x"> </span><span class="cp">{%</span>- <span class="k">if</span> <span class="nv">article.date.year</span> <span class="k">not</span> <span class="k">in</span> <span class="nv">years_month</span> -<span class="cp">%}</span><span class="x"></span> <span class="x"> </span><span class="cp">{%</span>- <span class="k">do</span> <span class="nv">years_month.update</span><span class="o">({</span><span class="nv">article.date.year</span><span class="o">:[</span><span class="nv">article.date.month</span><span class="o">]})</span> -<span class="cp">%}</span><span class="x"></span> <span class="x"> </span><span class="cp">{%</span>- <span class="k">else</span> -<span class="cp">%}</span><span class="x"></span> <span class="x"> </span><span class="cp">{%</span>- <span class="k">if</span> <span class="nv">article.date.month</span> <span class="k">not</span> <span class="k">in</span> <span class="nv">years_month</span><span class="o">[</span><span class="nv">article.date.year</span><span class="o">]</span> -<span class="cp">%}</span><span class="x"> </span> <span class="x"> </span><span class="cp">{%</span>- <span class="k">do</span> <span class="nv">years_month</span><span class="o">[</span><span class="nv">article.date.year</span><span class="o">]</span><span class="nv">.append</span><span class="o">(</span><span class="nv">article.date.month</span><span class="o">)</span> -<span class="cp">%}</span><span class="x"></span> <span class="x"> </span><span class="cp">{%</span>- <span class="k">endif</span> -<span class="cp">%}</span><span class="x"></span> <span class="x"> </span><span class="cp">{%</span>- <span class="k">endif</span> -<span class="cp">%}</span><span class="x"></span> <span class="cp">{%</span>- <span class="k">endfor</span> <span class="cp">%}</span><span class="x"></span> <span class="cp">{%</span> <span class="k">for</span> <span class="nv">year</span> <span class="k">in</span> <span class="nv">years_month</span><span class="o">|</span><span class="nf">sort</span><span class="o">(</span><span class="nv">reverse</span><span class="o">=</span><span class="kp">True</span><span class="o">)</span> -<span class="cp">%}</span><span class="x"></span> <span class="x"> &lt;h2 class=&quot;year&quot;&gt;</span><span class="cp">{{</span> <span class="nv">year</span> <span class="cp">}}</span><span class="x">&lt;/h2&gt;&lt;dl&gt; </span> <span class="x"> </span><span class="cp">{%</span> <span class="k">for</span> <span class="nv">month</span> <span class="k">in</span> <span class="nv">years_month</span><span class="o">[</span><span class="nv">year</span><span class="o">]</span> -<span class="cp">%}</span><span class="x"></span> <span class="x"> &lt;dt class=&quot;month&quot;&gt;</span><span class="cp">{{</span> <span class="nv">months</span><span class="o">[</span><span class="nv">month</span><span class="o">]</span> <span class="cp">}}</span><span class="x">&lt;/dt&gt;</span> <span class="x"> </span><span class="cp">{%</span> <span class="k">for</span> <span class="nv">article</span> <span class="k">in</span> <span class="nv">dates</span> -<span class="cp">%}</span><span class="x"></span> <span class="x"> </span><span class="cp">{%</span> <span class="k">if</span> <span class="nv">article.date.year</span> <span class="o">==</span> <span class="nv">year</span> <span class="k">and</span> <span class="nv">article.date.month</span> <span class="o">==</span> <span class="nv">month</span> -<span class="cp">%}</span><span class="x"></span> <span class="x"> &lt;dd&gt;&lt;span class=&quot;day&quot;&gt;</span><span class="cp">{{</span> <span class="nv">article.locale_date.split</span><span class="o">()[</span><span class="m">1</span><span class="o">]</span> <span class="cp">}}</span><span class="x">&lt;/span&gt; &lt;a href=&#39;</span><span class="cp">{{</span> <span class="nv">article.url</span> <span class="cp">}}</span><span class="x">&#39;&gt;</span><span class="cp">{{</span> <span class="nv">article.title</span> <span class="cp">}}</span><span class="x">&lt;/a&gt;&lt;/dd&gt;</span> <span class="x"> </span><span class="cp">{%</span>- <span class="k">endif</span> <span class="cp">%}</span><span class="x"></span> <span class="x"> </span><span class="cp">{%</span>- <span class="k">endfor</span> <span class="cp">%}</span><span class="x"></span> <span class="x"> </span><span class="cp">{%</span> <span class="k">endfor</span> <span class="cp">%}</span><span class="x">&lt;/dl&gt;</span> <span class="cp">{%</span> <span class="k">endfor</span> <span class="cp">%}</span><span class="x"></span> <span class="x">&lt;/section&gt;</span> <span class="cp">{%</span> <span class="k">endblock</span> <span class="cp">%}</span><span class="x"></span> </pre></div> <p>Donde los artículos están archivados por año, mes y día, con un formato que personalmente me agrada bastante más.</p> <p>El repositorio de este blog se puede encontrar en <a href="http://github.com/joedicastro/joedicastro.com">github</a>.</p>joe di castroTue, 05 Jul 2011 23:02:00 +0200http://joedicastro.com/pelican-repositorio.htmlpelicanpythonmarkdownrestructuredtextblogmercurialhgPelican - Configuración y personalizaciónhttp://joedicastro.com/pelican-configuracion-y-personalizacion.html<p>Con este articulo cierro la serie que le he dedicado a <a href="http://joedicastro.com/tag/pelican.html">Pelican</a> como herramienta idónea para crear blogs estáticos con mantenimiento cero. Aquí voy a tratar de la parte más compleja de Pelican, la que nos permite personalizarlo y adaptarlo a nuestros gustos y necesidades. El primer nivel de personalización se obtiene a través del fichero de configuración (aunque no es necesario, es recomendable emplearlo). El segundo nivel vendría mediante la personalización del tema empleado, bien creando uno nuevo o bien modificando el que viene por defecto. El último nivel vendría de modificar el propio Pelican. Todos son posibles y están a nuestro alcance, gracias a que es Software Libre. </p> <p>Si bien yo he personalizado mi sitio con respecto al sitio por defecto, y aún quedan ciertas cosas que aún quiero cambiar, no he necesitado de momento más que modificar el fichero de configuración y el tema que viene por defecto. En Pelican no he tocado nada exceptuando el activar por defecto <strong>Markdown Extra</strong>, algo que Alexis tuvo como gentileza <a href="https://github.com/ametaireau/pelican/pull/138">aceptar como modificación</a> a Pelican. Es posible que en el futuro algunas de las cosas que tengo en mente me lleven a modificarlo, y espero poder así contribuir en alguna medida a su desarrollo. </p> <h2 id="configuraci+n">Configuración</h2> <p>La configuración se hace a través de un fichero python, que en el ejemplo por defecto se llama <code>pelican.conf.py</code> y en nuestro ejemplo estaría en <em>myblog.com/site/pelican.conf.py</em>. Para llamar al fichero de configuración se utiliza la opción <code>-s</code> y en nuestro ejemplo sería:</p> <div class="codehilite"><pre><span class="gp">$</span> pelican -s ./site/pelican.conf.py </pre></div> <p>Este es un tema que está muy bien resuelto en la <a href="http://docs.notmyidea.org/alexis/pelican/settings.html">documentación</a>. De todos modos voy a hablar de unos cuantos campos interesantes y alguno no incluido dentro de la documentación. Entre paréntesis indico los valores por defecto.</p> <ul> <li> <p><strong>OUTPUT_PATH</strong> (<code>'output/'</code>) y <strong>PATH</strong> (<code>None</code>)</p> <p>Empleando estos dos valores, conseguimos que solo tengamos que especificar el fichero de configuración en la linea de comandos empleada para llamar a Pelican. El primero define el directorio de salida donde queremos que se genere nuestro sitio y el segundo el directorio origen de nuestro contenido. </p> </li> <li> <p><strong>SITESUBTITLE</strong> (<code>u''</code>)</p> <p>Un subtitulo que se puede poner al blog, e.g. un lema. No aparece documentado.</p> </li> <li> <p><strong>JINJA_EXTENSIONS</strong> (<code>[]</code>)</p> <p>Puede ser necesario habilitar ciertas extensiones de Jinja2 para personalizar el tema que vamos a emplear. Por ejemplo, para mostrar la nube de etiquetas con las etiquetas ordenadas alfabéticamente, he habilitado una extensión que necesitaba para el proceso de esta manera:</p> <div class="codehilite"><pre><span class="n">JINJA_EXTENSIONS</span> <span class="o">=</span> <span class="p">[</span><span class="s">&#39;jinja2.ext.do&#39;</span><span class="p">]</span> </pre></div> </li> <li> <p><strong>STATIC_PATHS</strong> (<code>['images',]</code>)</p> <p>Te permite especificar los contenidos estáticos que quieres añadir a tu blog y que acabaran colgando de la carpeta <em>static</em>. Yo por ejemplo lo empleo para alojar las imágenes en <em>static/pictures</em> y el mapa flash que utilizo en el articulo <a href="http://joedicastro.com/combatir-el-spam-en-drupal.html">Combatir el spam en Drupal</a> en <em>static/ammap</em> así:</p> <div class="codehilite"><pre><span class="n">STATIC_PATHS</span> <span class="o">=</span> <span class="p">[</span><span class="s">&quot;pictures&quot;</span><span class="p">,</span> <span class="s">&quot;ammap&quot;</span><span class="p">,</span> <span class="p">]</span> </pre></div> </li> <li> <p><strong>TAG_FEED</strong> (<code>None</code>) y <strong>TAG_FEED_RSS</strong> (<code>None</code>)</p> <p>Te permiten establecer fuentes Atom y RSS por etiqueta, que es una opción muy interesante para quienes solo les interesa un tema de los que trates o para formar parte de un <a href="http://es.wikipedia.org/wiki/Planeta_%28agregador%29">Planet</a> sin mezclar temas. Eso si, lo lógico es modificar luego el tema para que aparezcan disponibles. </p> </li> <li> <p><strong>DIRECT_TEMPLATES</strong> (<code>('index', 'tags', 'categories', 'archives')</code>)</p> <p>Estas son las plantillas del tema que generan una página por si mismas. No viene documentada, pero yo he cambiado los valores por defecto para añadir una página personalizada a la que redirijo los errores 404 (Página no encontrada) de esta manera:</p> <div class="codehilite"><pre><span class="n">DIRECT_TEMPLATES</span> <span class="o">=</span> <span class="p">(</span><span class="s">&#39;index&#39;</span><span class="p">,</span> <span class="s">&#39;tags&#39;</span><span class="p">,</span> <span class="s">&#39;categories&#39;</span><span class="p">,</span> <span class="s">&#39;archives&#39;</span><span class="p">,</span> <span class="s">&#39;notfound&#39;</span><span class="p">)</span> </pre></div> </li> <li> <p><strong>PIWIK_URL</strong> y <strong>PIWIK_SITE_ID</strong></p> <p>Te permiten configurar tu sitio para emplear el magnifico sistema de analíticas web <a href="http://piwik.org/">Piwik</a>. Yo hace unos dos años que lo empleo en mis sitios, porque tiene la ventaja de que no dependes de un script de un dominio externo. Esto te ahorra consultas DNS y que la página se quede esperando a cargar completamente cuando estos fallan. De esta manera tienes el control total sobre las estadísticas de tu web sin tener que renunciar a la calidad de otros servicios externos.</p> </li> <li> <p><strong>FILES_TO_COPY</strong> (<code>()</code>)</p> <p>Básica si queremos emplear ficheros como <em>.htaccess</em> o <em>robots.txt</em>. No está documentada tampoco. El uso de la misma consiste en una tupla de tuplas con los valores de las rutas del fichero origen y su destino. En este sitio por ejemplo:</p> <div class="codehilite"><pre><span class="n">FILES_TO_COPY</span> <span class="o">=</span> <span class="p">((</span><span class="s">&#39;extra/robots.txt&#39;</span><span class="p">,</span> <span class="s">&#39;robots.txt&#39;</span><span class="p">),</span> <span class="p">(</span><span class="s">&#39;extra/favicon.ico&#39;</span><span class="p">,</span> <span class="s">&#39;favicon.ico&#39;</span><span class="p">),</span> <span class="p">(</span><span class="s">&#39;extra/.htaccess&#39;</span><span class="p">,</span> <span class="s">&#39;.htaccess&#39;</span><span class="p">),)</span> </pre></div> </li> </ul> <h2 id="personalizaci+n">Personalización</h2> <p>Pero si realmente queremos personalizar el sitio, tanto en funcionalidad básica como en su aspecto, nos toca modificar el tema por defecto. Aquí podemos optar por tres vías: Crear el nuestro propio, empezar un tema casi desde cero, eligiendo el tema por defecto <code>simple</code> (solo texto) o partir de la base del tema por defecto <code>notmyidea</code>. Este último es el que hemos estado empleado en nuestro ejemplo y el que yo modifiqué hasta llegar donde lo tengo ahora. </p> <p>Para comprender de que consta un tema y como podemos personalizarlo, lo mejor es analizar el tema <code>notmyidea</code>.</p> <div class="codehilite"><pre><span class="go">notmyidea/</span> <span class="go">├── static</span> <span class="go">│   ├── css</span> <span class="go">│   │   ├── main.css</span> <span class="go">│   │   ├── pygment.css</span> <span class="go">│   │   ├── reset.css</span> <span class="go">│   │   └── wide.css</span> <span class="go">│   └── images</span> <span class="go">│   └── icons</span> <span class="go">│   ├── delicious.png</span> <span class="go">│   ├── lastfm.png</span> <span class="go">│   ├── linkedin.png</span> <span class="go">│   ├── rss.png</span> <span class="go">│   └── twitter.png</span> <span class="go">└── templates</span> <span class="go"> ├── analytics.html</span> <span class="go"> ├── archives.html</span> <span class="go"> ├── article.html</span> <span class="go"> ├── article_infos.html</span> <span class="go"> ├── base.html</span> <span class="go"> ├── categories.html</span> <span class="go"> ├── category.html</span> <span class="go"> ├── comments.html</span> <span class="go"> ├── disqus_script.html</span> <span class="go"> ├── github.html</span> <span class="go"> ├── index.html</span> <span class="go"> ├── page.html</span> <span class="go"> ├── pagination.html</span> <span class="go"> ├── piwik.html</span> <span class="go"> ├── skribit_tab_script.html</span> <span class="go"> ├── skribit_widget_script.html</span> <span class="go"> ├── tag.html</span> <span class="go"> ├── taglist.html</span> <span class="go"> ├── tags.html</span> <span class="go"> ├── translations.html</span> <span class="go"> └── twitter.html</span> </pre></div> <ul> <li> <p><strong><em>static/css</em></strong></p> <p>Aquí es donde se guardan las <a href="http://es.wikipedia.org/wiki/CSS">Hojas de estilo en cascada (CSS)</a> que emplea el tema. Aunque la el fichero <em>wide.css</em> no es empleado por el tema, solo para la versión wide del mismo. Yo la eliminé como primera medida. Luego tenemos <em>main.css</em> que es la hoja de estilo principal, <em>pygment.css</em> que es la que emplea Pygments para el resaltado de sintaxis y <em>reset.css</em> para resetear los navegadores a unos valores comunes por defecto. </p> <p>Si lo que queremos es tener un sitio con un buen rendimiento, deberíamos dar como mínimo dos pasos, consolidar todas la hojas de estilo en una sola y minimizar el tamaño de esta. Consolidarla en este caso es realmente sencillo, simplemente debemos insertar el contenido de <em>reset.css</em> al principio del fichero <em>main.css</em> y <em>pygment.css</em> al final del mismo. Depués hay que eliminar los imports de estas hojas en <em>main.css</em>*. Luego para minimizar su tamaño eliminar comentarios y lineas en blanco y poner una regla por línea. </p> <p>Otro paso que dí para mejorar el rendimiento es no usar las web fonts externas (ni internas), que aunque le dan un aspecto inmejorable, hay que reconocerlo, requieren cargar otro recurso externo, desde mi punto de vista innecesario.</p> <p>Lo mejor en estos casos es seguir siempre las recomendaciones de estas dos magnificas herramientas: <a href="http://developer.yahoo.com/yslow/">YSlow</a> de <strong>Yahoo</strong> y <a href="http://code.google.com/speed/page-speed/">Page Speed</a> de <strong>Google</strong>. Afortunadamente hay sitios web como <a href="http://gtmetrix.com/">GTmetrix</a> o <a href="http://www.webpagetest.org/">WebPagetest</a> que nos permiten ver los resultados de ambas herramientas en nuestro sitio web sin necesidad de instalarlas (aunque para el desarrollo es más que recomendable). Si por ejemplo emplearamos <strong>GTmetrix</strong> los valores que arroja un sitio con el tema por defecto son:</p> <table> <thead> <tr> <th>Page Speed (tema por defecto)</th> <th>YSlow (tema por defecto)</th> </tr> </thead> <tbody> <tr> <td><strong>B (80%)</strong></td> <td><strong>B (85%)</strong></td> </tr> </tbody> </table> <p>Valores bastante mejorables. Los valores actuales para este sitio, una vez personalizado el tema y configurado correctamente el <em>.htaccess</em> son:</p> <table> <thead> <tr> <th>Page Speed (tema personalizado)</th> <th>YSlow (tema personalizado)</th> </tr> </thead> <tbody> <tr> <td><strong>A (91%)</strong></td> <td><strong>A (95%)</strong></td> </tr> </tbody> </table> <p>Y si nos fijamos en <a href="http://gtmetrix.com/reports/joedicastro.com/BeFSzvAa">los resultados</a>, las penalizaciones de rendimiento vienen de los scrips externos de Piwik y Disqus, principalmente de este último. Sin emplear estos scripts los valores suben a:</p> <table> <thead> <tr> <th>Page Speed (sin scripts)</th> <th>YSlow (sin scripts)</th> </tr> </thead> <tbody> <tr> <td><strong>A (100%)</strong></td> <td><strong>A (98%)</strong></td> </tr> </tbody> </table> <p>En resumen, una optimización más que correcta, solo hay que ver los valores de las páginas del Top 1000 que ofrecen en GTmetrix. Obtener una optimización como esta con un CMS no es imposible (había conseguido unos valores solo un poquito peores con Drupal) pero si bastante más complicado. La experiencia del usuario depende mucho de estos valores, hay que contar con que no todo el mundo dispone de buenos accesos a Internet.</p> <p>Evidentemente, después cada uno retocara el fichero CSS resultante a su gusto para personalizar el aspecto del sitio. En este caso estoy empleando CSS 3 y valida correctamente. </p> </li> </ul> <p style="text-align:center;"> <a href="http://jigsaw.w3.org/css-validator/validator?uri=http%3A%2F%2Fjoedicastro.com%2F&amp;profile=css3&amp;usermedium=all&amp;warning=1&amp;vextwarning=&amp;lang=es"> <img style="border:0;width:88px;height:31px" src="pictures/valid-css3.png" alt="¡CSS 3 Válido!" title="¡CSS 3 Válido!" /> </a> </p> <ul> <li> <p><strong>static/images/icons</strong></p> <p>Son los iconos empleados por la hoja de estilo para los enlaces sociales de la parte inferior de la página. Yo no los empleo. ¿Entonces como se ven? Bueno lo primero que hice fue crear un <a href="http://www.w3schools.com/css/css_image_sprites.asp">sprite</a> para cargar una sola imagen en lugar de 6, es decir menos solicitudes al servidor. Después incorporé esta imagen <a href="http://www.websiteoptimization.com/speed/tweak/inline-images/">dentro del propio fichero CSS con un Data URL</a>, y gracias a haberla optimizado hasta ocupar solamente ~3k, me compensaba hacerlo. Una consulta menos al servidor. Lo mismo hice después con el logotipo (1K) y al final no se carga ninguna imagen por defecto en el blog, 0 consultas. Los navegadores modernos soportan esto sin problemas, los que no lo hacen, no muestran la imagen, solo el enlace, que tampoco es un ningún problema.</p> <p>Así es como queda en <em>main.css</em> la imagen que da vida a los iconos de los enlaces a la redes sociales:</p> <div class="codehilite"><pre><span class="nf">#extras</span> <span class="nt">div</span><span class="o">[</span><span class="nt">class</span><span class="o">=</span><span class="s1">&#39;social&#39;</span><span class="o">]</span> <span class="nt">a</span><span class="p">{</span><span class="k">background-repeat</span><span class="o">:</span><span class="k">no-repeat</span><span class="p">;</span><span class="k">background-image</span><span class="o">:</span><span class="sx">url(&quot;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAACSCAMAAAB7VbqAAAAAwFBMVEWQBQCWFxU5VpedVy+tUE5LZaBPZZZDabDdYSpke75vfZBkfbJZgc+heztshKvldjBgld91j9+Uj4p5ksZ/lLzthzLqhz+MmrAcvuaDofihpYRzq/D4mDeUp9KetkSirsnQpKWpvV/qqHvHsJjnqY/3qWK1ubbIun2jwLHEu7xm1O+6xoOtv++7wte0yNzxwH563e/3xJjK06ya5vXY3p7U2+3e3tbm6IT63cLn7czr7fbZ9Prz7+r8+O/3+fb9//z6WVfkAAADNElEQVRIx9WV4XqiPBCFoyu4aVjQBrW2ImBX3aJYdQERIbn/u9qTRKzd7/n+b88jxHlnMswEY4hIGYUcLZYKklLbtixqNBymhNl2yG/2lBFqu1LKKjD2dEioxfIKKOfaVgA+HkoptsoGoDxPA8orKZTtEIdyNWE4zXEbUgVokAq4p1JuqQHIX8G9lYK2EdOpkNuhlJxec+TTrcxpJVENAOK3iK9oLkOLEmbqGQZ4dMAtRlJj617QZErQvqpHiVLVvvhL/y6oFx40HhktaqJt9X2mtSDwHg7L1p6NAJZY9eZwB8aHsgF61zaAnr8spXxX9piMR8umxAQQZBp5ZDTSOZYgzXjkKTCbvTeKNPLgKaCTK/dCNldQlu9wL0aNHH9XADnK2UGWXil/GoDJyFx6P69gNlPPWy698cIDWOj68DzvO+Qt0D7MsXcV2v86by55+qSEPP3+pKf/ARfxF5Dy8gH2+/0N7Pc3oCUMSJIWyESBRANxgX4nyQ1cEiMDEkR8BheT4jYl2bdJW5DsdczlA9z09N/2v86bw1Vs4vl8c6xbcI7ncQxkCBFFPM8a0QAfDTjOM70453lc630bx2ezXJt5oUARx40BmQF3EfFroXJs5gaU30inF+G3vombBnuu7JFer9OJ1JQMZcQ/SK8WEekRVRYqjb+RSMq60yHF8VzXRVHAWUsV0TZVIEekctzafEPKTnS/o+qog7z361FHkfhK/5ZV0MrnPAgqEvBWYZoGPCSt6aujLGScuC5j+LAdNkAVALCrUuVndwARvhoJs3C3WSXUFB8HjtW1LFxCvz3WtQC03Bw5fOsDdEPl794BPMW9Ap3DAMuyCc5nJQ2sO2AB+BgYCU1dCkwwhjjnfNUO8ycTl/lf6pxTtzzfQXl1BduXAQ5/7jiDl50CgcMnq6Ku69WEOQHAgD8+Pq5WbysMLle78tdq8jDR4oMc4HzKsuPuBRoMLKHB6+spG2hgrwCydQZpQH0NTmsgB/4BTVe1AphyNCBXoMk2p9MvB7bT1xEitB+eFXCch3WhSl/Z/T6dcMddr581KAD6fdd9fnyoTbdvrN93+v2uXbTt17sQyvV6/AE7UZJYs2UOngAAAABJRU5ErkJggg==&quot;)</span><span class="p">;</span><span class="k">padding-left</span><span class="o">:</span><span class="m">25px</span><span class="p">;}</span> <span class="nc">.social</span> <span class="nt">a</span><span class="o">[</span><span class="nt">href</span><span class="o">*=</span><span class="s1">&#39;atom.xml&#39;</span><span class="o">]</span><span class="p">{</span><span class="k">background-position</span><span class="o">:</span><span class="m">3px</span> <span class="m">6px</span><span class="p">;}</span> <span class="nc">.social</span> <span class="nt">a</span><span class="o">[</span><span class="nt">href</span><span class="o">*=</span><span class="s1">&#39;rss.xml&#39;</span><span class="o">]</span><span class="p">{</span><span class="k">background-position</span><span class="o">:</span><span class="m">3px</span> <span class="m">-20px</span><span class="p">;}</span> <span class="nc">.social</span> <span class="nt">a</span><span class="o">[</span><span class="nt">href</span><span class="o">*=</span><span class="s1">&#39;twitter.com&#39;</span><span class="o">]</span><span class="p">{</span><span class="k">background-position</span><span class="o">:</span><span class="m">3px</span> <span class="m">-46px</span><span class="p">;}</span> <span class="nc">.social</span> <span class="nt">a</span><span class="o">[</span><span class="nt">href</span><span class="o">*=</span><span class="s1">&#39;identi.ca&#39;</span><span class="o">]</span><span class="p">{</span><span class="k">background-position</span><span class="o">:</span><span class="m">3px</span> <span class="m">-72px</span><span class="p">;}</span> <span class="nc">.social</span> <span class="nt">a</span><span class="o">[</span><span class="nt">href</span><span class="o">*=</span><span class="s1">&#39;facebook.com&#39;</span><span class="o">]</span><span class="p">{</span><span class="k">background-position</span><span class="o">:</span><span class="m">3px</span> <span class="m">-98px</span><span class="p">;}</span> <span class="nc">.social</span> <span class="nt">a</span><span class="o">[</span><span class="nt">href</span><span class="o">*=</span><span class="s1">&#39;bitbucket.org&#39;</span><span class="o">]</span><span class="p">{</span><span class="k">background-position</span><span class="o">:</span><span class="m">3px</span> <span class="m">-124px</span><span class="p">;}</span> </pre></div> </li> <li> <p><strong>static/templates</strong></p> <p>Estas son las plantillas que dan vida al tema y emplean Jinja2. Los nombres son bastante descriptivos de la función que realiza cada una de ellas. En mi caso hay una serie de ellas que no empleo, como son: <em>analytics.html</em>, <em>article_infos.html</em>, <em>github.html</em>, <em>skribit_tab_script.html</em>, <em>skribit_widget_script.html</em>, <em>translations.html</em> y <em>twitter.html</em>. He realizado bastantes modificaciones en las plantillas y me extendería demasiado explicándolo, además sigo realizando cambios. Aún no lo tengo todo como yo lo quiero, y aún voy a personalizar y optimizar más cosas. Cuando lo tenga todo listo, pienso publicar un repositorio con el contenido que genera este blog, tanto a efectos de copia de seguridad, como de que le pueda servir a alguien como guía para montar el suyo propio. </p> <p>De todos modos si puedo decir que he añadido una que no existía, <em>notfound.html</em> para los errores 404 y pienso crear una nueva para los errores 403. Además he creado los enlaces para los feeds RSS y Atom de las etiquetas y eliminado el bloque de información que aparecía en cada articulo. Además en la plantilla <em>tags.html</em> que por defecto viene vacía, he creado lo necesario para generar la nube de etiquetas. <em>tags.html</em> queda entonces así:</p> <div class="codehilite"><pre><span class="cp">{%</span> <span class="k">extends</span> <span class="s2">&quot;base.html&quot;</span> <span class="cp">%}</span> <span class="cp">{%</span> <span class="k">block</span> <span class="nv">content</span> <span class="cp">%}</span> <span class="nt">&lt;section</span> <span class="na">id=</span><span class="s">&quot;content&quot;</span> <span class="na">class=</span><span class="s">&quot;body&quot;</span><span class="nt">&gt;</span> <span class="nt">&lt;h1&gt;</span>etiquetas<span class="nt">&lt;/h1&gt;</span> <span class="nt">&lt;ul</span> <span class="na">id=</span><span class="s">&quot;cloud&quot;</span><span class="nt">&gt;</span> <span class="cp">{%</span>- <span class="k">set</span> <span class="nv">all_tags</span> <span class="o">=</span> <span class="o">{}</span> -<span class="cp">%}</span> <span class="cp">{%</span> <span class="k">for</span> <span class="nv">ctag</span> <span class="k">in</span> <span class="nv">tag_cloud</span> -<span class="cp">%}</span> <span class="cp">{%</span> <span class="k">do</span> <span class="nv">all_tags.update</span><span class="o">({</span><span class="nv">ctag.0</span><span class="o">:</span><span class="nv">ctag.1</span><span class="o">})</span> <span class="cp">%}</span> <span class="cp">{%</span>- <span class="k">endfor</span> <span class="cp">%}</span> <span class="cp">{%</span> <span class="k">for</span> <span class="nv">tag</span> <span class="k">in</span> <span class="nv">all_tags</span><span class="o">|</span><span class="nf">sort</span> <span class="cp">%}</span> <span class="nt">&lt;li</span> <span class="na">class=</span><span class="s">&quot;tag-</span><span class="cp">{{</span> <span class="nv">all_tags</span><span class="o">[</span><span class="nv">tag</span><span class="o">]</span> <span class="cp">}}</span><span class="s">&quot;</span><span class="nt">&gt;&lt;a</span> <span class="na">href=</span><span class="s">&quot;tag/</span><span class="cp">{{</span> <span class="nv">tag</span><span class="o">|</span><span class="nf">replace</span><span class="o">(</span><span class="s2">&quot; &quot;</span><span class="o">,</span> <span class="s2">&quot;%20&quot;</span><span class="o">)</span> <span class="cp">}}</span><span class="s">.html&quot;</span><span class="nt">&gt;</span><span class="cp">{{</span> <span class="nv">tag</span> <span class="cp">}}</span><span class="nt">&lt;/a&gt;&lt;/li&gt;</span> <span class="cp">{%</span> <span class="k">endfor</span> <span class="cp">%}</span> <span class="nt">&lt;/ul&gt;</span> <span class="nt">&lt;/section&gt;</span> <span class="cp">{%</span> <span class="k">endblock</span> <span class="cp">%}</span> </pre></div> <p>También he realizado las modificaciones pertinentes para que el contenido validara perfectamente en HTML 5. </p> </li> </ul> <p style="text-align:center;"> <a href="http://validator.w3.org/check?uri=http%3A%2F%2Fjoedicastro.com%2F"> <img style="border:0;width:88px;height:31px" src="pictures/valid-html5.png" alt="¡HTML 5 Válido!" title="¡HTML 5 Válido!" /> </a> </p> <p>Pero como ya he dicho es un proceso que aún no he finalizado. Cuando lo termine y publique el repositorio, actualizaré también este articulo.</p>joe di castroThu, 30 Jun 2011 01:21:00 +0200http://joedicastro.com/pelican-configuracion-y-personalizacion.htmlpelicanpythonmarkdownrestructuredtextbloghtmlcssjinja2Pelican - Publicación y automatizaciónhttp://joedicastro.com/pelican-publicacion-y-automatizacion.html<p>Una vez que sabemos como <a href="http://joedicastro.com/pelican-introduccion-e-instalacion.html">instalar Pelican</a> y <a href="http://joedicastro.com/pelican-creacion-de-contenido.html">crear contenido</a> con él, es hora de saber como convertir ese contenido en un blog real disponible en internet. Es decir, saber como publicar ese contenido. Como hemos visto hasta ahora, al constar básicamente de simples ficheros HTML, un servidor de archivos es más que suficiente para servir el blog. Esto nos abre un gran abanico de posibilidades, desde emplear un potente (y barato) servidor de ficheros en la <em>nube</em> como <strong>Amazon S3</strong>, pasando por las páginas web estáticas que nos permiten repositorios como <strong>Bitbucket</strong> o <strong>GitHub</strong>, por los tradiciones hostings compartidos (e.g. este blog), hasta un servidor casero sencillo montado sobre un <a href="http://es.wikipedia.org/wiki/Network-attached_storage">NAS</a>. </p> <p>Aún cuando es posible emplear un simple servidor de archivos para alojar el blog, siempre es mejor contar con un servidor web detrás (Apache, nginx, lighttpd, ...) que nos permita hacer redirecciones para nuestras antiguas páginas si ya disponíamos de un blog anterior o manejar los errores HTTP <a href="http://es.wikipedia.org/wiki/Error_404">404</a> o <a href="http://es.wikipedia.org/wiki/Anexo:C%C3%B3digos_de_estado_HTTP">403</a> de forma personalizada. </p> <h2 id="publicar_el_contenido">Publicar el contenido</h2> <p>Publicar el contenido de una web es tan sencillo como volcar el contenido del directorio que nos genera Pelican (en nuestro ejemplo sería <em>myblog.com/site/output/*</em>) en el directorio destino de nuestro servidor web. Dependiendo del método que hayamos elegido para alojar nuestro blog, puede ser tan sencillo como una copia de archivos o emplear FTP (SFTP) ó <a href="http://es.wikipedia.org/wiki/SSH">SSH</a> (<a href="http://es.wikipedia.org/wiki/SCP">SCP</a>, <a href="http://en.wikipedia.org/wiki/Unison_%28file_synchronizer%29">Unison</a> ó <a href="http://es.wikipedia.org/wiki/Rsync">rsync</a>). Aquí el tema radica no en la primera vez que vayamos a subir el contenido al servidor, si no en las sucesivas, a medida que vayamos creando contenido nuevo. No tendría ningún sentido volver a subir todo el contenido cada vez, si no solamente el nuevo o el que haya cambiado. Para eso necesitamos sincronizar los dos directorios. </p> <p>Si solamente disponemos de acceso FTP (o SFTP) a nuestro servidor, entonces tendremos que emplear una herramienta que nos permita la sincronización sobre FTP, como puede ser <strong>lftp</strong>. Y el proceso se puede automatizar con un script como el que describo en <a href="http://joedicastro.com/sincronizar-una-carpeta-local-y-una-remota-a-traves-de-ftp-lftp-mirror.html">Sincronizar una carpeta local y una remota a través de FTP: lftp-mirror</a>. Si disponemos de acceso a través de SSH, entonces la elección es clarisima, <strong>rsync</strong>. Más adelante explico una manera de emplearlo de forma automática.</p> <p>Cualquiera de ambas soluciones nos permite subir el contenido en apenas segundos, (sobre todo en el caso de rsync) cuando se trata de añadir un articulo nuevo, por ejemplo. Y lo mismo a la hora de hacer una rectificación, es tan inmediato como lo pueden ser plataformas como Wordpress, Drupal y similares. Además, con las potentes herramientas que existen para hacer cambios múltiples en varios ficheros de texto a la vez, se pueden realizar tareas casi imposibles con una plataforma de blogs tradicional sin recurrir a consultas SQL en la BDD o a plugins externos. Una de estas herramientas, sin recurrir a <code>find</code>, <code>grep</code>, <code>awk</code> y <code>sed</code>, puede ser <a href="http://regexxer.sourceforge.net/">regexxer</a>.</p> <h2 id="generar_el_contenido_en_el_propio_servidor">Generar el contenido en el propio servidor</h2> <p>Si el alojamiento que hemos escogido nos permite instalar programas python, entonces tenemos la posibilidad de instalar Pelican en el servidor remoto. De esta formar podríamos subir únicamente los archivos markdown o reStructuredText al servidor y generar allí mismo el contenido web. De este modo la cantidad de datos a subir sería ridícula y un simple comando FTP nos serviría. Luego bien podríamos lanzar Pelican a través de una consola SSH o bien dependiendo del servidor, tener un <a href="http://es.wikipedia.org/wiki/Demonio_%28inform%C3%A1tica%29">demonio</a> corriendo que cuando detectara un cambio en el sistema de ficheros lanzará un script que generara el contenido con Pelican. </p> <p>Otra posibilidad que me convence más, es de la poder instalar un repositorio en el servidor con un software de control de versiones, como Git o Mercurial. La idea sería tener un repositorio local, y al hacer un push hacia el repositorio remoto, a través de un <em>hook</em> activar la generación de la página con Pelican. Esto nos permitiría además poder tener varias copias del repositorio (por ejemplo en GitHub o Bitbucket) y por lo tanto de la web, haciendo "innecesarias" las copias de seguridad. </p> <h2 id="automatizar_todos_los_procesos">Automatizar todos los procesos</h2> <p>Pero lo ideal es poder automatizar todas las tareas que hemos visto hasta ahora, empleando unos pocos comandos para realizarlas sin esfuerzo alguno (bueno, a menos que tengas tú <a href="http://es.wikipedia.org/wiki/Negro_%28escritor%29">ghostwriter</a> particular, me temo que los artículos los seguirás teniendo que escribir tú). Para poder realizar esto disponemos de la fantástica y potente herramienta <a href="http://fabfile.org">Fabric</a> (el <a href="http://en.wikipedia.org/wiki/Capistrano">Capistrano</a> para Python) que nos permite ejecutar comandos locales o remotos en múltiples servidores. Esto nos permite hacer despliegues de software sin apenas esfuerzo en distintas máquinas, copiar ficheros o ejecutar tareas repetitivas empleado una corta serie de comandos. Una grandísima herramienta para administradores de sistema y desarrolladores.</p> <p>Lo único que necesitamos es instalar <strong>fabric</strong> y crear un fichero llamado <code>fabfile.py</code> donde especificaremos las tareas que queremos programar. Para instalar la última versión estable de fabric, lo mejor es emplear <code>easy_install</code> o <code>pip</code></p> <div class="codehilite"><pre><span class="gp">$</span> pip install fabric </pre></div> <p>Una vez creado el fichero <code>fabfile.py</code>, lo único que tendremos que hacer para ejecutar una tarea del mismo, sería escribir el comando <code>fab</code> seguido del nombre que le hayamos dado a la tarea (este sería el funcionamiento básico). Y la tarea se ejecutaría inmediatamente. </p> <p>Para comprender mejor como funciona Fabric, muestro aquí el contenido actual de mi fichero <code>fabfile.py</code><br /> </p> <div class="codehilite"><pre><span class="c">#!/usr/bin/env python</span> <span class="c"># -*- coding: utf8 -*-</span> <span class="sd">&quot;&quot;&quot;</span> <span class="sd"> fabfile.py: A fabric script for generate my personal blog</span> <span class="sd">&quot;&quot;&quot;</span> <span class="n">__author__</span> <span class="o">=</span> <span class="s">&quot;joe di castro &lt;joe@joedicastro.com&gt;&quot;</span> <span class="n">__license__</span> <span class="o">=</span> <span class="s">&quot;GNU General Public License version 3&quot;</span> <span class="n">__date__</span> <span class="o">=</span> <span class="s">&quot;28/06/2011&quot;</span> <span class="n">__version__</span> <span class="o">=</span> <span class="s">&quot;0.2&quot;</span> <span class="kn">import</span> <span class="nn">os</span> <span class="kn">from</span> <span class="nn">fabric.api</span> <span class="kn">import</span> <span class="o">*</span> <span class="kn">from</span> <span class="nn">fabric.contrib.project</span> <span class="kn">import</span> <span class="n">rsync_project</span> <span class="kn">from</span> <span class="nn">fabric.contrib.console</span> <span class="kn">import</span> <span class="n">confirm</span> <span class="n">PELICAN_REPOSITORY</span> <span class="o">=</span> <span class="s">&quot;git://github.com/ametaireau/pelican.git&quot;</span> <span class="n">PROD</span> <span class="o">=</span> <span class="s">&quot;joedicastro.com&quot;</span> <span class="n">PROD_PATH</span> <span class="o">=</span> <span class="s">&quot;/home/joedicastro/webapps/joedicastro&quot;</span> <span class="n">LOCAL_WEB</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="s">&quot;~/www&quot;</span><span class="p">,</span> <span class="n">PROD</span><span class="p">)</span> <span class="n">ROOT_PATH</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">abspath</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">dirname</span><span class="p">(</span><span class="n">__file__</span><span class="p">))</span> <span class="n">ENV_PATH</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">ROOT_PATH</span><span class="p">,</span> <span class="s">&quot;env&quot;</span><span class="p">)</span> <span class="n">PELICAN</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">ROOT_PATH</span><span class="p">,</span> <span class="s">&quot;pelican&quot;</span><span class="p">)</span> <span class="n">CONFIG_FILE</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">ROOT_PATH</span><span class="p">,</span> <span class="s">&quot;site/pelican.conf.py&quot;</span><span class="p">)</span> <span class="n">OUTPUT</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">ROOT_PATH</span><span class="p">,</span> <span class="s">&quot;site/output&quot;</span><span class="p">)</span> <span class="k">def</span> <span class="nf">_valid_HTML</span><span class="p">():</span> <span class="sd">&quot;&quot;&quot;Remove the obsolete rel=&quot;&quot; and rev=&quot;&quot; links in footnotes.&quot;&quot;&quot;</span> <span class="k">for</span> <span class="n">path</span><span class="p">,</span> <span class="n">dirs</span><span class="p">,</span> <span class="n">files</span> <span class="ow">in</span> <span class="n">os</span><span class="o">.</span><span class="n">walk</span><span class="p">(</span><span class="n">OUTPUT</span><span class="p">):</span> <span class="k">for</span> <span class="n">fil</span> <span class="ow">in</span> <span class="n">files</span><span class="p">:</span> <span class="k">if</span> <span class="n">fil</span><span class="p">[</span><span class="o">-</span><span class="mi">5</span><span class="p">:]</span> <span class="o">==</span> <span class="s">&quot;.html&quot;</span><span class="p">:</span> <span class="n">local</span><span class="p">(</span><span class="s">&quot;sed -i {0} -r -e &#39;s/re[l|v]=</span><span class="se">\&quot;</span><span class="s">footnote</span><span class="se">\&quot;</span><span class="s">//g&#39; {0}&quot;</span><span class="o">.</span> <span class="n">format</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">path</span><span class="p">,</span> <span class="n">fil</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s">&quot; &quot;</span><span class="p">,</span> <span class="s">r&quot;\ &quot;</span><span class="p">))))</span> <span class="k">def</span> <span class="nf">_make_env</span><span class="p">():</span> <span class="sd">&quot;&quot;&quot;Make a virtual enviroment&quot;&quot;&quot;</span> <span class="n">local</span><span class="p">(</span><span class="s">&quot;virtualenv {0}&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">ENV_PATH</span><span class="p">))</span> <span class="k">def</span> <span class="nf">_del_env</span><span class="p">():</span> <span class="sd">&quot;&quot;&quot;Delete a virtual enviroment.&quot;&quot;&quot;</span> <span class="n">local</span><span class="p">(</span><span class="s">&quot;rm -rf {0}&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">ENV_PATH</span><span class="p">))</span> <span class="k">def</span> <span class="nf">_clone_pelican</span><span class="p">():</span> <span class="sd">&quot;&quot;&quot;Clone Pelican from repository.&quot;&quot;&quot;</span> <span class="n">local</span><span class="p">(</span><span class="s">&quot;git clone {0}&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">PELICAN_REPOSITORY</span><span class="p">))</span> <span class="k">def</span> <span class="nf">_install</span><span class="p">():</span> <span class="sd">&quot;&quot;&quot;Install Pelican in the virtual enviroment.&quot;&quot;&quot;</span> <span class="k">with</span> <span class="n">lcd</span><span class="p">(</span><span class="n">PELICAN</span><span class="p">):</span> <span class="n">local</span><span class="p">(</span><span class="s">&quot;{0}/bin/python setup.py install&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">ENV_PATH</span><span class="p">))</span> <span class="k">def</span> <span class="nf">_browse</span><span class="p">():</span> <span class="sd">&quot;&quot;&quot;Browse the local Apache site.&quot;&quot;&quot;</span> <span class="n">local</span><span class="p">(</span><span class="s">&quot;firefox -new-window http://localhost/joedicastro.com 2&gt;/dev/null &amp;&quot;</span><span class="p">)</span> <span class="k">def</span> <span class="nf">_gen</span><span class="p">(</span><span class="n">autoreload</span><span class="o">=</span><span class="bp">False</span><span class="p">):</span> <span class="sd">&quot;&quot;&quot;Generate the site from source.&quot;&quot;&quot;</span> <span class="n">local</span><span class="p">(</span><span class="s">&quot;{0}/bin/pelican {2} -s {1}&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">ENV_PATH</span><span class="p">,</span> <span class="n">CONFIG_FILE</span><span class="p">,</span> <span class="s">&quot;-r&quot;</span> <span class="k">if</span> <span class="n">autoreload</span> <span class="k">else</span> <span class="s">&quot;&quot;</span><span class="p">))</span> <span class="k">def</span> <span class="nf">_clean</span><span class="p">():</span> <span class="s">&quot;Remove the output folder.&quot;</span> <span class="n">local</span><span class="p">(</span><span class="s">&quot;rm -rf {0}&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">OUTPUT</span><span class="p">))</span> <span class="k">def</span> <span class="nf">_local_deploy</span><span class="p">():</span> <span class="sd">&quot;&quot;&quot;Deploy to the local apache web server.&quot;&quot;&quot;</span> <span class="n">local</span><span class="p">(</span><span class="s">&quot;rm -rf {0}&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">LOCAL_WEB</span><span class="p">))</span> <span class="n">local</span><span class="p">(</span><span class="s">&quot;cp -r {0} {1}&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">OUTPUT</span><span class="p">,</span> <span class="n">LOCAL_WEB</span><span class="p">))</span> <span class="k">def</span> <span class="nf">pull_pelican</span><span class="p">():</span> <span class="sd">&quot;&quot;&quot;Update Pelican to last revision from repository.&quot;&quot;&quot;</span> <span class="k">with</span> <span class="n">lcd</span><span class="p">(</span><span class="n">PELICAN</span><span class="p">):</span> <span class="n">local</span><span class="p">(</span><span class="s">&quot;git pull&quot;</span><span class="p">)</span> <span class="k">def</span> <span class="nf">bootstrap</span><span class="p">():</span> <span class="sd">&quot;&quot;&quot;Get Pelican and install it in a virtual enviroment.&quot;&quot;&quot;</span> <span class="k">with</span> <span class="n">settings</span><span class="p">(</span><span class="n">warn_only</span><span class="o">=</span><span class="bp">True</span><span class="p">):</span> <span class="n">_del_env</span><span class="p">()</span> <span class="n">_make_env</span><span class="p">()</span> <span class="k">with</span> <span class="n">settings</span><span class="p">(</span><span class="n">warn_only</span><span class="o">=</span><span class="bp">True</span><span class="p">):</span> <span class="n">_clone_pelican</span><span class="p">()</span> <span class="n">_install</span><span class="p">()</span> <span class="k">def</span> <span class="nf">regen</span><span class="p">():</span> <span class="sd">&quot;&quot;&quot;Regenerate the site from source.&quot;&quot;&quot;</span> <span class="n">_clean</span><span class="p">()</span> <span class="n">_gen</span><span class="p">()</span> <span class="n">_valid_HTML</span><span class="p">()</span> <span class="n">_local_deploy</span><span class="p">()</span> <span class="nd">@hosts</span><span class="p">(</span><span class="s">&quot;my_user@&quot;</span> <span class="o">+</span> <span class="n">PROD</span><span class="p">)</span> <span class="k">def</span> <span class="nf">publish</span><span class="p">():</span> <span class="sd">&quot;&quot;&quot;Publish into remote web server with rsync.&quot;&quot;&quot;</span> <span class="n">regen</span><span class="p">()</span> <span class="n">_browse</span><span class="p">()</span> <span class="k">if</span> <span class="n">confirm</span><span class="p">(</span><span class="s">&quot;¿Estas seguro de querer publicarlo?&quot;</span><span class="p">):</span> <span class="n">rsync_project</span><span class="p">(</span><span class="n">PROD_PATH</span><span class="p">,</span> <span class="n">OUTPUT</span> <span class="o">+</span> <span class="s">&quot;/&quot;</span><span class="p">,</span> <span class="n">delete</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span> <span class="k">def</span> <span class="nf">new</span><span class="p">(</span><span class="n">title</span><span class="p">):</span> <span class="sd">&quot;&quot;&quot;Create a new blog article.&quot;&quot;&quot;</span> <span class="n">local</span><span class="p">(</span><span class="s">&quot;gedit --new-window {0}/site/source/blog/{1}.md 2&gt;/dev/null &amp;&quot;</span><span class="o">.</span> <span class="n">format</span><span class="p">(</span><span class="n">ROOT_PATH</span><span class="p">,</span> <span class="n">title</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s">&quot; &quot;</span><span class="p">,</span> <span class="s">&quot;\ &quot;</span><span class="p">)))</span> <span class="n">local</span><span class="p">(</span><span class="s">&quot;firefox --new-window {0}/index.html &amp;&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">OUTPUT</span><span class="p">))</span> <span class="n">_gen</span><span class="p">(</span><span class="bp">True</span><span class="p">)</span> <span class="k">def</span> <span class="nf">img4web</span><span class="p">(</span><span class="n">delete</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> <span class="n">source</span><span class="o">=</span><span class="s">&quot;&quot;</span><span class="p">):</span> <span class="sd">&quot;&quot;&quot;Optimize .jpg &amp; .png images and copy them into source pictures dir.&quot;&quot;&quot;</span> <span class="n">local</span><span class="p">(</span><span class="s">&quot;./img4web.py -d {0} {1} {2}&quot;</span><span class="o">.</span> <span class="n">format</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">ROOT_PATH</span><span class="p">,</span> <span class="s">&quot;site/source/pictures&quot;</span><span class="p">),</span> <span class="s">&quot;--delete&quot;</span> <span class="k">if</span> <span class="n">delete</span> <span class="k">else</span> <span class="s">&quot;&quot;</span><span class="p">,</span> <span class="s">&quot;-s {0}&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">source</span><span class="p">)</span> <span class="k">if</span> <span class="n">source</span> <span class="k">else</span> <span class="s">&quot;&quot;</span><span class="p">))</span> </pre></div> <p>Ahora, veremos el funcionamiento básico que nos permite este script. Primero vemos las tareas que tenemos disponibles:</p> <div class="codehilite"><pre><span class="gp">$</span> fab -l <span class="go"> fabfile.py: A fabric script for generate my personal blog</span> <span class="go">Available commands:</span> <span class="go"> bootstrap Get Pelican and install it in a virtual enviroment.</span> <span class="go"> img4web Optimize .jpg &amp; .png images and copy them into source pict...</span> <span class="go"> new Create a new blog article.</span> <span class="go"> publish Publish into remote server with rsync.</span> <span class="go"> pull_pelican Update Pelican to last revision from repository.</span> <span class="go"> regen Regenerate the site from source.</span> </pre></div> <p>Veamos que hacen cada una de ellas:</p> <ul> <li> <p><strong><em>bootstrap</em></strong> Si observamos el código, veremos que lo hace es, en este orden: eliminar cualquier entorno virtual previo, crear un entorno virtual nuevo, descargar Pelican desde el repositorio (si no lo hemos hecho anteriormente) e instalar Pelican dentro de este entorno virtual. Y todo esto en un solo paso, casi todos los comandos que explicaba en <a href="http://joedicastro.com/pelican-introduccion-e-instalacion.html">Pelican - Introducción e Instalación</a> con solo teclear <code>fab bootstrap</code>. Así de fácil. Con este comando podemos tanto crear una instalación de Pelican desde cero, como actualizar la instalación de Pelican después de actualizar este a la última versión con <strong><em>pull-pelican</em></strong>. Siguiendo con nuestro ejemplo, lo que haría este comando es crear los directorios <em>env</em> y <em>pelican</em> dentro de <em>myblog.com</em> con el entorno virtual creado y pelican instalado.</p> <div class="codehilite"><pre><span class="gp">$</span> fab bootstrap </pre></div> </li> <li> <p><strong><em>img4web</em></strong> Este comando hace uso del script que describía en <a href="http://joedicastro.com/optimizar-imagenes-para-la-web.html">Optimizar imágenes para la web</a> para hacer precisamente eso, reducir el peso de las imágenes que empleo en los artículos. Lo que hago es a medida que voy escribiendo el articulo es ir guardando las imágenes en el directorio raíz (en nuestro ejemplo, <em>myblog.com/</em>) y cuando lo termino, simplemente ejecuto el comando <code>fab img4web</code> y este me optimiza las imágenes, me guarda las optimizadas en el directorio de imágenes del contenido (<em>myblog.com/site/source/pictures/</em>) y me elimina las imágenes originales del directorio raíz. Cuando termina me muestra un resumen con la cantidad de imágenes procesadas y el ahorro en espacio conseguido. Espacio en disco ahorrado que se resume en menos ancho de banda consumido y en páginas web que se cargan más rápido.</p> <div class="codehilite"><pre><span class="gp">$</span> fab img4web </pre></div> </li> <li> <p><strong><em>new</em></strong> Con este creo o edito los artículos del blog. Realiza tres funciones: me abre una venta de Gedit con el articulo que le indico con la extensión <code>.md</code>, me abre una ventana de Firefox que me muestra el fichero <em>index.html</em> del directorio del sitio generado por Pelican (<em>myblog.com/site/output/index.html</em>) y finalmente me activa Pelican con la opción <code>autoreload</code>. Luego empleando el plugin <strong>Grid</strong> de Compiz, divido la pantalla en dos mitades y coloco a la izquierda Gedit y a la derecha Firefox. Esto me permite, como explicaba en <a href="http://joedicastro.com/de-drupal-a-pelican.html">De Drupal a Pelican</a> editar el contenido y previsualizar el resultado casi en tiempo real, disponiendo al mismo tiempo de un buen corrector ortográfico. </p> <div class="codehilite"><pre><span class="gp">$</span> fab new:<span class="s2">&quot;Articulo de prueba&quot;</span> </pre></div> </li> <li> <p><strong><em>publish</em></strong> El más importante, el que sube los artículos al servidor web. Publicar el contenido de la web es tan sencillo como ejecutar este comando. Lo que hace es regenerar el contenido (por si hubiera algún cambio sin guardar) y luego mostrarme el resultado en firefox. Pero el resultado que me muestra no es el del directorio de salida de Pelican, si no de una copia que tengo en un servidor Apache local. Esto me permite ver los cambios de manera más fiel a la versión web, puesto que hace uso del fichero .htaccess y de las reglas que tengo establecidas en él. Finalmente me pregunta si realmente deseo publicar el contenido, por si se me hubiera escapado algo. Si le digo que no, aborta la publicación, pero si le digo que si, me sincroniza el contenido de la carpeta local con la remota empleando <strong>rsync</strong>. De esta manera solo se transmiten los ficheros nuevos, se borran los que se hayan eliminado en local y <strong>solo transmite la parte que haya cambiado de los archivos modificados</strong>. Gracias a esto, modificar o añadir contenido es cuestión de segundos. Y sencillisimo.</p> <div class="codehilite"><pre><span class="gp">$</span> fab publish </pre></div> </li> <li> <p><strong><em>pull_pelican</em></strong> Nos sirve para actualizar Pelican a la última revisión disponible en el repositorio oficial. Si después de ejecutarlo, queremos instalar la nueva versión en nuestro entorno virtual para poder emplearla, simplemente tenemos que volver a ejecutar <code>fab bootstrap</code> y todo se realizará de forma automática.</p> <div class="codehilite"><pre><span class="gp">$</span> fab pull_pelican </pre></div> </li> <li> <p><strong><em>regen</em></strong> El proceso principal, es el que le pide a Pelican que genere el sitio web a partir de nuestro directorio de origen. También realiza varios procesos: primero eliminar el directorio de salida actual (para tener una copia fresca), genera el nuevo contenido, luego procesa los archivos para que validen en HTML5 y finalmente hace una copia del directorio de salida a mi servidor local Apache. El procesar los archivos para validar en HTML5 se debe a que markdown crea unos enlaces <code>rel = "footnote"</code> y <code>rev = "footnote"</code> en las notas al pie que se han quedado obsoletos y no son necesarios. De momento es un post-procesado, pero puede que finalmente modifique Pelican para que se haga en tiempo de generación del sitio. Aunque creo que el rendimiento de esta manera sería menor que emplear el comando <code>sed</code> que ejecuta este proceso, será cuestión de probarlo. También se podría modificar markdown.</p> </li> </ul> <p>Con solo <strong>6</strong> comandos tengo automatizadas todas las tareas básicas para administrar y crear contenido en mi blog. Ni siquiera el potente y buenísimo <a href="http://drupal.org/project/drush">drush</a> de Drupal me permitía este nivel de automatización (aunque se acercaba bastante). De esta manera solo me tengo que preocupar de crear artículos y de las posibles personalizaciones que le quiera realizar al tema del sitio. Me olvido de todo lo demás, de todo lo que conlleva un CMS. Solo hay una manera de bloguear más cómoda para los que a estos les parezca algo complejo, servicios como Tumblr. Aunque si quieres tener el control sobre tu sitio, no conozco manera más cómoda y con más ventajas que esta. </p>joe di castroTue, 28 Jun 2011 23:54:00 +0200http://joedicastro.com/pelican-publicacion-y-automatizacion.htmlpelicanpythonmarkdownrestructuredtextbloghtmlrsyncfabricPelican - Creación de contenidohttp://joedicastro.com/pelican-creacion-de-contenido.html<p>Crear contenido con <strong>Pelican</strong> es lo más sencillo que uno pueda imaginarse. Por ejemplo, crear este articulo, se puede hacer del siguiente modo. Abrimos un editor de textos cualquiera (por ejemplo vi o gedit) y creamos un archivo nuevo llamado Pelican, con la extensión <em>.md</em> si queremos emplear Markdown o <em>.rst</em> si queremos emplear reStructuredText. Vemos como lo haría, para este blog en concreto. Este sería el texto para crearlo en formato reStructuredText:</p> <div class="codehilite"><pre><span class="gh">Pelican - Creación de contenido</span> <span class="gh">###############################</span> <span class="nc">:tags:</span> <span class="nf">Pelican, python, markdown, reStructuredText, blog, HTML.</span> Crear contenido con <span class="gs">**Pelican**</span> es lo más sencillo que uno pueda imaginarse. Por ejemplo, crear este articulo, se puede hacer del siguiente modo. Abrimos un editor de textos cualquiera (por ejemplo vi o gedit) y creamos un archivo nuevo llamado Pelican, con la extensión <span class="ge">*.md*</span> si queremos emplear Markdown o <span class="ge">*.rst*</span> si queremos emplear reStructuredText. </pre></div> <p>Y este el que usaría para crearlo en markdown, que es el que yo empleo:</p> <div class="codehilite"><pre>title: Pelican - Creación de contenido tags: Pelican, python, markdown, reStructuredText, blog, HTML, Piwik, Disqus. Crear contenido con **Pelican** es lo más sencillo que uno pueda imaginarse. Por ejemplo, crear este articulo, se puede hacer del siguiente modo. Abrimos un editor de textos cualquiera (por ejemplo vi o gedit) y creamos un archivo nuevo llamado Pelican, con la extensión *.md* si queremos emplear Markdown o *.rst* si queremos emplear reStructuredText. Vemos como lo haría, para este blog en concreto. </pre></div> <p>Ahora solo tendríamos que guardar este fichero en la carpeta raíz de nuestro contenido y ejecutar Pelican para generar la página web resultante. Así de sencillo. Por ejemplo, creamos una carpeta <em>prueba</em> dentro de la estructura de ficheros que habíamos creado en el <a href="http://joedicastro.com/pelican-introduccion-e-instalacion.html">articulo anterior</a> (<em>myblog.com/</em>) y guardamos allí este fichero. Ahora ejecutamos pelican dentro del entorno virtual y nos creara una carpeta <em>output</em> donde como resultado tendremos un blog por defecto creado como por arte de magia. Es decir, hacemos esto:</p> <div class="codehilite"><pre><span class="gp">$</span> mkdir prueba <span class="gp">$</span> vi prueba/pelican.md <span class="gp">$</span> <span class="nb">source </span>env/bin/activate <span class="gp">$</span> pelican prueba/ <span class="gp">$</span> ls <span class="go">env output pelican prueba site temp</span> <span class="gp">$</span> firefox output/index.html </pre></div> <p>y obtenemos esto:</p> <p style="text-align:center;"><img src="pictures/sample_article.png" alt="pelican sample article" title="pelican sample article" width=700 height=465 /></p> <h2 id="estructura_del_articulo">Estructura del articulo</h2> <p>En el ejemplo anterior lo único que varía entre ambos formatos (aparte de la sintaxis) es la cabecera del mismo. En la cabecera se incluye el titulo del mismo (no tiene porque coincidir con el nombre del fichero) y los metadatos. El titulo en reStructuredText va subrayado con símbolos <code>#</code> y en markdown es un metadato más. Excepto el título, todos los metadatos son opcionales. Los metadatos en <em>.rst</em> van precedidos de dos puntos <code>:</code>. Después de los metadatos es suficiente con dejar una linea en blanco para comenzar a redactar el contenido de nuestro articulo. </p> <p>Los metadatos que se pueden incorporar son los siguientes:</p> <ul> <li> <p><strong>title</strong> (solo como metadato en markdown): Es el titulo del artículo o página.</p> </li> <li> <p><strong>date</strong>: Es la fecha y hora de publicación. Si no se indica, tomara como tal los valores del propio fichero de texto. El formato es el siguiente: año-mes-dia hora:minutos, es decir, <code>%Y-%m-%d %H:%M</code></p> </li> <li> <p><strong>category</strong>: La categoría en la que queremos englobar el articulo. Si no se especifica, puede coger la categoría por defecto que se haya especificado en el fichero de configuración si así se ha establecido (por defecto es <em>misc</em>). Otra forma aún más simple, es crear un directorio dentro de nuestro directorio de contenido y colgar los archivos dentro de él. Todos los que se encuentren dentro de ese directorio caerán en la categoría que coincida con el nombre del mismo. Así es como yo lo hago, con un directorio llamado blog, es idoneo para organizar el contenido. </p> <p>En el tema por defecto, las categorías se añaden como una entrada al menú superior que al ser seleccionada, muestra todos los artículos englobados dentro de ella.</p> </li> <li> <p><strong>author / authors</strong>: El autor(es) del articulo. Si se omite, escoge por defecto el que se haya establecido en el fichero de configuración. Yo lo omito, pero puede ser muy útil para blogs escritos por varios autores.</p> </li> <li> <p><strong>tags</strong>: Las etiquetas con las que etiquetamos a nuestro articulo. El tema por defecto solo nos permite seleccionar una y ver todos los artículos etiquetados de igual modo, pero es bastante sencillo crear una nube de etiquetas como la que empleo en este blog.</p> </li> <li> <p><strong>summary</strong>: Es el resumen que queremos que se vea del articulo cuando se emplea la paginación. Por defecto, si no se especifica este campo, los artículos se resumen con las primeras 50 palabras del mismo.</p> </li> <li> <p><strong>slug</strong>: Esta es uno de los campos más curiosos, pero al mismo tiempo más geniales. Este campo es el nexo que nos permite enlazar varias versiones del mismo articulo en distintos idiomas. En el tema por defecto, nos muestra las distintas traducciones de un articulo, si es que existen.</p> </li> <li> <p><strong>status</strong>: Esta es un campo especial que solo admite dos valores, <code>draft</code> (borrador) y <code>published</code> (publicado). Cualquier otro valor es ignorado. Si el valor es <code>draft</code>, el articulo o pagina no aparece publicado ni referenciado de algún modo al generar el contenido, y solo está disponible si accedemos a él a través del directorio <em>drafts/</em>. Esto es una ayuda para evitar que por un descuido subamos a la web un articulo sin terminar. Yo no lo empleo, ya veremos cuando hable de le automatización, como he resuelto este posible problema de otro modo. Si lo empleamos, deberíamos añadir el directorio <em>drafts/</em> a nuestro fichero <em>robots.txt</em> como <code>Disallow</code> para que no fuera indexado por los buscadores (de poco importaría ocultar el el borrador si lo haces accesible a través del buscador). </p> </li> </ul> <p>Para comprender el resto de opciones disponibles para crear el contenido, voy a centrarme en el sitio de ejemplo que viene por defecto con Pelican. Empezaremos eliminando las pruebas que acabamos de realizar.</p> <div class="codehilite"><pre><span class="gp">$</span> rm -r output/ <span class="gp">$</span> rm -r prueba/ <span class="gp">$</span> ls <span class="go">env pelican site</span> </pre></div> <h2 id="estructura_del_contenido_del_ejemplo">Estructura del contenido del ejemplo</h2> <p>Ahora, en el directorio de contenido del sitio de ejemplo, tenemos la siguiente estructura de ficheros:</p> <div class="codehilite"><pre><span class="gp">$</span> <span class="nb">cd </span>site/ <span class="gp">$</span> tree <span class="nb">source</span>/ <span class="go">source/</span> <span class="go">├── another_super_article-fr.rst</span> <span class="go">├── another_super_article.rst</span> <span class="go">├── cat1</span> <span class="go">│   ├── article1.rst</span> <span class="go">│   ├── article2.rst</span> <span class="go">│   ├── article3.rst</span> <span class="go">│   └── markdown-article.md</span> <span class="go">├── draft_article.rst</span> <span class="go">├── extra</span> <span class="go">│   └── robots.txt</span> <span class="go">├── pages</span> <span class="go">│   └── test_page.rst</span> <span class="go">├── pictures</span> <span class="go">│   ├── Fat_Cat.jpg</span> <span class="go">│   ├── Sushi.jpg</span> <span class="go">│   └── Sushi_Macro.jpg</span> <span class="go">├── super_article.rst</span> <span class="go">├── unbelievable.rst</span> <span class="go">└── unwanted_file</span> </pre></div> <p>Donde:</p> <ul> <li> <p><strong><em>another_super_article-fr.rst</em></strong> y <strong><em>another_super_article.rst</em></strong> son dos versiones del mismo articulo en inglés y francés. Aunque cuelgan del directorio raíz, ambos están englobados dentro del sitio en la categoría <em>bar</em> a través del metadato <strong>category</strong> y enlazados traducciones mediante el metadato <strong>slug</strong> <code>:slug: oh-yeah</code></p> </li> <li> <p><strong><em>draft_article.rst</em></strong> es un articulo que no aparece publicado en el sitio de ejemplo al estar marcado como borrador con el metadato <strong>status</strong>, pero al que podemos acceder igualmente a través de <code>myblog.com/site/source/drafts/a-draft-article.html</code></p> </li> <li> <p><strong><em>super_article.rst</em></strong> y <strong><em>unbelievable.rst</em></strong> son ejemplos de uso de metadados. El primero es un articulo que cuelga de la categoría <em>yeah</em> y que sirve como ejemplo del empleo de <strong>summary</strong> y del uso de imágenes y código. El segundo es un ejemplo de articulo sin más metadatos que la fecha del mismo y de como cae en la categoría <strong>misc</strong> por defecto.</p> </li> <li> <p><strong><em>unwanted_file</em></strong> es un articulo que no se procesa de ningún modo por carecer de extensión que lo identifique como markdown o reStructuredText. Como consecuencia este fichero ni siquiera se copia al sitio web generado. Puede ser un truco útil para emplearlo como fichero de notas personales de cualquier tipo, por ejemplo un recordatorio de como hemos definido la estructura de archivos, una chuleta como usar marcado o reStructuredText, artículos pendientes, ...</p> </li> <li> <p><strong><em>cat1</em></strong> Este directorio es un ejemplo de como todos los artículos que cuelgan de él son englobados dentro de la categoría <em>cat1</em> de forma automática. Esto nos evita escribir el metadato <strong>category</strong> en cada uno de ellos y nos ayuda a clasificarlos en el directorio. Y nos muestra como se pueden mezclar archivos markdown y reStructuredText sin ningún tipo de problemas.</p> </li> <li> <p><strong><em>extra</em></strong> En esta carpeta (puede ser otra, es configurable) englobamos archivos que queremos incluir en el sitio, pero que no han de ser procesados. Como por ejemplo: .htaccess, .robots.txt, <a href="http://humanstxt.org/ES">.humans.txt</a>, ... Esto puede cambiarse en el fichero de configuración, especificando el origen dentro del directorio de nuestro contenido y la ruta en la que queremos que esté en el sitio web. En este caso, sería así en el fichero de configuración <code>pelican.conf.py</code></p> <div class="codehilite"><pre><span class="n">FILES_TO_COPY</span> <span class="o">=</span> <span class="p">((</span><span class="s">&#39;extra/robots.txt&#39;</span><span class="p">,</span> <span class="s">&#39;robots.txt&#39;</span><span class="p">),)</span> </pre></div> </li> <li> <p><strong><em>pages</em></strong> Serían las páginas estáticas del sitio, lo que no son artículos. Este nombre de directorio está reservado para esta función por defecto. Por ejemplo la página <a href="http://joedicastro.com/pages/markdown.html"><em>markdown</em></a> que empleo en este blog, sería una de estas páginas estáticas. En estas páginas no están disponibles los comentarios. Si se especifica en el fichero de configuración, estas páginas aparecerán como entradas en el menú principal del tema por defecto. </p> </li> <li> <p><strong><em>pictures</em></strong> Este es uno de los directorios que se pueden emplear para albergar contenido estático como son las imágenes. Esto es configurable en el fichero de configuración. En este caso lo que se guardan en el son las imágenes empleadas en los artículos. Estas acabaran dentro del directorio <code>static/pictures/</code> de nuestro sitio. </p> </li> </ul> <p>Y ya está, es una estructura muy sencilla y que genera un resultado bastante decente, comparado con los cientos de archivos que emplea (a parte de la BDD) cualquier CMS como Wordpress o Drupal.</p> <p>Si partiéramos de un blog ya creado, Pelican proporciona una herramienta, que en nuestro caso estaría en <em>/myblog.com/pelican/tools/importer.py</em> y que nos permite importar artículos desde Wordpress o desde un fichero RSS y que nos genera los contenidos en reStructuredText. Si quisiéramos emplear markdown, existe una herramienta externa, <a href="http://www.codefu.org/wiki/Main/Html2markdown"><strong>html2markdown</strong></a> que nos permite obtener un texto en markdown desde una página web. Otra herramienta similar a esta última sería <a href="http://www.aaronsw.com/2002/html2text/">html2text</a>.</p> <p>No tiene más secreto que este, crear ficheros de texto plano en formato <em>.md</em> o <em>.rst</em>, guardarlos en el directorio que empleamos para albergar el contenido y generar el blog.</p>joe di castroMon, 27 Jun 2011 18:27:00 +0200http://joedicastro.com/pelican-creacion-de-contenido.htmlpelicanpythonmarkdownrestructuredtextbloghtmlPelican - Introducción e Instalaciónhttp://joedicastro.com/pelican-introduccion-e-instalacion.html<p><a href="http://docs.notmyidea.org/alexis/pelican/">Pelican</a> es un generador de sitios web con contenido estático. Está orientado originalmente a la creación de blogs. <strong>Pelican</strong> (Pelicano) es una anagrama de la palabra francesa <em>Calepin</em> que significa en español "cuaderno de notas" (blog). Su creador y desarrollador principal es el programador francés <a href="http://blog.notmyidea.org/">Alexis Métaireau</a>. Y es la aplicación que genera el contenido para este blog. Personalmente le veo muchas ventajas frente a una plataforma de blogs convencional como Wordpress o Drupal, como ya comentaba en mi <a href="http://joedicastro.com/de-drupal-a-pelican.html">anterior articulo</a>. </p> <p>Pelican genera este contenido estático (páginas HTML) a partir de ficheros de texto plano formateados en un lenguaje de marcado ligero como <a href="http://es.wikipedia.org/wiki/Markdown">Markdown</a> o <a href="http://es.wikipedia.org/wiki/ReStructuredText">reStructuredText</a>. También crea fuentes RSS y Atom de los artículos. Y dependiendo del tema empleado se pueden tener un archivo de los artículos publicados, clasificación por categorías, nube de etiquetas, un <a href="http://es.wikipedia.org/wiki/Blogroll">blogroll</a>, enlaces a redes sociales, botón para tweeter, paginación, traducciones, etc. Aunque viene un tema completo por defecto y están disponibles <a href="https://github.com/ametaireau/pelican-themes">algunos más</a>, se puede crear uno completamente personalizado desde cero. La creación de estos temas se basa en el sistema de plantillas <a href="http://jinja.pocoo.org/">jinja2</a>, lo que nos permite una gran flexibilidad. También disponemos de varios scripts que nos proporcionan soporte para comentarios con <a href="http://disqus.com">Disqus</a> y de analíticas con <a href="http://www.google.com/intl/es/analytics/">Google Analytics</a> ó <a href="http://piwik.org/">Piwik</a>. También nos permite generar ficheros PDFs de los artículos automáticamente y mostrar los enlaces a ellos, siempre que los artículos se hayan creado con reStructuredText.</p> <p>Es un software muy joven, el primer commit en <a href="https://github.com/ametaireau/pelican">GitHub</a> data del 13 de Agosto de 2010, pero que ha evolucionado bastante rápido y que aún sigue desarrollándose a un buen ritmo. Es posible que por esto aún tenga alguna carencia o algún que otro fallo, pero su autor es muy receptivo y acepta de buena gana las sugerencias, informes de errores y colaboraciones de desarrollo. Cuenta con una documentación bastante decente y actualizada. Alguno que otra cosa no está documentada, pero lo veo normal dado el ritmo de desarrollo y de a quien va orientado un software como este. Es muy sencilla su instalación y su utilización cuando se ha leído esta, pero será mejor que lo explique con un ejemplo sobre la marcha.</p> <h2 id="instalaci+n_para_linux">Instalación (para Linux)</h2> <p>La instalación del mismo es relativamente sencilla si no queremos complicarnos la vida, siempre tenemos la última versión disponible en el <a href="http://pypi.python.org/pypi/pelican/2.7.2">PyPi</a>. Así que instalarlo podría ser tan sencillo como esto:</p> <div class="codehilite"><pre><span class="gp">$</span> easy_install pelican </pre></div> <p>Aunque recomiendo emplear <a href="http://www.pip-installer.org/en/latest/index.html"><code>pip</code></a> en lugar de <code>easy_install</code>, de este modo:</p> <div class="codehilite"><pre><span class="gp">$</span> pip install pelican </pre></div> <p>De todos modos desaconsejo emplear este método, me parece mejor solución, dada la velocidad de desarrollo del software, emplear un entorno virtual para su instalación. Un <a href="http://www.virtualenv.org/en/latest/index.html">entorno virtual</a> nos permite tener una versión de Python independiente de la del resto del sistema, con sus propias librerías y con el software instalado que nosotros deseemos. Todo esto solo estará disponible cuando nos encontremos dentro de este entorno virtual, sin afectar al resto del sistema. Y podemos eliminarlo o des/activarlo cuando deseemos. Es bastante más sencillo de utilizar de lo que parece y es realmente potente. </p> <p>Veamos, paso a paso, la forma en que yo lo instalaría.</p> <p>Creamos una carpeta que contendrá Pelican, el entorno virtual y el sitio que crearemos. Yo le daría el nombre de la URL del blog, por ejemplo, <em>myblog.com</em></p> <div class="codehilite"><pre><span class="gp">$</span> mdkir myblog.com <span class="gp">$</span> <span class="nb">cd </span>myblog.com </pre></div> <p>Descargamos la revisión actual del repositorio de Pelican en GitHub. Esto nos creara una carpeta llamada <em>pelican</em> que contendrá una copia del repositorio en local (lo cual nos será muy útil en el futuro para actualizarlo). </p> <div class="codehilite"><pre><span class="gp">$</span> git clone git://github.com/ametaireau/pelican.git <span class="go">Cloning into pelican...</span> <span class="go">remote: Counting objects: 2603, done.</span> <span class="go">remote: Compressing objects: 100% (1143/1143), done.</span> <span class="go">remote: Total 2603 (delta 1541), reused 2420 (delta 1374)</span> <span class="go">Receiving objects: 100% (2603/2603), 687.30 KiB | 397 KiB/s, done.</span> <span class="go">Resolving deltas: 100% (1541/1541), done.</span> </pre></div> <p>Ahora vamos a crear nuestro entorno virtual. En caso de no tener instalado <code>pip</code> o <code>virtualenv</code>, es rematadamente sencillo:</p> <div class="codehilite"><pre><span class="gp">$</span> easy_install pip <span class="gp">$</span> pip install virtualenv </pre></div> <p>Voy a llamar <em>env</em> a nuestro entorno virtual. Lo creamos así.</p> <div class="codehilite"><pre><span class="gp">$</span> virtualenv env <span class="go">New python executable in env/bin/python</span> <span class="go">Installing distribute...........................................................</span> <span class="go">................................................................................</span> <span class="go">.......................................done.</span> <span class="gp">$</span> ls <span class="go">env pelican</span> </pre></div> <p>Ahora activaremos nuestro entorno virtual para "sumergirnos" dentro de él. </p> <div class="codehilite"><pre><span class="gp">$</span> <span class="nb">source </span>env/bin/activate <span class="gp">(env)$</span> </pre></div> <p>Vemos que aparece el nombre del entorno virtual entre paréntesis antes de la línea del <a href="http://es.wikipedia.org/wiki/Prompt">prompt</a>. Eso quiere decir que nos encontramos dentro de este entorno virtual. Ahora procederemos a instalar Pelican. </p> <div class="codehilite"><pre><span class="gp">$</span> <span class="nb">cd </span>pelican/ <span class="gp">$</span> python setup.py install </pre></div> <p>Ahora tenemos ya instalado Pelican, <strong>solo dentro de nuestro entorno virtual</strong>. Si probamos a llamar al programa fuera de él, veremos que no está disponible, luego necesitaremos activar este entorno cada vez que queramos emplearlo.</p> <div class="codehilite"><pre><span class="gp">$</span> pelican <span class="go">CRITICAL: you need to specify a path containing the content (see pelican --help for </span> <span class="go">more information)</span> </pre></div> <p>Nos da un error porque no le hemos pasado los parámetros necesarios. Ahora desactivamos el entorno y volvemos a llamar al programa y nos dice que no existe.</p> <div class="codehilite"><pre><span class="gp">$</span> deactivate <span class="gp">$</span> pelican <span class="go">pelican: orden no encontrada</span> </pre></div> <p>Tenemos ahora dentro de <em>myblog.com/</em> dos directorios, <em>env</em> y <em>pelican</em>. Podríamos borrar ahora el directorio <em>pelican</em> porque ya lo tenemos instalado dentro del entorno virtual, pero sería bueno conservarlo para poder actualizarlo en el futuro mediante <code>git pull</code>. Yo crearía una tercer directorio, <em>site</em> donde se alojaría nuestro sitio, organizado a su vez en tres subdirectorios: </p> <ul> <li> <p><strong>source</strong>: sería la carpeta donde alojaríamos los archivos de texto de nuestro blog y todo aquello que quisiéramos que formara parte de nuestro sitio: imágenes, fichero <a href="http://es.wikipedia.org/wiki/Htaccess">.htacess</a>, fichero <a href="http://es.wikipedia.org/wiki/Robots.txt">robots.txt</a>, páginas personalizadas...</p> </li> <li> <p><strong>output</strong>: El resultado del procesamiento de Pelican, es decir, nuestro blog.</p> </li> <li><strong>theme</strong> : Sería el tema que usariamos para crear nuestro blog, en el estarían las plantillas <strong>jinja2</strong>, las hojas de estilo .css, el contenido estático (iconos, imágenes), ...</li> </ul> <p>Luego, lo haríamos así:</p> <div class="codehilite"><pre><span class="gp">$</span> <span class="nb">cd</span> .. <span class="gp">$</span> mkdir -p site/source <span class="gp">$</span> mkdir site/output <span class="gp">$</span> mkdir site/theme <span class="gp">$</span> ls site/ <span class="go">output source theme</span> </pre></div> <p>Ya está, tenemos instalado Pelican y creada nuestra estructura para empezar a trabajar con él. Para eso nada mejor que crear un primer sitio de ejemplo. Entramos en el entorno virtual y creamos el sitio que viene de ejemplo con Pelican:</p> <div class="codehilite"><pre><span class="gp">$</span> <span class="nb">source </span>env/bin/activate <span class="gp">$</span> pelican pelican/samples/content/ -o site/output -s pelican/samples/pelican.conf.py </pre></div> <p>Y ahora si abrimos el fichero <code>myblog.com/site/output/index.html</code> en un navegador, veremos algo como esto (en la imagen se ve la categoría cat1 seleccionada):</p> <p style="text-align:center;"><img src="pictures/sample_blog.png" alt="pelican sample blog" title="pelican sample blog" width=453 height=700 /></p> <p>Es así de fácil de emplear Pelican, simplemente especificarle el directorio donde está el origen del contenido, el directorio destino y el fichero de configuración. Aunque con el fichero de configuración correctamente creado, solo será necesario indicarle la ubicación del mismo. Para comprender mejor la estructura y como funciona Pelican, sería buena idea copiar el tema, el fichero de configuración y el contenido que han generado este sitio de ejemplo a la carpeta <em>site</em> para no empezar nuestro blog desde cero.</p> <div class="codehilite"><pre><span class="gp">$</span> cp -r pelican/samples/content/* site/source <span class="gp">$</span> cp -r pelican/pelican/themes/notmyidea/* site/theme/ <span class="gp">$</span> cp pelican/samples/pelican.conf.py site/ </pre></div> <p>En próximos artículos veremos como crear artículos, publicar el sitio, personalizar el tema y automatizar todos estos procesos para hacerlo todo mucho más sencillo. </p>joe di castroMon, 27 Jun 2011 10:21:00 +0200http://joedicastro.com/pelican-introduccion-e-instalacion.htmlpelicanpythonmarkdownrestructuredtextbloghtmlpiwikdisqusDe Drupal a Pelicanhttp://joedicastro.com/de-drupal-a-pelican.html<p>Este blog no está realizado con ningún <abbr title="Content Management System (en español, &quot;Sistema de gestión de contenidos&quot;)">CMS</abbr>, ni siquiera utiliza <abbr title="Base de datos">BDD</abbr> alguna, es simplemente HTML + CSS y nada más. Es decir, es contenido estático, no dinámico. Hasta hace 3 días estaba funcionando con el mejor <abbr title="Content Management System (en español, &quot;Sistema de gestión de contenidos&quot;)">CMS</abbr> <a href="http://es.wikipedia.org/wiki/PHP">PHP</a> que conozco, <a href="http://drupal.org">Drupal</a>. Pero persiguiendo el camino hacia el minimalismo y la productividad (fiel al espíritu <a href="http://es.wikipedia.org/wiki/Principio_KISS"><abbr title="Keep It Simple, Stupid (en español, &quot;Mantenlo simple, estúpido&quot;). Ver enlace"><abbr title="Keep It Simple, Stupid (en español, &quot;Mantenlo simple, estúpido&quot;). Ver enlace">KISS</abbr></abbr></a>) que ya inicie cuando <a href="http://joedicastro.com/markdown-la-mejor-opcion-para-crear-contenidos-web.html">comencé a escribir todos mis artículos en Drupal con Markdown</a>, el siguiente paso era evidente. La pregunta era muy sencilla, si un blog consta de contenidos que rara vez cambian (exceptuando los comentarios) ¿para que necesito un gestor de contenidos dinámicos?</p> <p>La respuesta es fácil, para nada. Actualmente, gracias a servicios como los de <a href="http://disqus.com">Disqus</a>, <a href="http://livefyre.com/">Livefyre</a>, <a href="http://intensedebate.com/">IntenseDebate</a> ó <a href="http://www.aboutecho.com/commenting">Echo</a> es posible externalizar el único contenido dinámico básico de un blog, los comentarios. Todo lo demás puede ser contenido puramente estático, solo HTML y CSS, sin renunciar a prácticamente nada de lo que nos ofrece un blog basado en un <abbr title="Content Management System (en español, &quot;Sistema de gestión de contenidos&quot;)">CMS</abbr> como Wordpress o Drupal. Se pueden emplear scripts externos en javascript si se desea, o insertarlos dentro del HTML. Lo que nos permite implementar lo mismo que en un blog normal. Además se puede disponer también de feeds RSS y Atom.<br /> </p> <h2 id="elegir_un_generador_de_contenido_est+tico">Elegir un generador de contenido estático</h2> <p>Evidentemente la idea no es crear las paginas HTML a mano, ni de broma, lo lógico era seguir empleando la misma estrategia que ya había iniciado con Drupal, emplear solo ficheros de texto en formato Markdown que nos generarán el HTML necesario de forma automática. Entonces lo que tenía que encontrar era un software que me permitiera hacer lo mismo que Drupal, pero sin toda la parafernalia que rodea a un <abbr title="Content Management System (en español, &quot;Sistema de gestión de contenidos&quot;)">CMS</abbr>. Un generador de sitios web estáticos (a partir de markdown) y que a ser posible estuviera escrito en <strong>Python</strong>, mi lenguaje favorito. Como ya adelante en el <a href="http://joedicastro.com/markdown-la-mejor-opcion-para-crear-contenidos-web.html">artículo sobre Markdown</a>, existen varias opciones:</p> <ul> <li><a href="http://docs.notmyidea.org/alexis/pelican/">Pelican</a> de Alexis Métaireau, que emplea en su propio <a href="http://blog.notmyidea.org/">blog</a></li> <li><a href="http://www.blogofile.com/">Blogofile</a> de Ryan McGuire que también lo usa en su <a href="http://www.enigmacurry.com/">blog</a></li> <li><a href="http://hyde.github.com/">Hyde</a> de Lakshmi Vyas. Su <a href="http://ringce.com/blog/">blog</a> con Hyde también.</li> <li><a href="https://github.com/mitsuhiko/rstblog">rstblog</a> de Armin Ronacher. Solo permite reStructuredText, con él crea su <a href="http://lucumr.pocoo.org/">blog</a>, un ejemplo de elegancia y calidad.</li> </ul> <p>Bueno, tenía varias posibilidades, solo tenía que elegir una que se adaptara mejor a mis necesidades. De entrada descarté <strong>rstblog</strong> porque no permitía el empleo de markdown, cuando los otros permitían tanto .rst como .md como formatos de entrada. Solo me quedaban 3 candidatos. Así que lo primero que hice antes de nada, fue buscar blogs creados con cada uno de ellos, para ver que posibilidades reales ofrecían. Encontré ejemplos de blogs de mucha calidad de todos ellos. Aunque enseguida me di cuenta de una cosa, en dos de ellos los mejores blogs lo eran porque tenían una elevada personalización detrás (artículos de sus autores contándolo). Y curiosamente con el tercero, casi todos preferían quedarse con la configuración estándar, sin tocar prácticamente nada, y la verdad es que el resultado era bastante decente. Luego miré que cargaba cada uno de ellos en la página de entrada, y volvía a repetirse la misma tendencia. En los dos primeros vi demasiadas hojas de estilo, imágenes y demasiados scripts javascript, en el tercero, nuevamente se cargaban menos elementos. Finalmente comparé características, modo de funcionamiento y le eché un vistazo rápido al código. La impresión era otra vez la misma, dos de ellos, <strong>Hyde</strong> y <strong>Blogofile</strong> aunque aparentemente potentes, los veía innecesariamente complejos, en cambió <strong>Pelican</strong> era bastante más sencillo. Otra forma de determinar su repercusión era contar el número de descargas de cada una de las aplicaciones desde PyPi. Los números son los siguientes (a 27 de Junio de 2011), obtenidos con <a href="https://github.com/aclark4life/vanity">Vanity</a> o <a href="http://pythonpackages.com/">pythonpackages.com</a>:</p> <table> <thead> <tr> <th>Paquete</th> <th>Descargas</th> <th>Descargas (2-12-2011)</th> <th>Descargas (7-4-2012)</th> </tr> </thead> <tbody> <tr> <td>Blogofile</td> <td>2.419</td> <td>3.854</td> <td>5.276</td> </tr> <tr> <td>Hyde</td> <td>1.945</td> <td>4.518</td> <td>7.644</td> </tr> <tr> <td>Pelican</td> <td>3.919</td> <td>6.138</td> <td>10.126</td> </tr> </tbody> </table> <p>La elección final era Pelican y no me arrepiento en absoluto, la prueba es que esté blog está funcionando gracias a él (Gracias Alexis!). Aunque las otras dos son también muy buenas opciones, y seguramente serían la primera opción para más de uno. Y siempre podría cambiar fácilmente, porque el contenido seguiría estando guardado en ficheros de texto con marcado markdown. </p> <blockquote> <p><strong>Actualización</strong> (2-12-2011): </p> <p>La estructura de Pelican es tan sencilla y eficaz, que <a href="http://www.solberg.is/">Jökull Sólberg</a> ha creado a partir de una versión hospedada del mismo (y modificada) una de las plataformas de blogs más simples de utilizar que existen, <a href="http://calepin.co/">calepin.co</a>. Publicar articulos es tán fácil como crear un archivo markdown y guardarlo en tu cuenta de <a href="http://www.dropbox.com/">Dropbox</a>. Así de sencillo.</p> </blockquote> <p>No entraré en detalles ahora de como instalar y emplear <strong>Pelican</strong>, eso lo dejo para otro próximo articulo, <a href="http://joedicastro.com/pelican-introduccion-e-instalacion.html">Pelican</a>. Pero si voy a hacer un repaso de los pros y los contras de emplear Pelican frente a un <abbr title="Content Management System (en español, &quot;Sistema de gestión de contenidos&quot;)">CMS</abbr> como Drupal para crear un blog.</p> <h2 id="ventajas_de_pelican_vs_cms">Ventajas de Pelican vs <abbr title="Content Management System (en español, &quot;Sistema de gestión de contenidos&quot;)">CMS</abbr></h2> <h3 id="solo_ficheros_de_texto_no_bdd">Solo ficheros de texto, No <abbr title="Base de datos">BDD</abbr></h3> <p>Simplemente te tienes que preocupar de eso, ficheros de texto, es donde guardas el contenido que creas. Todo lo demás lo genera Pelican por ti. Nada de crear y gestiónar bases de datos, ni copias de seguridad de la misma y un montón de espacio y recursos desaprovechado solamente para generar dinámicamente el mismo contenido que te genera Pelican.</p> <h3 id="mejor_rendimiento_carga_de_p+gina_m+s_r+pida">Mejor rendimiento, carga de página más rápida</h3> <p>Generar contenido dinámico es más caro en recursos y es más lento (consultas a la <abbr title="Base de datos">BDD</abbr>). Sobre todo a medida que llenas tu <abbr title="Content Management System (en español, &quot;Sistema de gestión de contenidos&quot;)">CMS</abbr> de personalizaciones y plugins. ¿Que hacen prácticamente todos los sistemas de caché?, generar contenido estático para luego servirlo más rápidamente. ¿No es un poco estúpido crear contenido que apenas cambia en el tiempo, en un sistema dinámico que genera ese contenido cada vez y que para mejorar su rendimiento lo convierte en estático? Y ya no hablemos de las múltiples hojas CSS, scripts javascript y enlaces a contenido externo que cargan la mayoría de los <abbr title="Content Management System (en español, &quot;Sistema de gestión de contenidos&quot;)">CMS</abbr> por defecto. Cada plugin que añadimos pone su granito de arena y optimizar todo esto requiere dedicación y esfuerzo (o seguir sumando aún más plugins en el mejor de los casos). Con Pelican ya tienes directamente el contenido estático y menos recursos que descargar. En este blog, sin contar con los ficheros javascript de Disqus y Piwik, lo único que se descarga es un fichero HTML, una hoja CSS y las imágenes que se incluyen en los artículos (cuando las hay). Es decir sirves el mismo contenido pero generando menos tráfico desde tu servidor. </p> <h3 id="soporta_mejor_el_tr+fico">Soporta mejor el tráfico</h3> <p>Cuando un sitio web soporta mucho tráfico, emplear un <abbr title="Content Management System (en español, &quot;Sistema de gestión de contenidos&quot;)">CMS</abbr> requiere de mucha optimización y generalmente de mucha maquina o complejas instalaciones. Y la base principal siempre es un sistema de caché que sirva contenido lo más estático posible. Se cachea todo lo que se puede, y si es en memoria mejor. Las <abbr title="Base de datos">BDD</abbr> son un problema aparte, desde soluciones NoSQL a clusters o <abbr title="Base de datos">BDD</abbr> distribuidas. Con contenido estático no te tienes que preocupar de optimizar los accesos a la <abbr title="Base de datos">BDD</abbr>, solo de tener un buen servidor web y si quieres, cachear en memoria o ampliar máquina. Pero poco más.</p> <h3 id="seguridad">Seguridad</h3> <p>Olvídate de problemas de seguridad, los únicos agujeros de seguridad de un sitio con contenido estático están del lado del servidor web, de todo lo demás, te olvidas. Establece bien los permisos en el sistema de ficheros y punto. El único contenido dinámico del sitio (javascript) ni siquiera es algo que deba preocuparte, es algo externo que le concierne a <strong>Disqus</strong> o al sistema de analíticas web que elijas (Google Analytics o Piwik).</p> <h3 id="olvidarse_de_gestionar_un_cms_mantenimiento_mucho_m+s_sencillo_nulo">Olvidarse de gestionar un <abbr title="Content Management System (en español, &quot;Sistema de gestión de contenidos&quot;)">CMS</abbr>. Mantenimiento mucho más sencillo (nulo)</h3> <p>Instalar el <abbr title="Content Management System (en español, &quot;Sistema de gestión de contenidos&quot;)">CMS</abbr>, crear la <abbr title="Base de datos">BDD</abbr>, encontrar, instalar y probar los plugins que necesitas, actualizaciones, actualizaciones de seguridad, personalizaciones, temas... Todo lo que rodea a cualquier <abbr title="Content Management System (en español, &quot;Sistema de gestión de contenidos&quot;)">CMS</abbr>. Y ya no digamos si hablamos de un <abbr title="Content Management System (en español, &quot;Sistema de gestión de contenidos&quot;)">CMS</abbr> potente y complejo como Drupal, con cientos de posibilidades. Y sin olvidar toda la basura que se va acumulando en las <abbr title="Base de datos">BDD</abbr> tras varias actualizaciones y múltiples pruebas de plugins, con Pelican siempre tienes un sistema limpio. Todo eso lo olvidas con Pelican, lo instalas, personalizas y automatizas una sola vez, luego te olvidas de todo lo que no sea escribir (si quieres, nada te impide seguir cambiándolo y mejorándolo). Emplea tú tiempo en crear contenido.</p> <h3 id="backups_m+s_sencillos">Backups más sencillos</h3> <p>Con un <abbr title="Content Management System (en español, &quot;Sistema de gestión de contenidos&quot;)">CMS</abbr> <abbr title="No hacerlas es una decisión nefasta">deberías hacer Backups</abbr> del servidor web tanto del sistema de ficheros como de la <abbr title="Base de datos">BDD</abbr>. Y sería aconsejable tener un servidor web local montado para probar los cambios que vayas a hacer en el <abbr title="Content Management System (en español, &quot;Sistema de gestión de contenidos&quot;)">CMS</abbr> sin miedo a romper nada. Con Pelican ni siquiera necesitas hacer Backups del servidor ni del contenido web. Todo lo que necesitas para generarlo ya está en tu ordenador en esos ficheros de texto. Incluso si empleas un tema propio, también está en tu equipo. Así que las copias de seguridad de tu sitio web no son distintas a las que <abbr title="No me digas que aún no las haces, ¿estas de broma?">regularmente ya haces</abbr> de tu ordenador personal.</p> <h3 id="hosting_en_cualquier_sitio">Hosting en cualquier sitio</h3> <p>Solo tienes que alojar contenido estático, no necesitas <abbr title="Base de datos">BDD</abbr> ni soporte para ningún lenguaje o librería en particular. Puedes hasta utilizar recursos gratuitos como las páginas de <a href="https://github.com/">GitHub</a> o <a href="http://bitbucket.org/">BitBucket</a> o un sistema de ficheros en la nube económico como <a href="http://aws.amazon.com/es/s3/">Amazon S3</a> (o <a href="http://aws.amazon.com/es/cloudfront/">Amazon CloudFront</a>). Solo necesitas eso, servir ficheros, nada más. Hasta el hosting más económico te sirve. </p> <h3 id="emplear_un_cvs_para_gestionarlo">Emplear un <abbr title="Control Version System (en español, &quot;Sistema de Control de Versiones&quot;)">CVS</abbr> para gestionarlo</h3> <p>Poder emplear Git o Mercurial o cualquier otro <abbr title="Control Version System (en español, &quot;Sistema de Control de Versiones&quot;)">CVS</abbr> para gestionar los cambios del blog no tiene precio. Ningún sistema de revisiones de <abbr title="Content Management System (en español, &quot;Sistema de gestión de contenidos&quot;)">CMS</abbr> es tan potente. Además tienes la posibilidad de crear un <em>hook</em> para que al enviar un commit después de crear un articulo (o realizar un cambio) se suba el contenido automáticamente al servidor. Con esto realizar cualquier cambio o revertir un error es algo trivial. Además te permite subir una copia a un sitio como GitHub o BitBucket y tenerlo siempre disponible en cualquier sitio con conexión a la red. Como maravillosa opción, esto permite que el contenido de un blog, incluso de un mismo articulo, sea editado por más de una persona de manera bastante más sencilla, potente y menos propensa a errores que con un <abbr title="Content Management System (en español, &quot;Sistema de gestión de contenidos&quot;)">CMS</abbr>. </p> <h3 id="crear_los_articulos_off-line">Crear los articulos off-line</h3> <p>Eso te permite ir creando los artículos al ritmo que te de la gana, cuando quieras y en cualquier sitio con un portátil. No necesitas estar conectado a la red. Esto también puede hacerse con un <abbr title="Content Management System (en español, &quot;Sistema de gestión de contenidos&quot;)">CMS</abbr>, pero suele ser más complejo (exceptuando emplear cortar y pegar) e inseguro (si se habilita el envío remoto de artículos). Yo lo había logrado en Drupal empleando markdown, pero seguía necesitando un segundo paso on-line para personalizar las etiquetas. </p> <h3 id="edici+n_de_art+culos_m+s_c+moda">Edición de artículos más cómoda</h3> <p>Puede parecer que un <abbr title="Content Management System (en español, &quot;Sistema de gestión de contenidos&quot;)">CMS</abbr> con su editor WYSIWYG es más cómodo, pero todo lo contrario. Ya lo comentaba en el <a href="http://joedicastro.com/markdown-la-mejor-opcion-para-crear-contenidos-web.html">artículo sobre markdown</a>. Pero es que además me proporciona una mejor experiencia de edición y más potente. Explico como redacto yo los artículos para que se entienda mejor. Divido la pantalla en dos mitades, a la izquierda el editor de textos y a la derecha el navegador. Como editor de textos empleo Gedit, que tiene resaltado de texto para markdown y un corrector ortográfico (por esto no uso vim para esto) bastante mejor que el de Firefox (que solo examina el texto hasta cierto número de casos dudosos). Además Pelican tiene una maravillosa opción, <code>autoreload</code> que lo hace correr en segundo plano y cuando detecta un cambio en uno de los ficheros, vuelve a generar el contenido. Entonces en gedit le digo que autoguarde el contenido cada 3 minutos (o a voluntad, manualmente) y cuando Pelican lo detecta, automáticamente regenera los ficheros HTML. Como navegador empleo Firefox y tengo, abierto en una pestaña, el fichero <code>index.html</code> que genera Pelican y empleando la extensión <a href="https://addons.mozilla.org/es-ES/firefox/addon/auto-reload/?src=api">Auto Reload</a> el contenido de la página (en local) se actualiza automáticamente al detectar un cambio en el fichero. Es decir, como en la primera página se puede ver el contenido completo del último articulo, lo que estoy viendo es una previsualización automática del contenido en la página cada 3 minutos. Y todo esto en off-line, sin estar conectado a internet. Esto si es un verdadero editor WYSIWYG, y no los otros. Además, que demonios, los navegadores no se diseñaron para crear texto, cualquier editor de texto es más potente.</p> <h3 id="control_del_spam">Control del Spam</h3> <p>El Spam, esa lacra que azota toda la web. En Pelican, ese problema, lo tiene que gestionar Disqus, no tú. Tú solo tienes que gestionar el poco que se le escape. Pero el buscar un plugin, configurarlo y que funcione bien, es algo de lo que no tienes que preocuparte. En Drupal tenía este asunto solucionado, pero fue cosa de probar varios plugins, hasta que al final <a href="http://joedicastro.com/combatir-el-spam-en-drupal.html">di con uno que me lo solucionaba de verdad</a>. </p> <h3 id="recursos_de_cpu_y_ram">Recursos de CPU y RAM</h3> <p>El contenido dinámico consume mucha más memoria RAM y CPU en el servidor que servir contenido estático. Al fin y al cabo, en el caso del contenido estático, es poco más complejo que servir ficheros. Si tienes que compartir el servidor con más proyectos, agradecerás no tener que emplear un <abbr title="Content Management System (en español, &quot;Sistema de gestión de contenidos&quot;)">CMS</abbr> para servir el blog.</p> <h3 id="resaltado_de_sintaxis_incorporada_con_pygments">Resaltado de Sintaxis incorporada con Pygments</h3> <p>Mientras en la mayoría de <abbr title="Content Management System (en español, &quot;Sistema de gestión de contenidos&quot;)">CMS</abbr> necesitas un plugin para habilitar el resaltado de sintaxis para código fuente, en Pelican esto viene por defecto empleando el excelente <a href="http://pygments.org/">Pygments</a></p> <h3 id="cumplimiento_de_est+ndares_web">Cumplimiento de Estándares Web</h3> <p>Con Pelican es relativamente sencillo configurar el tema para que cumpla los estándares web y genere contenido valido. Y una vez que lo haces, es para siempre, a no ser que modifiques algo en el tema, todo el contenido que generes cumplirá con los estándares (a no ser que incluyas HTML dentro que no lo sea). De este modo, este sitio valida HTML5, CSS3 y genera feeds RSS y Atom validos. Conseguir esto con un <abbr title="Content Management System (en español, &quot;Sistema de gestión de contenidos&quot;)">CMS</abbr> y empleando editores WYSIWYG es bastante más complejo y doloroso. Aunque yo lo había conseguido con Drupal y markdown, tuve que modificar un tema casi por completo, casi como crearlo desde cero. </p> <h2 id="inconvenientes_de_pelican_vs_cms">Inconvenientes de Pelican vs <abbr title="Content Management System (en español, &quot;Sistema de gestión de contenidos&quot;)">CMS</abbr></h2> <h3 id="comentarios_sin_resaltado_de_sintaxis">Comentarios sin resaltado de sintaxis</h3> <p>Algo que me permitía Drupal y no me permite Disqus (por ahora) era emplear markdown en los comentarios y resaltado de sintaxis para el código fuente. Es el mayor inconveniente que he encontrado hasta ahora. Pero bueno, tampoco es algo imprescindible y esperemos que Disqus lo soporte en un futuro.</p> <h3 id="sitemap">Sitemap</h3> <p>Tampoco Pelican genera sitemaps en xml para los buscadores. Aunque tampoco es algo imprescindible y Drupal tampoco lo soporta por defecto, si no a través de un módulo. El autor lo tiene como tarea pendiente, y si tarda mucho, a lo mejor me animo y lo creo yo mismo.</p> <h3 id="personalizaci+n_m+s_sencilla_para_non_geeks">Personalización más sencilla para non geeks</h3> <p>Esta es la parte que menos me afecta, pero es el gran inconveniente para la gran mayoría sin conocimientos avanzados. Aunque Pelican no es difícil de instalar y configurar, si queremos personalizarlo bastante, la cosa cambia. Los <abbr title="Content Management System (en español, &quot;Sistema de gestión de contenidos&quot;)">CMS</abbr> son mucho más sencillos en ese sentido, pero el coste a pagar por otro lado no me compensa. </p> <h3 id="no_tiene_b+squeda_incorporada">No tiene búsqueda incorporada</h3> <p>Es otro pequeño inconveniente que puede suplirse empleando la de Google AdSense en el sitio, por ejemplo. Personalmente no me importa demasiado, teniendo disponibles en el sitio recursos como el archivo de todos los artículos publicados o la nube de etiquetas.</p> <h3 id="no_puedes_personalizar_el_contenido_din+micamente">No puedes personalizar el contenido dinámicamente</h3> <p>Con un <abbr title="Content Management System (en español, &quot;Sistema de gestión de contenidos&quot;)">CMS</abbr> puedes hacer cosas como mostrar un contenido o un tema distinto según el perfil del usuario, o según la carga del servidor, etc. Con contenido estático lógicamente no puedes hacer esto. A mi me da igual, no lo necesito, es solo un blog.</p> <br /> <p>Llevo varios años empleando Drupal en varios sitios y me sigue pareciendo un <abbr title="Content Management System (en español, &quot;Sistema de gestión de contenidos&quot;)">CMS</abbr> excelente y una buenísima opción para generar contenido dinámico para no desarrollladores (de otro modo prefiero un framework como Django). Pero actualmente, para crear blogs, si se tienen conocimientos suficientes, emplear un <abbr title="Content Management System (en español, &quot;Sistema de gestión de contenidos&quot;)">CMS</abbr> me parece una decisión poco acertada, es matar moscas a cañonazos. Hoy en día hay soluciones como Pelican y las mencionadas arriba (y otras alternativas en otros lenguajes) que te permiten crear blogs con facilidad, centrándote únicamente en crear los artículos y automatizar todo lo demás. ¿Acaso esa no es la razón principal del grandisimo éxito de <a href="http://twitter.com/">twitter</a> o <a href="http://www.tumblr.com/">tumblr</a>? La inmediatez de los resultados y la delegación de la gestión a terceros, tú solo escribes. Pelican te permite lo mismo, solo requiere la personalización inicial y listo, con la ventaja añadida de que puedes personalizarlo a tu gusto y hasta donde te dé la gana o seas capaz.</p>joe di castroWed, 22 Jun 2011 02:10:00 +0200http://joedicastro.com/de-drupal-a-pelican.htmlmarkdownrestructuredtextpelicandrupalcmspythonbloghtmlMarkdown, la mejor opción para crear contenidos webhttp://joedicastro.com/markdown-la-mejor-opcion-para-crear-contenidos-web.html<p>Normalmente cuando se crea contenido en un blog o CMS, como Wordpress, Blogger, Drupal, Joomla, Plone, Typo, etc, se hace a través de un editor visual (<abbr title="What You See Is What You Get (en inglés, &quot;lo que ves es lo que obtienes&quot;)">WYSIWYG</abbr>). Algunos editores de este tipo son <a href="http://tinymce.moxiecode.com/">TinyMCE</a>, <a href="http://ckeditor.com/">CKeditor</a>, <a href="http://nicedit.com/">NicEdit</a>, <a href="http://www.wymeditor.org/">WYMEditor</a>, <a href="http://markitup.jaysalvat.com/home/">markItUP!</a>, <a href="http://www.openwebware.com/">openWYSIWYG</a>, etc.</p> <p>Yo mismo he empleado varios de ellos durante años, en varias plataformas como Blogger, Wordpress, Joomla, Drupal, etc. Y si, hay que reconocerlo, te hacen la vida muy fácil, sobre todo para aquellos que no quieran preocuparse más que de añadir contenido en su página. E incluso usuarios más avanzados como administradores o diseñadores web, lo suelen emplear por comodidad frente a un área de texto plano. Y si, es cómodo, muy cómodo, a corto plazo. A largo plazo... a largo plazo es cuando empiezas a verle los peros y los problemas, que los tienen, y bastantes. Veamos cuales son esos problemas y la alternativa, que para mi personalmente, es la solución.</p> <h2 id="los_problemas_de_los_editores_wysiwyg">Los problemas de los editores <abbr title="What You See Is What You Get (en inglés, &quot;lo que ves es lo que obtienes&quot;)">WYSIWYG</abbr></h2> <p>Los editores visuales están pensados para que de una forma muy fácil, se pueda editar el contenido de forma visualmente atractiva, sin tenerse que andar preocupando del HTML que se genera a partir de él, esto es, no es necesario conocer nada de HTML para usar un editor <abbr title="What You See Is What You Get (en inglés, &quot;lo que ves es lo que obtienes&quot;)">WYSIWYG</abbr>. Puedes añadir negritas, cursivas, alinear el texto, cambiar el tamaño, el color, crear tablas, etc, sin conocimiento alguno de HTML o CSS. Se supone que el editor genera HTML valido correctamente por ti. Y aquí es donde empiezan los problemas:</p> <ul> <li> <p>Los editores visuales generalmente crean el formato con <strong>CSS embebido dentro del HTMl</strong>, es decir mezclando el contenido y el estilo de la página. Algunos incluso te permiten incluir tus propias hojas de estilo para que el contenido se ajuste al estilo actual de tu web.</p> <p>¿Pero que ocurre cuando al cabo de un tiempo, con decenas o más de artículos generados quieres cambiar el estilo de tú página? Pues dependiendo de como haya realizado el trabajo tu editor <abbr title="What You See Is What You Get (en inglés, &quot;lo que ves es lo que obtienes&quot;)">WYSIWYG</abbr>, te puedes encontrar con el desagradable problema de que todo queda desencajado o no se ajusta al estilo actual. Yo me he tenido que enfrentar con este problema en el pasado al actualizar una versión de Drupal y cambiar completamente el tema, y no fue nada cómodo de solucionar, o al importar contenido de un CMS a otro.</p> </li> <li> <p>Los editores visuales <strong>se crearon inicialmente para impresión en papel</strong>, no para HTML. Y HTML se emplea en multitud de dispositivos (desde móviles hasta ereaders) y bien empleado proporciona una flexibilidad que se rompe al mezclar la estructura del documento (HTML) con el estilo del mismo (CSS) en el mismo archivo. Así que a la hora de crear versiones para dispositivos móviles, con todas esas etiquetas CSS embebidas, puede ser un verdadero quebradero de cabeza.</p> </li> <li> <p>Se supone que <strong>tienen que generar HTML válido</strong>, pero durante mucho tiempo <strong>esto no ha sido siempre así</strong>, sobre todo si el editor no está bien configurado o tiene algún plug-in que no respeta este tema. Además, generan HTML valido ahora, ¿que pasa en el futuro? Es decir, si quieres pasar contenido antiguo para por ejemplo pasar de HTML 2.0 a HTML 4.0 o incluso 5 y eliminar etiquetas obsoletas y generar HTML que cumpla con el estándar, prepárate, porque te espera una ardua tarea. Por no decir que muchos de estos editores tienen errores en su propio código javascript, lo que lleva a frecuentes actualizaciones de los mismos.</p> </li> <li> <p>Pueden <strong>generar cantidades absurdas de HTML</strong>, sobre todo si no están correctamente configurados. Algunos editores (a veces con la configuración por defecto hacen esto, y tienes que ser tú quien lo ajuste para que no ocurra) crean toneladas de <code>&lt;div&gt;</code>,<code>&lt;p&gt;</code> y <code>&lt;span&gt;</code> sin sentido y totalmente superfluos. Cuando no emplean tablas para formatear algunas presentaciones complejas. Y ni que decir tiene de aquellos editores visuales que te dejan pegar contenido desde un procesador de textos como Word, el HTML generado en estos casos, bueno, hay que verlo para creerlo, un absoluto despropósito.</p> </li> <li> <p>Es incluso factible que un usuario inexperto pueda <strong>romper el diseño de una página a través de un editor <abbr title="What You See Is What You Get (en inglés, &quot;lo que ves es lo que obtienes&quot;)"><abbr title="What You See Is What You Get (en inglés, &quot;lo que ves es lo que obtienes&quot;)">WYSIWYG</abbr></abbr></strong>, creando párrafos o <code>&lt;div&gt;</code> de forma inadecuada. Incluso al reescribir un texto es posible que se mezclen estilos CSS embebidos antiguos con nuevos, generando unos embrollos inmensos a nivel de HTML. Y ya no digo nada de los que rompen el estilo visual de un tema abusando de colores en las fuentes, tamaños, etc</p> </li> <li> <p>El <strong>contenido</strong> que se guarda <strong>en la base de datos</strong> esta <strong>mezclado con</strong> las etiquetas <strong>HTML y CSS</strong>, todo junto, vamos que no se parece en nada a lo que has introducido en tu editor. Todo esto en principio carece de importancia, pero puede suponer hasta el 20% del tamaño de las páginas de tu sitio, espacio absurdamente desperdiciado en tu BDD. De hecho el contenido XHTML se genera por lo normal cada vez que se visualiza la página de forma dinámica. Si te preocupa el rendimiento, tranquilo, los sistemas de cache están ahí para echarte una mano y que te dejes de preocupar por eso.</p> </li> <li> <p><strong>Distraen la atención</strong>, el problema de absolutamente todos los editores visuales, incluidos procesadores de texto, el centrarse en el formato y no en el contenido. Una gran mayoría de usuarios desperdicia un tiempo notable preocupándose por más el aspecto visual del documento, que por el contenido del mismo. Que si esto en negrita, que si mejor con esta fuente, que si mejor con la otra... Se desvía la atención de lo importante, el contenido. Mal amigo de la productividad, se tarda bastante más en general, por esta razón, en generar el mismo contenido en un editor <abbr title="What You See Is What You Get (en inglés, &quot;lo que ves es lo que obtienes&quot;)">WYSIWYG</abbr>.</p> </li> <li> <p><strong>Son bastante poco flexibles</strong>, si quieres introducir tu propio HTMl en el contenido (e.g. para tener un control más fino sobre las tablas, yo lo hago en este articulo) puede que te encuentres que lo genera como lo tiene preestablecido, eliminado la estructura que tu quieras darle. Y embeber contenido multimedia o scripts también es frecuentemente un problema, siendo hasta habitual que existan plugins para estos editores para insertar contenidos de sitios como YouTube.</p> </li> <li> <p>Todos los editores <abbr title="What You See Is What You Get (en inglés, &quot;lo que ves es lo que obtienes&quot;)">WYSIWYG</abbr> <strong>aumentan el peso por página y disminuyen la velocidad de carga</strong>, al necesitar pesado código javascipt que necesita tanto ser descargado como ejecutado por tu navegador. Ya de por si los CMS suelen emplear bastante código javascript, como para encima añadirle un editor visual. Además realizan bastantes llamadas HTTP, ralentizando aún más la velocidad de carga. Ejemplo: tienes un articulo de 80 lineas de texto cuyo contenido XHTML puede pesar tranquilamente de 10 á 20 veces menos que el javascript del editor, ¿no es un poco ridículo?. Aunque muy pocos editores web se preocupan de esto, la verdad, es que hay que pensar que no todo el mundo disfruta de buenas conexiones a la red.</p> </li> <li> <p>Por último y no menos importante, <strong>no cuidan la accesibilidad</strong>. El HTML valido que cumpla con los estándares, es esencial para crear páginas con una buena accesibilidad, pensando en aquellos que no lo tienen tan fácil para navegar por nuestros sitios web. Deberían tenerse al menos en cuenta un mínimo de puntos sobre este tema al crear contenidos en la web.</p> </li> </ul> <p>En conclusión, que los editores <abbr title="What You See Is What You Get (en inglés, &quot;lo que ves es lo que obtienes&quot;)">WYSIWYG</abbr> pueden no dar problemas hasta que tus necesidades cambian, entonces pueden darte más de un quebradero de cabeza.</p> <br /> <h2 id="mark">Texto plano y Markdown</h2> <p>¿Cual sería entonces la solución para esquivar estos problemas? Texto plano, nada más, que se transforme automáticamente en HTML valido respetando el formato que nosotros queramos darle. Esto existe, y es posible gracias a los lenguajes de marcado ligero, entre los que se encuentra <a href="http://daringfireball.net/projects/markdown/">Markdown</a>. Nada mejor que empezar demostrándolo con un ejemplo:</p> <div> <table> <thead><tr><th style="width: 50%;">Markdown</th><th>Resultado</th></tr></thead> <tbody><tr> <td><pre class="no_mrkdwn"> <p>Documento de ejemplo ====================</p><p>Lorem ipsum [dolor sit amet](#mark), consectetur adipiscing elit. Curabitur eget ante nunc. Pellentesque a tortor ipsum, id rhoncus orci. Quisque leo sapien, rutrum id convallis id, rutrum in ligula. Vestibulum **semper adipiscing leo** et blandit.</p><p>Sed nibh quam, hendrerit _sit amet aliquam_ vel, pulvinar molestie augue.</p><p>&gt; Integer cursus, nunc eu ultrices pellentesque, eros leo malesuada turpis, vel convallis neque dolor a nunc. Sed lacus risus, condimentum vitae posuere quis, ultrices pharetra nunc.</p><p>Lista numerada (ordenada)</p><p>1. Este es el primer elemento 2. Este es el segundo elemento * Una lista de puntos anidada * Se llama también desordenada * Tercer nivel de anidamiento 3. Este es el tercer elemento</p><p>![avatar](pictures/avatar.png)</p><p>### Cabecera ###</p><p>- - -</p><p>Morbi erat augue, feugiat eu pellentesque eget, hendrerit quis lectus. Fusce dignissim pretium nibh sed dignissim. Pellentesque lobortis ante eu dui fermentum vitae blandit risus aliquet.</p><p> | | solo texto | HTML Limpio | | -------------- | -- | ------- | | Markdown | Si | Si | | Editor WYSISWG | X | A veces |</p><p> &nbsp;&nbsp;&nbsp;&nbsp;:::python &nbsp;&nbsp;&nbsp;&nbsp;import lifetime &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;for each_day in lifetime.days(): &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;carpe_diem()</p><p>Suspendisse posuere velit et velit vehicula at scelerisque orci suscipit. Nulla facilisis lorem eu sem viverra varius nec ut felis.</p><p>Esto es un texto con nota al pie [^prima] y esta es otra nota [^secunda]</p><p> *[vehicula]: automobila [^prima]: Esto es una nota al pie. [^secunda]: Esto es la segunda nota.</p></pre> </td> <td> <h1>Documento de ejemplo</h1> <p>Lorem ipsum <a href="#mark">dolor sit amet</a>, consectetur adipiscing elit. Curabitur eget ante nunc. Pellentesque a tortor ipsum, id rhoncus orci. Quisque leo sapien, rutrum id convallis id, rutrum in ligula. Vestibulum <strong>semper adipiscing leo</strong> et blandit.</p> <p>Sed nibh quam, hendrerit <em>sit amet aliquam</em> vel, pulvinar molestie augue.</p> <blockquote> <p>Integer cursus, nunc eu ultrices pellentesque, eros leo malesuada turpis, vel convallis neque dolor a nunc. Sed lacus risus, condimentum vitae posuere quis, ultrices pharetra nunc.</p> </blockquote> <p>Lista numerada (ordenada)</p> <ol><li>Este es el primer elemento</li> <li>Este es el segundo elemento <ul><li>Una lista de puntos anidada</li> <li>Se llama también desordenada <ul><li>Tercer nivel de anidamiento</li> </ul></li> </ul></li> <li>Este es el tercer elemento</li> </ol><p><img src="pictures/avatar.png" alt="avatar" /></p> <h3>Cabecera</h3> <p><hr /><p>Morbi erat augue, feugiat eu pellentesque eget, hendrerit quis lectus. Fusce dignissim pretium nibh sed dignissim. Pellentesque lobortis ante eu dui fermentum vitae blandit risus aliquet.</p></p> <table><thead><tr><th></th> <th>solo texto</th> <th>HTML Limpio</th> </tr></thead><tbody><tr><td>Markdown</td> <td>Si</td> <td>Si</td> </tr><tr><td>Editor WYSISWG</td> <td>X</td> <td>A veces</td> </tr></tbody></table> <div class="codehilite"><pre><span class="kn">import</span> <span class="nn">lifetime</span> <p><span class="k">for</span> <span class="n">each_day</span> <span class="ow">in</span> <span class="n">lifetime</span><span class="o">.</span><span class="n">days</span><span class="p">():</span> <span class="n"> carpe_diem</span><span class="p">()</span></pre></div> <p>Suspendisse posuere velit et velit <abbr title="automobila">vehicula</abbr> at scelerisque orci suscipit. Nulla facilisis lorem eu sem viverra varius nec ut felis.</p></p> <p>Esto es un texto con nota al pie <sup id="fnref:prima"><a href="#fn:prima" rel="footnote">1</a></sup> y esta es otra nota <sup id="fnref:secunda"><a href="#fn:secunda" rel="footnote">2</a></sup></p> <div class="footnotes"> <hr /><ol><li id="fn:prima"> <p>Esto es una nota al pie. <a href="#fnref:prima" rev="footnote">↩</a></p> </li> <li id="fn:secunda"> <p>Esto es la segunda nota. <a href="#fnref:secunda" rev="footnote">↩</a></p> </li> <p></ol> </td> </tr> </tbody></table> </div></p> <p>Es así de sencillo, el texto plano que se escribe en la columna de la izquierda genera el HTML que se puede ver representado en la derecha. Es además HTML valido, sin CSS embebido (exceptuando el código con resaltado de sintaxis, pero esto es necesario y tampoco es generado por <strong>Markdown</strong> si no por <a href="http://qbnz.com/highlighter/">GeSHi</a> anteriormente y ahora por <a href="http://pygments.org/">Pygments</a>) y empleando el mínimo necesario, siendo lo más limpio posible. Pero el contenido que se guarda en la base de datos y el que tú editas es el de la izquierda. Este contenido generará HTML valido hoy y mañana, es totalmente independiente del estilo que emplees en tu página y puedes migrarlo de un CMS a otro sin problema alguno. Todo son ventajas, el único inconveniente es que tienes que aprender a usar <strong>Markdown</strong>, algo que es sumamente sencillo, a la par que incrementa la legibilidad del texto plano.</p> <p>La legibilidad del texto es uno de los pilares fundamentales de <strong>Markdown</strong>, tal y como el mismo autor, <a href="http://en.wikipedia.org/wiki/John_Gruber">John Gruber</a>, lo cuenta<sup id="fnref:1"><a href="#fn:1" rel="footnote">1</a></sup>:</p> <blockquote> <p>El objetivo fundamental de diseño para la sintaxis de Markdown es hacerlo tan legible como sea posible. La idea es que un documento formateado con Markdown debería poder ser publicado tal y como está, como texto plano, sin que parezca que ha sido marcado con etiquetas o instrucciones de formateado. Mientras que la sintaxis de Markdown ha sido influenciada por muchos filtros texto-a-HTML existentes, la principal fuente de inspiración es el formato de los correos electronicos en texto plano.</p> </blockquote> <p>No voy ahora, en este articulo, a enseñarte a emplear <strong>Markdown</strong>, pero tienes una guía de prácticamente todas las posibilidades que te brinda en <a href="http://joedicastro.com/pages/markdown.html">Markdown &amp; Pygments Lexers Cheat Sheet</a>. Además, si somos así de vagos, podemos emplear también algunos editores visuales que generan y emplean markdown, como <a href="http://markitup.jaysalvat.com/home/">markItUP!</a> o el conocido <a href="http://code.google.com/p/wmd/">WMD</a> que empleamos en <a href="http://python.majibu.org">python majibu</a>. Aunque ambos editores solo soportan Markdown estándar, cuando en este sitio también soporto las capacidades adicionales de <a href="http://michelf.com/projects/php-markdown/extra/">Markdown Extra</a>.</p> <p>Todo el contenido de este sitio (exceptuando el automático, como las búsquedas, etiquetas, acerca de, ...) está generado empleando <strong>Markdown</strong> y todo está en HTML 5 valido. Un ejemplo del HTML que genera Markdown sería el siguiente:</p> <table> <thead> <tr> <th style="width: 50%;">Markdown</th><th>HTML</th> </tr> <tbody> <tr> <td> <pre class="no_mrkdwn"> Documento de ejemplo ==================== Lorem ipsum [dolor sit amet](#mark), consectetur adipiscing elit. Curabitur eget ante nunc. Pellentesque a tortor ipsum, id rhoncus orci. Quisque leo sapien, rutrum id convallis id, rutrum in ligula. Vestibulum **semper adipiscing leo** et blandit. Sed nibh quam, hendrerit _sit amet aliquam_ vel, pulvinar molestie augue. </pre> </td> <td> <pre class="no_mrkdwn"> &lt;h1&gt;Documento de ejemplo&lt;/h1&gt; &lt;p&gt;Lorem ipsum &lt;a href="#mark"&gt;dolor sit amet&lt;/a&gt;, consectetur adipiscing elit. Curabitur eget ante nunc. Pellentesque a tortor ipsum, id rhoncus orci. Quisque leo sapien, rutrum id convallis id, rutrum in ligula. Vestibulum &lt;strong&gt;semper adipiscing leo&lt;/strong&gt; et blandit.&lt;/p&gt; &lt;p&gt;Sed nibh quam, hendrerit &lt;em&gt;sit amet aliquam&lt;/em&gt; vel, pulvinar molestie augue.&lt;/p&gt; </pre> </td> </tr> </tbody> </table> <p>Como se puede ver es el HTMl justo, limpio y cumpliendo estándares, ni más ni menos. Este es un ejemplo muy sencillo, y posiblemente cualquier editor <abbr title="What You See Is What You Get (en inglés, &quot;lo que ves es lo que obtienes&quot;)">WYSIWYG</abbr> sea capaz de dar el mismo resultado, el problema aparece con documentos más complejos, con sucesivas re-ediciones del texto y con editores mal configurados. Eso si, lo que se almacena en la BDD con <strong>Markdown</strong> es texto plano, con los otros editores, el texto, las etiquetas HTML y CSS embebido.</p> <h2 id="+porque_markdown_y_no_otros">¿Porque Markdown y no otros?</h2> <p>Evidentemente <strong>Markdown</strong> no es el único <a href="http://es.wikipedia.org/wiki/Lenguajes_de_marcas_ligeros">lenguaje de marcado ligero</a>, existen otros también conocidos y extendidos como <a href="http://textile.thresholdstate.com/">Textile</a>, <a href="http://www.bbcode.org/">BBCode</a>, <a href="http://docutils.sourceforge.net/rst.html">reStructuredText</a>, <a href="http://texy.info/en/">Texy!</a>, <a href="http://txt2tags.org/">Txt2tags</a> o los empleados en los Wikis como <a href="http://www.wikicreole.org/">Creole</a> o el de <a href="http://www.mediawiki.org/wiki/Help:Formatting">MediaWiki</a>.</p> <p>En primer lugar <strong>Markdown</strong> es uno de los que más características soporta, uno de los que más salidas puede generar (no solo HTML, también LaTeX, RTF, PDF, EPUB, ...) y además es probablemente el más extendido y soportado de todos (exceptuando BBCode y los de los Wikis, empleados en sus nichos particulares). Pero también es uno de los más fáciles de emplear (saliendo del formato básico como negritas, etc) y que produce un texto plano más vistoso y legible.</p> <h3 id="comparativa">Comparativa</h3> <p>Como no, lo mejor, es ver una comparativa con un ejemplo del mismo documento y el texto empleado por cada uno de los lenguajes para generarlo. Para ello he creado un articulo aparte para mostrarla.</p> <p><a href="http://joedicastro.com/comparativa-de-lenguajes-de-marcado-ligero.html">Comparativa</a></p> <h2 id="+qui+n_emplea_markdown">¿Quién emplea Markdown?</h2> <p>Una de las razones para emplear <strong>Markdown</strong> es porque es uno de los más extendidos, sobre todo en el mundo de la programación. Por ejemplo, <a href="http://stackoverflow.com/">Stack Overflow</a> y todos los sitios de <a href="http://stackexchange.com/">Stack Exchange</a> emplean una variante de Markdown para la entrada de texto. Repositorios de código como <a href="https://github.com/">GitHub</a> y <a href="https://bitbucket.org/">Bitbucket</a> también lo emplean para ciertas funciones. También lo emplea el sistema de seguimiento de incidencias <a href="http://lighthouseapp.com/">LightHouse</a>.</p> <p>Fuera del ámbito de la programación, sitios tan conocidos como <a href="http://www.reddit.com/">Reddit</a> lo emplean. Plataformas para la educación online como <a href="http://moodle.org/">Moodle</a> o <a href="http://podmedics.heroku.com/">Podmedics</a> también hacen uso de él. Un Wiki como <a href="http://www.instiki.org/">Instiki</a> permite emplear Markdown. Plataformas de blogs y contenidos como <a href="https://posterous.com/">Posterous</a>, <a href="http://www.tumblr.com/">Tumblr</a> y <a href="http://www.squarespace.com/">Squarespace</a> lo ofrecen como opción. Y seguro que me estoy dejando en el tintero muchos más lugares donde es empleado habitualmente.</p> <p>Hay que tener en cuenta de que aquí no he hablado de software CMS que lo soporta, eso lo contemplo en el próximo punto, si no más bien de organizaciones/compañías.</p> <h2 id="excusas_para_no_emplearlo">Excusas para no emplearlo</h2> <p>La primera que dice todo el mundo, es un incordio usarlo y aprenderlo, la pregunta es: ¿Has intentado emplearlo? Créeme se aprende en nada, sobre la marcha, y una vez que te acostumbras a él, lo elegirás frente a los editores <abbr title="What You See Is What You Get (en inglés, &quot;lo que ves es lo que obtienes&quot;)">WYSIWYG</abbr>, casi con toda seguridad. Una vez aprendido no tienes que separar los dedos de tu teclado, no necesitas para nada el ratón para crear tu contenido. Ganarás mucho tiempo para ti mismo y lo agredeceras, créeme.</p> <p>La segunda, no puedo usarlo en mi CMS o blog. ¿Seguro? A continuación te detallo las opciones que conozco para publicar contenidos empleando <strong>Markdown</strong>.</p> <h3 id="cms_y_blogs">CMS y Blogs:</h3> <ul> <li>Por defecto, como opción o nativamente:<ul> <li><a href="http://nestacms.com/">Nesta</a></li> <li><a href="http://kohanut.com/">Kohanut</a></li> <li><a href="http://www.movabletype.org/">MovableType</a></li> <li><a href="http://fdv.github.com/typo/">Typo</a></li> </ul> </li> <li>Con añadidos:<ul> <li><a href="http://drupal.org/">Drupal</a> A través de un modulo, <a href="http://drupal.org/project/markdown">Markdown Filter</a></li> <li><a href="http://wordpress.org/">Wordpress</a> Hay varios plugins disponibles para emplearlo.</li> <li><a href="http://djangoproject.com/">Django</a> Hay varias formas de soportarlo.</li> <li><a href="http://plone.org">Plone</a> Se puede habilitar a través de un modulo.</li> <li><a href="http://blogger.com">Blogger</a> A través de algunos proyectos externos, <a href="http://code.google.com/p/blogger-markdown-editor/">Blogger-markdown-editor</a></li> <li><a href="http://expressionengine.com/">ExpressionEngine</a> A través de un plugin.</li> <li><a href="http://www.joomla.org/">Joomla</a> A través de una extensión, <a href="http://extensions.joomla.org/extensions/edition/code-display/8391">jMarkdown</a></li> </ul> </li> </ul> <h3 id="generadores_de_sitios_con_contenido_est+tico_html">Generadores de sitios con contenido estático (HTML):</h3> <ul> <li><a href="https://github.com/ametaireau/pelican/">Pelican</a></li> <li><a href="http://ringce.com/hyde">hyde</a></li> <li><a href="http://www.blogofile.com/">Blogofile</a></li> <li><a href="https://bitbucket.org/obensonne/poole/src">Poole</a></li> <li><a href="https://github.com/xfire/growl/tree">Growl</a></li> <li><a href="http://markdoc.org/">Markdoc</a></li> <li><a href="http://webgen.rubyforge.org/">Webgen</a></li> <li><a href="http://nanoc.stoneship.org/">nanoc</a></li> <li><a href="http://jekyllrb.com/">jekyll</a></li> <li><a href="http://jaspervdj.be/hakyll/">Hakyll</a></li> <li><a href="http://webby.rubyforge.org/">Webby</a></li> <li><a href="http://cloudhead.io/toto">toto</a></li> <li><a href="http://rote.rubyforge.org/">Rote</a></li> </ul> <h3 id="plataforma_de_blogs_con_contenido_est+tico_html">Plataforma de Blogs con contenido estático (HTML):</h3> <ul> <li><a href="http://calepin.co/">Calepin.co</a> es un <strong>Pelican</strong> hospedado, que lee ficheros markdown desde <strong>DropBox</strong></li> </ul> <h3 id="wiki">Wiki:</h3> <ul> <li>Por defecto, como opción o nativamente:<ul> <li><a href="http://instiki.org">Instiki</a></li> <li><a href="http://ikiwiki.info/">ikiwiki</a></li> <li><a href="http://sputnik.freewisdom.org/">sputnik</a></li> <li><a href="http://alt.textdrive.com/nanoki/">nanoki</a></li> <li><a href="https://github.com/jgm/gitit">gitit</a></li> </ul> </li> <li>Con añadidos:<ul> <li><a href="http://moinmo.in/">MoinMoin</a> con una <a href="http://moinmo.in/ParserMarket/Markdown">extensión</a></li> <li><a href="http://www.mediawiki.org">MediaWiki</a> con una <a href="http://www.mediawiki.org/wiki/Extension:MarkdownSyntax">extensión</a></li> <li><a href="http://www.dokuwiki.org/">DokuWiki</a></li> <li><a href="http://oddmuse.org/">Oddmuse</a></li> <li><a href="http://www.pmwiki.org/">PmWiki</a></li> </ul> </li> </ul> <h3 id="foros">Foros:</h3> <ul> <li><a href="http://www.phpbb.com/">phpBB</a> A través de un <a href="http://www.phpbb.com/community/viewtopic.php?f=70&amp;t=2093183">MOD</a></li> </ul> <h3 id="conversor_markdown_desdea_otros_formatos">Conversor Markdown desde/a otros formatos:</h3> <ul> <li><a href="http://johnmacfarlane.net/pandoc/try">Pandoc</a></li> </ul> <h3 id="editores_de_texto_que_lo_soportan_marcado_de_sintaxis">Editores de Texto que lo soportan (marcado de sintaxis):</h3> <ul> <li><a href="http://www.vim.org/">Vim</a> con <a href="https://github.com/plasticboy/vim-markdown">Vim-Markdown</a></li> <li><a href="http://www.gnu.org/software/emacs/">Emacs</a> con <a href="http://jblevins.org/projects/markdown-mode/">markdown-mode</a></li> <li><a href="http://projects.gnome.org/gedit/">Gedit</a> con <a href="http://live.gnome.org/Gedit/MarkdownSupport">gedit-markdown</a></li> <li><a href="http://www.eclipse.org/">Eclipse</a> con el experimental <a href="http://www.winterwell.com/software/markdown-editor.php">markdown editor</a></li> <li><a href="http://macromates.com/">TextMate</a></li> <li><a href="http://www.codingmonkeys.de/subethaedit/">SubEthaEdit</a></li> <li><a href="http://ecto.kung-foo.tv/">Ecto</a></li> <li><a href="http://www.red-sweater.com/marsedit/">MarsEdit</a></li> </ul> <h3 id="editor_markdown">Editor Markdown:</h3> <ul> <li><a href="http://sourceforge.net/p/retext/home/">ReText</a></li> <li><a href="http://markdownpad.com/">Markdown Pad</a></li> <li><a href="http://bywordapp.com/">Byword</a></li> </ul> <h3 id="editor_offline_para_blogs">Editor Offline para blogs:</h3> <ul> <li><a href="http://qtm.blogistan.co.uk/">QTM</a></li> </ul> <h3 id="editores_online_para_probar_markdown">Editores Online para probar Markdown:</h3> <ul> <li><a href="http://daringfireball.net/projects/markdown/dingus">Dingus</a> por <a href="http://daringfireball.net/">John Gruber</a></li> <li><a href="http://michelf.com/projects/php-markdown/dingus/">Dingus PHP</a> por Michel Fortin</li> <li><a href="http://anthonybush.com/markdown_extra_geshi/">Markdown Extra + GeShi</a> por Anthony Bush</li> <li><a href="http://dillinger.io/">Dillinger</a> es una aplicación en HTML 5 por Joe McCann</li> <li><a href="http://babelmark.bobtfish.net/?markdown=*This+**is+a+test*.&amp;normalize=on">Babelmark</a> para comparar las distintas implementaciones de Markdown</li> <li><a href="http://joncom.be/experiments/markdown-editor/edit/">Markdown Editor</a> por John Combe</li> <li><a href="http://softwaremaniacs.org/playground/showdown-highlight/">Showdown</a></li> <li><a href="http://markdownr.com/">Markdownr</a></li> </ul> <p>Y si eres desarrollador, tienes disponibles distintas implementaciones de Markdown:</p> <table> <thead> <tr> <th>Lenguaje</th> <th>Implementaciones</th> </tr> </thead> <tbody> <tr> <td>Python</td> <td><a href="http://www.freewisdom.org/projects/python-markdown/">Python-markdown</a></td> </tr> <tr> <td>PHP</td> <td><a href="http://michelf.com/projects/php-markdown/">PHP Markdown y PHP Markdown Extra</a></td> </tr> <tr> <td>Perl</td> <td><a href="http://daringfireball.net/projects/markdown/">Original</a> y <a href="https://github.com/fletcher/MultiMarkdown">MultiMarkdown</a></td> </tr> <tr> <td>Ruby</td> <td><a href="http://deveiate.org/projects/BlueCloth">BlueCloth</a>, <a href="https://github.com/nex3/maruku">Maruku</a> y <a href="http://kramdown.rubyforge.org/">Kramdown</a></td> </tr> <tr> <td>C#</td> <td><a href="http://aspnetresources.com/blog/markdown_announced">Markdown.NET</a></td> </tr> <tr> <td>C</td> <td><a href="http://www.pell.portland.or.us/~orc/Code/markdown/">Discount</a> y <a href="https://github.com/jgm/peg-markdown">Peg-Markdown</a></td> </tr> <tr> <td>C++</td> <td><a href="http://cpp-markdown.sourceforge.net/">Cpp-markdown</a></td> </tr> <tr> <td>Java</td> <td><a href="http://sourceforge.net/projects/markdownj/">MarkdownJ</a></td> </tr> <tr> <td>Javascript</td> <td><a href="https://github.com/coreyti/showdown">Showdown</a></td> </tr> <tr> <td>Lua</td> <td><a href="http://www.frykholm.se/files/markdown.lua">markdown.lua</a></td> </tr> <tr> <td>Haskell</td> <td><a href="http://johnmacfarlane.net/pandoc/">Pandoc</a></td> </tr> <tr> <td>Common Lisp</td> <td><a href="http://common-lisp.net/project/cl-markdown/">CL-Markdown</a></td> </tr> <tr> <td>Scala</td> <td><a href="http://tristanhunt.com/projects/knockoff/">Knockoff</a> y <a href="http://henkelmann.eu/projects/actuarius/">Actuarius</a></td> </tr> </tbody> </table> <p>Entonces, habiendo tantas opciones, ¿por qué no lo pruebas?</p> <p>Y si hay más excusas, pues la verdad, no las conozco, dímelas tú.</p> <div class="footnote"> <hr /> <ol> <li id="fn:1"> <p>The overriding design goal for Markdown’s formatting syntax is to make it as readable as possible. The idea is that a Markdown-formatted document should be publishable as-is, as plain text, without looking like it’s been marked up with tags or formatting instructions. While Markdown’s syntax has been influenced by several existing text-to-HTML filters, the single biggest source of inspiration for Markdown’s syntax is the format of plain text email. <a href="http://daringfireball.net/projects/markdown/">fuente</a>&#160;<a href="#fnref:1" rev="footnote" title="Jump back to footnote 1 in the text">&#8617;</a></p> </li> </ol> </div>joe di castroSat, 02 Apr 2011 20:29:00 +0200http://joedicastro.com/markdown-la-mejor-opcion-para-crear-contenidos-web.htmlmarkdownwysiwygtextileeditoresmarcadohtmlxhtmlComparativa de Lenguajes de marcado ligerohttp://joedicastro.com/comparativa-de-lenguajes-de-marcado-ligero.html<p>Esta es una comparativa de los lenguajes de marcado ligero más empleados de los disponibles actualmente. Dicha comparativa surge a partir de este articulo, <a href="http://joedicastro.com/markdown-la-mejor-opcion-para-crear-contenidos-web.html">Markdown, la mejor opción para crear contenidos web</a>, donde defiendo la idoneidad de markdown para crear contenidos web.</p> <p>En esta comparativa se verá como emplear cada uno de los lenguajes de marcado disponibles para crear un contenido web similar. Tomo como referencia a markdown, aunque no todos los lenguajes soportan todas o las mismas características que este.</p> <h2 id="documento_de_ejemplo_realizado_con_markdown">Documento de ejemplo realizado con Markdown</h2> <div> <table> <thead> <tr> <th style="width: 50%;">Markdown</th><th>Resultado</th> </tr> <tbody> <tr> <td> <pre class="no_mrkdwn"> <p>Documento de ejemplo ====================</p><p>Lorem ipsum [dolor sit amet](#mark), consectetur adipiscing elit. Curabitur eget ante nunc. Pellentesque a tortor ipsum, id rhoncus orci. Quisque leo sapien, rutrum id convallis id, rutrum in ligula. Vestibulum **semper adipiscing leo** et blandit.</p><p>Sed nibh quam, hendrerit _sit amet aliquam_ vel, pulvinar molestie augue.</p><p>&gt; Integer cursus, nunc eu ultrices pellentesque, eros leo malesuada turpis, vel convallis neque dolor a nunc. Sed lacus risus, condimentum vitae posuere quis, ultrices pharetra nunc.</p><p>Lenguajes de marcado ligero</p><p> * **Markdown** * Textile * reStructuredText * Texy! * Txt2tags * Marcado Wiki 1. Creole 2. MediaWiki</p><p>![avatar](pictures/no_wysiwyg.png)</p><p>### Cabecera H3 ###</p><p>- - -</p><p>Morbi erat augue, feugiat eu pellentesque eget, hendrerit quis lectus. Fusce dignissim pretium nibh sed dignissim. Pellentesque lobortis ante eu dui fermentum vitae blandit risus aliquet.</p><p>| | solo texto | HTML Limpio | | -------------- | -- | ------- | | Markdown | Si | Si | | Editor WYSISWG | X | A veces |</p>_Ejemplo de código_</p><p>&nbsp;&nbsp;&nbsp;&nbsp;import lifetime &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;for each_day in lifetime.days(): &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;carpe_diem()</p><p>Suspendisse posuere velit et velit vehicula at scelerisque orci suscipit. Nulla facilisis lorem eu sem viverra varius nec ut felis.</p><p>Esto es un texto con nota al pie [^ejemplo] y esta es otra nota [^segunda]</p><p> *[vehicula]: automobila [^ejemplo]: Esto es una nota al pie. [^segunda]: Esto es la segunda nota.</p></pre> </td> <td> <h1>Documento de ejemplo</h1> <p>Lorem ipsum <a href="#mark">dolor sit amet</a>, consectetur adipiscing elit. Curabitur eget ante nunc. Pellentesque a tortor ipsum, id rhoncus orci. Quisque leo sapien, rutrum id convallis id, rutrum in ligula. Vestibulum <strong>semper adipiscing leo</strong> et blandit.</p> <p>Sed nibh quam, hendrerit <em>sit amet aliquam</em> vel, pulvinar molestie augue.</p> <blockquote> <p>Integer cursus, nunc eu ultrices pellentesque, eros leo malesuada turpis, vel convallis neque dolor a nunc. Sed lacus risus, condimentum vitae posuere quis, ultrices pharetra nunc.</p> </blockquote> <p>Lenguajes de marcado ligero</p> <ul> <li><strong>Markdown</strong></li> <li>Textile</li> <li>reStructuredText</li> <li>Texy!</li> <li>Txt2tags</li> <li>Marcado Wiki <ol> <li>Creole</li> <li>MediaWiki</li> </ol></li> </ul> <p><img src="pictures/no_wysiwyg.png" alt="avatar" /></p> <h3>Cabecera H3</h3> <hr /> <p>Morbi erat augue, feugiat eu pellentesque eget, hendrerit quis lectus. Fusce dignissim pretium nibh sed dignissim. Pellentesque lobortis ante eu dui fermentum vitae blandit risus aliquet.</p> <table> <thead> <tr> <th></th> <th>solo texto</th> <th>HTML Limpio</th> </tr> </thead> <tbody> <tr> <td>Markdown</td> <td>Si</td> <td>Si</td> </tr> <tr> <td>Editor WYSISWG</td> <td>X</td> <td>A veces</td> </tr> </tbody> </table> <p><em>Ejemplo de código</em></p> <pre class="txt" style="font-family:monospace;">import lifetime &nbsp; for each_day in lifetime.days(): carpe_diem()</pre> <p>Suspendisse posuere velit et velit <abbr title="automobila">vehicula</abbr> at scelerisque orci suscipit. Nulla facilisis lorem eu sem viverra varius nec ut felis.</p> <p>Esto es un texto con nota al pie <sup id="fnref:ejemplo"><a href="#fn:ejemplo" rel="footnote">1</a></sup> y esta es otra nota <sup id="fnref:segunda"><a href="#fn:segunda" rel="footnote">2</a></sup></p> <div class="footnotes"> <hr /> <ol> <li id="fn:ejemplo"> <p>Esto es una nota al pie.&#160;<a href="#fnref:ejemplo" rev="footnote">&#8617;</a></p> </li> <li id="fn:segunda"> <p>Esto es la segunda nota.&#160;<a href="#fnref:segunda" rev="footnote">&#8617;</a></p> </li> <p></ol> </div> </td> </tr> </tbody> </table> </div></p> <hr /> <h2 id="textile">Textile</h2> <p>Es una buena alternativa a Markdown y bastante extendido, aunque quizás menos que Markdown. Tiene algunas posibilidades que no tiene Markdown como emplear colores, poder alinear el texto o emplear superindice y subindice. También tiene carencias como el no poder dibujar líneas horizontales o el poder emplear acronimos solo con mayusculas y tener que declararlos en cada una de las partes del texto que aparezcan. Pero quiźas para mi la mayor desventaja es la menor legibilidad del texto, es menos evidente a un vistazo que markdown.</p> <table> <thead> <tr> <th style="width: 50%;">Textile</th><th>Resultado</th> </tr> <tbody> <tr> <td> <pre class="no_mrkdwn"> h1. Documento de ejemplo Lorem ipsum "dolor sit amet":#mark, consectetur adipiscing elit. Curabitur eget ante nunc. Pellentesque a tortor ipsum, id rhoncus orci. Quisque leo sapien, rutrum id convallis id, rutrum in ligula. Vestibulum **semper adipiscing leo** et blandit. Sed nibh quam, hendrerit _sit amet aliquam_ vel, pulvinar molestie augue. bq. Integer cursus, nunc eu ultrices pellentesque, eros leo malesuada turpis, vel convallis neque dolor a nunc. Sed lacus risus, condimentum vitae posuere quis, ultrices pharetra nunc. Lenguajes de marcado ligero * **Markdown** * Textile * reStructuredText * Texy! * Txt2tags * Marcado Wiki ## Creole ## MediaWiki !pictures/no_wysiwyg.png (avatar)! h3. Cabecera H3 Morbi erat augue, feugiat eu pellentesque eget, hendrerit quis lectus. Fusce dignissim pretium nibh sed dignissim. Pellentesque lobortis ante eu dui fermentum vitae blandit risus aliquet. |_. @@|_. solo texto|_. HTML Limpio| |Markdown|Si|Si| |Editor WYSISWG|X|A veces| _Ejemplo de código_ bc.. import lifetime for each_day in lifetime.days(): carpe_diem() p. Suspendisse posuere velit et velit VEHICULA(automobila) at scelerisque orci suscipit. Nulla facilisis lorem eu sem viverra varius nec ut felis. Esto es un texto con nota al pie[1] y esta es otra nota[2] fn1. Esto es una nota al pie. fn2. Esto es la segunda nota. </pre> </td> <td> <h1>Documento de ejemplo</h1> <p>Lorem ipsum <a href="#mark">dolor sit amet</a>, consectetur adipiscing elit. Curabitur eget ante nunc. Pellentesque a tortor ipsum, id rhoncus orci. Quisque leo sapien, rutrum id convallis id, rutrum in ligula. Vestibulum <b>semper adipiscing leo</b> et blandit.</p> <p>Sed nibh quam, hendrerit <em>sit amet aliquam</em> vel, pulvinar molestie augue.</p> <blockquote> <p>Integer cursus, nunc eu ultrices pellentesque, eros leo malesuada turpis, vel convallis neque dolor a nunc. Sed lacus risus, condimentum vitae posuere quis, ultrices pharetra nunc.</p> </blockquote> <p>Lenguajes de marcado ligero </p> <ul> <li><b>Markdown</b></li> <li>Textile</li> <li>reStructuredText</li> <li>Texy!</li> <li>Txt2tags</li> <li>Marcado Wiki <ol> <li>Creole</li> <li>MediaWiki</li> </ol></li> </ul> <p><img src="pictures/no_wysiwyg.png" title="avatar" alt="avatar" /></p> <h3>Cabecera H3</h3> <p>Morbi erat augue, feugiat eu pellentesque eget, hendrerit quis lectus. Fusce dignissim pretium nibh sed dignissim. Pellentesque lobortis ante eu dui fermentum vitae blandit risus aliquet.</p> <table> <tr> <th></th> <th>solo texto</th> <th><span class="caps"><span class="caps">HTML</span></span> Limpio</th> </tr> <tr> <td>Markdown</td> <td>Si</td> <td>Si</td> </tr> <tr> <td>Editor <span class="caps"><span class="caps">WYSISWG</span></span></td> <td>X</td> <td>A veces</td> </tr> </table> <p><em>Ejemplo de código</em></p> <pre> import lifetime for each_day in lifetime.days(): carpe_diem() </pre> <p>Suspendisse posuere velit et velit <acronym title="automobila"><span class="caps">VEHICULA</span></acronym> at scelerisque orci suscipit. Nulla facilisis lorem eu sem viverra varius nec ut felis.</p> <p>Esto es un texto con nota al pie<sup class="footnote"><a href="#fn8701048694d94660b0d4d4">1</a></sup> y esta es otra nota<sup class="footnote"><a href="#fn13831162204d94660b122f5">2</a></sup></p> <p id="fn8701048694d94660b0d4d4" class="footnote"><sup>1</sup> Esto es una nota al pie.</p> <p id="fn13831162204d94660b122f5" class="footnote"><sup>2</sup> Esto es la segunda nota.</p> <p></td> </tr> </tbody> </table></p> <hr /> <h2 id="bbcode">BBCode</h2> <p>Es uno de los más extendido porque es ampliamente usado en foros por toda la red. Nació para ser empleado en foros y es prácticamente el único ámbito en el que se emplea. Es también muy limitado porque no soporta muchas de las características de los otros lenguajes y además hay múltiples variantes que no ayudan a crear un estándar. Por ejemplo las listas y las tablas no son contempladas en algunas de esas variantes.</p> <table> <thead> <tr> <th style="width: 50%;">BBCode</th><th>Resultado</th> </tr> </thead> <tbody> <tr> <td> <pre class="no_mrkdwn"> Documento de ejemplo Lorem ipsum [url=http://joedicastro.com]dolor sit amet[/url], consectetur adipiscing elit. Curabitur eget ante nunc. Pellentesque a tortor ipsum, id rhoncus orci. Quisque leo sapien, rutrum id convallis id, rutrum in ligula. Vestibulum [b]semper adipiscing leo[/b] et blandit. Sed nibh quam, hendrerit [i]sit amet aliquam[/i] vel, pulvinar molestie augue. [quote]Integer cursus, nunc eu ultrices pellentesque, eros leo malesuada turpis, vel convallis neque dolor a nunc. Sed lacus risus, condimentum vitae posuere quis, ultrices pharetra nunc.[/quote] [img]http://joedicastro/files/ imagenes/no_wysiwyg.png[/img] Cabecera H3 Morbi erat augue, feugiat eu pellentesque eget, hendrerit quis lectus. Fusce dignissim pretium nibh sed dignissim. Pellentesque lobortis ante eu dui fermentum vitae blandit risus aliquet. [i]Ejemplo de codigo[/i] [code] import lifetime for each_day in lifetime.days(): carpe_diem() [/code] </pre> </td> <td><div> <p> Documento de ejemplo<br /> </p> <p> Lorem ipsum <a href="http://joedicastro.com" target="_new">dolor sit amet</a>, consectetur adipiscing elit. Curabitur eget ante nunc. Pellentesque a tortor ipsum, id rhoncus orci. Quisque leo sapien, rutrum id convallis id, rutrum in ligula. Vestibulum <strong>semper adipiscing leo</strong> et blandit. </p> <p> Sed nibh quam, hendrerit <em>sit amet aliquam</em> vel, pulvinar molestie augue. </p> <blockquote> <p> Integer cursus, nunc eu ultrices pellentesque, eros leo malesuada turpis, vel convallis neque dolor a nunc. Sed lacus risus, condimentum vitae posuere quis, ultrices pharetra nunc. </p> </blockquote> <p><img src="pictures/no_wysiwyg.png" alt="" /></p> <p>Cabecera H3</p> <p>Morbi erat augue, feugiat eu pellentesque eget, hendrerit quis lectus. Fusce dignissim pretium nibh sed dignissim. Pellentesque lobortis ante eu dui fermentum vitae blandit risus aliquet.</p> <em>Ejemplo de codigo</em> <pre class="code"> import lifetime for each_day in lifetime.days(): carpe_diem() </pre></div> </td> </tr> </tbody> </table> <hr /> <h2 id="restructuredtext">reStructuredText</h2> <p>Fue creado para crear documentación, en concreto documentación para lenguajes de programación como Python. Tiene algunas carencias al no estar orientado a HTML, pero también tiene posibilidades de las que carece Markdown. Es muy potente, bastante legible, pero un poco incomodo para según que cosas, a mi modo de ver. </p> <table> <thead> <tr> <th style="width: 53%;">reStructuredText</th><th>Resultado</th> </tr> <tbody> <tr> <td> <pre class="no_mrkdwn"> Documento de ejemplo ==================== Lorem ipsum `dolor sit amet <#mark>`_, consectetur adipiscing elit. Curabitur eget ante nunc. Pellentesque a tortor ipsum, id rhoncus orci. Quisque leo sapien, rutrum id convallis id, rutrum in ligula. Vestibulum **semper adipiscing leo** et blandit. Sed nibh quam, hendrerit *sit amet aliquam* vel, pulvinar molestie augue. Integer cursus, nunc eu ultrices pellentesque, eros leo malesuada turpis, vel convallis neque dolor a nunc. Sed lacus risus, condimentum vitae posuere quis, ultrices pharetra nunc. Lenguajes de marcado ligero &nbsp;* **Markdown** &nbsp;* Textile &nbsp;* reStructuredText &nbsp;* Texy! &nbsp;* Txt2tags &nbsp;* Marcado Wiki &nbsp;&nbsp;&nbsp;1. Creole &nbsp;&nbsp;&nbsp;2. MediaWiki .. image:: pictures/no_wysiwyg.png :alt: avatar --------------- Cabecera H3 ^^^^^^^^^^^ Morbi erat augue, feugiat eu pellentesque eget, hendrerit quis lectus. Fusce dignissim pretium nibh sed dignissim. Pellentesque lobortis ante eu dui fermentum vitae blandit risus aliquet. ============== ========== =========== \ solo texto HTML Limpio ============== ========== =========== Markdown Si Si Editor WYSISWG X A veces ============== ========== =========== *Ejemplo de código*:: &nbsp;&nbsp;&nbsp;&nbsp;import lifetime &nbsp;&nbsp;&nbsp;&nbsp;for each_day in lifetime.days(): &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;carpe_diem() Suspendisse posuere velit et velit vehicula at scelerisque orci suscipit. Nulla facilisis lorem eu sem viverra varius nec ut felis. Esto es un texto con nota al pie [1]_ y esta es otra nota [2]_ .. [1] Esto es una nota al pie. .. [2] Esto es la segunda nota. </pre> </td> <td> <h1 id="documento-de-ejemplo">Documento de ejemplo</h1> <p>Lorem ipsum <a href="#mark">dolor sit amet</a>, consectetur adipiscing elit. Curabitur eget ante nunc. Pellentesque a tortor ipsum, id rhoncus orci. Quisque leo sapien, rutrum id convallis id, rutrum in ligula. Vestibulum <strong>semper adipiscing leo</strong> et blandit.</p> <p>Sed nibh quam, hendrerit <em>sit amet aliquam</em> vel, pulvinar molestie augue.</p> <blockquote> <p>Integer cursus, nunc eu ultrices pellentesque, eros leo malesuada turpis, vel convallis neque dolor a nunc. Sed lacus risus, condimentum vitae posuere quis, ultrices pharetra nunc.</p> </blockquote> <p>Lenguajes de marcado ligero</p> <ul> <li><strong>Markdown</strong></li> <li>Textile</li> <li>reStructuredText</li> <li>Texy!</li> <li>Txt2tags</li> <li>Marcado Wiki <ol style="list-style-type: decimal"> <li>Creole</li> <li>MediaWiki</li> </ol></li> </ul><p /> <img src="pictures/no_wysiwyg.png" alt="avatar" /> <hr /> <h2 id="cabecera-h3">Cabecera H3</h2> <p>Morbi erat augue, feugiat eu pellentesque eget, hendrerit quis lectus. Fusce dignissim pretium nibh sed dignissim. Pellentesque lobortis ante eu dui fermentum vitae blandit risus aliquet.</p> <table> <thead> <tr class="header"> <th align="left"> </th> <th align="left">solo texto</th> <th align="left">HTML Limpio</th> </tr> </thead> <tbody> <tr class="odd"> <td align="left">Markdown</td> <td align="left">Si</td> <td align="left">Si</td> </tr> <tr class="even"> <td align="left">Editor WYSISWG</td> <td align="left">X</td> <td align="left">A veces</td> </tr> </tbody> </table> <p><em>Ejemplo de código</em>:</p> <pre>import lifetime <p>for each_day in lifetime.days(): carpe_diem() </pre> <p>Suspendisse posuere velit et velit vehicula at scelerisque orci suscipit. Nulla facilisis lorem eu sem viverra varius nec ut felis.</p> <p>Esto es un texto con nota al pie <sup><a href="#fn1" class="footnoteRef" id="fnref1">1</a></sup> y esta es otra nota <sup><a href="#fn2" class="footnoteRef" id="fnref2">2</a></sup></p> <div class="footnotes"> <hr /> <ol> <li id="fn1"><p>Esto es una nota al pie. <a href="#fnref1" class="footnoteBackLink" title="Jump back to footnote 1">↩</a></p></li> <li id="fn2"><p>Esto es la segunda nota. <a href="#fnref2" class="footnoteBackLink" title="Jump back to footnote 2">↩</a></p></li> </ol> </div> </td> </tr> </tbody> </table></p> <hr /> <h2 id="texy">Texy!</h2> <p>Fue específicamente diseñado para crear documentos XHTML, por ello es bastante completo, pero no está muy extendido. Es legible, pero también tiene carece de soporte para ciertos tags de HTML.</p> <table> <thead> <tr> <th style="width: 53%;">Texy!</th><th>Resultado</th> </tr> <tbody> <tr> <td> <pre class="no_mrkdwn"> Documento de ejemplo ==================== Lorem ipsum [dolor sit amet | http://joedicastro.com], consectetur adipiscing elit. Curabitur eget ante nunc. Pellentesque a tortor ipsum, id rhoncus orci. Quisque leo sapien, rutrum id convallis id, rutrum in ligula. Vestibulum **semper adipiscing leo** et blandit. Sed nibh quam, hendrerit *sit amet aliquam* vel, pulvinar molestie augue. > Integer cursus, nunc eu ultrices pellentesque, eros leo malesuada turpis, vel convallis neque dolor a nunc. Sed lacus risus, condimentum vitae posuere quis, ultrices pharetra nunc. Lenguajes de marcado ligero - **Markdown** - Textile - reStructuredText - Texy! - Txt2tags - Marcado Wiki 1) Creole 2) MediaWiki [* pictures/no_wysiwyg.png .(alt text)[avatar] *] ### Cabecera H3 ### ----- Morbi erat augue, feugiat eu pellentesque eget, hendrerit quis lectus. Fusce dignissim pretium nibh sed dignissim. Pellentesque lobortis ante eu dui fermentum vitae blandit risus aliquet. |------------------------------ | | solo texto | HTML Limpio |------------------------------ | Markdown | Si | Si | Editor WYSISWG | X | A veces *Ejemplo de código* /---code &nbsp;&nbsp;import lifetime &nbsp;&nbsp;for each_day in lifetime.days(): &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;carpe_diem() \--- Suspendisse posuere velit et velit "vehicula"((automobila)) at scelerisque orci suscipit. Nulla facilisis lorem eu sem viverra varius nec ut felis. </pre> </td> <td> <h1 id="toc-documento-de-ejemplo">Documento de ejemplo</h1> <p>Lorem ipsum <a href="http://joedicastro.com">dolor sit amet</a>, consectetur adipiscing elit. Curabitur eget ante nunc. Pellentesque a tortor ipsum, id rhoncus orci. Quisque leo sapien, rutrum id convallis id, rutrum in ligula. Vestibulum <strong>semper adipiscing leo</strong> et blandit.</p> <p>Sed nibh quam, hendrerit <em>sit amet aliquam</em> vel, pulvinar molestie&nbsp;augue.</p> <blockquote> <p>Integer cursus, nunc eu ultrices pellentesque, eros leo malesuada turpis, vel convallis neque dolor a nunc. Sed lacus risus, condimentum vitae posuere quis, ultrices pharetra&nbsp;nunc.</p> </blockquote> <p>Lenguajes de marcado ligero</p> <ul> <li><strong>Markdown</strong></li> <li>Textile</li> <li>reStructuredText</li> <li>Texy!</li> <li>Txt2tags</li> <li>Marcado Wiki <ol> <li>Creole</li> <li>MediaWiki</li> </ol> </li> </ul> <div><img src="pictures/no_wysiwyg.png" class="avatar" alt="alt text"></div> <h1 id="toc-cabecera-h3">Cabecera H3</h1> <hr> <p>Morbi erat augue, feugiat eu pellentesque eget, hendrerit quis lectus. Fusce dignissim pretium nibh sed dignissim. Pellentesque lobortis ante eu dui fermentum vitae blandit risus aliquet.</p> <table> <thead> <tr> <th>&nbsp;</th> <th>solo texto</th> <th>HTML Limpio</th> </tr> </thead> <tbody> <tr> <td>Markdown</td> <td>Si</td> <td>Si</td> </tr> <tr> <td>Editor WYSISWG</td> <td>X</td> <td>A&nbsp;veces</td> </tr> </tbody> </table> <p><em>Ejemplo de código</em></p> <pre>import lifetime for each_day in lifetime.days(): carpe_diem()</pre> <p>Suspendisse posuere velit et velit <acronym title="automobila">vehicula</acronym> at scelerisque orci suscipit. Nulla facilisis lorem eu sem viverra varius nec ut&nbsp;felis.</p> <p></td> </tr> </tbody> </table></p> <hr /> <h2 id="txt2tags">txt2tags</h2> <p>Está escrito en Python y es muy potente, al igual que RestructuredText, permitiendo macros. Permite la salida en muchos formatos, incluido el XHTML. Es muy legible y muy fácil de emplear, es una pena que no esté más extendido y soportado. Aunque aún tiene algunas carencias como las notas al pie o las abreviaturas, que pueden ser soportadas con macros, también tiene un desarrollo muy activo. En la futura versión 3.0 serán soportados directamente las notas al pie. Es una alternativa con muy buen futuro.</p> <table> <thead> <tr> <th style="width: 53%;">txt2tags</th><th>Resultado</th> </tr> <tbody> <tr> <td> <pre class="no_mrkdwn"> =Documento de ejemplo= Lorem ipsum [dolor sit amet #mark], consectetur adipiscing elit. Curabitur eget ante nunc. Pellentesque a tortor ipsum, id rhoncus orci. Quisque leo sapien, rutrum id convallis id, rutrum in ligula. Vestibulum **semper adipiscing leo** et blandit. Sed nibh quam, hendrerit //sit amet aliquam// vel, pulvinar molestie augue. <tab>Integer cursus, nunc eu ultrices pellentesque, eros leo malesuada turpis, vel convallis neque dolor a nunc. Sed lacus risus, condimentum vitae posuere quis, ultrices pharetra nunc. Lenguajes de marcado ligero - **Markdown** - Textile - reStructuredText - Texy! - Txt2tags - Marcado Wiki + Creole + MediaWiki [pictures/no_wysiwyg.png] ===Cabecera H3=== -------------------- Morbi erat augue, feugiat eu pellentesque eget, hendrerit quis lectus. Fusce dignissim pretium nibh sed dignissim. Pellentesque lobortis ante eu dui fermentum vitae blandit risus aliquet. || | solo texto | HTML Limpio | Markdown | Si | Si | | Editor WYSISWG | X | A veces | //Ejemplo de codigo// ``` import lifetime for each_day in lifetime.days(): carpe_diem() ``` </pre> </td> <td> <h1>Documento de ejemplo</h1> <p> Lorem ipsum <a href="#mark">dolor sit amet</a>, consectetur adipiscing elit. Curabitur eget ante nunc. Pellentesque a tortor ipsum, id rhoncus orci. Quisque leo sapien, rutrum id convallis id, rutrum in ligula. Vestibulum <b>semper adipiscing leo</b> et blandit. </p> <p> Sed nibh quam, hendrerit <i>sit amet aliquam</i> vel, pulvinar molestie augue. </p> <blockquote><p> Integer cursus, nunc eu ultrices pellentesque, eros leo malesuada turpis, vel convallis neque dolor a nunc. Sed lacus risus, condimentum vitae posuere quis, ultrices pharetra nunc.</p> </blockquote> <p> Lenguajes de marcado ligero </p> <ul> <li><b>Markdown</b> <li>Textile <li>reStructuredText <li>Texy! <li>Txt2tags <li>Marcado Wiki <ol> <li>Creole <li>MediaWiki </ol> </ul> <p> <img src="pictures/no_wysiwyg.png" alt=""> </p> <h3>Cabecera H3</h3> <hr /> <p> Morbi erat augue, feugiat eu pellentesque eget, hendrerit quis lectus. Fusce dignissim pretium nibh sed dignissim. Pellentesque lobortis ante eu dui fermentum vitae blandit risus aliquet. </p> <table cellpadding="4"> <tr> <th></th> <th>solo texto</th> <th>HTML Limpio</th> </tr> <tr> <td>Markdown</td> <td align="center">Si</td> <td align="center">Si</td> </tr> <tr> <td>Editor WYSISWG</td> <td align="center">X</td> <td align="center">A veces</td> </tr> </table> <p> <i>Ejemplo de codigo</i> </p> <pre> import lifetime for each_day in lifetime.days(): carpe_diem() </pre> </td> </tr> </tbody> </table> <hr /> <h2 id="creole">Creole</h2> <p>Creado a partir de los lenguajes más empleados en los Wikis y usado fundamentalmente en Wikis, por lo que también tiene ciertas carencias.</p> <table> <thead> <tr> <th style="width: 50%;">Creole</th><th>Resultado</th> </tr> <tbody> <tr> <td> <pre class="no_mrkdwn"> == Documento de ejemplo == Lorem ipsum [[#mark|dolor sit amet]], consectetur adipiscing elit. Curabitur eget ante nunc. Pellentesque a tortor ipsum, id rhoncus orci. Quisque leo sapien, rutrum id convallis id, rutrum in ligula. Vestibulum **semper adipiscing leo** et blandit. Sed nibh quam, hendrerit //sit amet aliquam// vel, pulvinar molestie augue. > Integer cursus, nunc eu ultrices pellentesque, eros leo malesuada turpis, vel convallis neque dolor a nunc. Sed lacus risus, condimentum vitae posuere quis, ultrices pharetra nunc. Lenguajes de marcado ligero * **Markdown** * Textile * reStructuredText * Texy! * Txt2tags * Marcado Wiki ## Creole ## MediaWiki {{pictures/no_wysiwyg.png|avatar}} ==== Cabecera H3 ==== ----- Morbi erat augue, feugiat eu pellentesque eget, hendrerit quis lectus. Fusce dignissim pretium nibh sed dignissim. Pellentesque lobortis ante eu dui fermentum vitae blandit risus aliquet. |= |= solo texto |= HTML Limpio | | Markdown | Si | Si | | Editor WYSISWG | X | A veces | //Ejemplo de código// {{{ import lifetime for each_day in lifetime.days(): carpe_diem() }}} </pre> </td> <td> <h1>Documento de ejemplo</h1> <p>Lorem ipsum <a href="#mark">dolor sit amet</a>, consectetur adipiscing elit. Curabitur eget ante nunc. Pellentesque a tortor ipsum, id rhoncus orci. Quisque leo sapien, rutrum id convallis id, rutrum in ligula. Vestibulum <strong>semper adipiscing leo</strong> et blandit.</p> <p>Sed nibh quam, hendrerit <em>sit amet aliquam</em> vel, pulvinar molestie augue.</p> <blockquote><p>Integer cursus, nunc eu ultrices pellentesque, eros leo malesuada turpis, vel convallis neque dolor a nunc. Sed lacus risus, condimentum vitae posuere quis, ultrices pharetra nunc.</p> </blockquote> <p>Lenguajes de marcado ligero </p> <ul><li><strong>Markdown</strong> </li><li>Textile </li><li>reStructuredText </li><li>Texy! </li><li>Txt2tags </li><li>Marcado Wiki <ol><li>Creole </li><li>MediaWiki </li></ol></li></ul> <p><img src="pictures/no_wysiwyg.png" alt="avatar" title="avatar" /></p> <h3>Cabecera H3</h3> <p>-----</p> <p>Morbi erat augue, feugiat eu pellentesque eget, hendrerit quis lectus. Fusce dignissim pretium nibh sed dignissim. Pellentesque lobortis ante eu dui fermentum vitae blandit risus aliquet.</p> <table><tr><th></th><th>solo texto</th><th>HTML Limpio</th></tr> <tr><td>Markdown</td><td>Si</td><td>Si</td></tr> <tr><td>Editor WYSISWG</td><td>X</td><td>A veces</td></tr> </table> <p><em>Ejemplo de código</em></p> <pre> import lifetime <p>for each_day in lifetime.days(): carpe_diem() </pre></p> <p></td> </tr> </tbody> </table></p> <hr /> <h2 id="mediawiki">MediaWiki</h2> <p>Quizás el más extendido, no en vano MediaWiki es el Wiki empleado por la Wikipedia. Igual que Creole, tiene ciertas limitaciones que suple con plugins y etiquetas HTML. No me acaba de gustar. La manera que tiene de crear tablas - por ejemplo - aunque potente, no me parece nada legible en texto plano.<br /> </p> <table> <thead> <tr> <th style="width: 53%;">MediaWiki</th><th>Resultado</th> </tr> <tbody> <tr> <td> <pre class="no_mrkdwn"> ==Documento de ejemplo== Lorem ipsum [http://joedicastro.com dolor sit amet], consectetur adipiscing elit. Curabitur eget ante nunc. Pellentesque a tortor ipsum, id rhoncus orci. Quisque leo sapien, rutrum id convallis id, rutrum in ligula. Vestibulum '''semper adipiscing leo''' et blandit. Sed nibh quam, hendrerit ''sit amet aliquam'' vel, pulvinar molestie augue. <blockquote>Integer cursus, nunc eu ultrices pellentesque, eros leo malesuada turpis, vel convallis neque dolor a nunc. Sed lacus risus, condimentum vitae posuere quis, ultrices pharetra nunc.</blockquote> Lenguajes de marcado ligero * '''Markdown''' * Textile * reStructuredText * Texy! * Txt2tags * Marcado Wiki *# Creole *# MediaWiki [[File:pictures/no_wysiwyg.png|caption]] === Cabecera H3 === ---- Morbi erat augue, feugiat eu pellentesque eget, hendrerit quis lectus. Fusce dignissim pretium nibh sed dignissim. Pellentesque lobortis ante eu dui fermentum vitae blandit risus aliquet. {| ! ! solo texto ! HTML Limpio |- |Markdown |Si |Si |- |Editor WYSISWG |X |A veces |} ''Ejemplo de código'' &nbsp;&nbsp;import lifetime &nbsp;&nbsp; &nbsp;&nbsp;for each_day in lifetime.days(): &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;carpe_diem() Suspendisse posuere velit et velit <span title="automobila">vehicula</span> at scelerisque orci suscipit. Nulla facilisis lorem eu sem viverra varius nec ut felis. Esto es un texto con nota al pie <ref name="ejemplo">Esto es una nota al pie.</ref> y esta es otra nota <ref name="segunda"> Esto es la segunda nota.</ref> {{reflist}} </pre> </td> <td> <h2><span class="mw-headline" id="Documento_de_ejemplo">Documento de ejemplo</span></h2> <p>Lorem ipsum <a href="http://joedicastro.com" class="external text" rel="nofollow">dolor sit amet</a>, consectetur adipiscing elit. Curabitur eget ante nunc. Pellentesque a tortor ipsum, id rhoncus orci. Quisque leo sapien, rutrum id convallis id, rutrum in ligula. Vestibulum <b>semper adipiscing leo</b> et blandit.</p> <p>Sed nibh quam, hendrerit <i>sit amet aliquam</i> vel, pulvinar molestie augue.</p> <blockquote> <p>Integer cursus, nunc eu ultrices pellentesque, eros leo malesuada turpis, vel convallis neque dolor a nunc. Sed lacus risus, condimentum vitae posuere quis, ultrices pharetra nunc.</p> </blockquote> <p>Lenguajes de marcado ligero</p> <ul> <li><b>Markdown</b></li> <li>Textile</li> <li>reStructuredText</li> <li>Texy!</li> <li>Txt2tags</li> <li>Marcado Wiki <ol> <li>Creole</li> <li>MediaWiki</li> </ol> </li> </ul> <p><img src="pictures/no_wysiwyg.png" alt="" /></p> <h3><span class="mw-headline" id="Cabecera_H3">Cabecera H3</span></h3> <hr /> <p>Morbi erat augue, feugiat eu pellentesque eget, hendrerit quis lectus. Fusce dignissim pretium nibh sed dignissim. Pellentesque lobortis ante eu dui fermentum vitae blandit risus aliquet.</p> <table> <tr> <th></th> <th>solo texto</th> <th>HTML Limpio</th> </tr> <tr> <td>Markdown</td> <td>Si</td> <td>Si</td> </tr> <tr> <td>Editor WYSISWG</td> <td>X</td> <td>A veces</td> </tr> </table> <p><i>Ejemplo de código</i></p> <pre> import lifetime <p>for each_day in lifetime.days(): carpe_diem()</p> <p></pre> <p>Suspendisse posuere velit et velit <span title="automobila">vehicula</span> at scelerisque orci suscipit. Nulla facilisis lorem eu sem viverra varius nec ut felis.</p></p> <p>Esto es un texto con nota al pie <sup id="cite_ref-ejemplo_0-0" class="reference"><a href="#cite_note-ejemplo-0"><span>[</span>1<span>]</span></a></sup> y esta es otra nota <sup id="cite_ref-segunda_1-0" class="reference"><a href="#cite_note-segunda-1"><span>[</span>2<span>]</span></a></sup></p> <div class="reflist" style="list-style-type: decimal;"> <ol class="references"> <li id="cite_note-ejemplo-0"><b><a href="#cite_ref-ejemplo_0-0">^</a></b> Esto es una nota al pie.</li> <li id="cite_note-segunda-1"><b><a href="#cite_ref-segunda_1-0">^</a></b> Esto es la segunda nota.</li> <p></ol> </td> </tr> </tbody> </table></p>joe di castroSat, 02 Apr 2011 20:29:00 +0200http://joedicastro.com/comparativa-de-lenguajes-de-marcado-ligero.htmlmarkdowntextilebbcoderestructuredtexttexy!txt2tagscreolemediawikimarcadohtmlxhtml