<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Yoandy Rodriguez Martinez</title>
    <description>The latest articles on Forem by Yoandy Rodriguez Martinez (@yorodm).</description>
    <link>https://forem.com/yorodm</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F61798%2Fe41b238e-9b69-482d-9211-3803d6621fda.png</url>
      <title>Forem: Yoandy Rodriguez Martinez</title>
      <link>https://forem.com/yorodm</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/yorodm"/>
    <language>en</language>
    <item>
      <title>Workshop de Golang</title>
      <dc:creator>Yoandy Rodriguez Martinez</dc:creator>
      <pubDate>Sat, 06 Feb 2021 02:01:15 +0000</pubDate>
      <link>https://forem.com/yorodm/workshop-de-golang-3eak</link>
      <guid>https://forem.com/yorodm/workshop-de-golang-3eak</guid>
      <description>&lt;p&gt;¡Hola Gophers!&lt;/p&gt;

&lt;p&gt;He compilado un conjunto de ejemplos y diapositivas para aprender Go. Si quieres aprender, colaborar o conoces a alguien interesado puedes darte una vuelta por &lt;a href="https://github.com/yorodm/golang-workshop/"&gt;el repo en github&lt;/a&gt;. Si gusta no olvide dejar su ⭐️.&lt;/p&gt;

</description>
      <category>go</category>
      <category>workshop</category>
      <category>spanish</category>
    </item>
    <item>
      <title>Pipelines en Rust (I)</title>
      <dc:creator>Yoandy Rodriguez Martinez</dc:creator>
      <pubDate>Thu, 24 Dec 2020 18:27:39 +0000</pubDate>
      <link>https://forem.com/yorodm/pipelines-en-rust-i-573e</link>
      <guid>https://forem.com/yorodm/pipelines-en-rust-i-573e</guid>
      <description>&lt;p&gt;&lt;strong&gt;Pipeline&lt;/strong&gt; es un patrón de diseño muy útil cuando tienes datos que&lt;br&gt;
deben ser procesados en una secuencia de etapas donde cada etapa toma&lt;br&gt;
como entrada la salida de la anterior. En cierta manera un&lt;br&gt;
pipeline es similar a &lt;em&gt;componer funciones&lt;/em&gt; pero el nivel de&lt;br&gt;
complejidad es mucho más elevado debido a factores como &lt;em&gt;backpressure&lt;/em&gt;, &lt;em&gt;deadlocks&lt;/em&gt; o cancelación.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Go&lt;/strong&gt; es un lenguaje especialmente capacitado para programar&lt;br&gt;
pipelines debido a sus características especiales para el manejo de errores y concurrencia. Pero ¿cómo sería usar pipelines en &lt;strong&gt;Rust&lt;/strong&gt;?&lt;/p&gt;

&lt;p&gt;En este post vamos a:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Definir las estructuras necesarias para crear pipelines.&lt;/li&gt;
&lt;li&gt;Hacer uso del sistema de tipos del lenguaje para nuestras ventajas.&lt;/li&gt;
&lt;li&gt;Hablar un poco de concurrencia usando hilos.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  Paso 1: El &lt;code&gt;trait Step&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;En el mejor espíritu de &lt;strong&gt;Rust&lt;/strong&gt; hagamos un trait que represente la&lt;br&gt;
capacidad de formar parte de un pipeline. Vamos a llamarle &lt;code&gt;Step&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;trait&lt;/span&gt; &lt;span class="n"&gt;Step&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nn"&gt;Self&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;Self&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Item&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hecho, hasta la próxima. O... mejor aún, miremos más de cerca la&lt;br&gt;
definición de &lt;code&gt;Step&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Es un &lt;code&gt;trait&lt;/code&gt; bastante sencillo. Tiene un tipo asociado &lt;code&gt;Item&lt;/code&gt; y una&lt;br&gt;
función &lt;code&gt;run&lt;/code&gt; que acepta y retorna &lt;code&gt;Item&lt;/code&gt;. La forma en que la función&lt;br&gt;
está especificada no permite que &lt;code&gt;Item&lt;/code&gt; sea una referencia. Y&lt;br&gt;
finalmente &lt;code&gt;it&lt;/code&gt; no es mutable, por lo que el parámetro de entrada es&lt;br&gt;
&lt;em&gt;consumido&lt;/em&gt; por la función y el valor de retorno es generado por ella.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Step&lt;/code&gt; es muy simple de implementar, veamos un ejemplo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;Multiplier&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;Step&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;Multiplier&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Item&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;u8&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.value&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Podemos usar &lt;code&gt;Multiplier&lt;/code&gt; para crear pasos que... bueno, multipliquen&lt;br&gt;
su valor de entrada por un número dado.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;by2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Multiplier&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Multiplicado por 2 {0}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;by2&lt;/span&gt;&lt;span class="nf"&gt;.run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c"&gt;// 10&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Paso 2: Pipeline
&lt;/h2&gt;

&lt;p&gt;Ahora solo tenemos que encadenar los pasos para formar un pipeline.&lt;br&gt;
Ya que tenemos un número variable de pasos y todos implementan el&lt;br&gt;
mismo &lt;code&gt;trait&lt;/code&gt;, podemos guardarlos en un vector de &lt;em&gt;trait objects&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;Pipeline&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;Box&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;dyn&lt;/span&gt; &lt;span class="n"&gt;Step&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Item&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;La implementación de &lt;code&gt;Pipeline&lt;/code&gt; es extremadamente corta.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;impl&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Pipeline&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Pipeline&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Pipe&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nn"&gt;Vec&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;Step&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Item&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nv"&gt;'static&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.v&lt;/span&gt;&lt;span class="nf"&gt;.push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Box&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Un detalle en &lt;code&gt;add&lt;/code&gt;: para adicionar un &lt;code&gt;Step&lt;/code&gt;, debemos asegurarnos que&lt;br&gt;
&lt;em&gt;viva&lt;/em&gt; lo suficiente&lt;sup id="fnref1"&gt;1&lt;/sup&gt;, por lo que indicamos con &lt;code&gt;'static&lt;/code&gt;. Por&lt;br&gt;
cuestiones de estilo (y pensando en el futuro) podemos hacer que &lt;code&gt;Pipeline&lt;/code&gt; se comporte como cualquier otro &lt;code&gt;Step&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;impl&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Step&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;Pipeline&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Item&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nd"&gt;todo!&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Listo, tenemos la capacidad de hacer &lt;em&gt;subpipelines&lt;/em&gt; y sólo nos ha&lt;br&gt;
costado unas líneas. La operación dentro de &lt;code&gt;run&lt;/code&gt; es tan simple como hacer un &lt;code&gt;fold&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.v&lt;/span&gt;&lt;span class="nf"&gt;.iter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.fold&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="n"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="nf"&gt;.run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hagamos un pequeña prueba&lt;sup id="fnref2"&gt;2&lt;/sup&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[test]&lt;/span&gt;
&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;test_pipeline&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Pipeline&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="nf"&gt;.add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Multiplier&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="nf"&gt;.add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Multiplier&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="nd"&gt;assert_eq!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="nf"&gt;.run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Paso 3: Pipelines en el mundo real.
&lt;/h2&gt;

&lt;p&gt;Nuestras pipelines funcionan bastante bien en el mundo de las&lt;br&gt;
multiplicaciones de números pequeños, pero en el resto de los mundos existe algo llamado "errores" y con la definición actual (por muy elegante que sea) no tenemos modo de detectar si uno de los pasos falla. Es hora de sacar &lt;code&gt;Result&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;error&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;StepResult&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nb"&gt;Box&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;dyn&lt;/span&gt; &lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;trait&lt;/span&gt; &lt;span class="n"&gt;Step&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nn"&gt;Self&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;StepResult&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nn"&gt;Self&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Item&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;Step&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;Multiplier&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Item&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;StepResult&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.value&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Tener &lt;code&gt;Box&amp;lt;dyn Error&amp;gt;&lt;/code&gt; nos da la garantía de poder manejar errores de cualquier tipo. La implementación de &lt;code&gt;Pipeline&lt;/code&gt; debe tener esto en cuenta y &lt;em&gt;propagar&lt;/em&gt; el estado de error hasta el resultado final.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;impl&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Step&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;Pipeline&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Item&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;StepResult&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.v&lt;/span&gt;&lt;span class="nf"&gt;.iter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.fold&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="n"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;acc&lt;/span&gt;&lt;span class="nf"&gt;.and_then&lt;/span&gt;&lt;span class="p"&gt;(|&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="nf"&gt;.run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hora de ajustar nuestra prueba.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[test]&lt;/span&gt;
&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;test_pipeline_ok&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Pipeline&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="nf"&gt;.add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Multiplier&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="nf"&gt;.add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Multiplier&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="nd"&gt;assert_eq!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="nf"&gt;.run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Y crear una nueva para cuando algún &lt;code&gt;Step&lt;/code&gt; falla.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;ErrStep&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;Step&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;ErrStep&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Item&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;StepResult&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nf"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"This will fail"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;test_pipeline_ok&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Pipeline&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="nf"&gt;.add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Multiplier&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="nf"&gt;.add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ErrStep&lt;/span&gt;&lt;span class="p"&gt;{});&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="nf"&gt;.run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.is_err&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Pensando en paralelismo y concurrencia.
&lt;/h2&gt;

&lt;p&gt;Recuento:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Tenemos la posibilidad de hacer un &lt;code&gt;Pipeline&lt;/code&gt; compuesto de
distintas implementaciones de &lt;code&gt;Step&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Tenemos la forma de propagar errores en el &lt;code&gt;Pipeline&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;El próximo paso natural sería intentar usar nuestro diseño actual para ejecutar tareas &lt;em&gt;en paralelo&lt;/em&gt;. Por desgracia, aún no hemos llegado a ese punto.&lt;/p&gt;

&lt;p&gt;Una de las ventajas de &lt;strong&gt;Rust&lt;/strong&gt; es la garantía de que el compilador va a detectar problemas comunes de seguridad de hilos (ejemplo, acceder desde dos hilo distintos a la misma zona de memoria), para esto el la biblioteca estándard incluye marcadores como &lt;code&gt;Send&lt;/code&gt; y &lt;code&gt;Sync&lt;/code&gt;, o tipos especiales como &lt;code&gt;Arc&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Adicionalmente, en el espíritu de &lt;a href="https://blog.golang.org/codelab-share"&gt;compartir comunicando&lt;/a&gt;, los datos entre implementaciones de &lt;code&gt;Step&lt;/code&gt; deberían pasar usando canales o colas concurrentes, esto ayudaría también con otros aspectos que mencionamos al inicio del artículo (como &lt;em&gt;backpressure&lt;/em&gt;) pero que no tratamos por no ser necesarios para una implementación secuencial.&lt;/p&gt;

&lt;h2&gt;
  
  
  The end.
&lt;/h2&gt;

&lt;p&gt;Con todos los puntos del plan cumplidos, me retiro hasta la próxima aventura. Mientras tanto si estás interesado en el tema de &lt;em&gt;pipelines&lt;/em&gt; en &lt;strong&gt;Rust&lt;/strong&gt; recomiendo mirar &lt;a href="https://crates.io/crates/pipelines"&gt;pipelines&lt;/a&gt; o &lt;a href="https://crates.io/crates/rayon"&gt;rayon&lt;/a&gt;, ambas con implementaciones muy interesantes.&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;Aunque implementar &lt;code&gt;Step&lt;/code&gt; para una referencia o un tipo con&lt;br&gt;
restricciones de tiempo de vida no es trivial, tampoco es&lt;br&gt;
imposible. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;Las autoridades advierten que hacer pruebas unitarias&lt;br&gt;
&lt;strong&gt;después&lt;/strong&gt; de escribir funcionalidades es malo para la salud. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>rust</category>
      <category>patterns</category>
    </item>
    <item>
      <title>Emacs + Hugo: Haciendo hugo-blog-mode  (II)</title>
      <dc:creator>Yoandy Rodriguez Martinez</dc:creator>
      <pubDate>Tue, 06 Oct 2020 21:45:15 +0000</pubDate>
      <link>https://forem.com/yorodm/emacs-hugo-haciendo-hugo-blog-mode-ii-2b2d</link>
      <guid>https://forem.com/yorodm/emacs-hugo-haciendo-hugo-blog-mode-ii-2b2d</guid>
      <description>&lt;p&gt;En el &lt;a href="https://yorodm.is-a.dev/blog/hugo-mode-emacs/"&gt;artículo anterior&lt;/a&gt; (hace unos cuantos meses ya) estuve hablando sobre como comencé&lt;br&gt;
automatizando el flujo de publicación del blog usando scripts. En este les mostraré como llevamos esos scripts a un modo de &lt;strong&gt;Emacs&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Manos al Emacs.
&lt;/h2&gt;

&lt;p&gt;Una de las ventajas de Emacs es su extensibilidad, con un poco de&lt;br&gt;
código &lt;strong&gt;Elisp&lt;/strong&gt; podemos adicionar nuevas funcionalidades al editor.&lt;br&gt;
Aunque sería posible hacer un modo&lt;sup id="fnref1"&gt;1&lt;/sup&gt; para crear toda una experiencia relacionada con el manejo de blogs, es mucho más sencillo crear comandos&lt;sup id="fnref2"&gt;2&lt;/sup&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Planeando las funcionalidades.
&lt;/h3&gt;

&lt;p&gt;Necesitamos 3 funcionalidades básicas para trabajar en nuestro blog.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Crear nuevos artículos.&lt;/li&gt;
&lt;li&gt;Publicar el blog en &lt;a href="https://github.com"&gt;GitHub Pages&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Visualizar en el entorno local cualquier cambio que se produzca.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Con esto en mente podemos crear el esqueleto de las funciones&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight common_lisp"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;defun&lt;/span&gt; &lt;span class="nv"&gt;hugo-blow-new&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="s"&gt;"Create new content in PATH."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;defun&lt;/span&gt; &lt;span class="nv"&gt;hugo-blog-publish&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="s"&gt;"Generate the site and commit everything."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;defun&lt;/span&gt; &lt;span class="nv"&gt;hugo-blog-preview&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="s"&gt;"Launches a preview HTTP server. If ARG is provided also render drafts."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Opciones de configuración.
&lt;/h3&gt;

&lt;p&gt;Vamos a necesitar algunas opciones configurables:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;El nombre (o camino) del ejecutable de &lt;code&gt;hugo&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;La raiz del proyecto del blog.&lt;/li&gt;
&lt;li&gt;El nombre del &lt;em&gt;buffer&lt;/em&gt; que usaremos para interactuar con el comando.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight common_lisp"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;defgroup&lt;/span&gt; &lt;span class="nv"&gt;hugo-blog&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
  &lt;span class="s"&gt;"Hugo blog mode customizations"&lt;/span&gt;
  &lt;span class="ss"&gt;:group&lt;/span&gt; &lt;span class="ss"&gt;'tools&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;defcustom&lt;/span&gt; &lt;span class="nv"&gt;hugo-blog-command&lt;/span&gt; &lt;span class="s"&gt;"hugo"&lt;/span&gt;
  &lt;span class="s"&gt;"Path to hugo's executable."&lt;/span&gt;
  &lt;span class="ss"&gt;:group&lt;/span&gt; &lt;span class="ss"&gt;'hugo-blog&lt;/span&gt;
  &lt;span class="ss"&gt;:type&lt;/span&gt; &lt;span class="ss"&gt;'string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;defcustom&lt;/span&gt; &lt;span class="nv"&gt;hugo-blog-project&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;
  &lt;span class="s"&gt;"Blog directory project."&lt;/span&gt;
  &lt;span class="ss"&gt;:group&lt;/span&gt; &lt;span class="ss"&gt;'hugo-blog&lt;/span&gt;
  &lt;span class="ss"&gt;:type&lt;/span&gt; &lt;span class="ss"&gt;'string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;defcustom&lt;/span&gt; &lt;span class="nv"&gt;hugo-blog-process-buffer&lt;/span&gt; &lt;span class="s"&gt;"*hugo-blog-process*"&lt;/span&gt;
  &lt;span class="s"&gt;"Hugo blog process buffer."&lt;/span&gt;
  &lt;span class="ss"&gt;:group&lt;/span&gt; &lt;span class="ss"&gt;'hugo-blog&lt;/span&gt;
  &lt;span class="ss"&gt;:type&lt;/span&gt; &lt;span class="ss"&gt;'string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Funciones de soporte.
&lt;/h3&gt;

&lt;p&gt;Definidos nuestros puntos de entrada y las opciones configurables&lt;br&gt;
necesitamos englobar algunas funcionalidades comunes en funciones de soporte.&lt;/p&gt;

&lt;p&gt;Emacs nos brinda funciones para ejecutar programas externos o comandos del shell. La forma simple sería ejecutar los &lt;em&gt;scripts&lt;/em&gt;&lt;br&gt;
de shell que tenemos definidos, pero es mucho más interesante reproducir la funcionalidad en Elisp. Veamos por ejemplo como podemos ejecutar &lt;code&gt;hugo&lt;/code&gt; y capturar la salida en busca de mensajes de error.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight common_lisp"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;defun&lt;/span&gt; &lt;span class="nv"&gt;hugo-blog-run-command&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;command&lt;/span&gt; &lt;span class="nv"&gt;parameters&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="s"&gt;"Run COMMAND with PARAMETERS with `hugo-blog-project' as working directory.
Returns the command's output as a string"&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;cd&lt;/span&gt; &lt;span class="nv"&gt;hugo-blog-project&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nv"&gt;output&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;shell-command-to-string&lt;/span&gt;
                 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;concat&lt;/span&gt; &lt;span class="nv"&gt;hugo-blog-command&lt;/span&gt;
                         &lt;span class="s"&gt;" "&lt;/span&gt;
                         &lt;span class="nv"&gt;command&lt;/span&gt;
                         &lt;span class="s"&gt;" "&lt;/span&gt;
                         &lt;span class="nv"&gt;parameters&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;string-match-p&lt;/span&gt; &lt;span class="s"&gt;"Error"&lt;/span&gt; &lt;span class="nv"&gt;output&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="no"&gt;nil&lt;/span&gt;
      &lt;span class="nv"&gt;output&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;La función retorna &lt;code&gt;nil&lt;/code&gt; en caso de error o el mensaje resultado de la llamada en otro caso&lt;/p&gt;

&lt;p&gt;Así mismo podemos definir el resto de las funciones necesarias.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight common_lisp"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="ss"&gt;'git&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;;; git related functions&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;defmacro&lt;/span&gt; &lt;span class="nv"&gt;with-git-repo&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;repo&lt;/span&gt; &lt;span class="k"&gt;&amp;amp;rest&lt;/span&gt; &lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="s"&gt;"Run BODY using git repository REPO."&lt;/span&gt;
  &lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nv"&gt;git-repo&lt;/span&gt; &lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;repo&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
     &lt;span class="o"&gt;,@&lt;/span&gt;&lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;defun&lt;/span&gt; &lt;span class="nv"&gt;git-modified-files&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="s"&gt;"Return list of untracked files."&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;git--lines&lt;/span&gt;
   &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;git-run&lt;/span&gt; &lt;span class="s"&gt;"ls-files"&lt;/span&gt; &lt;span class="s"&gt;"-m"&lt;/span&gt; &lt;span class="s"&gt;"--exclude-standard"&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;defsubst&lt;/span&gt; &lt;span class="nv"&gt;hugo-blog-submodule&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="s"&gt;"Inline function to get the submodule."&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;concat&lt;/span&gt; &lt;span class="nv"&gt;hugo-blog-project&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;f-path-separator&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="s"&gt;"public"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;defun&lt;/span&gt; &lt;span class="nv"&gt;hugo-blog--commit-all&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="s"&gt;"Commits the submodule and then the project."&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;with-git-repo&lt;/span&gt;  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;hugo-blog-submodule&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;when&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;git-modified-files&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                   &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;git-add&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                   &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;git-commit&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;concat&lt;/span&gt; &lt;span class="s"&gt;"Commit on "&lt;/span&gt;
                                       &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;current-time-string&lt;/span&gt;&lt;span class="p"&gt;)))))&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;with-git-repo&lt;/span&gt;  &lt;span class="nv"&gt;hugo-blog-project&lt;/span&gt;
                 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;when&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;git-modified-files&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                   &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;git-add&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                   &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;git-add&lt;/span&gt; &lt;span class="s"&gt;"public"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;;; Let's be really sure&lt;/span&gt;
                   &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;git-commit&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;concat&lt;/span&gt; &lt;span class="s"&gt;"Commit on "&lt;/span&gt;
                                       &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;current-time-string&lt;/span&gt;&lt;span class="p"&gt;))))))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Completando las funcionalidades
&lt;/h3&gt;

&lt;p&gt;Con ayuda de las funciones auxiliares podemos desarrollar los comandos necesarios.  Es importante notar que todas las funciones están marcadas como &lt;code&gt;autoload&lt;/code&gt; e &lt;code&gt;interactive&lt;/code&gt; así estarán disponibles como comandos en el editor y sería más fácil distribuirlas en un paquete.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight common_lisp"&gt;&lt;code&gt;
&lt;span class="c1"&gt;;;;###autoload&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;defun&lt;/span&gt; &lt;span class="nv"&gt;hugo-blog-new&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="s"&gt;"Create new content in PATH."&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;interactive&lt;/span&gt; &lt;span class="s"&gt;"sNew content path: "&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;cd&lt;/span&gt; &lt;span class="nv"&gt;hugo-blog-project&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nv"&gt;output&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;hugo-blog-run-command&lt;/span&gt; &lt;span class="s"&gt;"new"&lt;/span&gt; &lt;span class="nv"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;output&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;find-file-existing&lt;/span&gt;  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;car&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;split-string&lt;/span&gt; &lt;span class="nv"&gt;output&lt;/span&gt; &lt;span class="s"&gt;" "&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;error&lt;/span&gt; &lt;span class="s"&gt;"Command hugo returned an error, check your configuration"&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;

&lt;span class="c1"&gt;;;;###autoload&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;defun&lt;/span&gt; &lt;span class="nv"&gt;hugo-blog-publish&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="s"&gt;"Generate the site and commit everything."&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;interactive&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;save-some-buffers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;;; avoid commiting emacs weird files&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;when&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;yes-or-no-p&lt;/span&gt; &lt;span class="s"&gt;"This will commit changes, are you sure? "&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;hugo-blog-run-command&lt;/span&gt; &lt;span class="s"&gt;"--noChmod"&lt;/span&gt; &lt;span class="s"&gt;"--noTimes --ignoreCache"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;hugo-blog--commit-all&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;

&lt;span class="c1"&gt;;;;###autoload&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;defun&lt;/span&gt; &lt;span class="nv"&gt;hugo-blog-preview&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="s"&gt;"Launches a preview HTTP server. If ARG is provided also render drafts."&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;interactive&lt;/span&gt; &lt;span class="s"&gt;"P"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;unless&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;process-status&lt;/span&gt; &lt;span class="s"&gt;"hugo"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;cd&lt;/span&gt; &lt;span class="nv"&gt;hugo-blog-project&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;when&lt;/span&gt; &lt;span class="nv"&gt;arg&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;start-process&lt;/span&gt; &lt;span class="s"&gt;"hugo"&lt;/span&gt; &lt;span class="nv"&gt;hugo-blog-process-buffer&lt;/span&gt;
                   &lt;span class="nv"&gt;hugo-blog-command&lt;/span&gt; &lt;span class="s"&gt;"-D"&lt;/span&gt; &lt;span class="s"&gt;"server"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;unless&lt;/span&gt; &lt;span class="nv"&gt;arg&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;start-process&lt;/span&gt; &lt;span class="s"&gt;"hugo"&lt;/span&gt; &lt;span class="nv"&gt;hugo-blog-process-buffer&lt;/span&gt;
                   &lt;span class="nv"&gt;hugo-blog-command&lt;/span&gt; &lt;span class="s"&gt;"server"&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;sleep-for&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;with-current-buffer&lt;/span&gt; &lt;span class="nv"&gt;hugo-blog-process-buffer&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;goto-char&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;point-max&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;re-search-backward&lt;/span&gt; &lt;span class="s"&gt;"http://localhost:[0-9]+/"&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="no"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;browse-url&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;match-string&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;error&lt;/span&gt; &lt;span class="s"&gt;"Error executing hugo"&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;Los modos de son conjuntos de funcionalidades que extienden el editor en distintas maneras, muchos incluso hacen cambios en la forma en que interactuamos con Emacs ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;Los comandos son funcionalidades específicas que no tienen por que estar relacionadas con ningún modo en particular. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
    </item>
    <item>
      <title>Microservicios en .NET Core 3.1</title>
      <dc:creator>Yoandy Rodriguez Martinez</dc:creator>
      <pubDate>Fri, 06 Mar 2020 20:06:47 +0000</pubDate>
      <link>https://forem.com/yorodm/microservicios-en-net-core-3-1-1aap</link>
      <guid>https://forem.com/yorodm/microservicios-en-net-core-3-1-1aap</guid>
      <description>&lt;p&gt;La nueva versión LTS de .NET Core trae consigo muchas ventajas para ellos desarrolladores de microservicios. Una de las más esperadas es laestabilización de la API para ejecutar servicios en segundo plano o_workers_ utilizando &lt;code&gt;Microsoft.Extensions.Hosting&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Qué son los workers?
&lt;/h2&gt;

&lt;p&gt;Si eres desarrollador de ASP.NET Core debes estar familiarizado con elpaquete &lt;code&gt;Microsoft.AspNetCore.Hosting&lt;/code&gt; y las clases&lt;code&gt;WebHostBuilder&lt;/code&gt; y&lt;code&gt;WebHost&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class Program
{
    public static void Main(string[] args)
    {
       var config = new ConfigurationBuilder()
            .AddCommandLine(args)
            .AddJsonFile("hosting.json", optional: true)
            .AddEnvironmentVariables()
            .Build();
      var host = new WebHostBuilder()
           .UseKestrel()
           .UseContentRoot(Directory.GetCurrentDirectory())
           .UseConfiguration(config)
           .Build();

       host.Run();
    }
 }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;code&gt;WebHost&lt;/code&gt; es responsable de iniciar la configuración, manejar el ciclode vida de los servicios, mantener el contenedor de dependencias ycomunicarse/iniciar el servidor web (Kestrel en este caso).&lt;/p&gt;

&lt;p&gt;&lt;code&gt;WebHost&lt;/code&gt; también nos brinda la posibilidad de iniciar servicios ensegundo plano utilizando &lt;code&gt;IHostedService&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Si no estás familiarizado con el tema, puedes informarte más con &lt;a href="https://www.stevejgordon.co.uk/asp-net-core-2-ihostedservice"&gt;este excelente post&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Microservicios en aplicaciones de consola.
&lt;/h2&gt;

&lt;p&gt;El nuevo host genérico (&lt;code&gt;HostBuilder&lt;/code&gt;) no requiere de la maquinaria deASP.NET Core, lo cual hace posible crear aplicaciones de consola quehagan uso de las bondades a las que estamos adaptados.&lt;/p&gt;

&lt;p&gt;Veamos un ejemplo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt; public class Program
    {
        public static void Main(string[] args)
        {
            try {
            CreateHostBuilder(args).Build().Run();
            }
            catch(OperationCanceledException ex)
            {
                Console.WriteLine("-----Terminating-----");
            }
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =&amp;gt;
            Host.CreateDefaultBuilder(args)
                .ConfigureAppConfiguration((hostingContext, config) =&amp;gt;
                {
                    var env = hostingContext.HostingEnvironment.EnvironmentName;
                    var builder = new ConfigurationBuilder()
                            .SetBasePath(Directory.GetCurrentDirectory())
                            .AddJsonFile("settings.json")
                            .AddEnvironmentVariables()
                            .Build();
                })
                .ConfigureServices((hostingContext, services) =&amp;gt;
                {

                    // AWS Configuration
                    var options = hostingContext.Configuration.GetAWSOptions();
                    services.AddDefaultAWSOptions(options);
                    services.AddAWSService&amp;lt;IAmazonSQS&amp;gt;();

                    // Worker Service
                    services.AddHostedService&amp;lt;Worker&amp;gt;();
                    services.AddLogging();

                }).ConfigureLogging((hostcontext, configLogging) =&amp;gt;
                {
                    configLogging.AddConsole();
                    configLogging.AddDebug();
                });
    }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;El programa anterios hace uso del host genérico para:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Cargar la configuración externa (variables de entorno y archivo json).&lt;/li&gt;
&lt;li&gt;Inicializar un servicio para acceder a SQS.&lt;/li&gt;
&lt;li&gt;Configurar logs para la consola.&lt;/li&gt;
&lt;li&gt;Crear un servicio en segundo plano.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;La clase &lt;code&gt;Worker&lt;/code&gt; hereda de &lt;code&gt;BackgroundService&lt;/code&gt; y es la encargada deejecutar la lógica de nuestro microservicio&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class Worker: BackgroundService {

     public Worker(ILogger&amp;lt;Worker&amp;gt; logger, IAmazonSQS sqs)
        {
            _logger = logger;
            _sqs = sqs;
        }

     protected async Task ExecuteAsync(int number, CancellationToken cancel)
       {
            while (!cancel.IsCancellationRequested)
            {
                // Procesar mensajes desde SQS
            }
       }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Integración con el sistema operativo
&lt;/h2&gt;

&lt;p&gt;Si desarrollas servicios monolíticos o para software legado, puedeshacer uso del host genérico para integrar tu aplicación al sistemaoperativo.&lt;/p&gt;

&lt;p&gt;Para integrarse como servicio a Windows se puede utilizar lasextensiones en &lt;code&gt;Microsoft.Extensions.Hosting.WindowsService&lt;/code&gt; parainicializar nuestro programa.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt; Host.CreateDefaultBuilder(args)
        .UseWindowsService()
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;En el casos de Linux sólo están soportadas las distribuciones que incluyen&lt;code&gt;Systemd&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  Host.CreateDefaultBuilder(args)
        .UseSystemd()
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



</description>
      <category>dotnetcore</category>
      <category>microservicios</category>
    </item>
    <item>
      <title>awstail: AWS Logs a la vieja usanza</title>
      <dc:creator>Yoandy Rodriguez Martinez</dc:creator>
      <pubDate>Mon, 20 Jan 2020 16:50:59 +0000</pubDate>
      <link>https://forem.com/yorodm/awstail-aws-logs-a-la-vieja-usanza-13ib</link>
      <guid>https://forem.com/yorodm/awstail-aws-logs-a-la-vieja-usanza-13ib</guid>
      <description>&lt;p&gt;&lt;a href="https://github.com/yorodm/awstail"&gt;awstail&lt;/a&gt; es una herramienta muy simple que cumple dos funciones:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Darme la excusa para aprender &lt;strong&gt;Rust&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Monitorear un grupo de logs en &lt;code&gt;AWS Cloudwatch&lt;/code&gt; desde la terminal.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Por el momento, estas son las opciones que permite la herramienta:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;awstail 0.3.0
Yoandy Rodriguez &amp;lt;yoandy.rmartinez@gmail.com&amp;gt;
like tail -f for AWS Cloudwatch

USAGE:
    awstail.exe [OPTIONS] &amp;lt;LOG_GROUP&amp;gt;

FLAGS:
    -h, --help Prints help information
    -V, --version Prints version information

OPTIONS:
    -p &amp;lt;PROFILE&amp;gt; Profile if using other than 'default'
    -r &amp;lt;REGION&amp;gt; AWS region (defaults to us-east-1)
    -s &amp;lt;SINCE&amp;gt; Take logs since a given time (defaults to 5 minutes)
    -w &amp;lt;WATCH&amp;gt; Keep watching for new logs every n seconds (defaults to 10)

ARGS:
    &amp;lt;LOG_GROUP&amp;gt; Log group name
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Posibles opciones futuras:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Agregar logs de más de un grupo.&lt;/li&gt;
&lt;li&gt;Color diferenciado para mensajes de error.&lt;/li&gt;
&lt;li&gt;Listar grupos de logs existentes.&lt;/li&gt;
&lt;/ol&gt;

</description>
    </item>
    <item>
      <title>Cola de tareas en Python (I)</title>
      <dc:creator>Yoandy Rodriguez Martinez</dc:creator>
      <pubDate>Mon, 04 Nov 2019 18:01:46 +0000</pubDate>
      <link>https://forem.com/yorodm/cola-de-tareas-en-python-i-19c2</link>
      <guid>https://forem.com/yorodm/cola-de-tareas-en-python-i-19c2</guid>
      <description>&lt;p&gt;Después de unos meses trabajando en &lt;strong&gt;Go&lt;/strong&gt; se llegan a extrañar las abstracciones del lenguaje para concurrencia. Hoy por ejemplo necesitaba hacer una cola de tareas en &lt;strong&gt;Python&lt;/strong&gt; utilizando &lt;strong&gt;AsyncIO&lt;/strong&gt;. En &lt;strong&gt;Go&lt;/strong&gt; esto sigue una estructura sencilla:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Este es la gorutina que procesa los trabajos
func worker(jobChan &amp;lt;-chan Job) {
    for job := range jobChan {
        process(job)
    }
}
// Creamos un canal a donde enviar los datos
jobChan := make(chan Job, 10)
// Arrancamos la gorutina
go worker(jobChan)
// Enviamos datos para un trabajo, esto puede ser desde cualquier
// gorutina
jobChan &amp;lt;- job
//Indicamos que ya no vamos a procesar más datos
close(jobChan)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Veamos si podemos lograr un equivalente en Python:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Primer intento
import asyncio
async def worker(queue):
    while True:
        process(await queue.get())
        # indicamos que se procesó el trabajo
        queue.task_done()

# Creamos la cola de mensajes
queue = asyncio.Queue(10)
# arrancamos el worker
worker_task = asyncio.create_task(worker(queue))
# Enviamos mensajes a la cola
await queue.put(x)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hasta acá todo parece bien, pero: ¿Cómo indicamos que no se van a procesar más datos?&lt;/p&gt;

&lt;p&gt;En &lt;strong&gt;Go&lt;/strong&gt; la operación &lt;code&gt;close&lt;/code&gt; sobre un canal hace que el ciclo termine &lt;strong&gt;después de procesar cualquier elemento pendiente&lt;/strong&gt;. En &lt;strong&gt;Python&lt;/strong&gt; a primera vista podemos cancelar la tarea creada en&lt;code&gt;worker_task&lt;/code&gt; pero eso nos deja con la posibilidad de que varias tareas se queden en la cola. Por otro lado, la corutina &lt;code&gt;join()&lt;/code&gt; de &lt;code&gt;asyncio.Queue&lt;/code&gt; nos permite esperar a que ya no existan elementos en la cola, aunque no garantiza que &lt;code&gt;worker&lt;/code&gt; se detenga.&lt;/p&gt;

&lt;p&gt;La solución es utilizar una mezcla de los dos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;await queue.join() # Esperar a que se procesen los pendientes
worker_task.cancel() # Cancelar la tarea
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
    </item>
    <item>
      <title>A QA engineer enters a bar</title>
      <dc:creator>Yoandy Rodriguez Martinez</dc:creator>
      <pubDate>Wed, 03 Jul 2019 16:42:08 +0000</pubDate>
      <link>https://forem.com/yorodm/a-qa-engineer-enters-a-bar-5bb5</link>
      <guid>https://forem.com/yorodm/a-qa-engineer-enters-a-bar-5bb5</guid>
      <description>&lt;p&gt;A QA Engineer enters a bar:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Stares at the barman for twenty minutes. &lt;/li&gt;
&lt;li&gt;Asks for two beers and a straw.&lt;/li&gt;
&lt;li&gt;Asks for sparkling water with lemon juice.&lt;/li&gt;
&lt;li&gt;Asks for a unicorn, a lizard and some tequila.&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>jokes</category>
    </item>
    <item>
      <title>Github bloquea acceso desde Cuba</title>
      <dc:creator>Yoandy Rodriguez Martinez</dc:creator>
      <pubDate>Mon, 03 Jun 2019 15:36:08 +0000</pubDate>
      <link>https://forem.com/yorodm/github-bloquea-acceso-desde-cuba-1n4j</link>
      <guid>https://forem.com/yorodm/github-bloquea-acceso-desde-cuba-1n4j</guid>
      <description>&lt;p&gt;Bueno, GitHub a decidido que el código fuente de mis proyectos no debe ser visto desde el país donde vivo y los produzco. Muchas gracias por golpear aún más a los que ya tenemos pocas puertas abiertas y ninguna opinión en el proceso.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://twitter.com/yorodm/status/1135569500437405696"&gt;Ayúdame a protestar en Twitter&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  UPDATE
&lt;/h2&gt;

&lt;p&gt;Parece que han restaurado el acceso, no hay comunicados oficiales todavía.&lt;/p&gt;

</description>
      <category>github</category>
      <category>embargo</category>
      <category>news</category>
    </item>
    <item>
      <title>Emacs + Golang. Edición 2019</title>
      <dc:creator>Yoandy Rodriguez Martinez</dc:creator>
      <pubDate>Mon, 25 Mar 2019 19:34:27 +0000</pubDate>
      <link>https://forem.com/yorodm/emacs--golang-edicin-2019-2i52</link>
      <guid>https://forem.com/yorodm/emacs--golang-edicin-2019-2i52</guid>
      <description>&lt;p&gt;&lt;a href="https://blog.golang.org/go1.12"&gt;Go 1.12&lt;/a&gt; fue lanzado hace un mes y entre los cambios más significativos se encuentran varias mejoras en el soporte para módulos (que va a ser el método por defecto en la versión 1.13).&lt;/p&gt;

&lt;p&gt;Si eres usuario de &lt;a href="https://www.gnu.org/software/emacs"&gt;Emacs&lt;/a&gt; y te interesa desarrollar utilizando Go, aquí tienes una guía sencilla de como habilitar el soporte para el lenguaje.&lt;/p&gt;

&lt;h2&gt;
  
  
  Paso 1. Language server protocol
&lt;/h2&gt;

&lt;p&gt;Si tienes una versión actualizada de &lt;a href="https://github.com/emacs-lsp/lsp-mode"&gt;lsp-mode&lt;/a&gt; ya tienes soporte para &lt;a href="https://github.com/saibing/bingo"&gt;bingo&lt;/a&gt;, una herramienta que provee un servidor de lenguajes para Go y que tiene soporte integrado para trabajar con módulos&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(use-package lsp-mode
  :commands (lsp)
  :config
  (use-package company-lsp
    :config
    (add-to-list 'company-backends 'company-lsp)))

(use-package lsp-ui
  :hook (lsp-mode . lsp-ui-mode)
  :config
  (define-key lsp-ui-mode-map
    [remap xref-find-definitions] #'lsp-ui-peek-find-definitions)
  (define-key lsp-ui-mode-map
    [remap xref-find-references] #'lsp-ui-peek-find-references)
  (setq lsp-ui-sideline-enable nil
        lsp-ui-doc-enable t
        lsp-ui-flycheck-enable nil
        lsp-ui-imenu-enable t
        lsp-ui-sideline-ignore-duplicate t))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Paso 2. Go mode y utilidades
&lt;/h2&gt;

&lt;p&gt;Como &lt;a href="https://github.com/emacs-lsp/lsp-mode"&gt;lsp-mode&lt;/a&gt; es un &lt;em&gt;minor mode&lt;/em&gt; necesitamos el soporte para el lenguaje (font-lock entre otras cosas). Los pasos necesarios son:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Instalar &lt;a href="//golang.org/x/tools/cmd/goimports"&gt;goimports&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Instalar &lt;a href="https://github.com/golang/lint"&gt;golint&lt;/a&gt; o &lt;a href="https://golang.org/cmd/gofmt/"&gt;gofmt&lt;/a&gt;.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(use-package flycheck)
(use-package go-mode
  :config
  ; Use goimports instead of go-fmt
  (setq gofmt-command "goimports")
  (flycheck-mode)
  (add-hook 'go-mode-hook 'company-mode)
  ;; Call Gofmt before saving
  (add-hook 'before-save-hook 'gofmt-before-save)
  (add-hook 'go-mode-hook #'lsp)
  (add-hook 'go-mode-hook #'flycheck-mode)
  (add-hook 'go-mode-hook '(lambda ()
                 (local-set-key (kbd "C-c C-r") 'go-remove-unused-imports)))
  (add-hook 'go-mode-hook '(lambda ()
                 (local-set-key (kbd "C-c C-g") 'go-goto-imports)))
  (add-hook 'go-mode-hook (lambda ()
                (set (make-local-variable 'company-backends) '(company-go))
                (company-mode))))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Paso 3. Comenzar a programar en Go.
&lt;/h2&gt;

&lt;p&gt;Con la configuración anterior puedes empezar a programar en Go&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Completamiento y referencias cruzadas&lt;/li&gt;
&lt;li&gt;Revisión de código mientras escribes.&lt;/li&gt;
&lt;li&gt;Formato automático al salvar.&lt;/li&gt;
&lt;li&gt;Un efecto aprecido al &lt;em&gt;hover&lt;/em&gt; de &lt;a href="https://code.visualstudio.com/"&gt;ese editor taaan popular&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Paso 4. Compilar y debug.
&lt;/h2&gt;

&lt;p&gt;Puedes configurar el comando de compilación por defecto que utilizas cuando editas archivos Go.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;;; Adicionar en la sección :config de `go-mode`
(add-hook 'go-mode-hook #'setup-go-mode-compile)

;; adicionar en el mismo archivo

(defun setup-go-mode-compile ()
  ; Customize compile command to run go build
  (if (not (string-match "go" compile-command))
      (set (make-local-variable 'compile-command)
           "go build -v &amp;amp;&amp;amp; go test -v &amp;amp;&amp;amp; go vet")))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Si prefieres los &lt;em&gt;debuggers&lt;/em&gt; interactivos debes instalar &lt;a href="https://github.com/go-delve/delve"&gt;delve&lt;/a&gt; y añadir la siguiente línea en tu archivo de inicio de Emacs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(use-package go-dlv)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Los comandos &lt;code&gt;dlv&lt;/code&gt; y &lt;code&gt;dlv-current-func&lt;/code&gt; son los puntos de entrada al debugger.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>The Ultimate Web Framework Deathmatch!</title>
      <dc:creator>Yoandy Rodriguez Martinez</dc:creator>
      <pubDate>Thu, 14 Mar 2019 18:34:13 +0000</pubDate>
      <link>https://forem.com/yorodm/the-ultimate-web-framework-deathmatch-1op8</link>
      <guid>https://forem.com/yorodm/the-ultimate-web-framework-deathmatch-1op8</guid>
      <description>&lt;p&gt;Are those benchmarking blog post bothering you? Tired of listening to people boast about how good framework X is? Undecided wether to use framework X or framework Y in your new startup?. Fear not!!! You can now (easily) launch your own edition of: &lt;strong&gt;The Ultimate Web Framework Deathmatch&lt;/strong&gt;  using &lt;a href="https://www.techempower.com/benchmarks/"&gt;TechEmpower's Web Framework benchmarks suite&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The project has a &lt;a href="https://github.com/TechEmpower/FrameworkBenchmarks"&gt;Github repo&lt;/a&gt; with all the things you need to run your own tests. As this post is beeing written there's a fierce competition going between an &lt;a href="https://github.com/aio-libs/"&gt;aio-libs based python app&lt;/a&gt; and &lt;a href="https://godoc.org/net/http"&gt;net/http&lt;/a&gt; with &lt;a href="http://jmoiron.github.io/sqlx/"&gt;SQLx&lt;/a&gt;, both using PostgreSQL, so just read the &lt;a href="https://github.com/TechEmpower/FrameworkBenchmarks/wiki/Benchmarking-Getting-Started"&gt;instructions&lt;/a&gt; and let the games begin! You can add your results to the project via a PR or just post your benchmarking as a comment here.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Disclaimer&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In case someone is wondering, I have no idea of who the good folks at TechEmpower are, neither I work for them or receive any compensation from them. I just thought the whole Deathmatch thing sounded like a way to have some productive fun.&lt;/p&gt;

</description>
      <category>web</category>
      <category>benchmark</category>
    </item>
    <item>
      <title>Plumber: ETL simple para Python</title>
      <dc:creator>Yoandy Rodriguez Martinez</dc:creator>
      <pubDate>Tue, 12 Mar 2019 14:14:20 +0000</pubDate>
      <link>https://forem.com/yorodm/plumber-etl-simple-para-python-2knj</link>
      <guid>https://forem.com/yorodm/plumber-etl-simple-para-python-2knj</guid>
      <description>&lt;p&gt;Implementando una feature para uno de los proyectos en los que trabajo terminé necesitando hacer el típico proceso ETL que tomara las cosas de una fuente X, las pasara por 1 o varios filtros y las cargara en nuestra base de datos documental.&lt;/p&gt;

&lt;p&gt;Ahora, si bien existen frameworks de excelente calidad como &lt;a href="https://petl.readthedocs.io"&gt;petl&lt;/a&gt; y &lt;a href="https://www.bonobo-project.org"&gt;Bonobo&lt;/a&gt; que cubren este campo, me encontré con los siguientes problemas:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Existe mucho código &lt;em&gt;legacy&lt;/em&gt; en el proyecto.&lt;/li&gt;
&lt;li&gt;Exceptuando la parte de ETL, la complejidad de proceso es bastante alta, incrementarla no sería lo más adecuado.&lt;/li&gt;
&lt;li&gt;El componente ETL no se ejecutaría por si mismo sino como parte de una solución.&lt;/li&gt;
&lt;li&gt;La mayoría de los datos que agregamos usan formatos no convencionales.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Aunque en apariencia sencillos, estos cuatro puntos me llevaron a crear mipropio &lt;em&gt;miniframework&lt;/em&gt; para componentes ETL que es fácil de integrar con código existente y no hace ningún tipo de suposiciones con respecto a la forma de los datos, &lt;a href="https://github.com/yorodm/plumber"&gt;plumber&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Características de plumber.
&lt;/h2&gt;

&lt;p&gt;Para el desarrollo del framework me basé mucho en mi experiencia anterior con &lt;a href="https://www.kiba-etl.org"&gt;kiba&lt;/a&gt;, una de esas joyas que siempre vienen desde la comunidad de Ruby. Kiba hace uso de las bondades de Ruby para crear DSL’s dejando al desarrollador que se centre en los datos de la manera que considere correcta. En  &lt;a href="https://github.com/yorodm/plumber"&gt;plumber&lt;/a&gt; esta idea está reflejada en cuatro conceptos:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Extractors (que acceden al origen de datos).&lt;/li&gt;
&lt;li&gt;Transformers (que manipulan los datos obtenidos).&lt;/li&gt;
&lt;li&gt;Writers (que persisten los datos).&lt;/li&gt;
&lt;li&gt;Pipes (que controlan todo el proceso).&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Extractors.
&lt;/h3&gt;

&lt;p&gt;Un &lt;strong&gt;Extractor&lt;/strong&gt; es una clase o función que emite datos para una tubería (pipe), los datos pueden tener cualquier origen y cualquier forma, los extractors son independientes del resto del proceso.&lt;/p&gt;

&lt;p&gt;Aunque es posible utilizar una función como extractor, lo recomendado en la mayoría de los casos es heredar de la clase &lt;code&gt;plumber.pipe.Extractor&lt;/code&gt; e implementar los métodos &lt;code&gt;read&lt;/code&gt;, &lt;code&gt;setup&lt;/code&gt; y &lt;code&gt;cleanup&lt;/code&gt;. Varios extractors se pueden unir para formar uno solo que emita una secuencia (tupla) con los valores decada uno.&lt;/p&gt;

&lt;h3&gt;
  
  
  Transformers.
&lt;/h3&gt;

&lt;p&gt;Un &lt;strong&gt;Transformer&lt;/strong&gt; es cualquier función marcada con &lt;code&gt;@transformer&lt;/code&gt; o una clasederivada de &lt;code&gt;plumber.pipe.Transformer&lt;/code&gt;. Es posible unir varios transformers e nuna cadena de procesamiento&lt;/p&gt;

&lt;h3&gt;
  
  
  Writer.
&lt;/h3&gt;

&lt;p&gt;Finalmente los &lt;strong&gt;Writers&lt;/strong&gt; heredan de &lt;code&gt;plumber.pipe.Writer&lt;/code&gt;. Como generalmente acceden a recursos externos, es requerido que implementen los métodos &lt;code&gt;setup&lt;/code&gt; y&lt;code&gt;cleanup&lt;/code&gt; además de &lt;code&gt;write&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Todos los elementos usan anotaciones &lt;a href="https://www.python.org/dev/peps/pep-0484/"&gt;PEP 484&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Un ejemplo sencillo:
&lt;/h2&gt;

&lt;p&gt;Uno de los casos de uso que motivaron la creación del framework fue obtener una lista de registros de un archivo con formato propietario. El contenido delarchivo es más o menos el siguiente:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Campo identificador de cliente. Comienza en la posición 0, tiene longitud entre 1 y 20.&lt;/li&gt;
&lt;li&gt;Campo identificador de transacción. Comienza en la posición 22. Es numérico y tiene longitud 8.&lt;/li&gt;
&lt;li&gt;Campo identificador de transacción relacionada. Comienza en la posición 32.Tiene longitud 8, es opcional y de no estar se ponen espacios en blanco.&lt;/li&gt;
&lt;li&gt;Campo motivo de la transacción. Comienza en la posición 42 y longitud entre 10 y 50. Es de tipo alfanumérico, incluye espacios, no tiene delimitaciones.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Veamos un ejemplo de como procesar estos archivos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;plumber&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pipe&lt;/span&gt; &lt;span class="c1"&gt;# API síncrona.
&lt;/span&gt;
&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;extractor&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;read_file&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;file_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'FILENAME'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;readlines&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
            &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="n"&gt;process_line&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;transformer&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;csvfy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="s"&gt;','&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SaveData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Writer&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;filename&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s"&gt;'w'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;cleanup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;tuberia&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;read_file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;csvfy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;SaveData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"prueba.csv"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;tuberia&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  ¿Qúe queda por hacer?
&lt;/h2&gt;

&lt;p&gt;Ahora que &lt;a href="https://github.com/yorodm/plumber"&gt;plumber&lt;/a&gt; salió a la luz es hora de convertirlo en un framework ETL medianamente decente. Los próximos pasos son:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Adicionar la posibilidad de hacer &lt;strong&gt;Writers&lt;/strong&gt; como funciones con administración de contexto integrada.&lt;/li&gt;
&lt;li&gt;Poder inicializar los &lt;strong&gt;Extractors&lt;/strong&gt; de manera sencilla.&lt;/li&gt;
&lt;li&gt;Mejorar el tratamiento de errores.&lt;/li&gt;
&lt;li&gt;Concurrencia y/o paralelismo.&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>python</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Python: Decoradores estándar y su uso</title>
      <dc:creator>Yoandy Rodriguez Martinez</dc:creator>
      <pubDate>Wed, 16 Jan 2019 03:11:42 +0000</pubDate>
      <link>https://forem.com/yorodm/python-decoradores-estndar-y-su-uso-3fe</link>
      <guid>https://forem.com/yorodm/python-decoradores-estndar-y-su-uso-3fe</guid>
      <description>&lt;p&gt;Entre las &lt;em&gt;baterías includas&lt;/em&gt; de Python, vienen varios decoradores que nos facilitan la vida. Aquí una lista de algunos y breve explicación acerca de su uso.&lt;/p&gt;

&lt;h2&gt;
  
  
  Decoradores para OOP
&lt;/h2&gt;

&lt;h3&gt;
  
  
  property
&lt;/h3&gt;

&lt;p&gt;Uno de los más usados. Convierte un conjunto de métodos en un &lt;strong&gt;descriptor&lt;/strong&gt; que hace las funciones de propiedad. Útil cuando queremos adicionar algún tipo de lógica a propiedades de la clase.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class C:
    def __init__ (self):
        self._x = None

    def getx(self):
        return self._x or request.get('http://mydata.com/x')

    def setx(self, value):
        self._x = value
        request.post('http://mydata.com/x', data=x)

    def delx(self):
        del self._x
        request.delete('http://mydata.com/x')

    x = property(getx, setx, delx, "x como proxy a servicio REST.")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  staticmethod
&lt;/h3&gt;

&lt;p&gt;Define métodos estáticos&lt;sup id="fnref:1"&gt;1&lt;/sup&gt;. Pueden ser llamados tanto desde la clase o una de sus instancias&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class C:

    @staticmethod
    def calculo_externo(val, val2):
        return val + val2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nótese la falta del parámetro implicito inicial.&lt;/p&gt;

&lt;h3&gt;
  
  
  classmethod
&lt;/h3&gt;

&lt;p&gt;Convierte un método normal a un método de clase. Los métodos de clase reciben la clase como parámetro implícito en vez de una de las instancias. Uno de los casos de uso más comunes es crear formas alternativas de instanciar la clase.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class C:

    def __init__ (self, x, y ,z):
        self.x = x
        self.y = y
        self.z = z

    @classmethod
    def from_dict(cls, data):
        return cls(data[0], data[1], data[3])
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  abc.abstractmethod
&lt;/h3&gt;

&lt;p&gt;Métodos que tienen que ser implementados &lt;strong&gt;obligatoriamente&lt;/strong&gt; por las subclases. El equivalente a &lt;em&gt;interfaces&lt;/em&gt; o &lt;em&gt;clases abstractas&lt;/em&gt; que tanto encuentras en otros lenguajes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import abc

class Animal:

    @abc.abstractmethod
    def sonido(self):
        pass

class Perro(Animal):

    def sonido(self):
        print("Ladrido")

class Vaca(Animal):

    def sonido(self):
        print("Mugido")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Se puede utilizar en conjunción con &lt;em&gt;@property&lt;/em&gt; o &lt;em&gt;staticmethod&lt;/em&gt; para crear propiedades o métodos estáticos abstractos.&lt;/p&gt;

&lt;h3&gt;
  
  
  functools.total_ordering
&lt;/h3&gt;

&lt;p&gt;Nos permite crear clases que soporten operadores de comparación. Solo tenemos que proveer el método _ &lt;strong&gt;eq&lt;/strong&gt; _ y uno de los seis métodos predefinidos de orden. La documentación de la bilioteca estándar advierte que este decorador puede tener impactos en el rendimiento.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@total_ordering
class Student:
    def _is_valid_operand(self, other):
        return (hasattr(other, "lastname") and
                hasattr(other, "firstname"))
    def __eq__ (self, other):
        if not self._is_valid_operand(other):
            return NotImplemented
        return ((self.lastname.lower(), self.firstname.lower()) ==
                (other.lastname.lower(), other.firstname.lower()))
    def __lt__ (self, other):
        if not self._is_valid_operand(other):
            return NotImplemented
        return ((self.lastname.lower(), self.firstname.lower()) &amp;lt;
                (other.lastname.lower(), other.firstname.lower()))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  dataclasses.dataclass
&lt;/h3&gt;

&lt;p&gt;Nos permite omitir la declaración de _ &lt;strong&gt;init&lt;/strong&gt; _ y _ &lt;strong&gt;repr&lt;/strong&gt; _ en la declaración de clases en las que solo vamos a manejar datos. El uso puede ser extendido a subclases&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import dataclasses

@dataclasses.dataclass
class Point:
    x: float
    y: float

    def euclidian_distance(self, other: Point) -&amp;gt; float:
        return math.sqrt(
            (other.x - self.y)**2 + (other.y - self.y)**2
        )

@dataclasses.dataclass
class ThreeDPoint(Point):
    z: float

    def euclidian_distance(self,other: Point) -&amp;gt; float:
        dx = (other.x - self.y)**2
        dy = (other.y - self.y)**2
        dz = (other.z - self.z)**2
        return math.sqrt(
            dx+dy+dz
        )
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Decoradores para funciones
&lt;/h2&gt;

&lt;h3&gt;
  
  
  functools.lru_cache
&lt;/h3&gt;

&lt;p&gt;Caché de las últimas &lt;em&gt;n&lt;/em&gt; llamadas a una función. Los parametros tienen que poder ser utilizados como llaves de un diccionario.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from functools import lru_cache
@lru_cache(20)
def get_exchange(local, foreign):
    exchange_service.convert(local, foreign)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  asyncio.coroutine
&lt;/h3&gt;

&lt;p&gt;Convierte corutinas basadas en generadores para que sean compatibles con el nuevo modelo &lt;em&gt;async/await&lt;/em&gt;. Usar solamente en código que necesita ser portado&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from asyncio import coroutine

@coroutine
def render_view(view_name, context):
    template = Template(view_name, context)
    yield template.render()

async def hanlde_get(route):
    await render_view(route.view, route.params)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  contextlib.contextmanager
&lt;/h3&gt;

&lt;p&gt;Convierte una función en un &lt;em&gt;contextmanager&lt;/em&gt;. Puede ser usado de dos formas:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Utilizando una sentencia &lt;em&gt;with&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Como un decorador.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Personalmente para hacer decoradores que sean &lt;em&gt;contextmanagers&lt;/em&gt; prefiero utilizar la clase &lt;em&gt;ContextDecorator&lt;/em&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from contextlib import contextmanager

@contextmanager
def acquire_lock(key):
    credentials = get_credentials(key)
    lock = acquire_lock_using_credentials(credentials)
    try:
        yield lock
    finally:
        release_lock(lock)

with acquire_lock('my secret api key') as lock:
    use_critical_resource(lock)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Decoradores extra
&lt;/h2&gt;

&lt;h3&gt;
  
  
  functools.wraps
&lt;/h3&gt;

&lt;p&gt;Decorador para crear decoradores. Útil para hacer que las funciones conserven propiedades como _ &lt;strong&gt;name&lt;/strong&gt; _ y _ &lt;strong&gt;doc&lt;/strong&gt; _&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from functools import wraps
def my_decorator(f):
    @wraps(f)
    def wrapper(*args, **kwds):
        return f(*args, **kwds)
        return wrapper

@my_decorator
def funcion():
    """
    Esta es la doc
    """
    pass
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  functools.singledispatch
&lt;/h3&gt;

&lt;p&gt;Permite crear funciones sobrecargadas a partir del tipo del primer parámetro. Hace uso de las anotaciones de tipos.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Perro:
    pass

clas Vaca:
    pass

@singledispatch
def sonido(animal):
    pass

@sonido.register(Perro)
def _(animal):
    print("Ladra")

@sonido.register(Vaca)
def _(animal):
    print("Muge")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;ol&gt;
&lt;li&gt;No soy muy partidario de usar métodos estáticos en Python. &lt;sup&gt;[return]&lt;/sup&gt;
&lt;/li&gt;
&lt;/ol&gt;

</description>
    </item>
  </channel>
</rss>
