<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<title>Sebastian Rollen</title>
	<subtitle>A blog</subtitle>
	<link href="https://rollen.io/atom.xml" rel="self" type="application/atom+xml"/>
  <link href="https://rollen.io"/>
	<generator uri="https://www.getzola.org/">Zola</generator>
	<updated>2026-02-25T00:00:00+00:00</updated>
	<id>https://rollen.io/atom.xml</id>
	<entry xml:lang="en">
		<title>Binding my time: a Heisenbug story</title>
		<published>2026-02-17T00:00:00+00:00</published>
		<updated>2026-02-17T00:00:00+00:00</updated>
		<link href="https://rollen.io/blog/heisenbug/" type="text/html"/>
		<id>https://rollen.io/blog/heisenbug/</id>
		<content type="html">&lt;p&gt;I recently debugged a failing test where the issue itself was trivial,
but the investigation of the bug was surprisingly gnarly because
inspecting the bug using a debugger changed its behavior&lt;sup id=&quot;footnoteref:1&quot;&gt;&lt;a href=&quot;#footnote:1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what&quot;&gt;What?&lt;&#x2F;h2&gt;
&lt;p&gt;I&#x27;ve created a reproduction of the issue below, but the actual class and
methods have been modified, so don&#x27;t get hung up on the exact semantics
of the class. The gist of it is that we have a Rails model with a method
that checks some preconditions, returns early if the preconditions are
met, and otherwise goes on to perform additional logic.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rb&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rb &quot;&gt;&lt;code class=&quot;language-rb&quot; data-lang=&quot;rb&quot;&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# == Schema Information
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;#
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# Table name: orders
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;#
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;#  id                   :bigint           not null, primary key
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;#  canceled_at          :datetime
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;#  delivered_at         :datetime
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;class &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ebcb8b;&quot;&gt;Order &lt;&#x2F;span&gt;&lt;span style=&quot;color:#eff1f5;&quot;&gt;&amp;lt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;ApplicationRecord
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;update_status
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;return if&lt;&#x2F;span&gt;&lt;span&gt; canceled_at.present? || delivered_at.present?
&lt;&#x2F;span&gt;&lt;span&gt;    
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# process rest of order, potentially setting the canceled_at or
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# delivered_at field.
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The failing test indicated that the &lt;code&gt;delivered_at&lt;&#x2F;code&gt; field was not being
updated when we expected that it should be, so I added a debugging
statement inside the method and reran the test.&lt;&#x2F;p&gt;
&lt;p&gt;Nothing. The breakpoint didn&#x27;t trigger and the test was still failing. I
moved the breakpoint to the very top of the method and started walking
through the code, but the method immediately returned from the
precondition check. Normal enough, but when I then reran the test again
to check which of the two preconditions failed, things got &lt;em&gt;really&lt;&#x2F;em&gt;
weird.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rb&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rb &quot;&gt;&lt;code class=&quot;language-rb&quot; data-lang=&quot;rb&quot;&gt;&lt;span&gt;(ruby) canceled_at.present?
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;false
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;(ruby) delivered_at.present?
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;false
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;With some trepidation, I updated the code and ran again:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rb&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rb &quot;&gt;&lt;code class=&quot;language-rb&quot; data-lang=&quot;rb&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;update_status
&lt;&#x2F;span&gt;&lt;span&gt;  should_return = canceled_at.present? || delivered_at.present?
&lt;&#x2F;span&gt;&lt;span&gt;  debugger
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;return if&lt;&#x2F;span&gt;&lt;span&gt; should_return
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# process rest of order
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre data-lang=&quot;rb&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rb &quot;&gt;&lt;code class=&quot;language-rb&quot; data-lang=&quot;rb&quot;&gt;&lt;span&gt;(ruby) canceled_at.present?
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;false
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;(ruby) delivered_at.present?
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;false
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;(ruby) should_return
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;true
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Oh dear.&lt;&#x2F;p&gt;
&lt;p&gt;The chasm opened up. I was staring into the abyss, and the abyss was
staring back at me. What had seemed like a simple investigation into a
failing test now had me questioning my sanity. How could 
&lt;code&gt;(false || false) == true&lt;&#x2F;code&gt;? How do you even debug that?&lt;&#x2F;p&gt;
&lt;p&gt;My mind was spinning.&lt;&#x2F;p&gt;
&lt;p&gt;We must have done something silly and overridden
the &lt;code&gt;||&lt;&#x2F;code&gt; method somewhere in the code… But then how would anything work?
And indeed, &lt;code&gt;||&lt;&#x2F;code&gt; is not even a method that can be overridden, it&#x27;s a
built-in operator.&lt;&#x2F;p&gt;
&lt;p&gt;Okay, so there must be a ruby bug! But in the OR operator? C&#x27;mon… And in
any case, running &lt;code&gt;false || false&lt;&#x2F;code&gt; or even &lt;code&gt;canceled_at.present? || delivered_at.present?&lt;&#x2F;code&gt; returned &lt;code&gt;false&lt;&#x2F;code&gt;, as expected.&lt;&#x2F;p&gt;
&lt;p&gt;While flailing endlessly around for a logical explanation, I was also
instinctively poking around with the debugger, looking for a clue, and
while stepping deeper into the internals of Rails, I found one:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rb&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rb &quot;&gt;&lt;code class=&quot;language-rb&quot; data-lang=&quot;rb&quot;&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;34&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;43&lt;&#x2F;span&gt;&lt;span&gt;] &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;in &lt;&#x2F;span&gt;&lt;span&gt;~&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;.rbenv&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;versions&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;3.3&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;6&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;lib&#x2F;ruby&#x2F;gems&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;3.3&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;gems&#x2F;activerecord-&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;8.1&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;lib&#x2F;active_record&#x2F;attribute_methods&#x2F;read.rb
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;34&lt;&#x2F;span&gt;&lt;span&gt;|       &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;35&lt;&#x2F;span&gt;&lt;span&gt;|
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;36&lt;&#x2F;span&gt;&lt;span&gt;|       &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# This method exists to avoid the expensive primary_key check internally, without
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;37&lt;&#x2F;span&gt;&lt;span&gt;|       &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# breaking compatibility with the read_attribute API
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;38&lt;&#x2F;span&gt;&lt;span&gt;|       &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;_read_attribute&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;attr_name&lt;&#x2F;span&gt;&lt;span&gt;, &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;block&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# :nodoc:
&lt;&#x2F;span&gt;&lt;span&gt;=&amp;gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;39&lt;&#x2F;span&gt;&lt;span&gt;|         @&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;attributes&lt;&#x2F;span&gt;&lt;span&gt;.fetch_value(attr_name, &amp;amp;block)
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;40&lt;&#x2F;span&gt;&lt;span&gt;|       &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;41&lt;&#x2F;span&gt;&lt;span&gt;|
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;42&lt;&#x2F;span&gt;&lt;span&gt;|       &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;alias &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;:attribute :_read_attribute
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;43&lt;&#x2F;span&gt;&lt;span&gt;|       &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;private &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;:attribute
&lt;&#x2F;span&gt;&lt;span&gt;=&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;#0    ActiveRecord::AttributeMethods::Read#_read_attribute(attr_name=&amp;quot;delivered_at&amp;quot;, block=#&amp;lt;Proc:0x0000000127bf13c8 &#x2F;Users&#x2F;rollen&#x2F;....) at ~&#x2F;.rbenv&#x2F;versions&#x2F;3.3.6&#x2F;lib&#x2F;ruby&#x2F;gems&#x2F;3.3.0&#x2F;gems&#x2F;activerecord-8.1.2&#x2F;lib&#x2F;active_record&#x2F;attribute_methods&#x2F;read.rb:39
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;#1    Order::GeneratedAttributeMethods#delivered_at at ~&#x2F;.rbenv&#x2F;versions&#x2F;3.3.6&#x2F;lib&#x2F;ruby&#x2F;gems&#x2F;3.3.0&#x2F;gems&#x2F;activemodel-8.1.2&#x2F;lib&#x2F;active_model&#x2F;attribute_methods.rb:273
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# and 33 frames (use `bt&amp;#39; command for all frames)
&lt;&#x2F;span&gt;&lt;span&gt;(ruby) @&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;attributes&lt;&#x2F;span&gt;&lt;span&gt;.fetch_value(attr_name, &amp;amp;block)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;2026&lt;&#x2F;span&gt;&lt;span&gt;-&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;02&lt;&#x2F;span&gt;&lt;span&gt;-&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;15 01&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;56&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;45.107254000 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;UTC &lt;&#x2F;span&gt;&lt;span&gt;+&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;00&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;00
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;A-ha! So the &lt;code&gt;delivered_at&lt;&#x2F;code&gt; field is not &lt;code&gt;nil&lt;&#x2F;code&gt;, but actually has a set
date-time. This explains why &lt;code&gt;should_return&lt;&#x2F;code&gt; is &lt;code&gt;true&lt;&#x2F;code&gt;, but then why
would &lt;code&gt;delivered_at.present?&lt;&#x2F;code&gt; return &lt;code&gt;false&lt;&#x2F;code&gt;?&lt;&#x2F;p&gt;
&lt;p&gt;Some more poking around in the debugger pointed to an answer:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rb&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rb &quot;&gt;&lt;code class=&quot;language-rb&quot; data-lang=&quot;rb&quot;&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;11&lt;&#x2F;span&gt;&lt;span&gt;] &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;in &lt;&#x2F;span&gt;&lt;span&gt;~&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;src&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;heisenbug&#x2F;app&#x2F;models&#x2F;order.rb
&lt;&#x2F;span&gt;&lt;span&gt;     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;|
&lt;&#x2F;span&gt;&lt;span&gt;     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;3&lt;&#x2F;span&gt;&lt;span&gt;| &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;class &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ebcb8b;&quot;&gt;Order &lt;&#x2F;span&gt;&lt;span style=&quot;color:#eff1f5;&quot;&gt;&amp;lt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;ApplicationRecord
&lt;&#x2F;span&gt;&lt;span&gt;     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;4&lt;&#x2F;span&gt;&lt;span&gt;|   &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;update_status
&lt;&#x2F;span&gt;&lt;span&gt;     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;5&lt;&#x2F;span&gt;&lt;span&gt;|     should_return = canceled_at.present? || delivered_at.present?
&lt;&#x2F;span&gt;&lt;span&gt;     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;6&lt;&#x2F;span&gt;&lt;span&gt;|
&lt;&#x2F;span&gt;&lt;span&gt;=&amp;gt;   &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;7&lt;&#x2F;span&gt;&lt;span&gt;|     debugger
&lt;&#x2F;span&gt;&lt;span&gt;     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;8&lt;&#x2F;span&gt;&lt;span&gt;|
&lt;&#x2F;span&gt;&lt;span&gt;     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;9&lt;&#x2F;span&gt;&lt;span&gt;|     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;return if&lt;&#x2F;span&gt;&lt;span&gt; should_return
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;10&lt;&#x2F;span&gt;&lt;span&gt;|
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;11&lt;&#x2F;span&gt;&lt;span&gt;|     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# do stuff
&lt;&#x2F;span&gt;&lt;span&gt;=&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;#0    Order#update_status at ~&#x2F;src&#x2F;heisenbug&#x2F;app&#x2F;models&#x2F;order.rb:7
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;#1    &amp;lt;main&amp;gt; at (heisenbug):2
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# and 31 frames (use `bt&amp;#39; command for all frames)
&lt;&#x2F;span&gt;&lt;span&gt;(rdbg) info locals    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# command
&lt;&#x2F;span&gt;&lt;span&gt;%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;self &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;#&amp;lt;Order id: 1, canceled_at: nil, delivered_at: &amp;quot;2026-02-15 01:56:45...&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;should_return = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;true
&lt;&#x2F;span&gt;&lt;span&gt;delivered_at = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;nil
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;So the &lt;code&gt;delivered_at&lt;&#x2F;code&gt; column does indeed contain a value, but the &lt;em&gt;local
variable&lt;&#x2F;em&gt; &lt;code&gt;delivered_at&lt;&#x2F;code&gt; is &lt;code&gt;nil&lt;&#x2F;code&gt;. Some more &lt;del&gt;flailing&lt;&#x2F;del&gt; investigation
uncovered the culprit later in the method&lt;sup id=&quot;footnoteref:3&quot;&gt;&lt;a href=&quot;#footnote:3&quot;&gt;3&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rb&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rb &quot;&gt;&lt;code class=&quot;language-rb&quot; data-lang=&quot;rb&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;update_status
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;return if&lt;&#x2F;span&gt;&lt;span&gt; canceled_at.present? || delivered_at.present?
&lt;&#x2F;span&gt;&lt;span&gt;    
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# …
&lt;&#x2F;span&gt;&lt;span&gt;    delivered_at = schema.delivered_at
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt; delivered_at &amp;lt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;5&lt;&#x2F;span&gt;&lt;span&gt;.minutes_ago
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# …
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span&gt;    update_columns(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;delivered_at:&lt;&#x2F;span&gt;&lt;span&gt; delivered_at)
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# …
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;New theory: the local variable that we define later in the method must
somehow be hoisted up by the debugger to the interactive scope and
shadowing the method call even before the actual assignment to
&lt;code&gt;delivered_at&lt;&#x2F;code&gt; had run. Testing the theory, I renamed the &lt;code&gt;delivered_at&lt;&#x2F;code&gt;
local variable and re-ran the debugger:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rb&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rb &quot;&gt;&lt;code class=&quot;language-rb&quot; data-lang=&quot;rb&quot;&gt;&lt;span&gt;(ruby) delivered_at
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;2026&lt;&#x2F;span&gt;&lt;span&gt;-&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;02&lt;&#x2F;span&gt;&lt;span&gt;-&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;15 01&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;56&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;45.107254000 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;UTC &lt;&#x2F;span&gt;&lt;span&gt;+&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;00&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;00
&lt;&#x2F;span&gt;&lt;span&gt;(ruby) canceled_at.present? || delivered_at.present?
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;true
&lt;&#x2F;span&gt;&lt;span&gt;(ruby) should_return
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;true
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Success! The code behaved exactly as intended, and I was now quickly
able to fix the behavior leading to the broken test. But, of course, the
story doesn&#x27;t stop there; I desperately needed to know&lt;&#x2F;p&gt;
&lt;h2 id=&quot;why&quot;&gt;WHY??&lt;&#x2F;h2&gt;
&lt;p&gt;Though confusing, it&#x27;s important to note that the behavior I ran into
here is not a bug or even unintended behavior in the ruby debugger.
Indeed, though not explicitly called out, this behavior is exemplified
in the &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ruby&#x2F;debug&#x2F;blob&#x2F;bad4d38f8330219b62f2b253d59146f5a71fd39a&#x2F;README.md&quot;&gt;README of the debug repository&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rb&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rb &quot;&gt;&lt;code class=&quot;language-rb&quot; data-lang=&quot;rb&quot;&gt;&lt;span&gt;$ cat target.rb                        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# Sample program
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;require &lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;debug&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;a = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1
&lt;&#x2F;span&gt;&lt;span&gt;b = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;2
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;binding&lt;&#x2F;span&gt;&lt;span&gt;.break                          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# Program will stop here
&lt;&#x2F;span&gt;&lt;span&gt;c = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;3
&lt;&#x2F;span&gt;&lt;span&gt;d = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;4
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;binding&lt;&#x2F;span&gt;&lt;span&gt;.break                          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# Program will stop here
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;p &lt;&#x2F;span&gt;&lt;span&gt;[a, b, c, d]
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;$ ruby target.rb                       &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# Run the program normally.
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;DEBUGGER: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Session&lt;&#x2F;span&gt;&lt;span&gt; start (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;pid: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;7604&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;10&lt;&#x2F;span&gt;&lt;span&gt;] &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;in&lt;&#x2F;span&gt;&lt;span&gt; target.rb
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;| &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;require &lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;debug&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;|
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;3&lt;&#x2F;span&gt;&lt;span&gt;| a = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;4&lt;&#x2F;span&gt;&lt;span&gt;| b = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;2
&lt;&#x2F;span&gt;&lt;span&gt;=&amp;gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;5&lt;&#x2F;span&gt;&lt;span&gt;| &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;binding&lt;&#x2F;span&gt;&lt;span&gt;.break                 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# Now you can see it stops at this line
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;6&lt;&#x2F;span&gt;&lt;span&gt;| c = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;3
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;7&lt;&#x2F;span&gt;&lt;span&gt;| d = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;4
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;8&lt;&#x2F;span&gt;&lt;span&gt;| &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;binding&lt;&#x2F;span&gt;&lt;span&gt;.break
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;9&lt;&#x2F;span&gt;&lt;span&gt;| &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;p &lt;&#x2F;span&gt;&lt;span&gt;[a, b, c, d]
&lt;&#x2F;span&gt;&lt;span&gt;     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;10&lt;&#x2F;span&gt;&lt;span&gt;|
&lt;&#x2F;span&gt;&lt;span&gt;=&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;#0    &amp;lt;main&amp;gt; at target.rb:5
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;(rdbg) info locals                     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# You can show local variables
&lt;&#x2F;span&gt;&lt;span&gt;=&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;#0    &amp;lt;main&amp;gt; at target.rb:5
&lt;&#x2F;span&gt;&lt;span&gt;%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;self &lt;&#x2F;span&gt;&lt;span&gt;=&amp;gt; main
&lt;&#x2F;span&gt;&lt;span&gt;a =&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1
&lt;&#x2F;span&gt;&lt;span&gt;b =&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;2
&lt;&#x2F;span&gt;&lt;span&gt;c =&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;nil
&lt;&#x2F;span&gt;&lt;span&gt;d =&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;nil
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Notice that even though the execution has stopped on line 5, &lt;code&gt;c&lt;&#x2F;code&gt; and &lt;code&gt;d&lt;&#x2F;code&gt;
are still initialized with value &lt;code&gt;nil&lt;&#x2F;code&gt;. Dig deeper through the debugger
code, and you&#x27;ll find that this behavior comes from
&lt;a href=&quot;https:&#x2F;&#x2F;docs.ruby-lang.org&#x2F;en&#x2F;master&#x2F;Kernel.html#method-i-binding&quot;&gt;&lt;code&gt;Kernel#binding&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;,
a method that extracts all local variables and other information from
the current scope into an instance of the &lt;code&gt;Binding&lt;&#x2F;code&gt; class. Even more
powerfully, a &lt;a href=&quot;https:&#x2F;&#x2F;docs.ruby-lang.org&#x2F;en&#x2F;master&#x2F;Binding.html&quot;&gt;&lt;code&gt;Binding&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;
can be passed to &lt;code&gt;eval&lt;&#x2F;code&gt; to evaluate arbitrary code within the context of
that binding:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rb&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rb &quot;&gt;&lt;code class=&quot;language-rb&quot; data-lang=&quot;rb&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;class &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ebcb8b;&quot;&gt;User
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#eff1f5;&quot;&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;initialize&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;position&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;    @&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;name &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;name
&lt;&#x2F;span&gt;&lt;span&gt;    @&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;position &lt;&#x2F;span&gt;&lt;span&gt;= position
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;get_binding
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;binding
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;user = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ebcb8b;&quot;&gt;User&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;new&lt;&#x2F;span&gt;&lt;span&gt;(&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Joan&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;, &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;manager&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;)
&lt;&#x2F;span&gt;&lt;span&gt;template = &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;{name: @name, position: @position}&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# evaluate template in context of the object
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;eval&lt;&#x2F;span&gt;&lt;span&gt;(template, user.get_binding)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;#=&amp;gt; {:name=&amp;gt;&amp;quot;Joan&amp;quot;, :position=&amp;gt;&amp;quot;manager&amp;quot;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This is of course extremely powerful behavior for building a debugger.
You can even build a very simple debugger that lets users evaluate code
at any point in the program by sending the binding to
&lt;code&gt;irb&lt;&#x2F;code&gt;&lt;sup id=&quot;footnoteref:4&quot;&gt;&lt;a href=&quot;#footnote:4&quot;&gt;4&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rb&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rb &quot;&gt;&lt;code class=&quot;language-rb&quot; data-lang=&quot;rb&quot;&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;require &lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;irb&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;custom_debugger&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;context&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ebcb8b;&quot;&gt;IRB&lt;&#x2F;span&gt;&lt;span&gt;.setup(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;nil&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;    workspace = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ebcb8b;&quot;&gt;IRB&lt;&#x2F;span&gt;&lt;span&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ebcb8b;&quot;&gt;WorkSpace&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;new&lt;&#x2F;span&gt;&lt;span&gt;(context)
&lt;&#x2F;span&gt;&lt;span&gt;    irb = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ebcb8b;&quot;&gt;IRB&lt;&#x2F;span&gt;&lt;span&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ebcb8b;&quot;&gt;Irb&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;new&lt;&#x2F;span&gt;&lt;span&gt;(workspace)
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ebcb8b;&quot;&gt;IRB&lt;&#x2F;span&gt;&lt;span&gt;.conf[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;:MAIN_CONTEXT&lt;&#x2F;span&gt;&lt;span&gt;] = irb.context
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;catch&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;:IRB_EXIT&lt;&#x2F;span&gt;&lt;span&gt;) { irb.eval_input }
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;method_with_bug
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;name &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;My name&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;raise &lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;error!&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;rescue
&lt;&#x2F;span&gt;&lt;span&gt;    custom_debugger(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;binding&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;method_with_bug
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Throw that code into &lt;code&gt;debug.rb&lt;&#x2F;code&gt; and run it, and you&#x27;ll be placed in an
irb session with the context from &lt;em&gt;inside&lt;&#x2F;em&gt; the &lt;code&gt;method_with_bug&lt;&#x2F;code&gt; method:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rb&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rb &quot;&gt;&lt;code class=&quot;language-rb&quot; data-lang=&quot;rb&quot;&gt;&lt;span&gt;❯ ruby debug.rb
&lt;&#x2F;span&gt;&lt;span&gt;irb(main):&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;001&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;name
&lt;&#x2F;span&gt;&lt;span&gt;=&amp;gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;My name&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This only moves the question one step deeper: why does &lt;code&gt;binding&lt;&#x2F;code&gt; capture
local variables that haven&#x27;t been defined yet?&lt;&#x2F;p&gt;
&lt;p&gt;Unlike some other languages, ruby doesn&#x27;t require local variables to be
initialized before they can be assigned. Ruby also doesn&#x27;t require
parentheses to call methods, meaning that the identifier &lt;code&gt;foo&lt;&#x2F;code&gt; can
either be a reference to a local variable or a method call. If the Ruby
runtime had to make that determination every time it encountered an
identifier, performance would be much slower, so Ruby instead creates
all local variables in a scope when parsed, not when assigned. The &lt;a href=&quot;https:&#x2F;&#x2F;docs.ruby-lang.org&#x2F;en&#x2F;master&#x2F;syntax&#x2F;assignment_rdoc.html#local-variables-and-methods&quot;&gt;Ruby
documentation&lt;&#x2F;a&gt;
provides another example making this behavior clear:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rb&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rb &quot;&gt;&lt;code class=&quot;language-rb&quot; data-lang=&quot;rb&quot;&gt;&lt;span&gt;a = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;false &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# does not assign to a
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;p local_variables &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# prints [:a]
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;p&lt;&#x2F;span&gt;&lt;span&gt; a &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# prints nil
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;So there&#x27;s the full story: the &lt;code&gt;delivered_at&lt;&#x2F;code&gt; attribute was shadowed by
the &lt;code&gt;delivered_at&lt;&#x2F;code&gt; local variable in our debugging scope, because
&lt;code&gt;binding&lt;&#x2F;code&gt; (which is used by &lt;code&gt;ruby&#x2F;debug&lt;&#x2F;code&gt; to enable powerful debugging)
captures all local variables, even those that haven&#x27;t been assigned yet.
This capture happens at parse time, not runtime, for performance
reasons.&lt;&#x2F;p&gt;
&lt;p&gt;And the moral of the story is: don&#x27;t shadow your variables, kids.&lt;&#x2F;p&gt;
&lt;p id=&quot;footnote:1&quot;&gt;[1]&amp;nbsp;This class of bug is called a
&lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Heisenbug&quot;&gt;Heisenbug&lt;&#x2F;a&gt;, after the
Heisenberg Uncertainty Principle&lt;sup id=&quot;footnoteref:2&quot;&gt;&lt;a href=&quot;#footnote:2&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;, in which observing a particular aspect
of a (quantum) system invariably alters its state.&amp;nbsp;&lt;small&gt;&lt;a href=&quot;#footnoteref:1&quot;&gt;&amp;#8617;&amp;#65038;&lt;&#x2F;a&gt;&lt;&#x2F;small&gt;&lt;&#x2F;p&gt;
&lt;p id=&quot;footnote:2&quot;&gt;[2]&amp;nbsp;More accurately the &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Observer_effect_(physics)&quot;&gt;Observer
Effect&lt;&#x2F;a&gt;, which
is often conflated with the Heisenberg principle. The latter states that
the product of the standard deviations of position and momentum has a
lower bound, so if you try to reduce your uncertainty of one of the two,
your uncertainty of the other will increase to compensate.&lt;&#x2F;p&gt;
&lt;p&gt;This sounds (and is!) mysterious, but my favorite way of conceptualizing
it is to instead think of position&#x2F;wave-length uncertainty, where the
behavior is much more clear. If you think of the first extreme, an
infinitely repeating periodic wave, it&#x27;s very easy to calculate its
wavelength, but what is its position, if it extends to infinity? And at
the other extreme, if you think of squishing the wave down to a single
point, it&#x27;s very easy to locate it in space, but what is its wavelength?&lt;&#x2F;p&gt;
&lt;p&gt;And yes, this is a footnote to a footnote, and a physics digression in a
coding article, but it&#x27;s my blog and I do what I want, damn it! Now
where was I?&amp;nbsp;&lt;small&gt;&lt;a href=&quot;#footnoteref:2&quot;&gt;&amp;#8617;&amp;#65038;&lt;&#x2F;a&gt;&lt;&#x2F;small&gt;&lt;&#x2F;p&gt;
&lt;p id=&quot;footnote:3&quot;&gt;[3]&amp;nbsp;Sorry for burying the lede if you were reading this as an exercise and
trying to guess the answer! In my defense, while shadowing an attribute
with a local variable seemed perhaps slightly odious, I never expected
that it would lead to this level of confusion while debugging.&amp;nbsp;&lt;small&gt;&lt;a href=&quot;#footnoteref:3&quot;&gt;&amp;#8617;&amp;#65038;&lt;&#x2F;a&gt;&lt;&#x2F;small&gt;&lt;&#x2F;p&gt;
&lt;p id=&quot;footnote:4&quot;&gt;[4]&amp;nbsp;Code taken from this &lt;a href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=V1fjk1C5C60&quot;&gt;great
video&lt;&#x2F;a&gt; by @CarlosPohloddev&amp;nbsp;&lt;small&gt;&lt;a href=&quot;#footnoteref:4&quot;&gt;&amp;#8617;&amp;#65038;&lt;&#x2F;a&gt;&lt;&#x2F;small&gt;&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Rendering markdown views in Rails</title>
		<published>2023-01-30T00:00:00+00:00</published>
		<updated>2026-02-25T00:00:00+00:00</updated>
		<link href="https://rollen.io/blog/markdown-rails/" type="text/html"/>
		<id>https://rollen.io/blog/markdown-rails/</id>
		<content type="html">&lt;p&gt;Rails is a fantastic tool for building web applications, with a large set of conventions and &amp;quot;batteries-included&amp;quot; libraries guiding the development. One area where Rails does not have great support though is for hosting static Markdown pages along with the rest of the application. Luckily, it&#x27;s easy to hook into Rails&#x27; rendering flow to build out the functionality ourselves.&lt;&#x2F;p&gt;
&lt;p&gt;If you want to try this at home, here&#x27;s a &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;SebRollen&#x2F;rails-markdown-example&quot;&gt;GitHub link&lt;&#x2F;a&gt; to a demo application that follows the blog post below. Each commit corresponds to a section in the post.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;why&quot;&gt;Why?&lt;&#x2F;h2&gt;
&lt;p&gt;There&#x27;s many great ways to create and host static pages. This page is generated using &lt;a href=&quot;https:&#x2F;&#x2F;www.getzola.org&#x2F;&quot;&gt;zola&lt;&#x2F;a&gt;, and hosted from an S3 bucket, with AWS cloudfront in front as a CDN. This setup is extremely easy to manage, and cheap. Costs are usually below $2 &#x2F; month, and deployment is as simple as pushing to a git repo that synchronizes with the S3 bucket through a simple &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;SebRollen&#x2F;rollen.io&#x2F;blob&#x2F;main&#x2F;.github&#x2F;workflows&#x2F;main.yml&quot;&gt;GitHub action&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Even so, I recently found myself wanting to host some static pages in my Rails application. For my startup, RoQR, I wanted to move my documentation from the &lt;code&gt;docs.roqr.app&lt;&#x2F;code&gt; subdomain to the &lt;code&gt;roqr.app&lt;&#x2F;code&gt; domain&lt;sup id=&quot;footnoteref:1&quot;&gt;&lt;a href=&quot;#footnote:1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;. I host my Rails app at the latter, and though I might do some routing magic to forward from one domain to the other, I would much prefer deploying the full stack as a monolith, documentation included. &lt;&#x2F;p&gt;
&lt;p&gt;Another reason to host your static pages along with your Rails application is so that you can simplify sharing state between the two. For example, I would like to have a button on my documentation pages that links to a login page if the user is not signed in, but to the web app if the user &lt;em&gt;is&lt;&#x2F;em&gt; signed in. That&#x27;s much easier to do if Rails handles both the static pages and the app.&lt;&#x2F;p&gt;
&lt;p&gt;What I did &lt;em&gt;not&lt;&#x2F;em&gt; want to do is have to code my static pages using HTML, and so I set out to build out a solution to render my static pages from markdown files, using Rails. Here&#x27;s how you can do the same.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;minimum-viable-markdown-renderer&quot;&gt;Minimum viable markdown renderer&lt;&#x2F;h2&gt;
&lt;p&gt;Let&#x27;s start by getting a simple markdown file rendered and displayed in Rails. If you want to follow along, generate a new Rails&lt;sup id=&quot;footnoteref:2&quot;&gt;&lt;a href=&quot;#footnote:2&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; project:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rails&lt;&#x2F;span&gt;&lt;span&gt; new rails-markdown-example&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; --css&lt;&#x2F;span&gt;&lt;span&gt;=tailwind
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;cd&lt;&#x2F;span&gt;&lt;span&gt; rails-markdown-example
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;To render markdown files, we&#x27;re going to need a gem to convert the markdown into HTML. You have a few choices here, but I&#x27;m going to go with &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vmg&#x2F;redcarpet&quot;&gt;redcarpet&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;bundle&lt;&#x2F;span&gt;&lt;span&gt; add redcarpet
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now for the magic part: we hook into Rails&#x27; template handler system to register a handler for markdown files, and process those files with redcarpet:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rb&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rb &quot;&gt;&lt;code class=&quot;language-rb&quot; data-lang=&quot;rb&quot;&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# config&#x2F;initializers&#x2F;markdown.rb
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# We define a module that can parse markdown to HTML with its `call` method
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;module &lt;&#x2F;span&gt;&lt;span&gt;MarkdownHandler
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;erb
&lt;&#x2F;span&gt;&lt;span&gt;    @&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;erb &lt;&#x2F;span&gt;&lt;span&gt;||= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ebcb8b;&quot;&gt;ActionView&lt;&#x2F;span&gt;&lt;span&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ebcb8b;&quot;&gt;Template&lt;&#x2F;span&gt;&lt;span&gt;.registered_template_handler(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;:erb&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;call&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;template&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;source&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;    compiled_source = erb.call(template, source)
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Redcarpet::Markdown.new(Redcarpet::Render::HTML.new).render(begin;&lt;&#x2F;span&gt;&lt;span&gt;#{compiled_source}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;;end).html_safe&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# Now we tell Rails to process any files with the `.md` extension using our new MarkdownHandler
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ebcb8b;&quot;&gt;ActionView&lt;&#x2F;span&gt;&lt;span&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ebcb8b;&quot;&gt;Template&lt;&#x2F;span&gt;&lt;span&gt;.register_template_handler &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;:md&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;MarkdownHandler
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We&#x27;ll test it out by defining a simple controller and route:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rb&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rb &quot;&gt;&lt;code class=&quot;language-rb&quot; data-lang=&quot;rb&quot;&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# config&#x2F;routes.rb
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ebcb8b;&quot;&gt;Rails&lt;&#x2F;span&gt;&lt;span&gt;.application.routes.draw &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;do
&lt;&#x2F;span&gt;&lt;span&gt;  root &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;pages#index&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre data-lang=&quot;rb&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rb &quot;&gt;&lt;code class=&quot;language-rb&quot; data-lang=&quot;rb&quot;&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# app&#x2F;controllers&#x2F;pages_controller.rb
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;class &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ebcb8b;&quot;&gt;PagesController &lt;&#x2F;span&gt;&lt;span style=&quot;color:#eff1f5;&quot;&gt;&amp;lt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;ApplicationController
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;index&lt;&#x2F;span&gt;&lt;span&gt;; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Finally, let&#x27;s create our markdown file to render. Note that the extension is &lt;code&gt;.html.md&lt;&#x2F;code&gt;, not the usual &lt;code&gt;.html.erb&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;md&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-md &quot;&gt;&lt;code class=&quot;language-md&quot; data-lang=&quot;md&quot;&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&amp;lt;!-- # app&#x2F;views&#x2F;pages&#x2F;index.html.md --&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;# Test
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;- This
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;- is 
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;- a
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;- list
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Start your rails server using &lt;code&gt;.&#x2F;bin&#x2F;dev&lt;&#x2F;code&gt;&lt;sup id=&quot;footnoteref:3&quot;&gt;&lt;a href=&quot;#footnote:3&quot;&gt;3&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;, and navigate to &lt;code&gt;localhost:3000&lt;&#x2F;code&gt;. Success! The markdown file is rendered in our browser:&lt;&#x2F;p&gt;
&lt;figure&gt;

&lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;rollen.io&amp;#x2F;processed_images&amp;#x2F;cd381bceb8cb6a6500.png&quot; &#x2F;&gt;

&lt;figcaption align=&quot;center&quot;&gt;&lt;b&gt;Markdown file being rendered&lt;&#x2F;b&gt;&lt;&#x2F;figcaption&gt;
&lt;&#x2F;figure&gt;
&lt;p&gt;It doesn&#x27;t look very good though. This is because we&#x27;re using &lt;a href=&quot;https:&#x2F;&#x2F;tailwindcss.com&#x2F;&quot;&gt;tailwind&lt;&#x2F;a&gt; to style our page, but we haven&#x27;t defined any styles yet. Tailwind resets all styles using its &lt;a href=&quot;https:&#x2F;&#x2F;tailwindcss.com&#x2F;docs&#x2F;preflight&quot;&gt;preflight&lt;&#x2F;a&gt; plugin by default, so our page is looking very plain.&lt;&#x2F;p&gt;
&lt;p&gt;We could define custom styles for our page, but tailwind also comes with a &lt;a href=&quot;https:&#x2F;&#x2F;tailwindcss.com&#x2F;docs&#x2F;typography-plugin&quot;&gt;typography&lt;&#x2F;a&gt; plugin with a set of &lt;code&gt;prose&lt;&#x2F;code&gt; classes that define good looking typographic defaults. Let&#x27;s format our markdown using that plugin:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;diff&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-diff &quot;&gt;&lt;code class=&quot;language-diff&quot; data-lang=&quot;diff&quot;&gt;&lt;span&gt;# app&#x2F;views&#x2F;layouts&#x2F;application.html.erb
&lt;&#x2F;span&gt;&lt;span&gt;...
&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;main class=&amp;quot;container mx-auto mt-28 px-5 flex&amp;quot;&amp;gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;- &amp;lt;%= yield %&amp;gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;+  &amp;lt;article class=&amp;quot;prose&amp;quot;&amp;gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;+    &amp;lt;%= yield %&amp;gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;+  &amp;lt;&#x2F;article&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&#x2F;main&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;...
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;figure&gt;

&lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;rollen.io&amp;#x2F;processed_images&amp;#x2F;6306398f9e47467e00.png&quot; &#x2F;&gt;

&lt;figcaption align = &quot;center&quot;&gt;&lt;b&gt;Nicer formatting using `prose`&lt;&#x2F;b&gt;&lt;&#x2F;figcaption&gt;
&lt;&#x2F;figure&gt;
&lt;p&gt;That&#x27;s much nicer.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;SebRollen&#x2F;rails-markdown-example&#x2F;tree&#x2F;24287eb582204061d8a791e8a4764637335e2f83&quot;&gt;Explore the code at this point&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;using-highvoltage-for-routing&quot;&gt;Using HighVoltage for routing&lt;&#x2F;h2&gt;
&lt;p&gt;In the previous section, we defined the PagesController and an index route to register our markdown file at the root path. However, if we&#x27;re planning on adding a lot of static files, we would quickly get overwhelmed by the amount of routes and controller actions we&#x27;d have to create.&lt;&#x2F;p&gt;
&lt;p&gt;Fortunately, there&#x27;s another gem we can use that is designed to solve this specific issue: &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;thoughtbot&#x2F;high_voltage&quot;&gt;high_voltage&lt;&#x2F;a&gt;. Lets refactor our app to use it:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;bundle&lt;&#x2F;span&gt;&lt;span&gt; add high_voltage
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rm&lt;&#x2F;span&gt;&lt;span&gt; app&#x2F;controllers&#x2F;pages_controller.rb
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre data-lang=&quot;rb&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rb &quot;&gt;&lt;code class=&quot;language-rb&quot; data-lang=&quot;rb&quot;&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# config&#x2F;initializers&#x2F;high_voltage.rb
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ebcb8b;&quot;&gt;HighVoltage&lt;&#x2F;span&gt;&lt;span&gt;.configure &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;do &lt;&#x2F;span&gt;&lt;span&gt;|&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;config&lt;&#x2F;span&gt;&lt;span&gt;|
&lt;&#x2F;span&gt;&lt;span&gt;  config.home_page = &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;index&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre data-lang=&quot;diff&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-diff &quot;&gt;&lt;code class=&quot;language-diff&quot; data-lang=&quot;diff&quot;&gt;&lt;span&gt;# config&#x2F;routes.rb
&lt;&#x2F;span&gt;&lt;span&gt;Rails.application.routes.draw do
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;- root &amp;#39;pages#index
&lt;&#x2F;span&gt;&lt;span&gt;end
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Let&#x27;s restart out Rails server and verify that everything still works by navigating to &lt;code&gt;localhost:3000&lt;&#x2F;code&gt; again. It works.&lt;&#x2F;p&gt;
&lt;p&gt;Now, lets create one more markdown route to see how high_voltage deals with multiple files.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;md&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-md &quot;&gt;&lt;code class=&quot;language-md&quot; data-lang=&quot;md&quot;&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&amp;lt;!-- app&#x2F;views&#x2F;pages&#x2F;blog&#x2F;new_post.html.md --&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;# New blog post
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;small&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;Author: Seb&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;small&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;This is some blog text
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Let&#x27;s also link to the blog post from our home page:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;diff&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-diff &quot;&gt;&lt;code class=&quot;language-diff&quot; data-lang=&quot;diff&quot;&gt;&lt;span&gt;# app&#x2F;views&#x2F;pages&#x2F;index.html.md
&lt;&#x2F;span&gt;&lt;span&gt;...
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;+ ## Blog
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;+ [Blog post](&amp;lt;%= page_path(&amp;#39;blog&#x2F;new_post&amp;#39;) %&amp;gt;)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;figure&gt;

&lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;rollen.io&amp;#x2F;processed_images&amp;#x2F;a1ab2409986a2e3e00.png&quot; &#x2F;&gt;

&lt;figcaption align=&quot;center&quot;&gt;&lt;b&gt;Index&lt;&#x2F;b&gt;&lt;&#x2F;figcaption&gt;
&lt;&#x2F;figure&gt;
&lt;figure&gt;

&lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;rollen.io&amp;#x2F;processed_images&amp;#x2F;57f7fac49c35211f00.png&quot; &#x2F;&gt;

&lt;figcaption align=&quot;center&quot;&gt;&lt;b&gt;Blog post&lt;&#x2F;b&gt;&lt;&#x2F;figcaption&gt;
&lt;&#x2F;figure&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;SebRollen&#x2F;rails-markdown-example&#x2F;tree&#x2F;245e827d283456b3203becb64e43870c45050d35&quot;&gt;Explore the code at this point&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;customize-the-route&quot;&gt;Customize the route&lt;&#x2F;h2&gt;
&lt;p&gt;Our page is looking nice, but I&#x27;m not a big fan of the generated path for our blog-post: &lt;code&gt;pages&#x2F;blog&#x2F;new_post&lt;&#x2F;code&gt;. There&#x27;s two issues with it:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;The content is hosted under &lt;code&gt;&#x2F;pages&lt;&#x2F;code&gt;, but for this example, I would rather it be under &lt;code&gt;&#x2F;docs&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;The underscores in &lt;code&gt;new_post&lt;&#x2F;code&gt; are a bit of an eye-sore for a URL. &lt;code&gt;new-post&lt;&#x2F;code&gt; would be much nicer.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Let&#x27;s tackle #1 first. We&#x27;ll disable high_voltage&#x27;s automatic routing and replace it with our own.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;diff&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-diff &quot;&gt;&lt;code class=&quot;language-diff&quot; data-lang=&quot;diff&quot;&gt;&lt;span&gt;# config&#x2F;initializers&#x2F;high_voltage.rb
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;HighVoltage.configure do |config|
&lt;&#x2F;span&gt;&lt;span&gt;  config.home_page = &amp;#39;index&amp;#39;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;+ config.routes = false
&lt;&#x2F;span&gt;&lt;span&gt;end
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre data-lang=&quot;diff&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-diff &quot;&gt;&lt;code class=&quot;language-diff&quot; data-lang=&quot;diff&quot;&gt;&lt;span&gt;# config&#x2F;routes.rb
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;Rails.application.routes.draw do
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;+ get &amp;#39;&#x2F;docs&#x2F;*id&amp;#39; =&amp;gt; &amp;#39;pages#show&amp;#39;, :as =&amp;gt; :page, format =&amp;gt; false
&lt;&#x2F;span&gt;&lt;span&gt;end
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Easy as that. To tackle #2, we&#x27;re going to have to bring back PagesController: &lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rb&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rb &quot;&gt;&lt;code class=&quot;language-rb&quot; data-lang=&quot;rb&quot;&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# app&#x2F;controllers&#x2F;pages_controller.rb
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;class &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ebcb8b;&quot;&gt;PagesController &lt;&#x2F;span&gt;&lt;span style=&quot;color:#eff1f5;&quot;&gt;&amp;lt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;ApplicationController
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;include &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ebcb8b;&quot;&gt;HighVoltage&lt;&#x2F;span&gt;&lt;span&gt;::StaticPage
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;private
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;page_finder_factory
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;PageFinder
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Instead of relying on high_voltage&#x27;s default page finder, we&#x27;re going to provide our own:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rb&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rb &quot;&gt;&lt;code class=&quot;language-rb&quot; data-lang=&quot;rb&quot;&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# app&#x2F;models&#x2F;page_finder.rb
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;class &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ebcb8b;&quot;&gt;PageFinder &lt;&#x2F;span&gt;&lt;span style=&quot;color:#eff1f5;&quot;&gt;&amp;lt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;HighVoltage::PageFinder
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;find
&lt;&#x2F;span&gt;&lt;span&gt;    paths = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;super&lt;&#x2F;span&gt;&lt;span&gt;.split(&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;)
&lt;&#x2F;span&gt;&lt;span&gt;    directory = paths[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;..-&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;span&gt;    filename = paths[-&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;].tr(&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;-&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;, &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;_&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ebcb8b;&quot;&gt;File&lt;&#x2F;span&gt;&lt;span&gt;.join(*directory, filename)
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This finder just takes the path and replaces any underscores with hyphens in the final URL segment.&lt;&#x2F;p&gt;
&lt;p&gt;Now both issues are fixed!&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;SebRollen&#x2F;rails-markdown-example&#x2F;tree&#x2F;523542495200fc9b34d063cff514bda7987b328b&quot;&gt;Explore the code at this point&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;change-layout-based-on-the-url-path&quot;&gt;Change layout based on the URL path&lt;&#x2F;h2&gt;
&lt;p&gt;Our URL is looking good, but how about our blog page? What if we want the blog page to have a different layout from the rest of the pages?&lt;&#x2F;p&gt;
&lt;p&gt;We can define a custom layout in the pages controller based on our path:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;diff&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-diff &quot;&gt;&lt;code class=&quot;language-diff&quot; data-lang=&quot;diff&quot;&gt;&lt;span&gt;# app&#x2F;controllers&#x2F;pages_controller.rb
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;class PagesController &amp;lt; ApplicationController
&lt;&#x2F;span&gt;&lt;span&gt;  include HighVoltage::StaticPage
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;+ layout :layout_for_page
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  private
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;+ def resource
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;+   params[:id].split(&amp;#39;&#x2F;&amp;#39;).first
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;+ end
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;+
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;+ def layout_for_page
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;+   case resource
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;+   when &amp;#39;blog&amp;#39;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;+     &amp;#39;pages&#x2F;blog_post&amp;#39;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;+   else
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;+     &amp;#39;application&amp;#39;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;+   end
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;+ end
&lt;&#x2F;span&gt;&lt;span&gt;...
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In words, any page under the path &lt;code&gt;&#x2F;docs&#x2F;blog&#x2F;&lt;&#x2F;code&gt; is going to be rendered using the &lt;code&gt;pages&#x2F;blog_post&lt;&#x2F;code&gt; layout, and all other pages will use that standard &lt;code&gt;application&lt;&#x2F;code&gt; layout.&lt;&#x2F;p&gt;
&lt;p&gt;Let&#x27;s define our new layout. Specifically, I want this layout to render the page in dark-mode:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;html&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-html &quot;&gt;&lt;code class=&quot;language-html&quot; data-lang=&quot;html&quot;&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&amp;lt;!-- app&#x2F;views&#x2F;layouts&#x2F;pages&#x2F;blog_post.html.erb --&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;!&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;DOCTYPE &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;html&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;html&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;head&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;title&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;RailsMarkdownExample&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;title&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;meta &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;viewport&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;content&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;width=device-width,initial-scale=1&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;lt;%= csrf_meta_tags %&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;lt;%= csp_meta_tag %&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;lt;%= stylesheet_link_tag &amp;quot;tailwind&amp;quot;, &amp;quot;inter-font&amp;quot;, &amp;quot;data-turbo-track&amp;quot;: &amp;quot;reload&amp;quot; %&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;lt;%= stylesheet_link_tag &amp;quot;application&amp;quot;, &amp;quot;data-turbo-track&amp;quot;: &amp;quot;reload&amp;quot; %&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;lt;%= javascript_importmap_tags %&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;head&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;body &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;class&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;bg-gray-900&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;main &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;class&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;container mx-auto mt-28 px-5 flex&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;      &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;article &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;class&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;prose prose-invert&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;        &amp;lt;%= yield %&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;      &amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;article&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;main&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;body&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;html&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;A few things to note here:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;I styled the whole page with a dark background using &lt;code&gt;class=&amp;quot;bg-gray-900&amp;quot;&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;I inverted all the text colors by adding &lt;code&gt;prose-invert&lt;&#x2F;code&gt; to my &lt;code&gt;&amp;lt;article&amp;gt;&lt;&#x2F;code&gt; classes.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;It looks like this:&lt;&#x2F;p&gt;
&lt;figure&gt;

&lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;rollen.io&amp;#x2F;processed_images&amp;#x2F;1f208a8eb8f7a08e00.png&quot; &#x2F;&gt;

&lt;figcaption align=&quot;center&quot;&gt;&lt;b&gt;Dark mode&lt;&#x2F;b&gt;&lt;&#x2F;figcaption&gt;
&lt;&#x2F;figure&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;SebRollen&#x2F;rails-markdown-example&#x2F;tree&#x2F;ceb863661180b71532f250d804eb965d02d86dd2&quot;&gt;Explore the code at this point&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;parsing-and-rendering-front-matter&quot;&gt;Parsing and rendering front-matter.&lt;&#x2F;h2&gt;
&lt;p&gt;Many markdown converters use &lt;a href=&quot;https:&#x2F;&#x2F;daily-dev-tips.com&#x2F;posts&#x2F;what-exactly-is-frontmatter&#x2F;&quot;&gt;front-matter&lt;&#x2F;a&gt; to embed certain metadata in the document. For example, instead of beginning all our blog posts with &lt;code&gt;# Blog post title&lt;&#x2F;code&gt;, we might choose to instead encode that using front-matter. Lets refactor our blog post to use YAML&lt;sup id=&quot;footnoteref:4&quot;&gt;&lt;a href=&quot;#footnote:4&quot;&gt;4&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; front-matter, and add a published date as an additional point of metadata.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;diff&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-diff &quot;&gt;&lt;code class=&quot;language-diff&quot; data-lang=&quot;diff&quot;&gt;&lt;span&gt;&amp;lt;!-- app&#x2F;views&#x2F;pages&#x2F;blog&#x2F;new_post.html.md --&amp;gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;- # New blog post
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;- 
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;- &amp;lt;small&amp;gt;Author: Seb&amp;lt;&#x2F;small&amp;gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;+ ---
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;+ title: New blog post
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;+ author: Seb
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;+ date: 2023-01-30
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;+ ---
&lt;&#x2F;span&gt;&lt;span&gt;...
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We&#x27;ll add one more gem to help us separate the front-matter from the rest of the markdown content:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;bundle&lt;&#x2F;span&gt;&lt;span&gt; add ruby_matter
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We have to update our markdown renderer to ignore the front-matter in its normal course of rendering:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;diff&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-diff &quot;&gt;&lt;code class=&quot;language-diff&quot; data-lang=&quot;diff&quot;&gt;&lt;span&gt;# config&#x2F;initializers&#x2F;markdown.rb
&lt;&#x2F;span&gt;&lt;span&gt;...
&lt;&#x2F;span&gt;&lt;span&gt;def self.call(template, source)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;-  compiled_source = erb.call(template, source)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;+  parser = RubyMatter.parse(source)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;+  compiled_source = erb.call(template, parser.content)
&lt;&#x2F;span&gt;&lt;span&gt;   &amp;quot;Redcarpet::Markdown.new(Redcarpet::Render::HTML.new).render(begin;#{compiled_source};end).html_safe&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;end
&lt;&#x2F;span&gt;&lt;span&gt;...
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;To extract the front-matter into a usable format, let&#x27;s update our controller to parse the front-matter into an instance variable:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;diff&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-diff &quot;&gt;&lt;code class=&quot;language-diff&quot; data-lang=&quot;diff&quot;&gt;&lt;span&gt;# app&#x2F;controllers&#x2F;pages_controller.rb
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;...
&lt;&#x2F;span&gt;&lt;span&gt;  layout :layout_for_page
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;+ before_action :extract_frontmatter
&lt;&#x2F;span&gt;&lt;span&gt;...
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  private
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;+ def extract_frontmatter
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;+   @frontmatter = RubyMatter.parse(file_contents).data
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;+ end
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;+
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;+ def file_contents
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;+   File.read(File.join(&amp;#39;app&amp;#39;, &amp;#39;views&amp;#39;, &amp;quot;#{file}.html.md&amp;quot;))
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;+ end
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;+
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;+ def file
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;+   page_finder_factory.new(params[:id]).find
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;+ end
&lt;&#x2F;span&gt;&lt;span&gt;...
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This &lt;em&gt;almost&lt;&#x2F;em&gt; work, but we run into &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ruby&#x2F;psych&#x2F;issues&#x2F;604&quot;&gt;an issue&lt;&#x2F;a&gt; where the underlying library used for YAML parsing disallows values of &lt;code&gt;Date&lt;&#x2F;code&gt; and &lt;code&gt;Time&lt;&#x2F;code&gt; by default.&lt;&#x2F;p&gt;
&lt;p&gt;We can fix this by providing our own lambda for parsing YAML files, where we explicitly allow these classes:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;diff&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-diff &quot;&gt;&lt;code class=&quot;language-diff&quot; data-lang=&quot;diff&quot;&gt;&lt;span&gt;# app&#x2F;controllers&#x2F;pages_controller.rb
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;...
&lt;&#x2F;span&gt;&lt;span&gt;  layout :layout_for_page
&lt;&#x2F;span&gt;&lt;span&gt;  before_action :extract_frontmatter
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;+ ENGINES = {
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;+   yaml: {
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;+     parse: -&amp;gt;(yaml) { Psych.safe_load(yaml, permitted_classes: [Date, Time]) },
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;+     stringify: -&amp;gt;(hash) { Psych.dump(hash).sub(&#x2F;^---(\n|\s)?&#x2F;, &amp;#39;&amp;#39;) }
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;+   }
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;+ }.freeze
&lt;&#x2F;span&gt;&lt;span&gt;...
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  def extract_front_matter
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;-   @frontmatter = RubyMatter.parse(file_contents).data
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;+   @frontmatter = RubyMatter.parse(file_contents, engines: ENGINES).data
&lt;&#x2F;span&gt;&lt;span&gt;  end
&lt;&#x2F;span&gt;&lt;span&gt;...
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now it works.&lt;&#x2F;p&gt;
&lt;p&gt;As a final step, let&#x27;s render our extracted data in our layout:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;diff&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-diff &quot;&gt;&lt;code class=&quot;language-diff&quot; data-lang=&quot;diff&quot;&gt;&lt;span&gt;&amp;lt;!-- app&#x2F;views&#x2F;layouts&#x2F;pages&#x2F;blog_post.html.erb --&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;...
&lt;&#x2F;span&gt;&lt;span&gt;  &amp;lt;article class=&amp;quot;prose prose-invert&amp;quot;&amp;gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;+   &amp;lt;h1&amp;gt;&amp;lt;%= @frontmatter[&amp;#39;title&amp;#39; %&amp;gt;&amp;lt;&#x2F;h1&amp;gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;+   &amp;lt;p&amp;gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;+     Posted by &amp;lt;%= @frontmatter[&amp;#39;author&amp;#39;] %&amp;gt; on &amp;lt;%= @frontmatter[&amp;#39;date&amp;#39;] %&amp;gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;+   &amp;lt;&#x2F;p
&lt;&#x2F;span&gt;&lt;span&gt;...
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;figure&gt;

&lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;rollen.io&amp;#x2F;processed_images&amp;#x2F;51fe9dd8512e0f2f00.png&quot; &#x2F;&gt;

&lt;figcaption align=&quot;center&quot;&gt;&lt;b&gt;Blog post rendered with front-matter&lt;&#x2F;b&gt;&lt;&#x2F;figcaption&gt;
&lt;&#x2F;figure&gt;
&lt;p&gt;Excellent&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;SebRollen&#x2F;rails-markdown-example&#x2F;tree&#x2F;dd0ae0d8edabc41c492232e9144e2b5f83b3ba8b&quot;&gt;Explore the code at this point&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;So that does it: a bona-fide markdown-to-html workflow including front-matter in Rails. Do you have any suggested improvements to this approach? Let me know!&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;&lt;p id=&quot;footnote:1&quot;&gt;[1]&amp;nbsp;I&#x27;m no longer working on RoQR, and the domain is now owned by another party.&amp;nbsp;&lt;small&gt;&lt;a href=&quot;#footnoteref:1&quot;&gt;&amp;#8617;&amp;#65038;&lt;&#x2F;a&gt;&lt;&#x2F;small&gt;&lt;&#x2F;p&gt;

&lt;p id=&quot;footnote:2&quot;&gt;[2]&amp;nbsp;I&#x27;m using Rails version 7.0.4.2. You might run into some issues following this post if your version is significantly different.&amp;nbsp;&lt;small&gt;&lt;a href=&quot;#footnoteref:2&quot;&gt;&amp;#8617;&amp;#65038;&lt;&#x2F;a&gt;&lt;&#x2F;small&gt;&lt;&#x2F;p&gt;

&lt;p id=&quot;footnote:3&quot;&gt;[3]&amp;nbsp;We&#x27;re using &lt;code&gt;.&#x2F;bin&#x2F;dev&lt;&#x2F;code&gt; rather than the normal &lt;code&gt;rails s&lt;&#x2F;code&gt; as we&#x27;re running more than one process here using &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;theforeman&#x2F;foreman&quot;&gt;foreman&lt;&#x2F;a&gt;: the web server and a process for redefining our CSS using Tailwind. You can learn more about how that works &lt;a href=&quot;https:&#x2F;&#x2F;www.nickhammond.com&#x2F;learning-to-love-bin-slash-dev-in-rails-7&#x2F;&quot;&gt;here&lt;&#x2F;a&gt;&amp;nbsp;&lt;small&gt;&lt;a href=&quot;#footnoteref:3&quot;&gt;&amp;#8617;&amp;#65038;&lt;&#x2F;a&gt;&lt;&#x2F;small&gt;&lt;&#x2F;p&gt;

&lt;p id=&quot;footnote:4&quot;&gt;[4]&amp;nbsp;&lt;a href=&quot;https:&#x2F;&#x2F;hitchdev.com&#x2F;strictyaml&#x2F;why&#x2F;implicit-typing-removed&#x2F;&quot;&gt;Sorry, Norway!&lt;&#x2F;a&gt;&amp;nbsp;&lt;small&gt;&lt;a href=&quot;#footnoteref:4&quot;&gt;&amp;#8617;&amp;#65038;&lt;&#x2F;a&gt;&lt;&#x2F;small&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>In time</title>
		<published>2023-01-14T00:00:00+00:00</published>
		<updated>2023-01-15T00:00:00+00:00</updated>
		<link href="https://rollen.io/blog/in-time/" type="text/html"/>
		<id>https://rollen.io/blog/in-time/</id>
		<content type="html">&lt;blockquote&gt;
&lt;p&gt;As you are, we once were.&lt;br &#x2F;&gt;
As we are, you will be.&lt;br &#x2F;&gt;
Dust —yes— but so much more:&lt;&#x2F;p&gt;
&lt;p&gt;The breath you held, though you wanted to speak—&lt;br &#x2F;&gt;
confess—scream—profess—&lt;br &#x2F;&gt;
    why didn&#x27;t you?&lt;br &#x2F;&gt;
is with us now.&lt;br &#x2F;&gt;
From your lips: a gift, permeating&lt;br &#x2F;&gt;
to trees, who never once knew your kindness,&lt;br &#x2F;&gt;
in time.&lt;&#x2F;p&gt;
&lt;p&gt;The blood that trickled through your veins,&lt;br &#x2F;&gt;
but rarely ran red,&lt;br &#x2F;&gt;
is with us now.&lt;br &#x2F;&gt;
Percolating, then coarsing, roaring&lt;br &#x2F;&gt;
  like it never did in you&lt;br &#x2F;&gt;
through rivers and streams hidden from the sun.&lt;br &#x2F;&gt;
It evaporates, and falls gently, now,&lt;br &#x2F;&gt;
over lands, you only might have seen&lt;br &#x2F;&gt;
in time.&lt;&#x2F;p&gt;
&lt;p&gt;Your sinews and muscles that atrophied&lt;br &#x2F;&gt;
when you forgot that you were living, too,&lt;br &#x2F;&gt;
are with us now.&lt;br &#x2F;&gt;
Not as carrion, torn by raptors&lt;br &#x2F;&gt;
  (nothing so romantic)&lt;br &#x2F;&gt;
but churning softly, through soil and silt&lt;br &#x2F;&gt;
into dust —yes—&lt;br &#x2F;&gt;
in time.&lt;&#x2F;p&gt;
&lt;p&gt;We have plans for every part of you,&lt;br &#x2F;&gt;
the purpose that eluded you,&lt;br &#x2F;&gt;
when you step out of time.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Some useful git one-liners</title>
		<published>2023-01-13T00:00:00+00:00</published>
		<updated>2023-01-13T00:00:00+00:00</updated>
		<link href="https://rollen.io/blog/git-oneliners/" type="text/html"/>
		<id>https://rollen.io/blog/git-oneliners/</id>
		<content type="html">&lt;p&gt;I have a few useful git one-liners that I reach for relatively often. I don&#x27;t have them written down anywhere, but just search for them in my shell history (using the wonderful &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;cantino&#x2F;mcfly&quot;&gt;McFly&lt;&#x2F;a&gt;) whenever I need them. Until now!&lt;&#x2F;p&gt;
&lt;h2 id=&quot;list-the-number-of-commits-to-a-repo-by-day&quot;&gt;List the number of commits to a repo by day&lt;&#x2F;h2&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;❯&lt;&#x2F;span&gt;&lt;span&gt; git log&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; --date&lt;&#x2F;span&gt;&lt;span&gt;=short&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; --pretty&lt;&#x2F;span&gt;&lt;span&gt;=format:%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;ad &lt;&#x2F;span&gt;&lt;span&gt;| &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;sort &lt;&#x2F;span&gt;&lt;span&gt;| &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;uniq -c
&lt;&#x2F;span&gt;&lt;span&gt;   &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;8&lt;&#x2F;span&gt;&lt;span&gt; 2023-01-07
&lt;&#x2F;span&gt;&lt;span&gt;   &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt; 2023-01-09
&lt;&#x2F;span&gt;&lt;span&gt;   &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt; 2023-01-10
&lt;&#x2F;span&gt;&lt;span&gt;   &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt; 2023-01-12
&lt;&#x2F;span&gt;&lt;span&gt;   &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;4&lt;&#x2F;span&gt;&lt;span&gt; 2023-01-13
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;create-a-sparkline-chart-of-the-commit-history&quot;&gt;Create a sparkline chart of the commit history&lt;&#x2F;h2&gt;
&lt;p&gt;Bonus! Requires &lt;a href=&quot;https:&#x2F;&#x2F;zachholman.com&#x2F;spark&#x2F;&quot;&gt;spark&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;❯&lt;&#x2F;span&gt;&lt;span&gt; git log&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; --date&lt;&#x2F;span&gt;&lt;span&gt;=short&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; --pretty&lt;&#x2F;span&gt;&lt;span&gt;=format:%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;ad &lt;&#x2F;span&gt;&lt;span&gt;| &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;sort &lt;&#x2F;span&gt;&lt;span&gt;| &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;uniq -c &lt;&#x2F;span&gt;&lt;span&gt;| &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;awk &lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;{print $1}&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39; | &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;spark
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;▁▄▃▁▁▆█▁▂▁▇▁▁▂▃▁▁▁█▂▁▂▄
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;list-the-number-of-commits-to-a-repo-by-day-sorted-by-commits&quot;&gt;List the number of commits to a repo by day, sorted by commits&lt;&#x2F;h2&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;❯&lt;&#x2F;span&gt;&lt;span&gt; git log&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; --date&lt;&#x2F;span&gt;&lt;span&gt;=short&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; --pretty&lt;&#x2F;span&gt;&lt;span&gt;=format:%&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;ad &lt;&#x2F;span&gt;&lt;span&gt;| &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;sort &lt;&#x2F;span&gt;&lt;span&gt;| &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;uniq -c &lt;&#x2F;span&gt;&lt;span&gt;| &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;sort -r &lt;&#x2F;span&gt;&lt;span&gt;| &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;head
&lt;&#x2F;span&gt;&lt;span&gt;   &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;8&lt;&#x2F;span&gt;&lt;span&gt; 2023-01-07
&lt;&#x2F;span&gt;&lt;span&gt;   &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;8&lt;&#x2F;span&gt;&lt;span&gt; 2021-10-19
&lt;&#x2F;span&gt;&lt;span&gt;   &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;7&lt;&#x2F;span&gt;&lt;span&gt; 2022-04-23
&lt;&#x2F;span&gt;&lt;span&gt;   &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;6&lt;&#x2F;span&gt;&lt;span&gt; 2021-10-18
&lt;&#x2F;span&gt;&lt;span&gt;   &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;4&lt;&#x2F;span&gt;&lt;span&gt; 2023-01-13
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;delete-merged-branches-in-a-repo-that-squashes-commits&quot;&gt;Delete merged branches in a repo that squashes commits&lt;&#x2F;h2&gt;
&lt;p&gt;If you work a lot in a repo that uses squashes merge commits to main, you might have found that your local &lt;code&gt;git branch&lt;&#x2F;code&gt; listing quickly builds up, and answers like &lt;a href=&quot;https:&#x2F;&#x2F;stackoverflow.com&#x2F;questions&#x2F;6127328&#x2F;how-do-i-delete-all-git-branches-which-have-been-merged&quot;&gt;this one&lt;&#x2F;a&gt; don&#x27;t actually work. Try this instead:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;❯&lt;&#x2F;span&gt;&lt;span&gt; git fetch&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; -p &lt;&#x2F;span&gt;&lt;span&gt;; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;git&lt;&#x2F;span&gt;&lt;span&gt; branch&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; -r &lt;&#x2F;span&gt;&lt;span&gt;| &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;awk &lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;{print $1}&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39; | &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;egrep -v -f&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;dev&#x2F;fd&#x2F;0 &amp;lt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;git&lt;&#x2F;span&gt;&lt;span&gt; branch&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; -vv &lt;&#x2F;span&gt;&lt;span&gt;| &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;grep&lt;&#x2F;span&gt;&lt;span&gt; origin) | &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;awk &lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;{print $1}&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39; | &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;xargs&lt;&#x2F;span&gt;&lt;span&gt; git branch&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; -D
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;From&lt;&#x2F;span&gt;&lt;span&gt; github.com:SebRollen&#x2F;test-repo
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;- &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;deleted&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;           (none)     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;-&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt; origin&#x2F;test-branch
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Deleted&lt;&#x2F;span&gt;&lt;span&gt; branch test-branch (was f865934)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;.
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Let me know if you have any other good git tricks!&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>The paragraph I went vegan</title>
		<published>2023-01-09T00:00:00+00:00</published>
		<updated>2023-01-10T00:00:00+00:00</updated>
		<link href="https://rollen.io/blog/the-paragraph-i-went-vegan/" type="text/html"/>
		<id>https://rollen.io/blog/the-paragraph-i-went-vegan/</id>
		<content type="html">&lt;p&gt;The question that I usually get asked the most about going vegan along with &amp;quot;What food do you miss the most?&amp;quot; (cheese!) and &amp;quot;Is is it hard?&amp;quot; (yes) is &amp;quot;What made you decide to go vegan?&amp;quot;&lt;&#x2F;p&gt;
&lt;p&gt;It&#x27;s a question I have struggled to find a pithy answer to, but it is a fair question, and of a similar ilk as questions I am sure I have asked to others with different habits than mine.&lt;&#x2F;p&gt;
&lt;p&gt;My usual response is that it was a book that put me over the edge, specifically &lt;a href=&quot;https:&#x2F;&#x2F;www.littlebrown.com&#x2F;titles&#x2F;jonathan-safran-foer&#x2F;eating-animals&#x2F;9780316086646&#x2F;&quot;&gt;Eating Animals&lt;&#x2F;a&gt; by Jonathan Safran Foer. I describe to them that contrary to whatever the title might make you think, it&#x27;s not a book that shames you for eating animals, but rather a nuanced and rather lamentful consideration of the costs of &lt;em&gt;not&lt;&#x2F;em&gt; eating animals. The title is a double-entendre of the fact that we&#x27;re also eating-animals: animals who build traditions and bonds around our food. Friendships and kinships are in large part forged at the dinner table, and it&#x27;s almost hard to imagine being close to someone with whom you have not yet shared a meal. I tell them that Safran Foer is known as a fiction author, and that Eating Animals is not just a persuasive book - it&#x27;s also beautiful narrative of the human condition.&lt;&#x2F;p&gt;
&lt;p&gt;All of this is true. But it&#x27;s also not a complete and honest answer, because I know exactly at what point in the book I realized that I could not go back to eating animal products again, the exact paragraph. And though Eating Animals as a whole is nuanced, the paragraph in question is about as graphic of an account of a slaughterhouse as you could imagine. And though the book in general does not try to shame people out of eating meat, it&#x27;s hard to not feel shameful after reading it. Like one of Safran Foer&#x27;s fiction books, the account is &lt;em&gt;extremely loud&lt;&#x2F;em&gt; and &lt;em&gt;incredibly close&lt;&#x2F;em&gt;. This might of course be the intended effect, a book full of feints and jabs with a concealed upper-punch. It certainly put me down for the count.&lt;&#x2F;p&gt;
&lt;p&gt;The paragraph in question is in fact a quote from another book: &lt;a href=&quot;http:&#x2F;&#x2F;prometheusbooks.com&#x2F;books&#x2F;9781591024507&quot;&gt;Slaughterhouse&lt;&#x2F;a&gt; by Gail A. Eisnitz. Eisnitz spent years investigating the conditions in America&#x27;s slaughterhouses and interviewing the people who worked in them. The conditions she found were horrific and it&#x27;s in an interview with a worker in a slaughterhouse for pigs that we find the paragraph in Eating Animals:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Down in the blood pit they say that the smell of blood makes you aggressive. And it does. You get an attitude that if that hog kicks at me, I’m going to get even. You’re already going to kill the hog, but that’s not enough. It has to suffer.... You go in hard, push hard, blow the windpipe, make it drown in its own blood. Split its nose. A live hog would be running around the pit. It would just be looking up at me and I’d be sticking, and I would just take my knife and — eerk — cut its eye out while it was just sitting there. And this hog would just scream. One time I took my knife — it’s sharp enough — and I sliced off the end of a hog’s nose, just like a piece of bologna. The hog went crazy for a few seconds. Then it just sat there looking kind of stupid. So I took a handful of salt brine and ground it into his nose. Now that hog really went nuts, pushing its nose all over the place. I still had a bunch of salt left on my hand — I was wearing a rubber glove — and I stuck the salt right up the hog’s ass. The poor hog didn&#x27;t know whether to shit or go blind.... I wasn&#x27;t the only guy doing this kind of stuff. One guy I work with actually chases hogs into the scalding tank. And everybody — hog drivers, shacklers, utility men — uses lead pipes on hogs. Everybody knows it, all of it. &lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;The acts of the slaughterhouse worker above are undoubtedly wicked and inhumanely cruel, and yet they&#x27;re not as uncommon as we&#x27;d hope. One survey of slaughter plant employees at 25 U.S. and Canadian facilities between 1975 and 1987 found that employees at 32% of the plants displayed &amp;quot;[a]cts of deliberate cruelty on a regular basis&amp;quot;, with a further 12% demonstrating &amp;quot;[r]ough handling occurring as a routine practice&amp;quot;. And these were during announced audits - it&#x27;s hard not to imagine conditions being worse at times when the plant was not being audited.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;blockquote&gt;
&lt;p&gt;So much held in a heart in a lifetime. So much held in a heart in a day, an hour, a moment. We are utterly open with no one in the end—not mother and father, not wife or husband, not lover, not child, not friend. We open windows to each but we live alone in the house of the heart. Perhaps we must. Perhaps we could not bear to be so naked, for fear of a constantly harrowed heart. When young we think there will come one person who will savor and sustain us always; when we are older we know this is the dream of a child, that all hearts finally are bruised and scarred, scored and torn, repaired by time and will, patched by force of character, yet fragile and rickety forevermore, no matter how ferocious the defense and how many bricks you bring to the wall. You can brick up your heart as stout and tight and hard and cold and impregnable as you possibly can and down it comes in an instant, felled by a woman’s second glance, a child’s apple breath, the shatter of glass in the road, the words I have something to tell you, a cat with a broken spine dragging itself into the forest to die, the brush of your mother’s papery ancient hand in the thicket of your hair, the memory of your father’s voice early in the morning echoing from the kitchen where he is making pancakes for his children.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;&lt;small&gt;&lt;a href=&quot;https:&#x2F;&#x2F;theamericanscholar.org&#x2F;joyas-volardores&#x2F;&quot;&gt;Joyas Voladoras&lt;&#x2F;a&gt;, Bryan Doyle&lt;&#x2F;small&gt;&lt;&#x2F;p&gt;
&lt;p&gt;As children, I think we understand that animals are special, that they are living beings sharing this beautiful world with us. Most children would be horrified if you pointed out that the meat they were eating came from an animal. They&#x27;d know that it&#x27;s wrong to keep a cow continously pregnant, to separate them from their calves right after birth just so that we can have milk. As we grow older, we build up defences and justifications about which animals we can eat, and what types of lives they should live before we slaughter them. &lt;&#x2F;p&gt;
&lt;p&gt;And sometimes, the brick wall comes down in an instance with no hopes of ever rebuilding.&lt;&#x2F;p&gt;
&lt;p&gt;For me the wall came down from a paragraph about a hog just sitting there, looking kind of stupid.&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Crypto arguments from the head, the heart and the hands</title>
		<published>2022-06-07T00:00:00+00:00</published>
		<updated>2023-01-13T00:00:00+00:00</updated>
		<link href="https://rollen.io/blog/crypto-head-heart-hands/" type="text/html"/>
		<id>https://rollen.io/blog/crypto-head-heart-hands/</id>
		<content type="html">&lt;p&gt;My &lt;a href=&quot;&#x2F;blog&#x2F;crypto-climate&quot;&gt;previous post&lt;&#x2F;a&gt; on the climate-impact on cryptocurrencies garnered some attention on &lt;a href=&quot;https:&#x2F;&#x2F;www.reddit.com&#x2F;r&#x2F;environment&#x2F;comments&#x2F;v4fmcj&#x2F;cryptocurrencies_are_worse_for_the_climate_than&#x2F;&quot;&gt;reddit&lt;&#x2F;a&gt; and &lt;a href=&quot;https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=31594707&quot;&gt;Hacker News&lt;&#x2F;a&gt;, and I had originally planned a follow-up to address some of the criticisms I received in those comments. I never finalized the article&lt;sup id=&quot;footnoteref:1&quot;&gt;&lt;a href=&quot;#footnote:1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;, but it has been sitting in my drafts long enough now that I decided to post the outline of it anyway&lt;sup id=&quot;footnoteref:2&quot;&gt;&lt;a href=&quot;#footnote:2&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The title and structure of this post is a reference to the idea laid out in Buster Benson&#x27;s book &lt;a href=&quot;https:&#x2F;&#x2F;www.penguinrandomhouse.com&#x2F;books&#x2F;598274&#x2F;why-are-we-yelling-by-buster-benson&#x2F;&quot;&gt;Why Are We Yelling&lt;&#x2F;a&gt;, that most arguments can be categorized in three categories: those of the head, heart and hands. In order, those arguments boil down to disagreements about the truth, the meaning, and the usefulness of the argument.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;arguments-of-the-head-truth&quot;&gt;Arguments of the Head (Truth)&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;the-correct-calculation-yields-2-000-kwh-per-block-not-transaction&quot;&gt;&lt;a href=&quot;https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=31597066&quot;&gt;The correct calculation yields ~2,000 kWh per block, not transaction&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=31597229&quot;&gt;I addressed one of these comments directly&lt;&#x2F;a&gt; in the HackerNews thread, but for completeness, here&#x27;s how you can verify yourself that this argument is false. &lt;&#x2F;p&gt;
&lt;p&gt;We start by looking at the total energy consumption of the Bitcoin network as a whole. As of the time of writing, that figure is &lt;a href=&quot;https:&#x2F;&#x2F;digiconomist.net&#x2F;bitcoin-energy-consumption&#x2F;&quot;&gt;200 TWh per year&lt;&#x2F;a&gt;. 200 terawatt-hours is the same as 200,000,000,000 (200 billion) kWh. Next, we find the number of Bitcoin blocks mined each day. Since the Bitcoin network is designed to yield a block at a rate of about one block every 10 minutes, we expect this value to be around (1 block &#x2F; 10 minutes) *  (60 minutes &#x2F; hour) * (24 hours &#x2F; day) * (365 days &#x2F; year) = 52,560 blocks &#x2F; year. Empirically, we can also see that the number of blocks mined daily &lt;a href=&quot;https:&#x2F;&#x2F;stats.buybitcoinworldwide.com&#x2F;blocks-daily&#x2F;&quot;&gt;tends to track very closely&lt;&#x2F;a&gt; to the theoretical average. Dividing our two figures, we find that (200,000,000,000 kWh &#x2F; year) &#x2F; (52,560 blocks &#x2F; year) ≈ 3,800,000 kWh &#x2F; block, which is about 1,900 times larger than the figure I quoted for the effective kWh per transaction.&lt;&#x2F;p&gt;
&lt;p&gt;To bring the calculation all the way home, we can calculate the kWh per transaction by dividing our kWh per block figure by the number of transactions per block. There is no theoretical average for the number of transactions in a block since a block is limited by memory (1 MB) rather than number of transactions, but we can see empirically that the number of transactions per block &lt;a href=&quot;https:&#x2F;&#x2F;ycharts.com&#x2F;indicators&#x2F;bitcoin_average_transactions_per_block&quot;&gt;tends to hover around 1,900&lt;&#x2F;a&gt;. (3,800,000 kWh &#x2F; block) &#x2F; (1,900 transactions &#x2F; block) = 2,000 kWh &#x2F; transaction, which is very close to the figure I used in the original post.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;bitcoin-uses-mostly-renewable-energy&quot;&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.reddit.com&#x2F;r&#x2F;environment&#x2F;comments&#x2F;v4fmcj&#x2F;comment&#x2F;ib49rn2&#x2F;?utm_source=share&amp;amp;utm_medium=web2x&amp;amp;context=3&quot;&gt;Bitcoin uses mostly renewable energy&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;According to Digiconomist, &lt;a href=&quot;https:&#x2F;&#x2F;digiconomist.net&#x2F;bitcoin-energy-consumption&#x2F;&quot;&gt;about 25.1% of the energy used to mine Bitcoin comes from sustainable sources&lt;&#x2F;a&gt;. This is the lowest percentage for multiple years, partially due to many miners having to move their operation from China to other countries after &lt;a href=&quot;https:&#x2F;&#x2F;www.weforum.org&#x2F;agenda&#x2F;2022&#x2F;01&#x2F;what-s-behind-china-s-cryptocurrency-ban&#x2F;&quot;&gt;China cracked down on cryptocurrencies in 2021&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;25% may still seem like a large number, given that many sources for sources of global energy seem to indicate that the global average share of sustainable energy is much lower. However, most of those statistic include energy usage for applications that are not powered by an electric grid such as shipping and airlines. A more applicable comparison is to look at what percentage of energy consumed through the electrical grid comes from renewable sources. Globally, &lt;a href=&quot;https:&#x2F;&#x2F;ourworldindata.org&#x2F;electricity-mix&quot;&gt;that percentage is 26.4%&lt;&#x2F;a&gt;&lt;sup id=&quot;footnoteref:3&quot;&gt;&lt;a href=&quot;#footnote:3&quot;&gt;3&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;bitcoin-uses-less-energy-than-atms&quot;&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.reddit.com&#x2F;r&#x2F;environment&#x2F;comments&#x2F;v4fmcj&#x2F;comment&#x2F;ib47cz5&#x2F;?utm_source=share&amp;amp;utm_medium=web2x&amp;amp;context=3&quot;&gt;Bitcoin uses less energy than ATMs&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;This one we can also address with some quick maths. An standard ATM draws between &lt;a href=&quot;https:&#x2F;&#x2F;www.quora.com&#x2F;How-much-is-the-total-power-supply-consumption-of-an-ATM-machine&quot;&gt;60W&lt;&#x2F;a&gt; and &lt;a href=&quot;https:&#x2F;&#x2F;prineta.com&#x2F;atm-power-usage&#x2F;&quot;&gt;145W&lt;&#x2F;a&gt;. Let&#x27;s go with the larger number to be conservative: that then gives us an energy usage of 145Wh per hour per ATM. Yearly, that is (145Wh &#x2F; hour) * (24 hours &#x2F; day) * (365 days &#x2F; year) = 1,270,200 Wh &#x2F; year, or 1,270 kWh &#x2F; year&lt;sup id=&quot;footnoteref:4&quot;&gt;&lt;a href=&quot;#footnote:4&quot;&gt;4&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;. There&#x27;s about &lt;a href=&quot;https:&#x2F;&#x2F;www.finextra.com&#x2F;pressarticle&#x2F;78452&#x2F;number-of-atms-worldwide-drops-for-the-first-time-as-demand-for-cash-decreases&quot;&gt;3.2 million ATMs&lt;&#x2F;a&gt; in the world, so assuming that those machines are running 24&#x2F;7, that gives us a total energy usage of 1,270 kWh &#x2F; (ATM * year) * 3.2m ATMs = 4,060,000,000 kWh &#x2F; year, or about 4 TWh &#x2F; year. So in our worst-case scenario, ATMs use about 50 times less energy than Bitcoin yearly.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;bitcoin-uses-less-energy-that-christmas-lights&quot;&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.reddit.com&#x2F;r&#x2F;environment&#x2F;comments&#x2F;v4fmcj&#x2F;comment&#x2F;ib47bbn&#x2F;?utm_source=share&amp;amp;utm_medium=web2x&amp;amp;context=3&quot;&gt;Bitcoin uses less energy that Christmas lights&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;This would indeed be quite alarming if it was true. The comment I link to provided a &lt;a href=&quot;https:&#x2F;&#x2F;financialservices.house.gov&#x2F;uploadedfiles&#x2F;hhrg-117-ba00-wstate-brooksb-20211208.pdf&quot;&gt;source from oral testimony&lt;&#x2F;a&gt; in front of the U.S. House of Representatives Financial Services committee, which may give the statistic the veneer of being authoritative. However, it&#x27;s important to remember that a wide range of people get asked to give testimony in front of Congress for an equally wide variety of reasons. In this case, the speaker was Brian Brooks, CEO of the crypto company Bitfury, who claimed in his testimony that &amp;quot;bitcoin’s total global energy usage of about 188 terawatts is somewhat less than the total annual energy usage of Christmas lights (around 201 terawatts)&amp;quot;. There&#x27;s no source for his claim that Christmas lights use around 201 TWh (which is what I assume he means by terawatts) per year, but I was able to find an &lt;a href=&quot;https:&#x2F;&#x2F;www.energy.gov&#x2F;sites&#x2F;prod&#x2F;files&#x2F;maprod&#x2F;documents&#x2F;Energy_Savings_Light_Emitting_Diodes_Niche_Lighting_Apps.pdf&quot;&gt;estimate of the energy usage of various forms of lighting&lt;&#x2F;a&gt; in the United States from the Department of Energy. In this report, the DoE reports that as of 2007, around 6.63 TWh worth of energy is used to power &amp;quot;Decorative Holiday Lights&amp;quot; each year. They also helpfully note that at that time, around 5.2% of those lights were LEDs, which are much more energy efficient than traditional holiday lights. &lt;&#x2F;p&gt;
&lt;p&gt;It is very likely that the proportion of LED Christmas lights is much higher now than it was in 2007 given that LED usage as a whole has &lt;a href=&quot;https:&#x2F;&#x2F;www.iea.org&#x2F;reports&#x2F;lighting&quot;&gt;gone from virtually 0% to around 50% of the market&lt;&#x2F;a&gt;. This means that the total energy use from Christmas lights has likely gone down in the past 15 years, but for a worst-case analysis let&#x27;s assume that the energy use from Christmas lights remains the same in the U.S. Let&#x27;s also assume that the U.S. is a representative country for estimating the amount of energy used per capita on Christmas lights (another assumption that will most likely overestimate the consumption as many other countries use little to no Christmas lights). The U.S. has around 334m people, and the world population is around 7,952m, so in our worst-case analysis, we arrive at the figure of 6.63 * 7,952 &#x2F; 334 = 158 TWh &#x2F; year. A more conservative estimate where the U.S. uses twice as many decorative lights per capita as the average country and where market penetration for LEDs in Christmas lights has reached 50% would yield an estimate of around 40 TWh, around 1&#x2F;5 of Mr. Brooks&#x27; estimate. &lt;strong&gt;SEB CHECK THIS CALCULATION&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;https:&#x2F;&#x2F;www.iea.org&#x2F;reports&#x2F;lighting
https:&#x2F;&#x2F;www.earth-policy.org&#x2F;datacenter&#x2F;pdf&#x2F;book_wote_energy_efficiency.pdf&lt;&#x2F;p&gt;
&lt;h3 id=&quot;bitcoin-use-less-energy-than-data-centers&quot;&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.reddit.com&#x2F;r&#x2F;environment&#x2F;comments&#x2F;v4fmcj&#x2F;comment&#x2F;ib46jyd&#x2F;?utm_source=share&amp;amp;utm_medium=web2x&amp;amp;context=3&quot;&gt;Bitcoin use less energy than data centers&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;This one is pretty close. The best source I could find indicates that &lt;a href=&quot;https:&#x2F;&#x2F;www.statista.com&#x2F;statistics&#x2F;186992&#x2F;global-derived-electricity-consumption-in-data-centers-and-telecoms&#x2F;&quot;&gt;data centers consume about 190 TWh &#x2F; year&lt;&#x2F;a&gt;, with a clear trend in decreasing energy consumption from traditional data centers, and increasing consumption from cloud centers. Interestingly, the overall electricity usage from data centers is now decreasing year-by-year even as cloud computing is clearly on the rise, mainly due to the move to hyperscale server centers, which tend to be more efficient at the workload level. Bitcoin electricity consumption is already past 190 TWh &#x2F; year and has consistently increased, so though data centers may have used more electricity in the past, that is no longer true. It&#x27;s also worth noting that some of the electricity consumption from data centers may also be supporting cryptocurrency mining, so the gap between the two may be even larger.&lt;&#x2F;p&gt;
&lt;p&gt;There&#x27;s also a usefulness argument here, as I would wager that the commenters who wanted to see this comparison would also concede that there is a lot of usefulness to the types of workloads that are being run in data centers. My guess is that the commenters expected data center electricity consumption to far exceed that of cryptocurrencies and so they meant to point out that there is a lot of waste in general computation as well.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;general-confusion-about-energy-calculation&quot;&gt;&lt;a href=&quot;https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=31596231&quot;&gt;General confusion about energy calculation&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;Though the comment I link to in this section header does not add&lt;&#x2F;p&gt;
&lt;p&gt;https:&#x2F;&#x2F;www.reddit.com&#x2F;r&#x2F;environment&#x2F;comments&#x2F;v4fmcj&#x2F;comment&#x2F;ib4jt4i&#x2F;?utm_source=share&amp;amp;utm_medium=web2x&amp;amp;context=3&lt;&#x2F;p&gt;
&lt;h2 id=&quot;arguments-of-the-hands-usefulness&quot;&gt;Arguments of the Hands (Usefulness)&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;bitcoin-uses-less-energy-than-x&quot;&gt;Bitcoin uses less energy than X&lt;&#x2F;h3&gt;
&lt;p&gt;I addressed some specific examples of this type of question in &lt;a href=&quot;http:&#x2F;&#x2F;127.0.0.1:1111&#x2F;blog&#x2F;crypto-head-heart-hands&#x2F;#bitcoin-uses-less-power-than-data-centers&quot;&gt;Bitcoin uses less power than data centers&lt;&#x2F;a&gt;, &lt;a href=&quot;http:&#x2F;&#x2F;127.0.0.1:1111&#x2F;blog&#x2F;crypto-head-heart-hands&#x2F;#bitcoin-uses-less-power-than-atms&quot;&gt;Bitcoin uses less power than ATMs&lt;&#x2F;a&gt; and &lt;a href=&quot;http:&#x2F;&#x2F;127.0.0.1:1111&#x2F;blog&#x2F;crypto-head-heart-hands&#x2F;#bitcoin-uses-less-power-than-christmas-lights&quot;&gt;Bitcoin uses less power than Christmas lights&lt;&#x2F;a&gt;. In those two cases, we found that the statistics quoted in the comments were false, and we can consider them arguments of the head. However, given that aggregate energy usage for cryptocurrencies is still less than a percent there are of course a lot of things in the world that use more energy than Bitcoin.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;calculating-energy-usage-per-transaction-is-wrong-as-transaction-rate-for-bitcoin-is-constant&quot;&gt;&lt;a href=&quot;https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=31596640&quot;&gt;Calculating energy usage per transaction is wrong as transaction rate for Bitcoin is constant&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;h3 id=&quot;the-article-does-not-account-for-transactions-on-the-bitcoin-lightning-network&quot;&gt;[The article does not account for transactions on the Bitcoin lightning network]&lt;&#x2F;h3&gt;
&lt;h3 id=&quot;the-title-talks-about-cryptocurrencies-but-the-article-only-addresses-bitcoin&quot;&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.reddit.com&#x2F;r&#x2F;environment&#x2F;comments&#x2F;v4fmcj&#x2F;comment&#x2F;ib48133&#x2F;?utm_source=share&amp;amp;utm_medium=web2x&amp;amp;context=3&quot;&gt;The title talks about cryptocurrencies, but the article only addresses Bitcoin&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;Mostly true, though I did try to give a brief explanation in &lt;a href=&quot;https:&#x2F;&#x2F;rollen.io&#x2F;blog&#x2F;crypto-climate&#x2F;#footnote:1&quot;&gt;footnote 1&lt;&#x2F;a&gt;. Here&#x27;s the slightly longer argument:
Let&#x27;s pretend that humanity collectively decided to wind down the Bitcoin experiment and every single Bitcoin holder sold their Bitcoins to reinvest in other cryptocurrencies. If these investors reallocated their money in such a way to not affect the relative weights of market-capitalization for the other cryptocurrencies, they would then buy into the cryptocurrencies based on the ex-Bitcoin asset-weighted mix of all other cryptocurrencies. For example, if Ethereum currently accounts for about 10% of the global cryptocurrency market-cap and Bitcoin accounts for around 80%&lt;sup id=&quot;footnoteref:5&quot;&gt;&lt;a href=&quot;#footnote:5&quot;&gt;5&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;, we would now expect Ethereum to account for 10% &#x2F; (100% - 80%) = 50% of the total cryptocurrency market capitalization. If each cryptocurrency also kept its same power efficiency, we&#x27;d expect the electricity usage for each currency to scale up by an equal amount. The full calculation using the numbers from the original article finds that energy usage would increase by 31.61% &#x2F; 20.31% - 1 = 55.6%.&lt;&#x2F;p&gt;
&lt;p&gt;Even though there are cryptocurrencies that are more and less efficient than Bitcoin from an energy perspective, this calculation shows that the asset-weighted mix of all cryptocurrencies sans Bitcoin has worse energy efficiency than Bitcoin itself, and so my arguments from the previous article also hold for the cryptocurrency ecosystem as a whole.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;only-proof-of-work-cryptocurrencies-are-bad-for-the-environment&quot;&gt;&lt;a href=&quot;https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=31596756&quot;&gt;Only proof-of-work cryptocurrencies are bad for the environment&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;h3 id=&quot;cryptocurrencies-use-very-little-energy-on-an-aggregate-scale-compared-to-other-industries&quot;&gt;&lt;a href=&quot;https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=31596689&quot;&gt;Cryptocurrencies use very little energy on an aggregate scale compared to other industries&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;h3 id=&quot;it-s-more-important-to-consider-energy-production-than-consumption&quot;&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.reddit.com&#x2F;r&#x2F;environment&#x2F;comments&#x2F;v4fmcj&#x2F;comment&#x2F;ib45qao&#x2F;?utm_source=share&amp;amp;utm_medium=web2x&amp;amp;context=3&quot;&gt;It&#x27;s more important to consider energy production than consumption&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;h3 id=&quot;the-global-banking-system-is-worse-for-the-climate-than-bitcoin&quot;&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.reddit.com&#x2F;r&#x2F;environment&#x2F;comments&#x2F;v4fmcj&#x2F;comment&#x2F;ib45yqn&#x2F;?utm_source=share&amp;amp;utm_medium=web2x&amp;amp;context=3&quot;&gt;The global banking system is worse for the climate than Bitcoin&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;h2 id=&quot;arguments-of-the-heart-meaning&quot;&gt;Arguments of the Heart (Meaning)&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;corporations-are-worse-polluters-than-individuals&quot;&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.reddit.com&#x2F;r&#x2F;environment&#x2F;comments&#x2F;v4fmcj&#x2F;comment&#x2F;ib45rqg&#x2F;?utm_source=share&amp;amp;utm_medium=web2x&amp;amp;context=3&quot;&gt;Corporations are worse polluters than individuals&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;h3 id=&quot;anti-banking&quot;&gt;Anti-banking&lt;&#x2F;h3&gt;
&lt;h2 id=&quot;footnotes&quot;&gt;Footnotes&lt;&#x2F;h2&gt;
&lt;p id=&quot;footnote:1&quot;&gt;[1]&amp;nbsp;Though I would like to credit my non-posting as a sign of personal growth and a proof that I now know not to pick fights on the internet, in truth it was more of a victim of shiny-object syndrome.&amp;nbsp;&lt;small&gt;&lt;a href=&quot;#footnoteref:1&quot;&gt;&amp;#8617;&amp;#65038;&lt;&#x2F;a&gt;&lt;&#x2F;small&gt;&lt;&#x2F;p&gt;
&lt;p id=&quot;footnote:2&quot;&gt;[2]&amp;nbsp;In good news, the energy-usage of most crypto-currencies have plummeted since I originally drafted the article above. Not necessarily due to technological improvements though - just an artifact of the cratering crypto-prices. Hooray!&amp;nbsp;&lt;small&gt;&lt;a href=&quot;#footnoteref:2&quot;&gt;&amp;#8617;&amp;#65038;&lt;&#x2F;a&gt;&lt;&#x2F;small&gt;&lt;&#x2F;p&gt;
&lt;p id=&quot;footnote:3&quot;&gt;[3]&amp;nbsp;Though the Our World in Data link I used reports the non-fossil fuel percentage energy mix as 36.7%, that mix includes nuclear power. I&#x27;m all for nuclear power, but since the Digiconomist definition excluded nuclear from their sustainable sources in arriving at their figure, I do the same here to arrive at the 26.4% figure.&amp;nbsp;&lt;small&gt;&lt;a href=&quot;#footnoteref:3&quot;&gt;&amp;#8617;&amp;#65038;&lt;&#x2F;a&gt;&lt;&#x2F;small&gt;&lt;&#x2F;p&gt;
&lt;p id=&quot;footnote:4&quot;&gt;[4]&amp;nbsp;Note that right off the bat, we see that one Bitcoin transaction consumes about as much energy as 2 years worth worst-case usage of an ATM, so I&#x27;d say this argument is not off to a great start.&amp;nbsp;&lt;small&gt;&lt;a href=&quot;#footnoteref:4&quot;&gt;&amp;#8617;&amp;#65038;&lt;&#x2F;a&gt;&lt;&#x2F;small&gt;&lt;&#x2F;p&gt;
&lt;p id=&quot;footnote:5&quot;&gt;[5]&amp;nbsp;These weightings are based on the study linked in the original article, which is re-linked &lt;a href=&quot;https:&#x2F;&#x2F;www.ncbi.nlm.nih.gov&#x2F;pmc&#x2F;articles&#x2F;PMC7402366&#x2F;table&#x2F;tbl1&#x2F;?report=objectonly&quot;&gt;here&lt;&#x2F;a&gt; for easier reference.&amp;nbsp;&lt;small&gt;&lt;a href=&quot;#footnoteref:5&quot;&gt;&amp;#8617;&amp;#65038;&lt;&#x2F;a&gt;&lt;&#x2F;small&gt;&lt;&#x2F;p&gt;
&lt;p id=&quot;footnote:6&quot;&gt;[6]&amp;nbsp;Funnily enough, it doesn&#x27;t appear like Brian Brooks actually read the section touching on Christmas lights in the hearing for which he submitted his testimony. In the &lt;a href=&quot;https:&#x2F;&#x2F;financialservices.house.gov&#x2F;events&#x2F;eventsingle.aspx?EventID=408705&quot;&gt;video recording from the hearing&lt;&#x2F;a&gt;, he ends his opening statement in the paragraph before he talks about the sustainability issues of Bitcoin, at the 30:30 minute mark. There&#x27;s nothing abnormal about this: witnesses in congressional hearings often have limited time to provide their opening statements and can submit written statements that go into more detail than what their oral testimony would allow, but I still find it kind of funny that this very easily-disprovable argument seems to have garnered attention even though the main source of it didn&#x27;t even address it in his opening arguments.&lt;&#x2F;p&gt;
&lt;p&gt;For complete transparency, I did not watch the full 4.5 hours of the Congressional hearing, so my apologies to Mr. Brooks if he did in fact voice this part of his testimony at a later stage in the hearing, though I still stand by the fact that he grossly overestimated his electricity consumption figure for Christmas lights.&amp;nbsp;&lt;small&gt;&lt;a href=&quot;#footnoteref:6&quot;&gt;&amp;#8617;&amp;#65038;&lt;&#x2F;a&gt;&lt;&#x2F;small&gt;&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Cryptocurrencies are worse for the climate than you think</title>
		<published>2022-06-02T00:00:00+00:00</published>
		<updated>2022-06-02T00:00:00+00:00</updated>
		<link href="https://rollen.io/blog/crypto-climate/" type="text/html"/>
		<id>https://rollen.io/blog/crypto-climate/</id>
		<content type="html">&lt;p&gt;I came across a &lt;a href=&quot;https:&#x2F;&#x2F;www.forbes.com&#x2F;advisor&#x2F;investing&#x2F;cryptocurrency&#x2F;bitcoin-energy-consumption-survey&#x2F;&quot;&gt;pretty astounding article&lt;&#x2F;a&gt; the other day. The author of the article conducted a survey, asking a panel of 2,000 Americans familiar with cryptocurrency what impact they believe Bitcoin has on the environment and climate change. The results were as follows:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;6% said &lt;q&gt;It is a significant threat to the environment and climate change.&lt;&#x2F;q&gt;&lt;&#x2F;li&gt;
&lt;li&gt;26% said &lt;q&gt;It has a slight impact on the environment and climate change, but not enough to cause a threat.&lt;&#x2F;q&gt;&lt;&#x2F;li&gt;
&lt;li&gt;32% said &lt;q&gt;It has no impact on the environment and climate change.&lt;&#x2F;q&gt;&lt;&#x2F;li&gt;
&lt;li&gt;26% said &lt;q&gt;It is good for the environment.&lt;&#x2F;q&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;For those of you keeping score at home, that&#x27;s a total of 58% of respondents who believe that crypto is either a neutral or a positive influence on the environment. It&#x27;s hard to believe that this could be the case when &lt;a href=&quot;https:&#x2F;&#x2F;www.sciencedaily.com&#x2F;releases&#x2F;2018&#x2F;10&#x2F;181029130951.htm&quot;&gt;some scientists warn&lt;&#x2F;a&gt; that Bitcoin alone could produce enough emissions to push us past the 2°C global warming mark by 2032. I think that the scale and urgency of the climate risks of cryptocurrencies are often misinterpreted when presented at an aggregate level, so I set out to compile some statistics on how to view crypto consumption through the lens of the household and marginal consumption.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;at-the-household-level&quot;&gt;At the household level&lt;&#x2F;h2&gt;
&lt;p&gt;You might have seen articles like &lt;a href=&quot;https:&#x2F;&#x2F;www.nytimes.com&#x2F;interactive&#x2F;2021&#x2F;09&#x2F;03&#x2F;climate&#x2F;bitcoin-carbon-footprint-electricity.html&quot;&gt;this one&lt;&#x2F;a&gt; and &lt;a href=&quot;https:&#x2F;&#x2F;www.bbc.com&#x2F;news&#x2F;technology-56012952&quot;&gt;this one&lt;&#x2F;a&gt; stating that the Bitcoin&lt;sup id=&quot;footnoteref:1&quot;&gt;&lt;a href=&quot;#footnote:1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; network now uses more electricity than many large countries, like Ukraine. On one hand, this sounds like a lot: Ukraine has over 45 million people, and is about the same size as Texas. On the other hand, I think aggregate statistics like this can serve to obscure the issue. After all, Bitcoin is taking the world by storm, and is a global network - maybe it makes sense that it would rival some countries, even large ones. Comparisons to foreign countries also ask the reader to not only think about the question at hand (how wasteful are cryptocurrencies?), but also a geographical one (how large and developed is Ukraine?). It doesn&#x27;t help that &lt;a href=&quot;https:&#x2F;&#x2F;morningconsult.com&#x2F;2022&#x2F;02&#x2F;09&#x2F;can-americans-find-ukraine-on-a-map&#x2F;&quot;&gt;2&#x2F;3 of Americans couldn&#x27;t even locate Ukraine on a map&lt;&#x2F;a&gt; before March.&lt;&#x2F;p&gt;
&lt;p&gt;I find it more illuminating to approach the issue from a much more granular level. Each Bitcoin transaction consumes around &lt;a href=&quot;https:&#x2F;&#x2F;digiconomist.net&#x2F;bitcoin-energy-consumption&quot;&gt;2,150 kWh&lt;&#x2F;a&gt; as of the time of this writing. The kWh unit stands for kilo-watt hours - a watt is defined as one joule per second, so a kilo-watt hour is equivalent to consuming 1,000 joules per second for one hour which is 3.6 megajoules. The only everyday reference most of us has for joules or watts are our light bulbs. One way to think about the Bitcoin energy usage then is that one transaction uses as much energy as keeping a standard 60W light bulb lit for 35,833 hours. That&#x27;s almost exactly 4 years. Of course, 60W light bulbs are being phased out because &lt;em&gt;they&#x27;re so inefficient&lt;&#x2F;em&gt;. Modern LED bulbs are more typically in the 10W range, so by that standard a Bitcoin transaction is more like 24 straight years of light bulb usage. Do you like to dabble in cryptocurrencies, and also turn off your lights when you leave a room to save energy? Don&#x27;t bother.&lt;&#x2F;p&gt;
&lt;p&gt;Even the light bulb example can be hard to wrap your head around because us humans are not great at thinking about very large numbers. 24 years is longer than Bitcoin has even been around. Perhaps a better comparison is to look at household electricity consumption. In the US, which is among &lt;a href=&quot;https:&#x2F;&#x2F;www.statista.com&#x2F;statistics&#x2F;383633&#x2F;worldwide-consumption-of-electricity-by-country&#x2F;&quot;&gt;the countries that uses the most electricity per capita&lt;&#x2F;a&gt;, the average household uses &lt;a href=&quot;https:&#x2F;&#x2F;www.eia.gov&#x2F;energyexplained&#x2F;use-of-energy&#x2F;electricity-use-in-homes.php&quot;&gt;about 11,000 kWh per year&lt;&#x2F;a&gt;. In these terms, your Bitcoin purchase uses about as much electricity as &lt;em&gt;2.5 months of every other thing you use electricity for&lt;&#x2F;em&gt;. Did you make a round-trip transaction by also selling your Bitcoin at some point in the year? Now those two transactions account for close to half a year worth of all your other electrical uses.&lt;&#x2F;p&gt;
&lt;p&gt;The article I linked to above from the U.S. Energy Information Administration has a useful chart breaking down energy consumption for the average U.S. household by end use. Here&#x27;s a reproduction of the same chart, with an added bar for the energy consumption of a single Bitcoin transaction.&lt;&#x2F;p&gt;

&lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;rollen.io&amp;#x2F;processed_images&amp;#x2F;a37dfb55c077869a00.png&quot; &#x2F;&gt;
&lt;p&gt;That&#x27;s correct: on average if you make one Bitcoin transaction in a year, the electrical impact of that purchase is larger than any other use case in your household for the full year. Note that this calculation does not presuppose that you purchase a whole Bitcoin. It is equally true for any fraction of a Bitcoin you might purchase - it&#x27;s the number of transactions that count, not the size of the transaction&lt;sup id=&quot;footnoteref:2&quot;&gt;&lt;a href=&quot;#footnote:2&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;. Of course, as any good financial adviser worth their salt would tell you, it&#x27;s usually not good to try to time the market with a single purchase of a financial asset, and so you may be want to invest regularly in your cryptocurrency of choice. Most Americans are paid every two weeks, so if you were to practice common financial advice of diverting a portion of your paycheck to investments, you&#x27;d on average incur a transaction 26 times per year. Here&#x27;s how that would look like on the same chart:&lt;&#x2F;p&gt;

&lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;rollen.io&amp;#x2F;processed_images&amp;#x2F;0b7b32653f9990b600.png&quot; &#x2F;&gt;
&lt;p&gt;Yikes.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;at-the-incremental-level&quot;&gt;At the incremental level&lt;&#x2F;h2&gt;
&lt;p&gt;Another effective lens to view cryptocurrency energy consumption through is that of global incremental energy usage. Thankfully, cryptocurrencies do not yet account for a significant percentage of aggregate global electricity consumption, but just as we have seen some pretty meteoric increases in the price of many cryptocurrencies, the electricity usage of crypto networks is also increasing at an alarming rate. The IEA estimates that the &lt;a href=&quot;https:&#x2F;&#x2F;prod.iea.org&#x2F;data-and-statistics&#x2F;charts&#x2F;global-changes-in-electricity-generation-2015-2024&quot;&gt;total change in electricity generation between 2019 and 2021&lt;&#x2F;a&gt; equals around 1,753 TWh. In the same time-period, &lt;a href=&quot;https:&#x2F;&#x2F;www.nytimes.com&#x2F;interactive&#x2F;2021&#x2F;09&#x2F;03&#x2F;climate&#x2F;bitcoin-carbon-footprint-electricity.html&quot;&gt;Bitcoin&#x27;s consumption has grown&lt;&#x2F;a&gt; from 38 TWh per year at the end of 2018 to &lt;a href=&quot;https:&#x2F;&#x2F;digiconomist.net&#x2F;bitcoin-energy-consumption&#x2F;&quot;&gt;200 TWh&lt;&#x2F;a&gt; in 2021, an increase of 162 TWh per year. This means that close to 10% of all new electricity generated each year has gone to Bitcoin mining. There are roughly &lt;a href=&quot;https:&#x2F;&#x2F;www.blockchain.com&#x2F;charts&#x2F;n-transactions&quot;&gt;250,000 Bitcoin transactions per day&lt;&#x2F;a&gt;, so even if each of those transactions came from a different individual, it means that a maximum of 0.003% of the world&#x27;s population interacts with the technology per day. For us to blow 10%&lt;sup id=&quot;footnoteref:3&quot;&gt;&lt;a href=&quot;#footnote:3&quot;&gt;3&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; of our new electricity generation each year on a technology that quite frankly could never serve to replace current payment networks is insane.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;footnotes&quot;&gt;Footnotes&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;p id=&quot;footnote:1&quot;&gt;[1]&amp;nbsp;This article focuses on Bitcoin as it is the largest cryptocurrency and by far the worst climate offender on an aggregate scale, &lt;a href=&quot;https:&#x2F;&#x2F;www.ncbi.nlm.nih.gov&#x2F;pmc&#x2F;articles&#x2F;PMC7402366&#x2F;&quot;&gt;consuming about 2&#x2F;3 of the electricity of all cryptocurrencies combined&lt;&#x2F;a&gt;. However, the points made in this article also stand for the long tail of other cryptocurrencies, given that the &lt;a href=&quot;https:&#x2F;&#x2F;www.ncbi.nlm.nih.gov&#x2F;pmc&#x2F;articles&#x2F;PMC7402366&#x2F;table&#x2F;tbl1&#x2F;?report=objectonly&quot;&gt;same study linked earlier&lt;&#x2F;a&gt; found that Bitcoin accounts for 80% of the market capitalization of all cryptocurrencies, meaning that if all other cryptocurrencies gained market-share at Bitcoin&#x27;s expense, the problem would likely get worse, not better.&amp;nbsp;&lt;small&gt;&lt;a href=&quot;#footnoteref:1&quot;&gt;&amp;#8617;&amp;#65038;&lt;&#x2F;a&gt;&lt;&#x2F;small&gt;&lt;&#x2F;p&gt;

&lt;p id=&quot;footnote:2&quot;&gt;[2]&amp;nbsp;Technically, it&#x27;s limited by number of bytes, but the bytes of a transaction are not very dependent on the size of the transaction.&amp;nbsp;&lt;small&gt;&lt;a href=&quot;#footnoteref:2&quot;&gt;&amp;#8617;&amp;#65038;&lt;&#x2F;a&gt;&lt;&#x2F;small&gt;&lt;&#x2F;p&gt;

&lt;p id=&quot;footnote:3&quot;&gt;[3]&amp;nbsp;That&#x27;s 10% for now, but crypto electricity usage is still growing at a faster pace than average global consumption so that percentage will go up over time.&amp;nbsp;&lt;small&gt;&lt;a href=&quot;#footnoteref:3&quot;&gt;&amp;#8617;&amp;#65038;&lt;&#x2F;a&gt;&lt;&#x2F;small&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>You received an .asc attachment from me. Here&#x27;s why</title>
		<published>2022-04-26T00:00:00+00:00</published>
		<updated>2022-04-26T00:00:00+00:00</updated>
		<link href="https://rollen.io/blog/asc-attachment/" type="text/html"/>
		<id>https://rollen.io/blog/asc-attachment/</id>
		<content type="html">&lt;p&gt;If you&#x27;re on this page, it might be because you received an email I sent that had a file attached with the extension &lt;code&gt;.asc&lt;&#x2F;code&gt;. The file is a cryptographic signature, which you can use to verify that the email is actually sent from me, and that no one has tampered with or altered any of the other attachments to the email.  By default, I GPG sign all emails that I send which contain other attachments. &lt;&#x2F;p&gt;
&lt;p&gt;The easiest way to verify that the signature matches my public key is to use a mail client that supports GPG functionality natively. I use a terminal-based mail client called &lt;a href=&quot;http:&#x2F;&#x2F;www.mutt.org&#x2F;&quot;&gt;mutt&lt;&#x2F;a&gt;, but I can also recommend &lt;a href=&quot;https:&#x2F;&#x2F;www.thunderbird.net&#x2F;en-US&#x2F;&quot;&gt;Thunderbird&lt;&#x2F;a&gt;, a full-featured graphical mail client from Mozilla. Once you have your client set up, you will need to import my public key so that your mail client knows what a signature from me is &lt;em&gt;supposed&lt;&#x2F;em&gt; to look like. &lt;&#x2F;p&gt;
&lt;p&gt;My public keys are hosted on my website, available at &lt;a href=&quot;https:&#x2F;&#x2F;rollen.io&#x2F;sebrollen.pgp.asc&quot;&gt;this link&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Re-signing git commits</title>
		<published>2022-04-24T00:00:00+00:00</published>
		<updated>2023-08-30T00:00:00+00:00</updated>
		<link href="https://rollen.io/blog/resigning-git-commits/" type="text/html"/>
		<id>https://rollen.io/blog/resigning-git-commits/</id>
		<content type="html">&lt;p&gt;Git allows you to &lt;a href=&quot;https:&#x2F;&#x2F;git-scm.com&#x2F;book&#x2F;en&#x2F;v2&#x2F;Git-Tools-Signing-Your-Work&quot;&gt;sign commits&lt;&#x2F;a&gt; using a GPG key, as a way to prove that a commit that looks like it was made by you &lt;em&gt;was&lt;&#x2F;em&gt; in fact made by you. Perusers of the git history can then verify the signature by running &lt;code&gt;git log --show-signature&lt;&#x2F;code&gt;. On Github, it&#x27;s even easier to verify, as Github will add a green &amp;quot;Verified&amp;quot; stamp next to the commit, giving a quick visual indication that the signature came from a GPG key that you have asserted as your own in the Github settings. You can view the signing history for the git repository of this website &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;SebRollen&#x2F;rollen.io&#x2F;commits&#x2F;main&quot;&gt;here&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;By default, Github will add that stamp to verified commits, and leave any commits that were not signed without a stamp. However, it&#x27;s possible to activate &amp;quot;Vigilant mode&amp;quot; in the GPG settings of Github, in which case any unsigned commit is flagged with a yellow &amp;quot;Unverified&amp;quot; stamp. Since I&#x27;m planning on signing all my commits going forward, I&#x27;ve enabled vigilant mode on my account, but now I&#x27;m faced with the eyesore of seeing yellow stamps next to all the commits I made in my &lt;del&gt;halcyon&lt;&#x2F;del&gt; pre-GPG days. This can not stand.&lt;&#x2F;p&gt;
&lt;p&gt;I started exploring if it was possible to retroactively sign commits, and ended up with a pretty neat solution. The full command is &lt;code&gt;git rebase --root --gpg-sign --committer-date-is-author-date&lt;&#x2F;code&gt;. &lt;code&gt;--root&lt;&#x2F;code&gt; makes sure we rebase all the commits on the current branch back to our initial commit. &lt;code&gt;--gpg-sign&lt;&#x2F;code&gt; adds our shiny GPG signature to each commit. By default, git views these commits as new, and so updates the history to show that all our commits happened today. In order to retain the actual commit date for each commit, we add the final component: &lt;code&gt;--committer-date-is-author-date&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;So there you have it, a way to retroactively sign all your git commits on a branch. Even though we fixed the most obvious sign of us messing with the git history, it&#x27;s worth noting that this will most likely cause issues with any open branches that branched from the old history. We&#x27;re effectively rewriting the whole git history, with new commit hashes and all - you will need to force-push the new branch to update the view on Github.. It&#x27;s up to you whether the green badges are worth it. &lt;em&gt;Caveat lector&lt;&#x2F;em&gt;, and godspeed.&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>You, me, and GnuPG</title>
		<published>2022-04-23T00:00:00+00:00</published>
		<updated>2022-04-23T00:00:00+00:00</updated>
		<link href="https://rollen.io/blog/gpg/" type="text/html"/>
		<id>https://rollen.io/blog/gpg/</id>
		<content type="html">&lt;p&gt;Over the last few weeks, I&#x27;ve fallen down the GnuPG rabbit-hole. &lt;a href=&quot;https:&#x2F;&#x2F;gnupg.org&#x2F;&quot;&gt;GnuPG&lt;&#x2F;a&gt;, short for &amp;quot;the Gnu Privacy Guard&amp;quot; (long for &amp;quot;GPG&amp;quot;), is a tool for asymmetric encryption, meaning that you can use it to create messages that only a specific recipient is able to read. More concretely, the system relies on &lt;em&gt;private&lt;&#x2F;em&gt; and &lt;em&gt;public&lt;&#x2F;em&gt; keys, where you can use someone&#x27;s public key to encrypt a message that can only be decrypted with the corresponding private key. Not only have I made my own keys - I have now progressed to the stage where my emails, address book, calendar and passwords are all secured by a GnuPG foundation, with my private keys stored on a tiny device that I can carry with me. Bad idea? Maybe. Totally awesome? Abso-fricking-lutely!&lt;&#x2F;p&gt;
&lt;p&gt;In forthcoming articles, I&#x27;ll go into some detail about how I have – and you can – set up this system, starting with how to create your own GPG keys. In the meantime, feel free to send me an encrypted message using my public key. It&#x27;s the cryptic-looking thing at the bottom of my website footer, beginning with &lt;code&gt;0x&lt;&#x2F;code&gt;. You can paste that key, along with the message you want to encrypt, in an online tool &lt;a href=&quot;https:&#x2F;&#x2F;aliceandbob.io&#x2F;online-pgp-tool&quot;&gt;like this one&lt;&#x2F;a&gt; and then copy the message into an &lt;a href=&quot;mailto:seb@rollen.io&quot;&gt;email to me&lt;&#x2F;a&gt;. I&#x27;m looking forward to hearing from you!&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>American Primitive</title>
		<published>2021-10-18T00:00:00+00:00</published>
		<updated>2021-10-18T00:00:00+00:00</updated>
		<link href="https://rollen.io/blog/american-primitive/" type="text/html"/>
		<id>https://rollen.io/blog/american-primitive/</id>
		<content type="html">&lt;p&gt;Lately, I&#x27;ve been trying to disconnect from technology in my spare time (more on that soon), and I&#x27;ve found myself reading more as a consequence. One of my favorite literary discoveries of the year is &lt;a href=&quot;https:&#x2F;&#x2F;maryoliver.com&quot;&gt;Mary Oliver&lt;&#x2F;a&gt;, the late, great American poet.&lt;&#x2F;p&gt;
&lt;p&gt;Oliver&#x27;s poetry is hauntingly beautiful, but also very accessible for poetry novices such as myself. A few weeks ago, I took a library copy of Oliver&#x27;s Pulitzer-winning volume of poetry &lt;a href=&quot;%22https:&#x2F;&#x2F;www.goodreads.com&#x2F;book&#x2F;show&#x2F;178959.American_Primitive%22&quot;&gt;&lt;em&gt;American Primitive&lt;&#x2F;em&gt;&lt;&#x2F;a&gt; along for a walk in Central Park and ended up finishing it in a single sitting, shaded from the summer sun by a tulip-tree.
Since I don&#x27;t have any content yet on this website, I share two of my favorite Oliver poems below. Enjoy!&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;in-blackwater-woods&quot;&gt;In Blackwater Woods&lt;&#x2F;h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Look, the trees
are turning
their own bodies
into pillars&lt;&#x2F;p&gt;
&lt;p&gt;of light,
are giving off the rich
fragrance of cinnamon
and fulfillment,&lt;&#x2F;p&gt;
&lt;p&gt;the long tapers
of cattails
are bursting and floating away over
the blue shoulders&lt;&#x2F;p&gt;
&lt;p&gt;of the ponds,
and every pond,
no matter what its
name is, is&lt;&#x2F;p&gt;
&lt;p&gt;nameless now.
Every year
everything
I have ever learned&lt;&#x2F;p&gt;
&lt;p&gt;in my lifetime
leads back to this: the fires
and the black river of loss
whose other side&lt;&#x2F;p&gt;
&lt;p&gt;is salvation,
whose meaning
none of us will ever know.
To live in this world&lt;&#x2F;p&gt;
&lt;p&gt;you must be able
to do three things:
to love what is mortal;
to hold it&lt;&#x2F;p&gt;
&lt;p&gt;against your bones knowing
your own life depends on it;
and, when the time comes to let it go,
to let it go.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;humpbacks&quot;&gt;Humpbacks&lt;&#x2F;h2&gt;
&lt;blockquote&gt;
&lt;p&gt;There is, all around us,
this country
of original fire.
You know what I mean.
The sky, after all, stops at nothing, so something
has to be holding
our bodies
in its rich and timeless stables or else
we would fly away.&lt;&#x2F;p&gt;
&lt;p&gt;Off Stellwagen
off the Cape,
the humpbacks rise. Carrying their tonnage
of barnacles and joy
they leap through the water, they nuzzle back under it
like children
at play.&lt;&#x2F;p&gt;
&lt;p&gt;They sing, too.
And not for any reason
you can’t imagine.&lt;&#x2F;p&gt;
&lt;p&gt;Three of them
rise to the surface near the bow of the boat,
then dive
deeply, their huge scarred flukes
tipped to the air.
We wait, not knowing
just where it will happen; suddenly
they smash through the surface, someone begins
shouting for joy and you realize
it is yourself as they surge
upward and you see for the first time
how huge they are, as they breach,
and dive, and breach again
through the shining blue flowers
of the split water and you see them
for some unbelievable
part of a moment against the sky–
like nothing you’ve ever imagined–
like the myth of the fifth morning galloping
out of darkness, pouring
heavenward, spinning; then&lt;&#x2F;p&gt;
&lt;p&gt;they crash back under those black silks
and we all fall back
together into that wet fire, you
know what I mean.&lt;&#x2F;p&gt;
&lt;p&gt;I know a captain who has seen them
playing with seaweed, swimming
through the green islands, tossing
the slippery branches into the air.
I know a whale that will come to the boat whenever
she can, and nudge it gently along the bow
with her long flipper.
I know several lives worth living.&lt;&#x2F;p&gt;
&lt;p&gt;Listen, whatever it is you try
to do with your life, nothing will ever dazzle you
like the dreams of your body,
its spirit
longing to fly while the dead-weight bones
toss their dark mane and hurry
back into the fields of glittering fire
where everything,
even the great whale,
throbs with song.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Welcome</title>
		<published>2021-10-18T00:00:00+00:00</published>
		<updated>2021-10-18T00:00:00+00:00</updated>
		<link href="https://rollen.io/blog/welcome/" type="text/html"/>
		<id>https://rollen.io/blog/welcome/</id>
		<content type="html">&lt;p&gt;Hi, and welcome to my website. Yesterday I received an email from my domain provider that this domain will auto-renew in a week, meaning that I&#x27;ve been sitting on this domain without publishing something for close to a year - time to change that!&lt;&#x2F;p&gt;
&lt;p&gt;In the future, I will post some thoughts here about various things that interest me, including finance, the attention economy, etymology and technology. For now, I&#x27;ve contented myself with creating some basic CSS styling to provide a hopefully pleasant reading experience.&lt;&#x2F;p&gt;
&lt;p&gt;Thanks for stopping by, and feel free to contact me through the email link in the footer!&lt;&#x2F;p&gt;
</content>
	</entry>
</feed>
