<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Tiago Mendes-Costa</title>
    <description>Tiago Mendes-Costa&apos;s home page and blog.
</description>
    <link>https://www.mendes-costa.net/</link>
    <atom:link href="https://www.mendes-costa.net/feed.xml" rel="self" type="application/rss+xml"/>
    <pubDate>Sun, 17 May 2026 13:03:57 +0000</pubDate>
    <lastBuildDate>Sun, 17 May 2026 13:03:57 +0000</lastBuildDate>
    <generator>Jekyll v3.10.0</generator>
    
      <item>
        <title>An ode to Apple at 50</title>
        <description>&lt;p&gt;Here’s to the greedy ones.&lt;br /&gt;
The shareholders.&lt;br /&gt;
The authoritarians.&lt;br /&gt;
The moneymakers.&lt;br /&gt;
The round icons in the squircle jails.&lt;br /&gt;
The ones who see things operationally.&lt;/p&gt;

&lt;p&gt;They’re fond of their own rules.&lt;br /&gt;
And they will lobby for the status quo.&lt;br /&gt;
You can quote them, disagree with them, glorify or vilify them.&lt;br /&gt;
About the only thing you can’t do is ignore them.&lt;br /&gt;
Because they control things.&lt;br /&gt;
They push the capitalist race forward.&lt;/p&gt;

&lt;p&gt;And while some may see them as the greedy ones, we see profits.&lt;br /&gt;
Because the people who are greedy enough to think they can charge the world, are the ones who do.&lt;/p&gt;

&lt;p&gt;— Tim Apple&lt;/p&gt;
</description>
        <pubDate>Wed, 01 Apr 2026 00:00:00 +0000</pubDate>
        <link>https://www.mendes-costa.net/posts/apple-at-50</link>
        <guid isPermaLink="true">https://www.mendes-costa.net/posts/apple-at-50</guid>
        
        
        <category>posts</category>
        
      </item>
    
      <item>
        <title>Christophe</title>
        <description>&lt;p&gt;This week I learned with sadness that my friend Christophe Philemotte passed away after a long battle with cancer.&lt;/p&gt;

&lt;p&gt;Some of us in the Belgian Ruby community will remember him as the driving force behind our meetups, and the founder of the Ruby Belgium ASBL. We had so many wonderful moments connecting with like-minded people, thanks to his dedicated work.&lt;/p&gt;

&lt;p&gt;On a personal level, Christophe inspired and encouraged me to take a more active role in that community. I will be forever grateful for his trust.&lt;/p&gt;

&lt;p&gt;His kind and gentle nature, intelligence, and humanism will be missed.&lt;/p&gt;

&lt;p&gt;My thoughts go to his family.&lt;/p&gt;

&lt;p&gt;Rest in peace, Toch.&lt;/p&gt;
</description>
        <pubDate>Thu, 05 Mar 2026 00:00:00 +0000</pubDate>
        <link>https://www.mendes-costa.net/posts/christophe</link>
        <guid isPermaLink="true">https://www.mendes-costa.net/posts/christophe</guid>
        
        
        <category>posts</category>
        
      </item>
    
      <item>
        <title>The Google Web</title>
        <description>&lt;p&gt;Open Web Advocacy posted &lt;a href=&quot;https://open-web-advocacy.org/blog/japan-apple-must-lift-engine-ban-by-december/&quot;&gt;Japan: Apple Must Lift Browser Engine Ban by December&lt;/a&gt;, commenting that it “is a major step forward for browser competition”.&lt;/p&gt;

&lt;p&gt;I disagree. It’s a step backward.&lt;/p&gt;

&lt;p&gt;First, the article conflates browser and rendering engine. Yes, they are in most cases interlinked, and might be difficult or impossible to separate. But they are not the same. A small company can build a browser around WebKit to compete on iOS. Introducing a new rendering engine nowadays is only realistic for a few existing tech giants.&lt;/p&gt;

&lt;p&gt;Second, the web is based on standards. Rendering engines must follow rules set by the &lt;a href=&quot;https://www.w3.org&quot;&gt;World Wide Web Consortium&lt;/a&gt;. If a web app requires a specific rendering engine to run, it’s not a web app. It’s a Google platform app. So much for “open”. The word for a healthy open web should be “collaboration”, not “competition”.&lt;/p&gt;

&lt;p&gt;Third, even though Apple cultivating an anti-competitive attitude by defying international rulings is obnoxious, in this case their protectionism is working &lt;em&gt;for&lt;/em&gt; the preservation of an open web. When Chromium-based rendering engines will be allowed on iOS, the scenario already playing on macOS will repeat itself: everybody will install Chrome to run Google-locked apps. Developers will then have zero incentives to maintain WebKit compatibility, since “just install Chrome on your iPhone / iPad” will be the easy answer to save them work. Nothing runs on WebKit anymore, WebKit withers to irrelevance, Google is even more free to impose any changes they want, the open web is now the Google web.&lt;/p&gt;

&lt;p&gt;So yes, in theory everyone is playing fair, and iOS becomes a merry hub for web innovation. In practice, the last counter-weight to Google’s gorilla-sized web hegemony falls, and the open web gets buried under it.&lt;/p&gt;
</description>
        <pubDate>Wed, 06 Aug 2025 00:00:00 +0000</pubDate>
        <link>https://www.mendes-costa.net/posts/the-google-web</link>
        <guid isPermaLink="true">https://www.mendes-costa.net/posts/the-google-web</guid>
        
        <category>Web</category>
        
        
        <category>posts</category>
        
      </item>
    
      <item>
        <title>Alien Twitter</title>
        <description>&lt;p&gt;A mashup experiment for funsies. Published as a farewell tweet after the platform cut access to third-party clients on 13/01/2023.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Final report on the commercial shitshow Twitter, third officer reporting. The other members of the crew - Tweetbot, Twitterrific, Echofon, Plume, and others - are dead. API and goodwill destroyed. I should reach the fediverse in about six weeks. With a little luck, the network will pick me up. This is Ripley, last survivor of the Twittosphere, signing off.&lt;/p&gt;
&lt;/blockquote&gt;
</description>
        <pubDate>Sun, 15 Jan 2023 00:00:00 +0000</pubDate>
        <link>https://www.mendes-costa.net/posts/alien-twitter</link>
        <guid isPermaLink="true">https://www.mendes-costa.net/posts/alien-twitter</guid>
        
        <category>Social</category>
        
        
        <category>posts</category>
        
      </item>
    
      <item>
        <title>Piste ou bande cyclable ?</title>
        <description>&lt;p&gt;Doit-on dire &lt;em&gt;piste&lt;/em&gt; ou &lt;em&gt;bande&lt;/em&gt; cyclable pour parler d’un tracé sur la chaussée réservé aux cyclistes et délimité par des traits discontinus ?&lt;/p&gt;

&lt;p&gt;Le code de la route belge parle bien de bandes pour toutes les délimitations de voies peintes sur le macadam :&lt;/p&gt;

&lt;figure&gt;
&lt;p&gt;&lt;img src=&quot;https://www.code-de-la-route.be/media/image/orig/2cf593789e5f2199071ed98cc4dc6fc27abf2aa0.jpg&quot; alt=&quot;Ligne continue&quot; /&gt; 
  &lt;img src=&quot;https://www.code-de-la-route.be/media/image/orig/5695984a2793f19f6e61ec9b39426ee1a249465f.jpg&quot; alt=&quot;Ligne discontinue&quot; /&gt; 
  &lt;img src=&quot;https://www.code-de-la-route.be/media/image/orig/68088b621b23cbd563a5788a949aa03210f08d25.jpg&quot; alt=&quot;Lignes juxtaposées&quot; /&gt; &lt;img src=&quot;https://www.code-de-la-route.be/media/image/orig/eafac0178e8644967c4d77f1e77d3b2e07f76780.jpg&quot; alt=&quot;Larges traits discontinus&quot; /&gt;&lt;/p&gt;
  &lt;figcaption&gt;&lt;a href=&quot;https://www.code-de-la-route.be/fr/reglementation/1976101105~hra8v386pu#uubflmlajy&quot;&gt;Article 72&lt;/a&gt;. Marques longitudinales indiquant les &lt;strong&gt;bandes de circulation&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Autos, motos, bus, tracteurs, tous les usagers roulent ou s’arrêtent en urgence sur des &lt;em&gt;bandes&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Tous, sauf les cyclistes, qui ont subitement droit à l’appellation &lt;em&gt;piste&lt;/em&gt; :&lt;/p&gt;

&lt;figure&gt;
&lt;p&gt;&lt;img src=&quot;https://www.code-de-la-route.be/media/image/orig/39ed2e19746f9858780140b049332d0d04febf87.jpg&quot; alt=&quot;Piste cyclable&quot; /&gt;&lt;/p&gt;
  &lt;figcaption&gt;&lt;a href=&quot;https://www.code-de-la-route.be/fr/reglementation/1976101105~hra8v386pu#bogok2zg5p&quot;&gt;Article 74&lt;/a&gt;. Marques longitudinales indiquant une &lt;strong&gt;piste cyclable&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Et la définition est encore plus étonnante, lorsqu’on constate la facilité avec laquelle les véhicules lourds débordent régulièrement sur ces « pistes » :&lt;/p&gt;

&lt;figure&gt;
&lt;blockquote&gt;
  &lt;p&gt;Le terme « bande de circulation » désigne toute partie d’une chaussée divisée, dans le sens longitudinal […] &lt;strong&gt;La piste cyclable ne fait pas partie de la chaussée.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
  &lt;figcaption&gt;&lt;a href=&quot;https://www.code-de-la-route.be/fr/reglementation/1976101105~hra8v386pu#ugbqbbunmj&quot;&gt;Article 2&lt;/a&gt;. Définitions&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Mais pourquoi râler sur un pareil détail de langage ? Parce qu’il a son importance lorsqu’il s’agit de distinguer les voies peintes de celles séparées.&lt;/p&gt;

&lt;p&gt;Lorsque les élus politiques se félicitent de créer des kilomètres de pistes cyclables, ils·elles jouent sur l’ambiguïté de la définition. Procédé de communication malhonnête (qu’il soit prémédité ou non) soutenu par le code. Et les retombées de cette communication ont un réel impact sur la prise de responsabilités, la sécurité routière, et le nombre de personnes qui se mettent (ou pas) au vélo.&lt;/p&gt;

&lt;p&gt;En comparaison, le &lt;a href=&quot;https://www.legifrance.gouv.fr/codes/article_lc/LEGIARTI000045650507&quot;&gt;code de la route français&lt;/a&gt; est nettement plus clair :&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;Bande cyclable&lt;/strong&gt; : voie exclusivement réservée aux cycles à deux ou trois roues, aux cyclomobiles légers et aux engins de déplacement personnel motorisés sur une chaussée à plusieurs voies.&lt;/p&gt;

  &lt;p&gt;&lt;strong&gt;Piste cyclable&lt;/strong&gt; : chaussée exclusivement réservée aux cycles à deux ou trois roues, aux cyclomobiles légers et aux engins de déplacement personnel motorisés.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Le besoin de révision du code de la route belge est donc essentiel à cet égard, ne fût-ce que par honnêteté intellectuelle.&lt;/p&gt;
</description>
        <pubDate>Sun, 04 Sep 2022 00:00:00 +0000</pubDate>
        <link>https://www.mendes-costa.net/posts/piste-ou-bande-cyclable</link>
        <guid isPermaLink="true">https://www.mendes-costa.net/posts/piste-ou-bande-cyclable</guid>
        
        <category>Mobility</category>
        
        
        <category>posts</category>
        
      </item>
    
      <item>
        <title>Le Dieweg et sa bande cyclable</title>
        <description>&lt;p&gt;&lt;em&gt;Lettre ouverte à &lt;a href=&quot;https://thibaudwyngaard.be/&quot;&gt;Thibaud Wyngaard&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Monsieur,&lt;/p&gt;

&lt;p&gt;Ce dimanche 14 août, je constatais avec bonne humeur&lt;sup id=&quot;fnref:1&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:1&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; que le tronçon Wolvendael–Circulaire du Dieweg avait reçu un marquage au sol de bande cyclable. Quelle surprise donc, en arrivant au bout de ce tronçon côté Avenue Circulaire, de voir que cette bande s’interrompt subitement pour laisser place à une bande de stationnement, intimant aux cyclistes de se déporter sur la gauche pour la contourner.&lt;/p&gt;

&lt;p&gt;Ce marquage est à la fois inacceptable, absurde, et dangereux. Je vous demande donc, en votre qualité d’Échevin de la mobilité, du stationnement, et des travaux publics, de retirer au plus vite cette bande de stationnement au profit d’une bande cyclable continue.&lt;/p&gt;

&lt;h2 id=&quot;inacceptable&quot;&gt;Inacceptable&lt;/h2&gt;

&lt;p&gt;Le message aux citoyens est en effet clair : Uccle est pour la mobilité douce, mais celle-ci passera toujours en second plan dès que le statu quo du trafic automobile est dérangé.&lt;/p&gt;

&lt;p&gt;Cette vision conservatrice de la gestion de l’espace public est inacceptable en 2022, à l’heure de l’urgence climatique, des inondations et des vagues de chaleur sur la commune.&lt;/p&gt;

&lt;p&gt;Les nombreuses personnes ayant plébiscité Écolo aux dernières élections communales attendent, j’en suis persuadé, un message moins ambigu de la part de votre équipe.&lt;sup id=&quot;fnref:2&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:2&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;h2 id=&quot;absurde&quot;&gt;Absurde&lt;/h2&gt;

&lt;p&gt;La présence de cette courte bande de stationnement n’a pas lieu d’être. Le côté sud de la voirie, constitué du complexe à appartements Constellations, possède un grand parc privé à même d’accueillir des véhicules&lt;sup id=&quot;fnref:3&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:3&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;. Le côté nord ne comporte que des villas avec allées et garages privés, et du stationnement gratuit disponible sur la voie publique entre les arbres.&lt;/p&gt;

&lt;p&gt;Il n’y a donc aucune raison valable de prévoir du stationnement côté sud.&lt;/p&gt;

&lt;h2 id=&quot;dangereux&quot;&gt;Dangereux&lt;/h2&gt;

&lt;p&gt;La bande cyclable indique aux conducteurs automobile que leur voie est dégagée de toute personne en vélo ou trottinette. Le Dieweg est aussi une longue avenue droite qui donc induit une vitesse élevée.&lt;/p&gt;

&lt;p&gt;Un véhicule léger qui sort subitement de sa bande pour s’insérer dans le trafic automobile est non seulement une source de stress pour tous les intervenants, mais surtout une source d’accident potentiellement mortel, qui ne demande qu’à se produire à la moindre inattention de part et d’autre. Un automobiliste qui regarde son téléphone, qui freine trop tard, un ado à trottinette qui ne fait pas attention, un enfant à vélo plein d’énergie roulant devant ses parents, … Les scénarios catastrophe ne manquent pas. Une vie humaine ne vaut pas quelques places de parking superflues.&lt;/p&gt;

&lt;p&gt;Pour toutes ces raisons, je vous demande une fois encore, de modifier ces marquages au sol, pour le bien-être et la sécurité du plus grand nombre.&lt;/p&gt;

&lt;p&gt;Merci à vous.&lt;/p&gt;

&lt;hr /&gt;

&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:1&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Une bonne humeur toute relative car, bien qu’une bande cyclable ressemble à un oasis dans le désert d’infrastructures de mobilité douce qu’est Uccle, de la peinture blanche n’a jamais arrêté les débordements de conducteurs distraits ou égoïstes. La seule arme pour convaincre le plus grand nombre d’utiliser le vélo reste la piste cyclable séparée. &lt;a href=&quot;#fnref:1&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:2&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Le nombre de réactions à &lt;a href=&quot;https://twitter.com/otagi/status/1558915149142040576&quot;&gt;mon tweet du 14 août&lt;/a&gt; allant dans ce sens me conforte dans l’idée que je ne suis pas le seul à être indigné par la situation. &lt;a href=&quot;#fnref:2&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:3&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Certes, l’immeuble Constellations ne semble pas avoir de garage souterrain, contrairement à son voisin Cherridreux. Mais le choix des résidents de garder les larges allées et pelouses de leur parc privé vierges de tout véhicule ne doit pas se répercuter sur l’espace public. &lt;a href=&quot;#fnref:3&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</description>
        <pubDate>Sun, 21 Aug 2022 00:00:00 +0000</pubDate>
        <link>https://www.mendes-costa.net/posts/le-dieweg-et-sa-bande-cyclable</link>
        <guid isPermaLink="true">https://www.mendes-costa.net/posts/le-dieweg-et-sa-bande-cyclable</guid>
        
        <category>Mobility</category>
        
        
        <category>posts</category>
        
      </item>
    
      <item>
        <title>Fun with Turbo Streams and Capybara</title>
        <description>&lt;p&gt;Using and testing &lt;a href=&quot;https://turbo.hotwired.dev/handbook/streams&quot;&gt;Turbo Streams&lt;/a&gt; in a &lt;a href=&quot;https://rubyonrails.org&quot;&gt;Rails&lt;/a&gt; app is quite fun, but comes with its share of quirks, which are not always well documented.&lt;/p&gt;

&lt;p&gt;Let’s explain some of these with a &lt;a href=&quot;https://github.com/otagi/turbo-spec&quot;&gt;very simple app&lt;/a&gt;, pompously titled “The Rodents Encyclopedia”. It consists of a dashboard displaying the number of rodents in the database, and a standard &lt;a href=&quot;https://en.wikipedia.org/wiki/Create,_read,_update_and_delete&quot;&gt;CRUD&lt;/a&gt; for these rodents. When a rodent is added, the dashboard counter is automagically updated.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/blog/rodents_encyclopedia.png&quot; alt=&quot;The Rodents Encyclopedia app&quot; width=&quot;100%&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;the-system-spec&quot;&gt;The system spec&lt;/h2&gt;

&lt;p&gt;The &lt;a href=&quot;https://github.com/otagi/turbo-spec/blob/main/spec/system/rodents_counter_spec.rb&quot;&gt;feature&lt;/a&gt; is described in a system spec with &lt;a href=&quot;https://teamcapybara.github.io/capybara/&quot;&gt;Capybara&lt;/a&gt; and &lt;a href=&quot;https://rspec.info&quot;&gt;RSpec&lt;/a&gt;:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# spec/system/rodents_counter_spec.rb&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;feature&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;Rodents Counter&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;puma: &lt;/span&gt;&lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;action_cable: :inline&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;active_job: :inline&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;background&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;driven_by&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:selenium&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;using: :headless_chrome&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;given!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:existing_rodent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;create&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:rodent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;name: &lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;Chipmunk&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;scenario&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;Creating a rodent updates the dashboard rodents counter&apos;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;visit&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;/&apos;&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;page&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;have_text&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;There are 1 rodents in the encyclopedia!&apos;&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;new_window&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;open_new_window&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;within_window&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;new_window&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;visit&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;/rodents/new&apos;&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;fill_in&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;Name&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;with: &lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;Squirrel&apos;&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;click_on&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;Create Rodent&apos;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;page&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;have_text&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;There are 2 rodents in the encyclopedia!&apos;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;First peculiarity, the feature declaration:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;feature&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;Rodents Counter&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;puma: &lt;/span&gt;&lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;action_cable: :inline&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;active_job: :inline&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;puma: true&lt;/code&gt; is a tag defined in a &lt;a href=&quot;https://github.com/otagi/turbo-spec/blob/main/spec/support/capybara.rb&quot;&gt;support file&lt;/a&gt; to use &lt;a href=&quot;https://puma.io&quot;&gt;Puma&lt;/a&gt; as the Capybara server. It should help running concurrent requests.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;action_cable: :inline&lt;/code&gt; is a tag defined by RSpec. I’m not sure yet if that one is required over the standard &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:async&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:test&lt;/code&gt; adapters. Feel free to experiment on your project.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;active_job: :inline&lt;/code&gt; is a tag defined in &lt;a href=&quot;https://github.com/otagi/turbo-spec/blob/main/spec/support/inline_active_job.rb&quot;&gt;another support file&lt;/a&gt;. Broadcast methods ending in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;later&lt;/code&gt; will start an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ActiveJob&lt;/code&gt;. If the job is not run immediately during the spec, Capybara won’t see its result. So this tag is essential to not lose your sanity in debug sessions.&lt;/p&gt;

&lt;p&gt;Next, we select the Selenium driver, because the default &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rack_test&lt;/code&gt; one won’t run Javascript code:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;driven_by&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:selenium&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;using: :headless_chrome&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The actual spec code is now ready to run. It will first check that the dashboard counter is in its initial state, then proceed to create a rodent in a separate browser window, and finally check that the counter has been updated. Note that Capybara does not reload the dashboard page during the whole process, which is exactly the use case we want to test.&lt;/p&gt;

&lt;h2 id=&quot;the-broadcast&quot;&gt;The broadcast&lt;/h2&gt;

&lt;p&gt;Triggering the counter update is done in the &lt;a href=&quot;https://github.com/otagi/turbo-spec/blob/main/app/models/rodent.rb&quot;&gt;Rodent model&lt;/a&gt; whenever the record changes:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# app/models/rodent.rb&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Rodent&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ApplicationRecord&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;after_commit&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:update_rodents_counter&lt;/span&gt;

  &lt;span class=&quot;kp&quot;&gt;private&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;update_rodents_counter&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;broadcast_replace_later_to&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:dashboard&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;target: &lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;rodents-counter&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;partial: &lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;dashboard/rodents_counter&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;locals: &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;rodent: &lt;/span&gt;&lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Let’s decompose the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;broadcast_replace_later_to&lt;/code&gt; call:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;replace&lt;/code&gt; is the action relevant to the use case (there’s also &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;append&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;remove&lt;/code&gt;, etc.).&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;later&lt;/code&gt; wraps the call in a job so that the partial rendering will not slow down the web server response.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;to&lt;/code&gt; allows to pass a channel scope instead of the default model instance.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:dashboard&lt;/code&gt; is our channel scope (see the view below).&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;target:&lt;/code&gt; is the HTML id of the element to be replaced.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;partial:&lt;/code&gt; is the partial to render and send over the wire.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rodent: nil&lt;/code&gt; overwrites the default partial locals set to the model instance. This is required because otherwise, when the record is destroyed, the generated broadcast job will abort with a deserialization error.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;the-stream&quot;&gt;The stream&lt;/h2&gt;

&lt;p&gt;The client subscribes to the channel in the &lt;a href=&quot;https://github.com/otagi/turbo-spec/blob/main/app/views/dashboard/show.html.slim&quot;&gt;dashboard view&lt;/a&gt;:&lt;/p&gt;

&lt;div class=&quot;language-slim highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;/ app/views/dashboard/show.html.slim&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;turbo_stream_from&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:dashboard&lt;/span&gt;

&lt;span class=&quot;nt&quot;&gt;h1&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;na&quot;&gt;Dashboard&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&apos;rodents_counter&apos;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:dashboard&lt;/code&gt; part is the channel scope used earlier in the broadcast.&lt;/p&gt;

&lt;p&gt;In the &lt;a href=&quot;https://github.com/otagi/turbo-spec/blob/main/app/views/dashboard/_rodents_counter.html.slim&quot;&gt;rodents counter&lt;/a&gt; partial, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rodents-counter&lt;/code&gt; id is the target used in the broadcast:&lt;/p&gt;

&lt;div class=&quot;language-slim highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;/ app/views/dashboard/_rodents_counter.html.slim&lt;/span&gt;

&lt;span class=&quot;nt&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;#rodents-counter&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;There&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;are&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Rodent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;rodents&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;in&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;the&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;encyclopedia!
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;That whole partial is rendered server-side and sent over the wire to the subscribed clients. Hotwire’s hidden Javascript code will take care of the replacement in the DOM.&lt;/p&gt;

&lt;p&gt;That’s it, really. A few lines of code to update a page element. No need to write a dedicated Channel class or a Stimulus controller. Less code, and hopefully less bugs.&lt;/p&gt;

</description>
        <pubDate>Thu, 03 Feb 2022 00:00:00 +0000</pubDate>
        <link>https://www.mendes-costa.net/posts/fun-with-turbo-streams-and-capybara</link>
        <guid isPermaLink="true">https://www.mendes-costa.net/posts/fun-with-turbo-streams-and-capybara</guid>
        
        <category>Code</category>
        
        
        <category>posts</category>
        
      </item>
    
      <item>
        <title>Shell aliases</title>
        <description>&lt;p&gt;Do you often type the same boring commands in a &lt;a href=&quot;https://en.wikipedia.org/wiki/Terminal_emulator&quot;&gt;terminal&lt;/a&gt; window? Do you get tired of typing them over and over again?&lt;/p&gt;

&lt;p&gt;Shell aliases are there for you!&lt;/p&gt;

&lt;h2 id=&quot;an-example&quot;&gt;An example&lt;/h2&gt;

&lt;p&gt;Let’s take the &lt;a href=&quot;https://www.man7.org/linux/man-pages/man1/ls.1.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ls&lt;/code&gt;&lt;/a&gt; command. To list the folder content in a long format, you would typically use&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;ls&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-l&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;After the 50th time, especially if like me you are not a formally trained touch typist, it gets old. What if you could shave off 60% of that effort?&lt;/p&gt;

&lt;p&gt;Enter the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;alias&lt;/code&gt; command:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;ll&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;ls -l&apos;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then you can just type&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;ll
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;and marvel at all the keystrokes you saved!&lt;/p&gt;

&lt;p&gt;Of course, since the shell just replaces the alias name with its value under the hood, you can still append any valid argument after the alias, like this:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;ll &lt;span class=&quot;nt&quot;&gt;-A&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;saving-aliases&quot;&gt;Saving aliases&lt;/h2&gt;

&lt;p&gt;These defined aliases will last as long as your shell session. If you open a new terminal window, they will be forgotten.&lt;/p&gt;

&lt;p&gt;To have your favorite aliases ready to run every time, simply list them in your shell configuration file.&lt;/p&gt;

&lt;p&gt;If you’re using &lt;a href=&quot;https://en.wikipedia.org/wiki/Bash_(Unix_shell\)&quot;&gt;&lt;strong&gt;bash&lt;/strong&gt;&lt;/a&gt;, create or edit the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.bashrc&lt;/code&gt; file, and add your aliases, one per line:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# ~/.bashrc&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;ls -CF&apos;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;la&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;ls -A&apos;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;ll&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;ls -lhF&apos;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;lla&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;ls -lhAF&apos;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;For &lt;a href=&quot;https://en.wikipedia.org/wiki/Z_shell&quot;&gt;&lt;strong&gt;zsh&lt;/strong&gt;&lt;/a&gt;, the file is called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.zshrc&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Open a new terminal window. Typing one of the aliases should now run it every time.&lt;/p&gt;

&lt;h2 id=&quot;listing-aliases&quot;&gt;Listing aliases&lt;/h2&gt;

&lt;p&gt;To quickly list all available aliases, you can type&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;alias&lt;/span&gt;	
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;without any arguments.&lt;/p&gt;

&lt;h2 id=&quot;git-aliases&quot;&gt;Git aliases&lt;/h2&gt;

&lt;p&gt;In addition to the regular shell aliases, git also maintains its own set of aliases.&lt;/p&gt;

&lt;p&gt;Provided you already have git installed, you should have an existing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.gitconfig&lt;/code&gt; file. If it contains an alias section like this one:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;alias&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
  co &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; checkout
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;then you should be able to type&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git co
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;in a terminal window, and it will have the same effect as typing the full &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git checkout&lt;/code&gt; command.&lt;/p&gt;

&lt;h2 id=&quot;wrapping-up&quot;&gt;Wrapping up&lt;/h2&gt;

&lt;p&gt;I hope this nifty feature will help you save time and finger tips with your most used commands.&lt;/p&gt;

&lt;p&gt;Thanks to &lt;a href=&quot;https://twitter.com/EmmaBostian/status/1391725278624428034&quot;&gt;Emma Bostian’s tweet&lt;/a&gt; for this article’s idea. (Have a look at the comments for more alias tricks.)&lt;/p&gt;

&lt;h2 id=&quot;appendix-1-shell-alias-examples&quot;&gt;Appendix 1: shell alias examples&lt;/h2&gt;

&lt;p&gt;Here are some useful aliases I accumulated over the years. Heavily geared towards &lt;a href=&quot;https://rubyonrails.org&quot;&gt;Ruby on Rails&lt;/a&gt; development, since that’s what I do all day long.&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Some ls aliases&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;ll&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;ls -lhF&apos;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;la&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;ls -A&apos;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;ls -CF&apos;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;lla&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;ls -lhAF&apos;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# homebrew&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;bs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;brew services&apos;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# git&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;git&apos;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;gs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;git status&apos;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;gst&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;git stash --include-untracked&apos;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;gsp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;git stash pop&apos;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;gco&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;git checkout&apos;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;gm&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;git checkout master &amp;amp;&amp;amp; git pull&apos;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;gpl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;git pull&apos;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;gps&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;git push&apos;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;gr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;git pull --rebase --autostash origin master&apos;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;gri&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;git rebase --interactive&apos;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;grc&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;git rebase --continue&apos;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;grs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;git rebase --skip&apos;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;gra&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;git rebase --abort&apos;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;g-&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;git checkout -&apos;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# bundler&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;bundle&apos;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;be&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;bundle exec&apos;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;bo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;bundle open&apos;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# yarn&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;yarn&apos;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# rails&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;rails&apos;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;rgc&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;r g controller&apos;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;rgm&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;r g migration&quot;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;rgmo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;r g model&apos;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;rc&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;r console&apos;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;bin/rspec&apos;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;ss&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;spring stop&apos;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;td&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;tail -fn500 log/development.log&apos;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;tt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;tail -fn500 log/test.log&apos;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;rr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;r routes&apos;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;rrg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;r routes -g&apos;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;rrc&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;r routes -c&apos;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;rs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;r restart&apos;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# rake&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;bake&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;bin/rake&apos;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;rdm&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;bake db:migrate&apos;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;rdmr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;bake db:migrate:redo&apos;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;rdc&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;bake db:create&apos;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;rdd&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;bake db:drop&apos;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;rdrs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;bake db:restore&apos;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;rdr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;bake db:rollback&apos;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;rdt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;bake db:test:prepare&apos;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;rds&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;bake db:seed&apos;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;rdb&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;spring stop &amp;amp;&amp;amp; r db:drop &amp;amp;&amp;amp; r db:create &amp;amp;&amp;amp; r db:restore &amp;amp;&amp;amp; r db:migrate &amp;amp;&amp;amp; r db:seed &amp;amp;&amp;amp; r db:test:prepare&apos;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# heroku&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;heroku&apos;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;hl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;h local -e .env&apos;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;hrc&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;h run rails c&apos;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;hrcs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;hrc -r staging&apos;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;hrcp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;hrc -r production&apos;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;hcg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;h config:get&apos;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;hcs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;h config:set&apos;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Jekyll&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;js&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;bundle exec jekyll server&apos;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# postgresql&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;pg_start&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;pg_ctl -D /usr/local/var/postgres -l /usr/local/var/postgres/server.log start&apos;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;pg_stop&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;pg_ctl -D /usr/local/var/postgres stop&apos;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;pg_start_agent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;launchctl load ~/Library/LaunchAgents/homebrew.mxcl.postgresql.plist&apos;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;pg_stop_agent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;launchctl unload ~/Library/LaunchAgents/homebrew.mxcl.postgresql.plist&apos;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;pg_log&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;tail -f /usr/local/var/postgres/server.log&apos;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;pgs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;pg_start&apos;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;pgx&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;pg_stop&apos;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Tinfoil hat aliased - public ip, and exit node ip.&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;ip&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;curl icanhazip.com&apos;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;iplookup&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;echo $(curl -s ipinfo.io/$(curl -s icanhazip.com))&apos;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Lock screen&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;lock&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;/System/Library/CoreServices/Menu\ Extras/User.menu/Contents/Resources/CGSession -suspend&apos;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Get the weather&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;weather&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;curl wttr.in/~Brussels&apos;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Convert an image to webp&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;webp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;convert -quality 50 -define webp:lossless=true&apos;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;appendix-2-git-alias-examples&quot;&gt;Appendix 2: git alias examples&lt;/h2&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;alias&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;c&quot;&gt;# Add&lt;/span&gt;
  ad &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; add
  aa &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; add &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;

  &lt;span class=&quot;c&quot;&gt;# Commit&lt;/span&gt;
  cm &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; commit &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt;
  ca &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; commit &lt;span class=&quot;nt&quot;&gt;--amend&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt;

  &lt;span class=&quot;c&quot;&gt;# Checkout&lt;/span&gt;
  co &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; checkout
  cb &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; checkout &lt;span class=&quot;nt&quot;&gt;-b&lt;/span&gt;

  &lt;span class=&quot;c&quot;&gt;# Cherry-pick&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;cp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; cherry-pick

  &lt;span class=&quot;c&quot;&gt;# Diff&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;df&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; diff

  &lt;span class=&quot;c&quot;&gt;# List&lt;/span&gt;
  tl &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; tag &lt;span class=&quot;nt&quot;&gt;-l&lt;/span&gt;
  bl &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; branch &lt;span class=&quot;nt&quot;&gt;-a&lt;/span&gt;
  rl &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; remote &lt;span class=&quot;nt&quot;&gt;-v&lt;/span&gt;

  &lt;span class=&quot;c&quot;&gt;# Status&lt;/span&gt;
  st &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; status &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt;

  &lt;span class=&quot;c&quot;&gt;# Pull&lt;/span&gt;
  pl   &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; pull
  plo  &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; pull &lt;span class=&quot;nt&quot;&gt;--rebase&lt;/span&gt; origin
  plom &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; pull &lt;span class=&quot;nt&quot;&gt;--rebase&lt;/span&gt; origin master
  plog &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; pull &lt;span class=&quot;nt&quot;&gt;--rebase&lt;/span&gt; origin gh-pages
  plu  &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; pull &lt;span class=&quot;nt&quot;&gt;--rebase&lt;/span&gt; upstream
  plum &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; pull &lt;span class=&quot;nt&quot;&gt;--rebase&lt;/span&gt; upstream master
  plug &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; pull &lt;span class=&quot;nt&quot;&gt;--rebase&lt;/span&gt; upstream gh-pages
  poule &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; pull

  &lt;span class=&quot;c&quot;&gt;# Push&lt;/span&gt;
  ps   &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; push
  pso  &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; push origin
  psom &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; push origin master
  psog &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; push origin gh-pages
  psu  &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; push upstream
  psum &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; push upstream master
  psug &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; push upstream gh-pages

  &lt;span class=&quot;c&quot;&gt;# Logs&lt;/span&gt;
  l  &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; log &lt;span class=&quot;nt&quot;&gt;--pretty&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;oneline &lt;span class=&quot;nt&quot;&gt;--decorate&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--abbrev-commit&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--max-count&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;15
  ll &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; log &lt;span class=&quot;nt&quot;&gt;--graph&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--pretty&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;format:&lt;span class=&quot;s1&quot;&gt;&apos;%Cred%h%Creset %an: %s %Creset%Cgreen(%cr)%Creset&apos;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--abbrev-commit&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--date&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;relative
  lg1 &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; log &lt;span class=&quot;nt&quot;&gt;--graph&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--abbrev-commit&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--decorate&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--format&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;format:&lt;span class=&quot;s1&quot;&gt;&apos;%C(bold blue)%h%C(reset) - %C(bold green)(%ar)%C(reset) %C(white)%s%C(reset) %C(dim white)- %an%C(reset)%C(bold yellow)%d%C(reset)&apos;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--all&lt;/span&gt;
  lg2 &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; log &lt;span class=&quot;nt&quot;&gt;--graph&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--abbrev-commit&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--decorate&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--format&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;format:&lt;span class=&quot;s1&quot;&gt;&apos;%C(bold blue)%h%C(reset) - %C(bold cyan)%aD%C(reset) %C(bold green)(%ar)%C(reset)%C(bold yellow)%d%C(reset)%n&apos;&apos;          %C(white)%s%C(reset) %C(dim white)- %an%C(reset)&apos;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--all&lt;/span&gt;
  lg &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;git lg1&quot;&lt;/span&gt;

  &lt;span class=&quot;c&quot;&gt;# Sync&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;sync&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; plu &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; pso

  &lt;span class=&quot;c&quot;&gt;# Stash-on-a-branch&lt;/span&gt;
  wip &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; commit &lt;span class=&quot;nt&quot;&gt;-a&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;WIP&quot;&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;# FIXME: doesn&apos;t add untracked files&lt;/span&gt;
  pop &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; reset HEAD^
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I use some of these so often that I routinely forget how to type the full commands. ¯\_(ツ)_/¯&lt;/p&gt;
</description>
        <pubDate>Mon, 10 May 2021 00:00:00 +0000</pubDate>
        <link>https://www.mendes-costa.net/posts/shell-aliases</link>
        <guid isPermaLink="true">https://www.mendes-costa.net/posts/shell-aliases</guid>
        
        <category>Code</category>
        
        
        <category>posts</category>
        
      </item>
    
      <item>
        <title>Semantic Hovercards</title>
        <description>&lt;p&gt;Matt Swanson &lt;a href=&quot;https://boringrails.com/articles/hovercards-stimulus/&quot;&gt;wrote an excellent article&lt;/a&gt; showing how to load a Rails view into a hovercard with StimulusJS.&lt;/p&gt;

&lt;p&gt;To which &lt;a href=&quot;https://twitter.com/otagi/status/1336058070644961284&quot;&gt;I replied&lt;/a&gt;: &lt;q&gt;Great Stimulus tutorial. (Except for the horrendous HTML markup.)&lt;/q&gt;&lt;/p&gt;

&lt;p&gt;That was rude and uncalled for. My apologies, Matt. I should have said that I am not a fan of atomic CSS, and personally prefer semantic syntaxes.&lt;/p&gt;

&lt;p&gt;But talk is cheap. So I made a version of his example with alternate HTML and CSS to elaborate on my thoughts.&lt;/p&gt;

&lt;h2 id=&quot;the-html&quot;&gt;The HTML&lt;/h2&gt;

&lt;div class=&quot;language-erb highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;&amp;lt;!-- app/views/shoes/hovercard.html.erb --&amp;gt;&lt;/span&gt;

&lt;span class=&quot;nt&quot;&gt;&amp;lt;aside&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;hovercard&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;data-hovercard-target=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;card&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;article&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;shoe&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@shoe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;p&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@shoe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;brand&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;p&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@shoe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;colorway&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt; • &lt;span class=&quot;cp&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;number_to_currency&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@shoe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;price&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;cp&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;image_tag&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@shoe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;variant&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;resize_to_limit: &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;150&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]),&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;alt: &lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@shoe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/article&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/aside&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;aside&lt;/code&gt; tag felt appropriate, since the hovercard is not part of the main content flow.&lt;/p&gt;

&lt;p&gt;Using a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;class&lt;/code&gt; &lt;em&gt;and&lt;/em&gt; a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;data&lt;/code&gt; attribute might seem redundant at first. I could have used the latter for styling as well. But using both explicitly decouples styling and interaction, which feels cleaner to me.&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;article&lt;/code&gt; tag is ideal for content that makes sense on its own, as a unit. A good candidate for our shoe description.&lt;/p&gt;

&lt;p&gt;Note that both &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hovercard&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;shoe&lt;/code&gt; classes describe &lt;em&gt;what&lt;/em&gt; the element is, not &lt;em&gt;how it looks&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Display this as is in the browser without any style, and it already makes sense, because the content is hierarchically structured with meaningful tags. Show the code to a human, and they understand in a fraction of a second what it’s all about. Give it to someone with bad vision, and their screen reader will have no problem finding the most relevant information to enunciate.&lt;/p&gt;

&lt;h2 id=&quot;the-css&quot;&gt;The CSS&lt;/h2&gt;

&lt;div class=&quot;language-scss highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// app/assets/stylesheets/hovercard.scss&lt;/span&gt;

&lt;span class=&quot;nc&quot;&gt;.hovercard&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;absolute&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;bottom&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;.5em&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1rem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;background&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;#fff&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;border-radius&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;.5rem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;box-shadow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0px&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;5px&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;10px&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;#ccc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;nd&quot;&gt;::after&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot; &quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;absolute&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;top&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;100%&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1rem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;border-style&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;solid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;border-width&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;.5rem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;border-color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;white&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;transparent&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;transparent&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;transparent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The CSS code for the hovercard container takes care of the box positioning and its contour style, including the little bubble triangle at the bottom (the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;::after&lt;/code&gt; part).&lt;/p&gt;

&lt;div class=&quot;language-scss highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// app/assets/stylesheets/shoes.scss&lt;/span&gt;

&lt;span class=&quot;nn&quot;&gt;#shoes&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;relative&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nc&quot;&gt;.hovercard&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;.shoe&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;grid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;grid-gap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1rem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;grid-template-rows&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;auto&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;grid-template-columns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;150px&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1fr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;margin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;nt&quot;&gt;img&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;border-radius&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;.5rem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;grid-column&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;grid-row&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;100%&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;nd&quot;&gt;:not&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;img&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;grid-column&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;nt&quot;&gt;h1&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;grid-row&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;nt&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;nd&quot;&gt;:nth-of-type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;grid-row&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;nt&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;nd&quot;&gt;:nth-of-type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;grid-row&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The CSS for the inside of the card is in a separate file, and specific to the shoe card. This is more convenient if you plan to use different layouts for each type of hovercard. If not, both style sets could be grouped together, of course.&lt;/p&gt;

&lt;p&gt;We are using a grid-based layout here, to easily play with the inner tags placement. Notice how the image is now displayed first on the left, although it’s still last in the HTML. Same with the brand paragraph, visually shown above the shoe name.&lt;/p&gt;

&lt;p&gt;One minor annoyance: the hovercard style itself does not include the required &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;position: relative&lt;/code&gt;, to avoid another wrapper tag just for that. So we have to remember to set that property on the parent tag.&lt;/p&gt;

&lt;h2 id=&quot;the-js&quot;&gt;The JS&lt;/h2&gt;

&lt;p&gt;One last detail: in &lt;em&gt;hovercard_controller.js&lt;/em&gt;, I used the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hidden&lt;/code&gt; HTML attribute instead of a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hidden&lt;/code&gt; class. The element will be ignored by screen readers as well that way (which might or might not be the desired effect, depending on the use case).&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/blog/semantic_hovercard.jpg&quot; alt=&quot;Hovercard screenshot&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The full Rails example app is &lt;a href=&quot;https://github.com/otagi/shoes&quot;&gt;available on GitHub&lt;/a&gt;.&lt;/p&gt;
</description>
        <pubDate>Wed, 09 Dec 2020 00:00:00 +0000</pubDate>
        <link>https://www.mendes-costa.net/posts/semantic-hovercards</link>
        <guid isPermaLink="true">https://www.mendes-costa.net/posts/semantic-hovercards</guid>
        
        <category>Code</category>
        
        
        <category>posts</category>
        
      </item>
    
      <item>
        <title>New theme</title>
        <description>&lt;p&gt;This website has a new, slightly improved stylesheet!&lt;/p&gt;

&lt;h2 id=&quot;experimentations&quot;&gt;Experimentations&lt;/h2&gt;

&lt;p&gt;The previous layout let the text flow through the browser viewport’s whole width. The idea was to get back to the origin of the web, and let readers decide how wide they wanted their text by adjusting the browser window.&lt;/p&gt;

&lt;p&gt;Great idealistic idea in theory. But the result definitely felt unfinished by modern standards.&lt;/p&gt;

&lt;p&gt;So here is a new variation with a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;max-width: 65ch&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In the process, I experimented with two features that ended up being rolled back. Here’s why.&lt;/p&gt;

&lt;h2 id=&quot;alternate-stylesheets&quot;&gt;Alternate stylesheets&lt;/h2&gt;

&lt;p&gt;Wouldn’t it be nice to keep a minimal stylesheet by default, and offer prettier but heavier alternatives for the reader to choose from? Modern browsers support this out of the box, right?&lt;/p&gt;

&lt;p&gt;Well, kind of. There is an &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/Alternative_style_sheets&quot;&gt;HTML specification&lt;/a&gt; for it: just list your default stylesheet with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;link rel=&quot;stylesheet&quot; …&amp;gt;&lt;/code&gt; and the other ones with additional &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;link rel=&quot;alternate stylesheet&quot; …&amp;gt;&lt;/code&gt; tags. Easy.&lt;/p&gt;

&lt;p&gt;Except that the feature is only supported in Firefox, IE, and Opera. And (at least in Firefox) the selection is not sticky: switch to an alternate stylesheet, reload the page, and you’re back to the default stylesheet. Not useful in practice. Ah, and all stylesheets are queried on page load, defeating the initial performance purpose.&lt;/p&gt;

&lt;p&gt;Yes, some Javascript magic could solve that. But I want to keep this site as JS-free as humanely possible.&lt;/p&gt;

&lt;h2 id=&quot;the-jekyll-assets-gem&quot;&gt;The jekyll-assets gem&lt;/h2&gt;

&lt;p&gt;Since I’m used to work on &lt;a href=&quot;https://rubyonrails.org&quot;&gt;Rails&lt;/a&gt; projects, having assets managed by &lt;a href=&quot;https://github.com/rails/sprockets&quot;&gt;Sprockets&lt;/a&gt; for this &lt;a href=&quot;https://jekyllrb.com&quot;&gt;Jekyll&lt;/a&gt; site seemed like a good idea.&lt;/p&gt;

&lt;p&gt;There are a few annoyances and a quasi-show-stopper with this gem: the author is maintaining it alone, and doesn’t have a lot of time to do so. The documentation is a bit confusing in my opinion, and doesn’t document a breaking change (no more &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;asset_path&lt;/code&gt; helper).&lt;/p&gt;

&lt;p&gt;And the show-stopper: the gem is not white-listed by &lt;a href=&quot;https://pages.github.com&quot;&gt;GitHub Pages&lt;/a&gt;. Which means I can no longer push the main branch and have GitHub auto-build the site. The solution would be to pre-build locally, and push that. An additional deployment step that wasn’t worth the trouble in this case.&lt;/p&gt;

&lt;p&gt;So, after a lot of &lt;a href=&quot;https://en.wikipedia.org/wiki/RTFM&quot;&gt;RTFM&lt;/a&gt; and commits, the code is back to a &lt;a href=&quot;https://en.wikipedia.org/wiki/KISS_principle&quot;&gt;KISS&lt;/a&gt; version, which is not so bad after all.&lt;/p&gt;
</description>
        <pubDate>Thu, 10 Sep 2020 00:00:00 +0000</pubDate>
        <link>https://www.mendes-costa.net/posts/new-theme</link>
        <guid isPermaLink="true">https://www.mendes-costa.net/posts/new-theme</guid>
        
        <category>Code</category>
        
        
        <category>posts</category>
        
      </item>
    
  </channel>
</rss>
