<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"
  xmlns:dc="http://purl.org/dc/elements/1.1/">
  <author>
    <name>Brooke Kuhlmann</name>
    <uri>https://alchemists.io/team/brooke_kuhlmann</uri>
  </author>
  <category term="news"
    label="News"/>
  <generator uri="https://alchemists.io"
    version="0.3.0">Alchemists</generator>
  <icon>https://alchemists.io/favicon.ico</icon>
  <id>https://alchemists.io/</id>
  <link href="https://alchemists.io"
    rel="alternate"
    type="text/html"
    title="Alchemists: News (web)"/>
  <link href="https://alchemists.io/feeds/news.xml"
    rel="self"
    type="application/atom+xml"
    title="Alchemists: News (feed)"/>
  <logo>https://alchemists.io/images/logo/syndication.png</logo>
  <rights>2026</rights>
  <subtitle>All site wide software engineering related news and information.</subtitle>
  <title>Alchemists: News</title>
  <updated>2026-10-14T23:31:32+00:00</updated>
  <entry>
    <author>
      <name>Brooke Kuhlmann</name>
      <uri>https://alchemists.io/team/brooke_kuhlmann</uri>
    </author>
    <category term="projects"
      label="Projects"/>
    <content type="html">&lt;div align=&quot;center&quot;&gt;
  &lt;a href=&quot;/projects/metapath&quot;&gt;
    &lt;img src=&quot;/images/projects/metapath/logo.png&quot; width=&quot;200&quot; height=&quot;200&quot;&gt;
  &lt;/a&gt;

  &lt;h1&gt;&lt;a href=&quot;/projects/metapath&quot;&gt;Metapath&lt;/a&gt;&lt;/h1&gt;
&lt;/div&gt;

&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Dynamically parses and enriches paths metadata so you can obtain information from directories and files with minimal effort. Having metadata for each directory and/or file&amp;#8201;&amp;#8212;&amp;#8201;no matter how nested your directory structure is&amp;#8201;&amp;#8212;&amp;#8201;allows you to perform additional processing on your file structure for analysis, transformation, import, and so much more.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&quot;toc&quot; class=&quot;toc&quot;&gt;
&lt;div id=&quot;toctitle&quot; class=&quot;title&quot;&gt;Table of Contents&lt;/div&gt;
&lt;ul class=&quot;sectlevel1&quot;&gt;
&lt;li&gt;&lt;a href=&quot;#_features&quot;&gt;Features&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_requirements&quot;&gt;Requirements&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_setup&quot;&gt;Setup&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_usage&quot;&gt;Usage&lt;/a&gt;
&lt;ul class=&quot;sectlevel2&quot;&gt;
&lt;li&gt;&lt;a href=&quot;#_roots&quot;&gt;Roots&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_directories_and_files&quot;&gt;Directories and Files&lt;/a&gt;
&lt;ul class=&quot;sectlevel3&quot;&gt;
&lt;li&gt;&lt;a href=&quot;#_positions&quot;&gt;Positions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_tags&quot;&gt;Tags&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_attributes&quot;&gt;Attributes&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_configurations&quot;&gt;Configurations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_priority&quot;&gt;Priority&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_monads&quot;&gt;Monads&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_models&quot;&gt;Models&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_development&quot;&gt;Development&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_tests&quot;&gt;Tests&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_license&quot;&gt;License&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_security&quot;&gt;Security&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_code_of_conduct&quot;&gt;Code of Conduct&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_contributions&quot;&gt;Contributions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_developer_certificate_of_origin&quot;&gt;Developer Certificate of Origin&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_versions&quot;&gt;Versions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_community&quot;&gt;Community&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_credits&quot;&gt;Credits&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_features&quot;&gt;Features&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Dynamically obtains metadata about a directory or a file.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Supports an optional, per directory, configuration.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Supports nested directory structures.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Answers an array of paths with associated metadata.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_requirements&quot;&gt;Requirements&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;olist arabic&quot;&gt;
&lt;ol class=&quot;arabic&quot;&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://www.ruby-lang.org&quot;&gt;Ruby&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_setup&quot;&gt;Setup&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;To install &lt;em&gt;with&lt;/em&gt; security, run:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;c&quot;&gt;# 💡 Skip this line if you already have the public certificate installed.&lt;/span&gt;
gem cert &lt;span class=&quot;nt&quot;&gt;--add&lt;/span&gt; &amp;lt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;curl &lt;span class=&quot;nt&quot;&gt;--compressed&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--location&lt;/span&gt; https://alchemists.io/gems.pem&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
gem &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;metapath &lt;span class=&quot;nt&quot;&gt;--trust-policy&lt;/span&gt; HighSecurity&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;To install &lt;em&gt;without&lt;/em&gt; security, run:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;bash&quot;&gt;gem &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;metapath&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;You can also add the gem directly to your project:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;bash&quot;&gt;bundle add metapath&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Once the gem is installed, you only need to require it:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;metapath&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_usage&quot;&gt;Usage&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Getting started is as quick as creating an instance and then pointing it at a directory structure:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;metapath&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Metapath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;metapath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Pathname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;pwd&lt;/span&gt;

&lt;span class=&quot;no&quot;&gt;Success&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;#&amp;lt;data Metapath::Model:0x00002710&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;attributes&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{},&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;errors&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{},&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;label&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Crested Butte&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;crested_butte&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;path&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;#&amp;lt;Pathname:/Users/demo/Scratch/photos/Crested_Butte.jpeg&amp;gt;,&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;position&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;tags&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;#&amp;lt;data Metapath::Model:0x00002780&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;attributes&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{},&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;errors&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{},&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;label&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Flaming Gorge&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;flaming_gorge&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;path&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;#&amp;lt;Pathname:/Users/demo/Scratch/photos/Flaming_Gorge.jpeg&amp;gt;,&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;position&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;tags&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;#&amp;lt;data Metapath::Model:0x000027f0&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;attributes&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{},&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;errors&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{},&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;label&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Grand Canyon&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;grand_canyon&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;path&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;#&amp;lt;Pathname:/Users/demo/Scratch/photos/Grand_Canyon.jpeg&amp;gt;,&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;position&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;tags&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_roots&quot;&gt;Roots&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;When calling a metapath, you must always supply a root path for processing. In the earlier example, this was &lt;code&gt;Pathname.pwd&lt;/code&gt; (current path):&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;metapath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Pathname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;pwd&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Strings, if supplied, will be automatically converted into pathnames and auto-expanding into absolute paths. Examples:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;metapath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;~/photos&quot;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# Expands to: #&amp;lt;Pathname:/Users/&amp;lt;your user&amp;gt;/photos&amp;gt;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;metapath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;photos&quot;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# Expands to: #&amp;lt;Pathname:&amp;lt;current working directory&amp;gt;/photos&amp;gt;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;metapath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;/Users/demo/photos&quot;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# Identical: &quot;#&amp;lt;Pathname:/Users/demo/photos&amp;gt;&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;All directories and files will be processed within the root path supplied (no matter how deeply nested).&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_directories_and_files&quot;&gt;Directories and Files&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Each directory and file can have it&amp;#8217;s own metadata using any of the following characters:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;0-9&lt;/code&gt;: Any number is valid.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;a-z&lt;/code&gt;: Any lowercase letter is valid. This includes Unicode.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;A-Z&lt;/code&gt;: Any uppercase letter is valid. This includes Unicode.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;-&lt;/code&gt; (hyphen): Translates to &lt;code&gt;&quot; - &quot;&lt;/code&gt; when building the label. Example:&lt;/p&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Before: &lt;code&gt;A-Demo&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;After: &lt;code&gt;A - Demo&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;_&lt;/code&gt; (underscore): Translates to &lt;code&gt;&quot; &quot;&lt;/code&gt; when building the label. Example:&lt;/p&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Before: &lt;code&gt;A_Demo&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;After: &lt;code&gt;A Demo&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;+&lt;/code&gt; (plus): Marks the start of tag or attribute information. See examples below for details.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;,&lt;/code&gt; (comma): Specifies an array of tag or attribute metdata. See examples below for details.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;=&lt;/code&gt; (equals): Delimits the key and value of an attribute. For example &lt;code&gt;kind=demo&lt;/code&gt;, where &lt;code&gt;kind&lt;/code&gt; is the key and &lt;code&gt;demo&lt;/code&gt; is the value.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;%&lt;/code&gt; (percent): Reserved for token replacement as commonly found in &lt;a href=&quot;https://alchemists.io/projects/rubysmith&quot;&gt;Rubysmith&lt;/a&gt; for processing of templates where you want to dynamically replace each placeholder (example: &lt;code&gt;%demo%&lt;/code&gt;) with a dynamic value that matches the &lt;code&gt;demo&lt;/code&gt; key (in this example). Currently meant for post-processing.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;.&lt;/code&gt; (dot): Reserved for file extensions or multiple formats. Example: &lt;code&gt;demo.html&lt;/code&gt;, &lt;code&gt;demo.html.erb&lt;/code&gt;, etc.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;~&lt;/code&gt; (tilde): Reserved but currently not used.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;@&lt;/code&gt; (at): Reserved but currently not used.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;^&lt;/code&gt; (carrot): Reserved but currently not used.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;All of the characters shown above allow you to have files and directories that don&amp;#8217;t require special quoting which works well across multiple operating systems.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;sect3&quot;&gt;
&lt;h4 id=&quot;_positions&quot;&gt;Positions&lt;/h4&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Prefix your directories or files with a number immediately followed by a dash to keep them organized but also for sequential processing order.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Format&lt;/strong&gt;: &lt;code&gt;&amp;lt;position&amp;gt;-&amp;lt;name&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt; &lt;code&gt;01-demo&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The position is always &lt;code&gt;0&lt;/code&gt; when none is given.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect3&quot;&gt;
&lt;h4 id=&quot;_tags&quot;&gt;Tags&lt;/h4&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Use tags to provide additional metadata about your directories and files (use a comma to separate multiple values).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Format&lt;/strong&gt; (single): &lt;code&gt;&amp;lt;name&amp;gt;+&amp;lt;tag&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt; (single): &lt;code&gt;demo+blue&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Format&lt;/strong&gt; (multiple): &lt;code&gt;&amp;lt;name&amp;gt;+&amp;lt;tag&amp;gt;,&amp;lt;tag&amp;gt;,&amp;lt;tag&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt; (multiple): &lt;code&gt;demo+blue,red,green&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;💡 Use a directory configuration (&lt;code&gt;meta.yml&lt;/code&gt;) to extract common metadata if your metadata gets too long and unwieldy.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect3&quot;&gt;
&lt;h4 id=&quot;_attributes&quot;&gt;Attributes&lt;/h4&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Use attributes to provide additional metadata about your directories and files (use a comma to separate multiple values).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Format&lt;/strong&gt; (single): &lt;code&gt;&amp;lt;name&amp;gt;+&amp;lt;key&amp;gt;=&amp;lt;value&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt; (single): &lt;code&gt;demo+album=panoramas&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Format&lt;/strong&gt; (multiple): &lt;code&gt;&amp;lt;name&amp;gt;+&amp;lt;key&amp;gt;=&amp;lt;value&amp;gt;,&amp;lt;key&amp;gt;=&amp;lt;value&amp;gt;,&amp;lt;key&amp;gt;=&amp;lt;value&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt; (multiple): &lt;code&gt;demo+album=panoramas,kind=landscapes,location=snow_peak&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;💡 Use a directory configuration (&lt;code&gt;meta.yml&lt;/code&gt;) to extract common metadata if your metadata gets too long and unwieldy.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_configurations&quot;&gt;Configurations&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;You can configure common metadata per directory by placing a &lt;code&gt;meta.yml&lt;/code&gt; in the root of any directory. The following is an example of what this file might contain:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;na&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;demo&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;photos&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;attributes&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;album&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;panoramas&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;kind&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;landscapes&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;With the above, you can supply as many tags and attributes as necessary which will then be inherited as common metadata when processing files within the directory. This includes inheriting  configurations from parent directories. Keep in mind that any file with it&amp;#8217;s own metdata will take precedence.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Only the &lt;code&gt;tag&lt;/code&gt; and &lt;code&gt;attributes&lt;/code&gt; keys are honored, all other top level keys are ignored.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_priority&quot;&gt;Priority&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Metadata is resolved by merging each of the following in order listed (lowest to highest):&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;olist arabic&quot;&gt;
&lt;ol class=&quot;arabic&quot;&gt;
&lt;li&gt;
&lt;p&gt;Directory&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;meta.yml&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;File&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Resolution of the above happens by merging metadata from the lowest level into the next level until all levels are merged as one. This means you can set defaults at the lowest level which will be inherited, or overwritten, at the highest level. In pseudo code, it looks like this:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;directory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;deep_merge&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;meta&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;deep_merge&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;file&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_monads&quot;&gt;Monads&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Every time you call your metapath instance, you&amp;#8217;ll get either a &lt;code&gt;Success&lt;/code&gt; or &lt;code&gt;Failure&lt;/code&gt; as provided by &lt;a href=&quot;https://dry-rb.org/gems/dry-monads&quot;&gt;Dry Monads&lt;/a&gt;. This allows you to use the &lt;a href=&quot;https://alchemists.io/articles/railway_pattern&quot;&gt;Railway Pattern&lt;/a&gt; pattern to build fault tolerant functional pipelines for robust error processing.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;When results are a success, you&amp;#8217;ll get an array of models. Example:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;no&quot;&gt;Success&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;#&amp;lt;data Metapath::Model:0x00002710&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;attributes&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{},&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;label&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Crested Butte&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;crested_butte&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;path&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;#&amp;lt;Pathname:/Users/demo/Scratch/photos/Crested_Butte.jpeg&amp;gt;,&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;position&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;tags&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;You can get a success when errors are detected with metadata associated with your directories or files. For example, let&amp;#8217;s say your &lt;code&gt;meta.yml&lt;/code&gt; has the following content:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code&gt;attributes:&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;no&quot;&gt;Success&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;#&amp;lt;data Metapath::Model:0x00002710&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;attributes&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{},&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;errors&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;attributes: &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;must be filled&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]},&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;label&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Crested Butte&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;crested_butte&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;path&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;#&amp;lt;Pathname:/Users/demo/Scratch/photos/Crested_Butte.jpeg&amp;gt;,&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;position&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;tags&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;If a failure does occur, this usually means errors with your configuration. For example, let&amp;#8217;s say your &lt;code&gt;meta.yml&lt;/code&gt; has the following content:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;s&quot;&gt;Danger!&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This means you&amp;#8217;ll get the following result:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;no&quot;&gt;Failure&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Invalid content: Danger.&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_models&quot;&gt;Models&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Each model is a &lt;a href=&quot;https://alchemists.io/articles/ruby_data&quot;&gt;Data&lt;/a&gt; object. Additionally, the following methods are also provided for you:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Metapath&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;name: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;demo&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;label: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Demo&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;tags: &lt;/span&gt;&lt;span class=&quot;sx&quot;&gt;%w[demo photos]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;attributes: &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&quot;album&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;panoramas&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&quot;kind&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;landscapes&quot;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;fetch&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;album&quot;&lt;/span&gt;                  &lt;span class=&quot;c1&quot;&gt;# &quot;panoramas&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;fetch&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;bogus&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;fallback&quot;&lt;/span&gt;      &lt;span class=&quot;c1&quot;&gt;# &quot;fallback&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;bogus&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;fallback&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# &quot;fallback&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;fetch&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;bogus&quot;&lt;/span&gt;                  &lt;span class=&quot;c1&quot;&gt;# KeyError&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;key?&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;album&quot;&lt;/span&gt;                   &lt;span class=&quot;c1&quot;&gt;# true&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;key?&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;bogus&quot;&lt;/span&gt;                   &lt;span class=&quot;c1&quot;&gt;# false&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;tag?&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;photos&quot;&lt;/span&gt;                  &lt;span class=&quot;c1&quot;&gt;# true&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;tag?&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;bogus&quot;&lt;/span&gt;                   &lt;span class=&quot;c1&quot;&gt;# false&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;other&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Metapath&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;name: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;other&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;path: &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Pathname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;_demo.html&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;other&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;partial?&lt;/span&gt;                       &lt;span class=&quot;c1&quot;&gt;# true&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;partial?&lt;/span&gt;                       &lt;span class=&quot;c1&quot;&gt;# false&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;other&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Metapath&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;name: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;other&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;path: &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Pathname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;demo.html&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;errors: &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;message: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Danger!&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}]&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;other&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;errors?&lt;/span&gt;                       &lt;span class=&quot;c1&quot;&gt;# true&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;errors?&lt;/span&gt;                       &lt;span class=&quot;c1&quot;&gt;# false&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_development&quot;&gt;Development&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;To contribute, run:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;bash&quot;&gt;git clone https://github.com/bkuhlmann/metapath
&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;metapath
bin/setup&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;You can also use the IRB console for direct access to all objects:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;bash&quot;&gt;bin/console&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_tests&quot;&gt;Tests&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;To test, run:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;bash&quot;&gt;bin/rake&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_license&quot;&gt;&lt;a href=&quot;https://alchemists.io/policies/license&quot;&gt;License&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_security&quot;&gt;&lt;a href=&quot;https://alchemists.io/policies/security&quot;&gt;Security&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_code_of_conduct&quot;&gt;&lt;a href=&quot;https://alchemists.io/policies/code_of_conduct&quot;&gt;Code of Conduct&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_contributions&quot;&gt;&lt;a href=&quot;https://alchemists.io/policies/contributions&quot;&gt;Contributions&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_developer_certificate_of_origin&quot;&gt;&lt;a href=&quot;https://alchemists.io/policies/developer_certificate_of_origin&quot;&gt;Developer Certificate of Origin&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_versions&quot;&gt;&lt;a href=&quot;https://alchemists.io/projects/metapath/versions&quot;&gt;Versions&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_community&quot;&gt;&lt;a href=&quot;https://alchemists.io/community&quot;&gt;Community&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_credits&quot;&gt;Credits&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Built with &lt;a href=&quot;https://alchemists.io/projects/gemsmith&quot;&gt;Gemsmith&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Engineered by &lt;a href=&quot;https://alchemists.io/team/brooke_kuhlmann&quot;&gt;Brooke Kuhlmann&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
</content>
    <id>https://alchemists.io/projects/metapath</id>
    <link href="https://alchemists.io/projects/metapath"/>
    <published>2026-10-08T22:31:01+00:00</published>
    <rights>2026</rights>
    <title>Metapath Project</title>
    <updated>2026-10-14T23:31:32+00:00</updated>
    <dc:date>2026-10-14T23:31:32+00:00</dc:date>
  </entry>
  <entry>
    <author>
      <name>Brooke Kuhlmann</name>
      <uri>https://alchemists.io/team/brooke_kuhlmann</uri>
    </author>
    <category term="engineering"
      label="Engineering"/>
    <content type="html">&lt;div class=&quot;imageblock focal_point&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/images/articles/joy_of_the_craft/cover.png&quot; alt=&quot;Cover&quot; width=&quot;800&quot; height=&quot;195&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;title&quot;&gt;Joy of the Craft&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This collective was founded on a simple idea that you should enjoy the work you do including a strong sense of purpose in order to enrich the lives of your team and customers combined. Profit, while important to keep the lights on, is not the driving force. Building expertise and using software to make life more enjoyable for folks is much more rewarding. Plus, it feels good to wake up each morning knowing you are working in a code base that is well maintained, always up-to-date, a joy to use, and a benefit to society.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The &lt;a href=&quot;/oath&quot;&gt;Engineer&amp;#8217;s Oath&lt;/a&gt; helps us never lose sight of our purpose while our &lt;a href=&quot;/rigor&quot;&gt;Engineer&amp;#8217;s Rigor&lt;/a&gt; keeps us honest because you can&amp;#8217;t make an impact in life if your environment, codebase, and team is in constant disarray. This definitely takes work, which isn&amp;#8217;t always fun but, as the saying goes, nothing in life worth achieving is easy.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This also means having grit to persevere when things get tough and integrity to do the right thing when no one is looking. For comparison, let&amp;#8217;s look at the work of others who exhibit some or all of these qualities.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&quot;toc&quot; class=&quot;toc&quot;&gt;
&lt;div id=&quot;toctitle&quot; class=&quot;title&quot;&gt;Table of Contents&lt;/div&gt;
&lt;ul class=&quot;sectlevel1&quot;&gt;
&lt;li&gt;&lt;a href=&quot;#_crafters&quot;&gt;Crafters&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_sharpening_the_saw&quot;&gt;Sharpening the Saw&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_expert_beginners&quot;&gt;Expert Beginners&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_crafters&quot;&gt;Crafters&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Software engineering is both an art and a science. When expertly&amp;#8201;&amp;#8212;&amp;#8201;and seamlessly&amp;#8201;&amp;#8212;&amp;#8201;blended together, that&amp;#8217;s where the magic exists.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;You&amp;#8217;ve probably seen or worked with people&amp;#8201;&amp;#8212;&amp;#8201;if lucky&amp;#8201;&amp;#8212;&amp;#8201;which are the embodiment of joy while also being extremely skilled at the craft. &lt;a href=&quot;https://en.wikipedia.org/wiki/Jon_Batiste&quot;&gt;Jon Batiste&lt;/a&gt;, is one example, where his joy exudes from the stage, interviews, and especially in his music. Here&amp;#8217;s a few others:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Leonardo_da_Vinci&quot;&gt;Leonardo da Vinci&lt;/a&gt;: Often cited as champion of the High Renaissance not to mention an accomplished artist and engineer known for being a perfectionist where some ideas didn&amp;#8217;t see the light of day and while other ideas took years to complete.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Antoni_Gaud%C3%AD&quot;&gt;Antoni Gaudí&lt;/a&gt;: Devoted much of his life to the Sagrada Família, sometimes living on-site in his final years. He designed structural solutions decades ahead of the engineering math that would later validate his ideas.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/David_Bowie&quot;&gt;David Bowie&lt;/a&gt;: One of the greatest rock artists, and chameleon, that would constantly reinvent himself every few years (or less) to push the boundaries of what was possible. His last album, Blackstar, was released only a few days before his death.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Neil_Peart&quot;&gt;Neal Pert&lt;/a&gt;: After being known as an excellent drummer in &lt;a href=&quot;https://www.rush.com&quot;&gt;Rush&lt;/a&gt;, he relearned how to play the drums by practicing with jazz drummer Freddie Gruber in order to hone his skills further.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://www.longmontindiankitchen.com&quot;&gt;Sheel Joshi&lt;/a&gt;: An award winning, Michelin recognized, chef who is a master of the craft of Indian cuisine. Doesn&amp;#8217;t take long, after experiencing his cooking and getting the chance to talk with him, to know that he cares about the craft and sharing that joy through food. To quote from his site: &quot;A gathering place shaped by story and technique. A kitchen defined by heart.&quot;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Jiro_Ono&quot;&gt;Jiro Ono&lt;/a&gt;: Embodies shokunin (see below) ethics of duty and perfection while also known for a tough apprenticeship culture which even excluded his eldest son.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;What each of the above have in common is a mastery of the craft through constant rigor. They held onto human ingenuity and inherit skill to achieve greatness while sharing the fruits of their labor in order to bring joy to millions of others. May we all strive for the same.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_sharpening_the_saw&quot;&gt;Sharpening the Saw&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;You&amp;#8217;ll find, in many cultures, that rigor and grit are necessary to hone your craft in order to achieve expertise and a life worth living. The Japanese are especially well versed in this practice with many words representing various forms of this concept:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;/articles/shuhari&quot;&gt;Shuhari&lt;/a&gt; (守破離): This has been discussed before but shuhari is the life long pursuit of improving your craft by starting as an apprentice, evolving as a journeyer, and finally gaining mastery as a crafter. While mortally impossible to gain complete mastery, journey is where the joy the resides, not the destination.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Shokunin&lt;/strong&gt; (職人): Translates to &lt;em&gt;artisan&lt;/em&gt; or &lt;em&gt;craftsman&lt;/em&gt; which means one who endlessly pursues mastery of the craft with a strong sense of purpose and joy. This includes moral, ethical, and social consciousness to weld the craft for the benefit of others. Sound familiar? Yep, there&amp;#8217;s the &lt;a href=&quot;/oath&quot;&gt;Engineer&amp;#8217;s Oath&lt;/a&gt; again.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Kaizen&lt;/strong&gt; (改善): Translates as &lt;em&gt;improvement&lt;/em&gt; and is most notably attributed with The Toyota Way of working through constant improvement and refinement of processes. This includes a strong emphasis on quality including halting production if quality ever drops below a specific threshold. In terms of software, a good example of this is &lt;a href=&quot;/articles/ruby_code_quality/&quot;&gt;Ruby Code Quality&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Takumi&lt;/strong&gt; (匠): Means artisan, master crafter, or skilled expert. This harkens back to shuhari which is someone who has achieved mastery of the craft through decades of unyielding practice.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tatsujin&lt;/strong&gt; (達人): An expert who has arrived at mastery and who has attained the deepest level of the craft through intuitive, tacit, and effortless skill.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Dojo&lt;/strong&gt; (道場): Literally means &lt;em&gt;place of the way&lt;/em&gt; which is where folks gather to form unions, guilds, and places of continuous learning.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Habits are the key to achieving the above but can take time to become instinctual. It would be amazing to be like Neo, in &lt;a href=&quot;https://en.wikipedia.org/wiki/The_Matrix&quot;&gt;The Matrix&lt;/a&gt;, and instantly learn new skills with all the knowledge, experience, and wisdom necessary in only a few seconds but, unfortunately, that&amp;#8217;s now how we gain experience. First we learn, then we apply, and slowly we gain experience by testing the limits of our knowledge in new and interesting ways to unlock new ideas. For example, the path to software engineering mastery might look like this:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;olist arabic&quot;&gt;
&lt;ol class=&quot;arabic&quot;&gt;
&lt;li&gt;
&lt;p&gt;Learning the basics of the language by first writing simple programs and then advancing to more complex architectures.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Adding linters, code quality checks, keyboard shortcuts, macros, and anything that augments your workflow while enforcing consistency across all codebases.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Learning patterns and antipatterns including when to apply them and when alter them in elegant ways.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Extracting hard problems, solved well, as gems for reuse in other projects.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Learning from and constantly evolving design choices which might mean refactoring large chunks of an application or multiple gems in order to maintain consistency. This can be painful but is critical to building experience and new learnings on what to do and what not to do.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Writing and sharing your learnings with others. If you can&amp;#8217;t explain it, then you haven&amp;#8217;t learned it.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Creating video tutorials to augment your writings.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Speaking at conferences and connecting with others to spread new ideas and ways of thinking.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Writing books and becoming a knowledge expert in general.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Advancing and constantly evolving to the point where most knowledge is tacit and intuitive. There will always be new challenges but they become faster to debug and solve. This is pure gold because it&amp;#8217;s hard won and no one can take that away from you.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This is how you keep the saw sharp.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_expert_beginners&quot;&gt;Expert Beginners&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The antithesis of those who don&amp;#8217;t practice or understand the joy of the craft are known as an &lt;a href=&quot;/articles/expert_beginner&quot;&gt;Expert Beginner&lt;/a&gt;. These are people who hit a fork in the road and make the tragic mistake of heading down the path of supposed, or self-declared, mastery when they couldn&amp;#8217;t be father from the truth.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In short, and much has been written on this already, Expert Beginners tend to stagnate with minimal to no growth. They also have minimal to no ambition. This includes farming out learning, understanding, and personal growth to Large Language Models (LLMs). In some cases, they willingly give up what little expertise they have in favor of handing everything over to an LLM (also known as &lt;em&gt;brain rot&lt;/em&gt;). This is akin&amp;#8201;&amp;#8212;&amp;#8201;and vastly simplified&amp;#8201;&amp;#8212;&amp;#8201;to playing slot machines and hoping, this time, randomness favors your weakness. Worse, LLMs churn out the lowest common denominator of collective knowledge. This is because LLMs can&amp;#8217;t think, can&amp;#8217;t remember, and can&amp;#8217;t experience growth like humans can. Lastly, Expert Beginners definitely don&amp;#8217;t care about software architecture, code quality, maintenance, or team happiness.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Take the red pill, not the blue pill, to avoid becoming an Expert Beginner. Build upon what makes you unique and then share that joy with others.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;There will always be liars, grifters, &lt;a href=&quot;/articles/ghosting&quot;&gt;ghosters&lt;/a&gt;, fraudsters, and unsavory folk of weak constitution but this is a reminder that there is a better path in life. Harder, definitely, but much more rewarding and worth it in end.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;If this appeals to you and you truly care about the craft and the joy of getting up each day to tackle new challenges, learn new skills, write elegant code, and share what you know with others then join our &lt;a href=&quot;/community&quot;&gt;community&lt;/a&gt; or add your name to the list of &lt;a href=&quot;https://handcraftedcode.org&quot;&gt;Hand Crafted Coders&lt;/a&gt;. We&amp;#8217;re constantly working to share the joy by building a better future. We only have one shot at this life, so let&amp;#8217;s enjoy it!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</content>
    <id>https://alchemists.io/articles/joy_of_the_craft</id>
    <link href="https://alchemists.io/articles/joy_of_the_craft"/>
    <published>2026-10-01T13:59:52+00:00</published>
    <rights>2026</rights>
    <title>Joy of the Craft</title>
    <updated>2026-10-06T00:29:40+00:00</updated>
    <dc:date>2026-10-06T00:29:40+00:00</dc:date>
  </entry>
  <entry>
    <author>
      <name>Brooke Kuhlmann</name>
      <uri>https://alchemists.io/team/brooke_kuhlmann</uri>
    </author>
    <category term="ruby"
      label="Ruby"/>
    <category term="specifications"
      label="Specifications"/>
    <content type="html">&lt;div class=&quot;imageblock focal_point&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;a class=&quot;image&quot; href=&quot;https://www.rfc-editor.org&quot;&gt;&lt;img src=&quot;/images/articles/request_for_comments/cover.png&quot; alt=&quot;Cover&quot; width=&quot;842&quot; height=&quot;342&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;div class=&quot;title&quot;&gt;Request For Comments (RFCs)&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Request for Comments (RFCs) are the official guiding documents that shape the internet via technical standards, protocols, and procedures. This encompass the following:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;HyperText Transfer Protocol (HTTP)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Transmission Control Protocol (TCP)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Internet Protocol (IP)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Domain Name System (DNS)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Transport Layer Security (TLS)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;RFCs are also the primary output of the Internet Engineering Task Force (&lt;a href=&quot;https://www.ietf.org&quot;&gt;IETF&lt;/a&gt;) which was founded in 1986.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The following will help you stay on top of the ever changing RFC landscape.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&quot;toc&quot; class=&quot;toc&quot;&gt;
&lt;div id=&quot;toctitle&quot; class=&quot;title&quot;&gt;Table of Contents&lt;/div&gt;
&lt;ul class=&quot;sectlevel1&quot;&gt;
&lt;li&gt;&lt;a href=&quot;#_highlights&quot;&gt;Highlights&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_gems&quot;&gt;Gems&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_tools&quot;&gt;Tools&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_syndication&quot;&gt;Syndication&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_highlights&quot;&gt;Highlights&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;There are &lt;em&gt;a lot&lt;/em&gt; of RFCs to read through. At the time of this writing, there are 10,042 total. We don&amp;#8217;t have time to go through them all. That said, here&amp;#8217;s a few of my favorites (if not already aware, yourself):&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://www.rfc-editor.org/info/rfc5545&quot;&gt;RFC 5545&lt;/a&gt; (Internet Calendaring and Scheduling Core Object Specification (iCalendar): While not the greatest specification, due to the complexity of the format used, this provides the specification for sharing of calender information.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://www.rfc-editor.org/info/rfc6648&quot;&gt;RFC 6648&lt;/a&gt; (Deprecating the &quot;X-&quot; Prefix and Similar Constructs in Application Protocols): Specifies avoiding the use of &lt;code&gt;x-&lt;/code&gt; prefixes for custom HTTP headers. If you are using custom header like this, &lt;em&gt;please stop&lt;/em&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://www.rfc-editor.org/info/rfc8288&quot;&gt;RFC 8288&lt;/a&gt; (Web Linking): Specifies how to provide links, especially, navigation which allows you to provide rich information in HTTP responses for any content, not only APIs.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://www.rfc-editor.org/info/rfc8615/&quot;&gt;RFC 8615&lt;/a&gt; (Well-Known Uniform Resource Identifiers (URIs)): Specifies the files and formats in the &lt;code&gt;/.well-known/&lt;/code&gt; directory at the root of your site. These are authoritative and machine readable for discovery and information about your site. Sadly, some files don&amp;#8217;t adhere to this specification and live at the root of your site. Examples: &lt;code&gt;robots.txt&lt;/code&gt;, &lt;code&gt;humans.txt&lt;/code&gt;, and &lt;code&gt;sitemap.xml&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://www.rfc-editor.org/info/rfc9110&quot;&gt;RFC 9110&lt;/a&gt; (HTTP Semantics): Specifies all semantics for making HTTP requests/response especially all verbs and how to use them (see Section 9.3).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://www.rfc-editor.org/info/rfc9113&quot;&gt;RFC 9113&lt;/a&gt; (HTTP/2): Lots to read but important to note that header keys must be lower case (see Section 8.2).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://www.rfc-editor.org/info/rfc9114&quot;&gt;RFC 9114&lt;/a&gt; (HTTP/3): As mentioned with HTTP/2, above, header keys must be lower case (see Section 4.2).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://www.rfc-editor.org/info/rfc9264/&quot;&gt;RFC 9264&lt;/a&gt; (Linkset: Media Types and a Link Relation Type for Link Sets): Compliments RFC 8288 by specifying a JSON set of links which is especially handy when the number of links might be large by pointing to a specific, cacheable, document.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://www.rfc-editor.org/rfc/rfc9309.html&quot;&gt;RFC 9309&lt;/a&gt; (Robots Exclusion Protocol): Specifics how to use &lt;code&gt;robots.txt&lt;/code&gt; that must be at the root of your site (sadly, does not adhere to RFC 8615).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://www.rfc-editor.org/info/rfc9457&quot;&gt;RFC 9457&lt;/a&gt; (Problem Details for HTTP APIs): Specifies how to provide structured responses for API errors. If you&amp;#8217;re not using this already, definitely start.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://www.rfc-editor.org/rfc/rfc9745.html&quot;&gt;RFC 9745&lt;/a&gt; (The Deprecation HTTP Response Header Field): Specifies how to indicate to clients that the endpoint is deprecated including a future date/time so you know how long you have to make changes on your end. Plays nice with RFC 8288 (mentioned above).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://www.rfc-editor.org/info/rfc10008&quot;&gt;RFC 10008&lt;/a&gt; (The HTTP QUERY Method): Adds the new HTTP QUERY verb which is a hybrid of GET and POST requests which allows you to make idempotent GET requests but with the power of POST to supply a body of search criteria that would otherwise be too much for a GET request.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_gems&quot;&gt;Gems&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Some RFCs can be quite involved in terms of what is needed for compliance. This is where a &lt;a href=&quot;https://www.ruby-lang.org&quot;&gt;Ruby&lt;/a&gt; gem is a powerful solution in being able to provide an implementation for each specification. This allows you reuse a single implementation across multiple applications. A few of the following &lt;a href=&quot;/projects&quot;&gt;projects&lt;/a&gt; provide implementations to a couple of the RFCs mentioned above:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;/projects/rfc-api-problem&quot;&gt;RFC API Problem&lt;/a&gt;: A RFC 9457 Problem Details for HTTP APIs implementation.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;/projects/rfc-web-link&quot;&gt;RFC Web Link&lt;/a&gt;: A RFC 8288 Web Linking implementation.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Definitely recommend adding to your stack to enhance your HTTP responses/requests further.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_tools&quot;&gt;Tools&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;To augment your workflow, you&amp;#8217;ll want tap into the following tools for quick information sourcing including staying on top of the latest changes within the industry:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://www.rfc-editor.org&quot;&gt;RFC Editor&lt;/a&gt;: The primary source of information where you can search and read up on all RFCs as well as subscribe, via syndicated feed, for all of the latest news and information.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://rfcexplorer.net&quot;&gt;RFC Explorer&lt;/a&gt;: Provides a graphical interface to all RFCs as nodes linked to each other. This allows you to click on each RFC (node) to dive further, zoom in and out, etc. The main interface groups all material by areas of work. Unfortunately, there isn&amp;#8217;t a way to quickly search by RFC number.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://datatracker.ietf.org&quot;&gt;IETF Datatracker&lt;/a&gt;: The primary database for authors and maintainers of RFCs. The best part about this tool is a visual timeline at the top of each RFC which provides a clear and quick understanding of the RFC over time.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://author-tools.ietf.org/iddiff&quot;&gt;IETF Diff&lt;/a&gt;: Handy for comparing and contrasting the changes between document revisions.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;/projects/pennyworth&quot;&gt;Pennyworth&lt;/a&gt;: For &lt;a href=&quot;https://www.alfredapp.com&quot;&gt;Alfred&lt;/a&gt; fans, this gem allows you to quickly access the &lt;a href=&quot;https://www.rfc-editor.org&quot;&gt;RFC Editor&lt;/a&gt;, search, and fuzzy type to lookup documentation on any RFC.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_syndication&quot;&gt;Syndication&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;a href=&quot;/articles/syndication&quot;&gt;Syndication&lt;/a&gt; is a powerful way to stay on top of the changes being introduced. You can subscribe via RSS or Atom by adding the &lt;a href=&quot;https://www.rfc-editor.org&quot;&gt;RFC Editor&lt;/a&gt; URL to your feed reader and letting it do the work of informing you when new changes are posted.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;As software engineer, especially in web development, staying on top of the latest RFCs news and information is critical. Even better, automatically getting the latest updates via syndication allows you to learn about changes within the industry with minimal effort.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Enjoy and may your stack be built upon the wisdom of others.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</content>
    <id>https://alchemists.io/articles/request_for_comments</id>
    <link href="https://alchemists.io/articles/request_for_comments"/>
    <published>2026-09-01T12:06:06+00:00</published>
    <rights>2026</rights>
    <title>Request for Comments (RFCs)</title>
    <updated>2026-09-30T17:12:43+00:00</updated>
    <dc:date>2026-09-30T17:12:43+00:00</dc:date>
  </entry>
  <entry>
    <author>
      <name>Brooke Kuhlmann</name>
      <uri>https://alchemists.io/team/brooke_kuhlmann</uri>
    </author>
    <category term="projects"
      label="Projects"/>
    <content type="html">&lt;div align=&quot;center&quot;&gt;
  &lt;a href=&quot;/projects/superfluid&quot;&gt;
    &lt;img src=&quot;/images/projects/superfluid/logo.png&quot; width=&quot;200&quot; height=&quot;200&quot;&gt;
  &lt;/a&gt;

  &lt;h1&gt;&lt;a href=&quot;/projects/superfluid&quot;&gt;Superfluid&lt;/a&gt;&lt;/h1&gt;
&lt;/div&gt;

&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Enhances &lt;a href=&quot;https://shopify.github.io/liquid/&quot;&gt;Liquid&lt;/a&gt; by smoothing out the rough edges with a strong focus on object composition and functional design. This includes a fully functional filter and tag registry so you can reuse lower level filters and tags within all aspects of your view layer.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&quot;toc&quot; class=&quot;toc&quot;&gt;
&lt;div id=&quot;toctitle&quot; class=&quot;title&quot;&gt;Table of Contents&lt;/div&gt;
&lt;ul class=&quot;sectlevel1&quot;&gt;
&lt;li&gt;&lt;a href=&quot;#_features&quot;&gt;Features&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_requirements&quot;&gt;Requirements&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_setup&quot;&gt;Setup&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_usage&quot;&gt;Usage&lt;/a&gt;
&lt;ul class=&quot;sectlevel2&quot;&gt;
&lt;li&gt;&lt;a href=&quot;#_configuration&quot;&gt;Configuration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_environments&quot;&gt;Environments&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_systems&quot;&gt;Systems&lt;/a&gt;
&lt;ul class=&quot;sectlevel3&quot;&gt;
&lt;li&gt;&lt;a href=&quot;#_memory&quot;&gt;Memory&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_local&quot;&gt;Local&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_blank&quot;&gt;Blank&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_filters&quot;&gt;Filters&lt;/a&gt;
&lt;ul class=&quot;sectlevel3&quot;&gt;
&lt;li&gt;&lt;a href=&quot;#_defaults&quot;&gt;Defaults&lt;/a&gt;
&lt;ul class=&quot;sectlevel4&quot;&gt;
&lt;li&gt;&lt;a href=&quot;#_jsonify&quot;&gt;&lt;code&gt;jsonify&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_parse_json&quot;&gt;&lt;code&gt;parse_json&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_pluralize&quot;&gt;&lt;code&gt;pluralize&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_singularize&quot;&gt;&lt;code&gt;singularize&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_trim_end&quot;&gt;&lt;code&gt;trim_end&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_trim_middle&quot;&gt;&lt;code&gt;trim_middle&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_modules&quot;&gt;Modules&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_functionables&quot;&gt;Functionables&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_procs_and_lambdas&quot;&gt;Procs and Lambdas&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_classes&quot;&gt;Classes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_containers&quot;&gt;Containers&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_tags&quot;&gt;Tags&lt;/a&gt;
&lt;ul class=&quot;sectlevel3&quot;&gt;
&lt;li&gt;&lt;a href=&quot;#_defaults_2&quot;&gt;Defaults&lt;/a&gt;
&lt;ul class=&quot;sectlevel4&quot;&gt;
&lt;li&gt;&lt;a href=&quot;#_template&quot;&gt;&lt;code&gt;template&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_containers_2&quot;&gt;Containers&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_development&quot;&gt;Development&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_tests&quot;&gt;Tests&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_license&quot;&gt;License&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_security&quot;&gt;Security&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_code_of_conduct&quot;&gt;Code of Conduct&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_contributions&quot;&gt;Contributions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_developer_certificate_of_origin&quot;&gt;Developer Certificate of Origin&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_versions&quot;&gt;Versions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_community&quot;&gt;Community&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_credits&quot;&gt;Credits&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_features&quot;&gt;Features&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Uses a customizable default environment with a cleaner Object API.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Uses &lt;a href=&quot;https://alchemists.io/projects/containable&quot;&gt;Containable&lt;/a&gt; for filter and tag registries.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Registers filters via a &lt;code&gt;Module&lt;/code&gt;, &lt;a href=&quot;https://alchemists.io/projects/functionable&quot;&gt;Functionable&lt;/a&gt;, commands (see &lt;a href=&quot;https://alchemists.io/articles/command_pattern&quot;&gt;Command Pattern&lt;/a&gt; for details), or containers (see &lt;a href=&quot;https://alchemists.io/projects/containable&quot;&gt;Containable&lt;/a&gt; for details).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Registers tags via classes or containers (see &lt;a href=&quot;https://alchemists.io/projects/containable&quot;&gt;Containable&lt;/a&gt; for details).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Provides a default renderer for quick rendering of templates and associated data.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_requirements&quot;&gt;Requirements&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;olist arabic&quot;&gt;
&lt;ol class=&quot;arabic&quot;&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://www.ruby-lang.org&quot;&gt;Ruby&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://shopify.github.io/liquid/&quot;&gt;Liquid&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_setup&quot;&gt;Setup&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;To install &lt;em&gt;with&lt;/em&gt; security, run:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;c&quot;&gt;# 💡 Skip this line if you already have the public certificate installed.&lt;/span&gt;
gem cert &lt;span class=&quot;nt&quot;&gt;--add&lt;/span&gt; &amp;lt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;curl &lt;span class=&quot;nt&quot;&gt;--compressed&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--location&lt;/span&gt; https://alchemists.io/gems.pem&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
gem &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;superfluid &lt;span class=&quot;nt&quot;&gt;--trust-policy&lt;/span&gt; HighSecurity&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;To install &lt;em&gt;without&lt;/em&gt; security, run:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;bash&quot;&gt;gem &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;superfluid&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;You can also add the gem directly to your project:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;bash&quot;&gt;bundle add superfluid&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Once the gem is installed, you only need to require it:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;superfluid&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_usage&quot;&gt;Usage&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The quickest way to get started is to create a new instance:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;renderer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Superfluid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Then you can render your template and associated data:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;renderer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Hi, this is a {{ value }}.&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;value&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;demo&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The above will yield the following output:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;&quot;Hi, this is a demo.&quot;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The following sections detail how you can configure your environment, register filters, and register tags.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_configuration&quot;&gt;Configuration&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The configuration is used by the environment. This is created for you automatically but if you want an instance of the default configuration, use:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;configuration&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Superfluid&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Configuration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;#&amp;lt;Struct:Superfluid::Configuration:0x00001780&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;default_resource_limits&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{},&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;error_mode&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:strict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;exception_renderer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;#&amp;lt;Proc:0x0000000131200ee0 (lambda)&amp;gt;,&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;file_system&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;#&amp;lt;data Superfluid::Systems::Memory:0x000017b0 templates = {}&amp;gt;,&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;filter_registry&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;#&amp;lt;Superfluid::Registries::Filter:0x000000012f5a1290 @container=Superfluid::Filters::Container, @mode=:strict&amp;gt;,&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;tag_registry&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;#&amp;lt;Superfluid::Registries::Tag:0x000000012f5860d0 @container=Superfluid::Tags::Container&amp;gt;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;As you can see, the configuration is a &lt;a href=&quot;https://alchemists.io/articles/ruby_structs&quot;&gt;Struct&lt;/a&gt; which means you can customize using any of these attributes:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;default_resource_limits&lt;/code&gt;: Limits the resources that a template can consume. Default: &lt;code&gt;{}&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;error_mode&lt;/code&gt;: The error mode (&lt;a href=&quot;https://github.com/Shopify/liquid#error-modes&quot;&gt;details&lt;/a&gt;). Default: &lt;code&gt;:strict&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;exception_renderer&lt;/code&gt;: The function used to render error messages. Default: &lt;code&gt;Core::Identity&lt;/code&gt; (see &lt;a href=&quot;https://alchemists.io/projects/core&quot;&gt;Core&lt;/a&gt;).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;file_system&lt;/code&gt;: The file system. Default: &lt;code&gt;Superfluid::Systems::Memory.new&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;filter_registry&lt;/code&gt;: The filter registry. Default: &lt;code&gt;Superfluid::Registries::Filter.new&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;tag_registry&lt;/code&gt;: The tag registry. Default: &lt;code&gt;Superfluid::Registries::Tag.new&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_environments&quot;&gt;Environments&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;To build the default environment, use:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;environment&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Superfluid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;build&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;To build the default environment directly (which is what the above does), use:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;environment&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Superfluid&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Environment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;If you&amp;#8217;d like to build a custom environment, you can do this several ways. For demonstration purposes, only the &lt;code&gt;error_mode&lt;/code&gt; is used below but all configuration attributes are accepted:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;environment&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Superfluid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;build&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;error_mode: :lax&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;environment&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Superfluid&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Environment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;error_mode: :lax&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;environment&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Superfluid&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Environment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Superfluid&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Configuration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;error_mode: :lax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;You can also freeze the environment&amp;#8201;&amp;#8212;&amp;#8201;which also freezes the filter and tag registries&amp;#8201;&amp;#8212;&amp;#8201;once you&amp;#8217;ve registered any/all filters and tags as follows:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;freeze&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_systems&quot;&gt;Systems&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;These are the file systems used to obtain templates for use within your custom tags. By default, an in memory system is provided for you: &lt;code&gt;Superfluid::Systems::Memory&lt;/code&gt;. &lt;a href=&quot;https://shopify.github.io/liquid/&quot;&gt;Liquid&lt;/a&gt; also provides it&amp;#8217;s own systems as well. Each are described below.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;sect3&quot;&gt;
&lt;h4 id=&quot;_memory&quot;&gt;Memory&lt;/h4&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Provided by this gem. Use to access templates via an in memory file system. This is enabled for you be default when using &lt;code&gt;Superfluid.new&lt;/code&gt; and works in conjunction with the &lt;code&gt;template&lt;/code&gt; tag which is also provided by this gem (see below for details). Again, this system is provided for you but you can be explicit if desired:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;environment&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Superfluid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;build&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;file_system: &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Superfluid&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Systems&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Memory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;renderer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Superfluid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;template&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;~&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;CONTENT&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;
  {% template demo %}
    Hi, this is a {{ subject }}.
  {% endtemplate %}

  {% render &quot;demo&quot;, subject: &quot;demo&quot; %}
&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;CONTENT&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;renderer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;template&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# &quot;Hi, this is a demo.&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect3&quot;&gt;
&lt;h4 id=&quot;_local&quot;&gt;Local&lt;/h4&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Provided by &lt;a href=&quot;https://shopify.github.io/liquid/&quot;&gt;Liquid&lt;/a&gt;. Use to access templates via your local file system within a specific root folder. Usage:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;no&quot;&gt;Pathname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;templates&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;tap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:mkdir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;_demo.liquid&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;tap&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;write&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;{{ salutation }}&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;environment&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Superfluid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;build&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;file_system: &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Liquid&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;LocalFileSystem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Pathname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;templates&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;renderer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Superfluid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;renderer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sx&quot;&gt;%({% include &quot;demo&quot; %}, this is a demo)&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;salutation&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Hi&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# &quot;Hi, this is a demo&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The above configures the local system to look for partials (templates) within the &lt;code&gt;templates&lt;/code&gt; folder. You then reference them via the &lt;code&gt;include&lt;/code&gt; tag.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;By default, this system uses &lt;a href=&quot;https://docs.ruby-lang.org/en/master/Kernel.html#method-i-format&quot;&gt;Kernel#format&lt;/a&gt; syntax to find your partials (i.e. &lt;code&gt;&quot;_%s.liquid&quot;&lt;/code&gt;). If you don&amp;#8217;t like this pattern, you can configure differently when creating a new instance. Example:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;no&quot;&gt;Liquid&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;LocalFileSystem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;/a/path&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;%s.html&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect3&quot;&gt;
&lt;h4 id=&quot;_blank&quot;&gt;Blank&lt;/h4&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Provided by &lt;a href=&quot;https://shopify.github.io/liquid/&quot;&gt;Liquid&lt;/a&gt;. This is an abstract class&amp;#8201;&amp;#8212;&amp;#8201;meant for subclassing&amp;#8201;&amp;#8212;&amp;#8201;because it will fail with a &lt;code&gt;FileSystemError&lt;/code&gt; when &lt;code&gt;read_template_file&lt;/code&gt; isn&amp;#8217;t implemented. Usage:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;environment&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Superfluid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;build&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;file_system: &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Liquid&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;BlankFileSystem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Pathname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;templates&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;renderer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Superfluid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The above does nothing and is benign.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_filters&quot;&gt;Filters&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;By default, &lt;a href=&quot;https://shopify.github.io/liquid/&quot;&gt;Liquid&lt;/a&gt; only allows registration of filters as instance methods on a namespace (&lt;code&gt;Module&lt;/code&gt;). Unfortunately, this leads to terrible design, bad practices, and unnecessarily hard to test objects. You can still register namespaces but this gem encourages the use of commands (see &lt;a href=&quot;https://alchemists.io/articles/command_pattern&quot;&gt;Command Pattern&lt;/a&gt; for further details) and containers via &lt;a href=&quot;https://alchemists.io/projects/containable&quot;&gt;Containable&lt;/a&gt; which allows you tap into Functional Programming by using procs, lambdas, and any object that responds to &lt;code&gt;#call&lt;/code&gt;. This allows you to build&amp;#8201;&amp;#8212;&amp;#8201;and reuse&amp;#8201;&amp;#8212;&amp;#8201;more powerful filters. The following details the different kinds of filters you can use, each broken down by category.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;sect3&quot;&gt;
&lt;h4 id=&quot;_defaults&quot;&gt;Defaults&lt;/h4&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Default filters are provided for you automatically and can be viewed via your environment. Example:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;environment&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Superfluid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;build&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;filter_registry&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;names&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The above will produce a list of all registered filters. These including all filters provided by &lt;a href=&quot;https://shopify.github.io/liquid/&quot;&gt;Liquid&lt;/a&gt; and those unique to this gem which are:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;sect4&quot;&gt;
&lt;h5 id=&quot;_jsonify&quot;&gt;&lt;code&gt;jsonify&lt;/code&gt;&lt;/h5&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Renders objects as JSON. Example:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;renderer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sx&quot;&gt;%({{ data | jsonify }})&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;data&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;a&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}})&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# &quot;{\&quot;a\&quot;:1}&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect4&quot;&gt;
&lt;h5 id=&quot;_parse_json&quot;&gt;&lt;code&gt;parse_json&lt;/code&gt;&lt;/h5&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Parses JSON as a primitive. Example:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;renderer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&quot;{% assign data = payload | parse_json %}{{ data.one }}&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;payload&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;sx&quot;&gt;%({&quot;one&quot;: 1, &quot;two&quot;: 2})&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# &quot;1&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect4&quot;&gt;
&lt;h5 id=&quot;_pluralize&quot;&gt;&lt;code&gt;pluralize&lt;/code&gt;&lt;/h5&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Renders a plural string. Example:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;renderer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sx&quot;&gt;%({{ text | pluralize: 0 }})&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;text&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;apple&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# &quot;0 apples&quot;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;renderer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sx&quot;&gt;%({{ text | pluralize: 1 }})&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;text&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;apple&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# &quot;1 apple&quot;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;renderer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sx&quot;&gt;%({{ text | pluralize: 2 }})&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;text&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;apple&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# &quot;2 apples&quot;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;renderer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sx&quot;&gt;%({{ text | pluralize: 3, &quot;i&quot;, &quot;us&quot; }})&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;text&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;octopus&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# &quot;3 octopi&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect4&quot;&gt;
&lt;h5 id=&quot;_singularize&quot;&gt;&lt;code&gt;singularize&lt;/code&gt;&lt;/h5&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Renders a singular string. Example:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;renderer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sx&quot;&gt;%({{ text | singularize: 0 }})&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;text&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;apples&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# &quot;0 apples&quot;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;renderer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sx&quot;&gt;%({{ text | singularize: 1 }})&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;text&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;apples&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# &quot;1 apple&quot;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;renderer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sx&quot;&gt;%({{ text | singularize: 2 }})&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;text&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;apples&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# &quot;2 apples&quot;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;renderer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sx&quot;&gt;%({{ text | singularize: 1, &quot;i&quot;, &quot;us&quot; }})&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;text&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;octopi&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# &quot;1 octopus&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect4&quot;&gt;
&lt;h5 id=&quot;_trim_end&quot;&gt;&lt;code&gt;trim_end&lt;/code&gt;&lt;/h5&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Renders string with trimmed end. Example:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;renderer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sx&quot;&gt;%({{ text | trim_end: 10 }})&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;text&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;A demo.&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# &quot;A demo.&quot;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;renderer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sx&quot;&gt;%({{ text | trim_end: 10 }})&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;text&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;This is a demo.&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# &quot;This is...&quot;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;renderer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sx&quot;&gt;%({{ text | trim_end: 10, &quot;&quot;, &quot;---&quot; }})&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;text&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;This is a demo.&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# &quot;This is---&quot;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;renderer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sx&quot;&gt;%({{ text | trim_end: 10, &quot;&quot;, &quot;&quot; }})&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;text&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;This is a demo.&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# &quot;This is a&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect4&quot;&gt;
&lt;h5 id=&quot;_trim_middle&quot;&gt;&lt;code&gt;trim_middle&lt;/code&gt;&lt;/h5&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Renders string with trimmed middle. Example:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;renderer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sx&quot;&gt;%({{ text | trim_middle: 20 }})&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;text&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;This is a demo.&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# &quot;A demo.&quot;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;renderer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sx&quot;&gt;%({{ text | trim_middle: 13 }})&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;text&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;This is a demo.&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# &quot;This...demo.&quot;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;renderer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sx&quot;&gt;%({{ text | trim_middle: 13, &quot;--&quot; }})&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;text&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;This is a demo.&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# &quot;This--demo.&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect3&quot;&gt;
&lt;h4 id=&quot;_modules&quot;&gt;Modules&lt;/h4&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Module instance methods are what &lt;a href=&quot;https://shopify.github.io/liquid/&quot;&gt;Liquid&lt;/a&gt; supports by default. You only need to define instance methods within a module and then register your module. Example:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# Namespaces&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Primary&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;echo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;text&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Secondary&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;capitalize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;capitalize&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;suffix&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;count&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Renderer&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;renderer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Superfluid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;register_filters&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Primary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Secondary&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Results&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;renderer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt; &lt;span class=&quot;sx&quot;&gt;%({{ &quot;demo&quot; | echo }})&lt;/span&gt;        &lt;span class=&quot;c1&quot;&gt;# &quot;demo&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;renderer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt; &lt;span class=&quot;sx&quot;&gt;%({{ &quot;demo&quot; | capitalize }})&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# &quot;Demo&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;renderer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt; &lt;span class=&quot;sx&quot;&gt;%({{ &quot;demo&quot; | suffix }})&lt;/span&gt;      &lt;span class=&quot;c1&quot;&gt;# &quot;demo-1&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;renderer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt; &lt;span class=&quot;sx&quot;&gt;%({{ &quot;demo&quot; | suffix: 2 }})&lt;/span&gt;   &lt;span class=&quot;c1&quot;&gt;# &quot;demo-2&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;As you can see, all three methods via the two namespaces are properly registered and immediately available for use. You&amp;#8217;ll also notice multiple namespaces were registered at once but you can register them individually and/or chain them. Examples:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;no&quot;&gt;Superfluid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# Single.&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;register_filter&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Primary&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;# Multiple.&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;register_filters&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Primary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Secondary&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;# Chained.&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;register_filter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Primary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
             &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;register_filter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Secondary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
             &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;register_filters&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Primary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Secondary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect3&quot;&gt;
&lt;h4 id=&quot;_functionables&quot;&gt;Functionables&lt;/h4&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;a href=&quot;https://alchemists.io/projects/functionable&quot;&gt;Functionable&lt;/a&gt; modules are identical to the module examples, as shown above, except you require and extend instead. Example:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;functionable&quot;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Namespaces&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Primary&lt;/span&gt;
  &lt;span class=&quot;kp&quot;&gt;extend&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Functionable&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;echo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;text&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Secondary&lt;/span&gt;
  &lt;span class=&quot;kp&quot;&gt;extend&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Functionable&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;capitalize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;capitalize&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;suffix&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;count&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This allows you to use purely functionable methods (see &lt;a href=&quot;https://alchemists.io/projects/functionable&quot;&gt;Functionable&lt;/a&gt; documentation for details). At this point, you can register your functionable namespaces as follows:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# Renderer&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;renderer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Superfluid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;register_filters&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Primary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Secondary&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Results&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;renderer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt; &lt;span class=&quot;sx&quot;&gt;%({{ &quot;demo&quot; | echo }})&lt;/span&gt;        &lt;span class=&quot;c1&quot;&gt;# &quot;demo&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;renderer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt; &lt;span class=&quot;sx&quot;&gt;%({{ &quot;demo&quot; | capitalize }})&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# &quot;Demo&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;renderer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt; &lt;span class=&quot;sx&quot;&gt;%({{ &quot;demo&quot; | suffix }})&lt;/span&gt;      &lt;span class=&quot;c1&quot;&gt;# &quot;demo-1&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;renderer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt; &lt;span class=&quot;sx&quot;&gt;%({{ &quot;demo&quot; | suffix: 2 }})&lt;/span&gt;   &lt;span class=&quot;c1&quot;&gt;# &quot;demo-2&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Registration is identical to modules:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;no&quot;&gt;Superfluid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# Single.&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;register_filter&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Primary&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;# Multiple.&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;register_filters&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Primary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Secondary&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;# Chained.&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;register_filter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Primary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
             &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;register_filter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Secondary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
             &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;register_filters&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Primary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Secondary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect3&quot;&gt;
&lt;h4 id=&quot;_procs_and_lambdas&quot;&gt;Procs and Lambdas&lt;/h4&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Procs and lambdas are not supported by &lt;a href=&quot;https://shopify.github.io/liquid/&quot;&gt;Liquid&lt;/a&gt; but are via this gem. Example:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# Setup&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;proc&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;capitalize&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;text&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;capitalize&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;suffix&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;count&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Renderer&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;renderer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Superfluid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;register_filters&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;echo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;capitalize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;suffix: &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Results&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;renderer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt; &lt;span class=&quot;sx&quot;&gt;%({{ &quot;demo&quot; | echo }})&lt;/span&gt;        &lt;span class=&quot;c1&quot;&gt;# &quot;demo&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;renderer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt; &lt;span class=&quot;sx&quot;&gt;%({{ &quot;demo&quot; | capitalize }})&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# &quot;Demo&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;renderer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt; &lt;span class=&quot;sx&quot;&gt;%({{ &quot;demo&quot; | suffix }})&lt;/span&gt;      &lt;span class=&quot;c1&quot;&gt;# &quot;demo-1&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;renderer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt; &lt;span class=&quot;sx&quot;&gt;%({{ &quot;demo&quot; | suffix: 2 }})&lt;/span&gt;   &lt;span class=&quot;c1&quot;&gt;# &quot;demo-2&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Registration can be singular, plural, or chained:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;renderer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Superfluid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# Single.&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;register_filter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;echo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:)&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;# Multiple.&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;register_filters&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;echo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;capitalize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;suffix&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:)&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;# Chained.&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;register_filter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;echo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:)&lt;/span&gt;
             &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;register_filter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;capitalize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:)&lt;/span&gt;
             &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;register_filters&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;echo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;capitalize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;suffix&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect3&quot;&gt;
&lt;h4 id=&quot;_classes&quot;&gt;Classes&lt;/h4&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Classes, especially composable classes, are not supported by &lt;a href=&quot;https://shopify.github.io/liquid/&quot;&gt;Liquid&lt;/a&gt; but are via this gem. You only need to ensure you include &lt;code&gt;Core::Composable&lt;/code&gt; and implement the &lt;code&gt;#call&lt;/code&gt; method. Example:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;core&quot;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Suffixer&lt;/span&gt;
  &lt;span class=&quot;kp&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Core&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Composable&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;initialize&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;default: &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@default&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;default&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;suffix&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;suffix&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;

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

  &lt;span class=&quot;nb&quot;&gt;attr_reader&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:default&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Now you can register and render with the above class as follows:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# Renderer&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;renderer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Superfluid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;register_filters&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;suffix: &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Suffixer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Results&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;renderer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt; &lt;span class=&quot;sx&quot;&gt;%({{ &quot;demo&quot; | suffix }})&lt;/span&gt;      &lt;span class=&quot;c1&quot;&gt;# &quot;demo-1&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;renderer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt; &lt;span class=&quot;sx&quot;&gt;%({{ &quot;demo&quot; | suffix: 2 }})&lt;/span&gt;   &lt;span class=&quot;c1&quot;&gt;# &quot;demo-2&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Registration can be singular, plural, or chained:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;suffix&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Suffixer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;renderer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Superfluid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# Single.&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;register_filter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;suffix&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:)&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;# Multiple.&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;register_filters&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;suffix&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:)&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;# Chained.&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;register_filter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;suffix&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:)&lt;/span&gt;
             &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;register_filters&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;suffix&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect3&quot;&gt;
&lt;h4 id=&quot;_containers&quot;&gt;Containers&lt;/h4&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Containers are not supported by &lt;a href=&quot;https://shopify.github.io/liquid/&quot;&gt;Liquid&lt;/a&gt; but are via this gem using &lt;a href=&quot;https://alchemists.io/projects/containable&quot;&gt;Containable&lt;/a&gt;. To use, create a container and then register your dependencies:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;containable&quot;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Container&lt;/span&gt;
  &lt;span class=&quot;kp&quot;&gt;extend&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Containable&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;register&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:echo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;text&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;register&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:suffix&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;count&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Now you can merge the container as follows:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;renderer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Superfluid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;merge_filters&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Container&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;You can also selectively merge by supplying only the filters you care about from the container:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;renderer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Superfluid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;merge_filters&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Container&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:suffix&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Once registered, then you can use as follows:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;renderer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt; &lt;span class=&quot;sx&quot;&gt;%({{ &quot;demo&quot; | echo }})&lt;/span&gt;       &lt;span class=&quot;c1&quot;&gt;# &quot;demo&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;renderer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt; &lt;span class=&quot;sx&quot;&gt;%({{ &quot;demo&quot; | suffix }})&lt;/span&gt;     &lt;span class=&quot;c1&quot;&gt;# &quot;demo-1&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;renderer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt; &lt;span class=&quot;sx&quot;&gt;%({{ &quot;demo&quot; | suffix: 2 }})&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# &quot;demo-2&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;With containers, you have the full capabilities of the &lt;a href=&quot;https://alchemists.io/projects/containable&quot;&gt;Containable&lt;/a&gt;. The above only scratches the surface of what&amp;#8217;s possible.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_tags&quot;&gt;Tags&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;As per &lt;a href=&quot;https://shopify.github.io/liquid/&quot;&gt;Liquid&lt;/a&gt; documentation, tags only need to inherit from &lt;code&gt;Liquid::Tag&lt;/code&gt; and be initialized with &lt;code&gt;tag_name&lt;/code&gt;, &lt;code&gt;factor&lt;/code&gt;, and &lt;code&gt;tokens&lt;/code&gt; parameters. Then you can implement a render method which accepts a &lt;code&gt;context&lt;/code&gt;. Example:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# Tag&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Sample&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Liquid&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Block&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;sub&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&amp;lt;placeholder&amp;gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;rand&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Renderer&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;renderer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Superfluid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;register_tag&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:sample&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Sample&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Results&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;renderer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;{% sample %}Your value is: &amp;lt;placeholder&amp;gt;.{% endsample %}&quot;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# &quot;Your value is: 80.&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;You can also register single or multiple tags at once:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;renderer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Superfluid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# Single.&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;register_tag&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:sample&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Sample&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;# Multiple.&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;register_tags&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;one: &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Sample&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;two: &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Sample&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;# Chained.&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;register_tag&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:sample&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Sample&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
             &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;register_tags&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;one: &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Sample&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;two: &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Sample&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect3&quot;&gt;
&lt;h4 id=&quot;_defaults_2&quot;&gt;Defaults&lt;/h4&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;You have access to all tags supported by &lt;a href=&quot;https://shopify.github.io/liquid/&quot;&gt;Liquid&lt;/a&gt; including the tags provided by this gem (which is only the &lt;code&gt;template&lt;/code&gt; tag at the moment).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;sect4&quot;&gt;
&lt;h5 id=&quot;_template&quot;&gt;&lt;code&gt;template&lt;/code&gt;&lt;/h5&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This tag must be used with the &lt;code&gt;Memory&lt;/code&gt; system (see &lt;em&gt;Systems&lt;/em&gt;, mentioned earlier, for details). You can use this tag as follows:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;renderer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Superfluid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;template&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;~&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;CONTENT&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;
  {% template demo %}
    Hi, this is a {{ subject }}.
  {% endtemplate %}

  {% render &quot;demo&quot;, subject: &quot;demo&quot; %}
&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;CONTENT&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;renderer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;template&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# &quot;Hi, this is a demo.&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;As you can see this tag requires two steps:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;olist arabic&quot;&gt;
&lt;ol class=&quot;arabic&quot;&gt;
&lt;li&gt;
&lt;p&gt;Define by using the &lt;code&gt;template&lt;/code&gt; tag followed by a unique name for your template (in this case: &lt;code&gt;demo&lt;/code&gt;). You can then use any filters and/or additional tags with your template. Finally, close the tag with &lt;code&gt;endtemplate&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Render your template by using &lt;code&gt;render&lt;/code&gt; followed by the unique name of your template (i.e. &lt;code&gt;demo&lt;/code&gt;) and any attributes you need to provide to the template.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The above allows you to define multiple templates for rendering later. Great for situations where you want to organize your in memory code for final later rendering.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect3&quot;&gt;
&lt;h4 id=&quot;_containers_2&quot;&gt;Containers&lt;/h4&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Containers are not supported by &lt;a href=&quot;https://shopify.github.io/liquid/&quot;&gt;Liquid&lt;/a&gt; but are via this gem using &lt;a href=&quot;https://alchemists.io/projects/containable&quot;&gt;Containable&lt;/a&gt;. To use, create a container and then register your dependencies:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;containable&quot;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Container&lt;/span&gt;
  &lt;span class=&quot;kp&quot;&gt;extend&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Containable&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;register&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:sample&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Sample&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Now you can merge the container as follows:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;renderer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Superfluid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;merge_tags&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Container&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;You can also selectively merge by supplying only the tags you care about from the container:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;renderer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Superfluid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;merge_tags&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Container&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:sample&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Once registered, then you can use as follows:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;renderer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;{% sample %}Your value is: &amp;lt;placeholder&amp;gt;.{% endsample %}&quot;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# &quot;Your value is: 85.&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;With containers, you have the full capabilities of the &lt;a href=&quot;https://alchemists.io/projects/containable&quot;&gt;Containable&lt;/a&gt;. The above only scratches the surface of what&amp;#8217;s possible.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_development&quot;&gt;Development&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;To contribute, run:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;bash&quot;&gt;git clone https://github.com/bkuhlmann/superfluid
&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;superfluid
bin/setup&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;You can also use the IRB console for direct access to all objects:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;bash&quot;&gt;bin/console&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_tests&quot;&gt;Tests&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;To test, run:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;bash&quot;&gt;bin/rake&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_license&quot;&gt;&lt;a href=&quot;https://alchemists.io/policies/license&quot;&gt;License&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_security&quot;&gt;&lt;a href=&quot;https://alchemists.io/policies/security&quot;&gt;Security&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_code_of_conduct&quot;&gt;&lt;a href=&quot;https://alchemists.io/policies/code_of_conduct&quot;&gt;Code of Conduct&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_contributions&quot;&gt;&lt;a href=&quot;https://alchemists.io/policies/contributions&quot;&gt;Contributions&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_developer_certificate_of_origin&quot;&gt;&lt;a href=&quot;https://alchemists.io/policies/developer_certificate_of_origin&quot;&gt;Developer Certificate of Origin&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_versions&quot;&gt;&lt;a href=&quot;https://alchemists.io/projects/superfluid/versions&quot;&gt;Versions&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_community&quot;&gt;&lt;a href=&quot;https://alchemists.io/community&quot;&gt;Community&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_credits&quot;&gt;Credits&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Built with &lt;a href=&quot;https://alchemists.io/projects/gemsmith&quot;&gt;Gemsmith&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Engineered by &lt;a href=&quot;https://alchemists.io/team/brooke_kuhlmann&quot;&gt;Brooke Kuhlmann&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
</content>
    <id>https://alchemists.io/projects/superfluid</id>
    <link href="https://alchemists.io/projects/superfluid"/>
    <published>2026-08-30T20:54:20+00:00</published>
    <rights>2026</rights>
    <title>Superfluid Project</title>
    <updated>2026-10-14T23:33:08+00:00</updated>
    <dc:date>2026-10-14T23:33:08+00:00</dc:date>
  </entry>
  <entry>
    <author>
      <name>Brooke Kuhlmann</name>
      <uri>https://alchemists.io/team/brooke_kuhlmann</uri>
    </author>
    <category term="projects"
      label="Projects"/>
    <content type="html">&lt;div align=&quot;center&quot;&gt;
  &lt;a href=&quot;/projects/rfc-api-problem&quot;&gt;
    &lt;img src=&quot;/images/projects/rfc-api-problem/logo.png&quot; width=&quot;200&quot; height=&quot;200&quot;&gt;
  &lt;/a&gt;

  &lt;h1&gt;&lt;a href=&quot;/projects/rfc-api-problem&quot;&gt;RFC API Problem&lt;/a&gt;&lt;/h1&gt;
&lt;/div&gt;

&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;RFC API Problem implements &lt;a href=&quot;https://www.rfc-editor.org/rfc/rfc9457&quot;&gt;RFC 9457&lt;/a&gt;: Problem Details for HTTP APIs. This allows you to produce HTTP error responses that are structured, machine readable, and consistent.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&quot;toc&quot; class=&quot;toc&quot;&gt;
&lt;div id=&quot;toctitle&quot; class=&quot;title&quot;&gt;Table of Contents&lt;/div&gt;
&lt;ul class=&quot;sectlevel1&quot;&gt;
&lt;li&gt;&lt;a href=&quot;#_features&quot;&gt;Features&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_requirements&quot;&gt;Requirements&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_setup&quot;&gt;Setup&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_usage&quot;&gt;Usage&lt;/a&gt;
&lt;ul class=&quot;sectlevel2&quot;&gt;
&lt;li&gt;&lt;a href=&quot;#_members&quot;&gt;Members&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_media_types&quot;&gt;Media Types&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_payload&quot;&gt;Payload&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_json&quot;&gt;JSON&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_xml&quot;&gt;XML&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_examples&quot;&gt;Examples&lt;/a&gt;
&lt;ul class=&quot;sectlevel3&quot;&gt;
&lt;li&gt;&lt;a href=&quot;#_hateoas&quot;&gt;HATEOAS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_semantic_structure&quot;&gt;Semantic Structure&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_development&quot;&gt;Development&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_tests&quot;&gt;Tests&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_resources&quot;&gt;Resources&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_license&quot;&gt;License&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_security&quot;&gt;Security&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_code_of_conduct&quot;&gt;Code of Conduct&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_contributions&quot;&gt;Contributions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_developer_certificate_of_origin&quot;&gt;Developer Certificate of Origin&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_versions&quot;&gt;Versions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_community&quot;&gt;Community&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_credits&quot;&gt;Credits&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_features&quot;&gt;Features&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Provides JSON and XML serialization and deserialization.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Provides HTTP header and media type support.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_requirements&quot;&gt;Requirements&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;olist arabic&quot;&gt;
&lt;ol class=&quot;arabic&quot;&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://www.ruby-lang.org&quot;&gt;Ruby&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_setup&quot;&gt;Setup&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;To install &lt;em&gt;with&lt;/em&gt; security, run:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;c&quot;&gt;# 💡 Skip this line if you already have the public certificate installed.&lt;/span&gt;
gem cert &lt;span class=&quot;nt&quot;&gt;--add&lt;/span&gt; &amp;lt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;curl &lt;span class=&quot;nt&quot;&gt;--compressed&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--location&lt;/span&gt; https://alchemists.io/gems.pem&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
gem &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;rfc-api-problem &lt;span class=&quot;nt&quot;&gt;--trust-policy&lt;/span&gt; HighSecurity&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;To install &lt;em&gt;without&lt;/em&gt; security, run:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;bash&quot;&gt;gem &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;rfc-api-problem&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;You can also add the gem directly to your project:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;bash&quot;&gt;bundle add rfc-api-problem&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Once the gem is installed, you only need to require it:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;rfc/api/problem&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_usage&quot;&gt;Usage&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The quickest way to get started is to create a new instance and then cast as JSON or XML:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;payload&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;RFC&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;API&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Problem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;type: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;https://demo.io/problem_details/timeout&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;status: &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;413&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;detail: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;You&#39;ve exceeded the 5MB upload limit.&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;instance: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/profile/3a1bfd54-ae6c-4a61-8d0d-90c132428dc3&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;payload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_json&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# {&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   &quot;type&quot; =&amp;gt; &quot;https://demo.io/problem_details/timeout&quot;,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   &quot;title&quot; =&amp;gt; &quot;Content Too Large&quot;,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   &quot;status&quot; =&amp;gt; 413,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   &quot;detail&quot; =&amp;gt; &quot;You&#39;ve exceeded the 5MB upload limit.&quot;,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   &quot;instance&quot; =&amp;gt; &quot;/profile/3a1bfd54-ae6c-4a61-8d0d-90c132428dc3&quot;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# }&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;payload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_xml&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# &amp;lt;?xml version=&#39;1.0&#39; encoding=&#39;UTF-8&#39;?&amp;gt;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# &amp;lt;problem xmlns=&#39;urn:ietf:rfc:7807&#39;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   &amp;lt;type&amp;gt;https://demo.io/problem_details/timeout&amp;lt;/type&amp;gt;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   &amp;lt;title&amp;gt;Content Too Large&amp;lt;/title&amp;gt;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   &amp;lt;status&amp;gt;413&amp;lt;/status&amp;gt;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   &amp;lt;detail&amp;gt;You&amp;amp;apos;ve exceeded the 5MB upload limit.&amp;lt;/detail&amp;gt;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   &amp;lt;instance&amp;gt;/profile/3a1bfd54-ae6c-4a61-8d0d-90c132428dc3&amp;lt;/instance&amp;gt;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# &amp;lt;/problem&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;💡 You can also use &lt;code&gt;RFC::API::Problem.new&lt;/code&gt; to create instances if you don&amp;#8217;t like &lt;code&gt;RFC::API::Problem.[]&lt;/code&gt;, as shown above, but &lt;code&gt;.[]&lt;/code&gt; is preferred.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_members&quot;&gt;Members&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;As briefly shown above, the minimum members (attributes) that make up problem details are:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;type&lt;/code&gt; (optional): The full (or relative) URI that links to additional documentation. Default: &lt;code&gt;&quot;about:blank&quot;&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;status&lt;/code&gt; (optional): The &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status&quot;&gt;HTTP status code&lt;/a&gt; (or symbol) that must match your HTTP status code. Default: &lt;code&gt;nil&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;title&lt;/code&gt; (optional): The HTTP status label that must match your HTTP status code label. Default: HTTP status label (dynamically computed based on code unless overwritten).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;detail&lt;/code&gt; (optional): The human readable reason for the error (should not include debugging information). Default: &lt;code&gt;nil&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;instance&lt;/code&gt; (optional): The full (or relative) URI that represents the cause of the error. Default: &lt;code&gt;nil&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;extensions&lt;/code&gt; (optional): A free form hash of additional details. Default: &lt;code&gt;{}&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_media_types&quot;&gt;Media Types&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;For convenience, you can obtain the necessary media types for your HTTP headers as follows:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;no&quot;&gt;RFC&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;API&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Problem&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;MEDIA_TYPE_JSON&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# &quot;application/problem+json&quot;&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;RFC&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;API&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Problem&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;MEDIA_TYPE_XML&lt;/span&gt;   &lt;span class=&quot;c1&quot;&gt;# &quot;application/problem+xml&quot;&lt;/span&gt;

&lt;span class=&quot;no&quot;&gt;RFC&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;API&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Problem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;media_type_for&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:json&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# &quot;application/problem+json&quot;&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;RFC&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;API&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Problem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;media_type_for&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:xml&lt;/span&gt;   &lt;span class=&quot;c1&quot;&gt;# &quot;application/problem+xml&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_payload&quot;&gt;Payload&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;You&amp;#8217;ll always get a &lt;code&gt;RFC::API::Problem::Payload&lt;/code&gt; object answered back when using &lt;code&gt;RFC::API::Problem.[]&lt;/code&gt; or &lt;code&gt;RFC::API::Problem.new&lt;/code&gt; for which you can cast to JSON, XML, and other types. There are few conveniences provided for you when constructing a new payload. For instance, you can also use status to set default title:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;no&quot;&gt;RFC&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;API&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Problem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;status: &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;413&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# #&amp;lt;data RFC::API::Problem::Payload:0x00002950&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   detail = nil,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   extensions = {},&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   instance = nil,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   status = 413,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   title = &quot;Content Too Large&quot;,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   type = &quot;about:blank&quot;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# &amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Notice that standard HTTP 413 title of &quot;Content Too Large&quot; is provided for you but only if you don&amp;#8217;t supply a title. This works for symbols too. Example:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;no&quot;&gt;RFC&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;API&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Problem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;status: :bad_request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# #&amp;lt;data RFC::API::Problem::Payload:0x00002970&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   detail = nil,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   extensions = {},&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   instance = nil,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   status = 400,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   title = &quot;Bad Request&quot;,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   type = &quot;about:blank&quot;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# &amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This is similar to the above, but notice the status is cast to an integer while the title is also populated for you. Using either an integer or symbol for the HTTP status is handy for situations where you don&amp;#8217;t need a custom title and prefer the default HTTP title.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Due to the payload being a &lt;a href=&quot;https://alchemists.io/articles/ruby_data&quot;&gt;Data&lt;/a&gt; object, you have all of the standard methods available to you which are frozen by default. That said, you can still add or check for extensions after the fact. Example:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code&gt;payload = RFC::API::Problem[status: :forbidden]

payload.add_extension(:account, &quot;/accounts/1&quot;)
       .add_extension(:balance, 50)

# #&amp;lt;data RFC::API::Problem::Payload:0x000029a0
#   detail = nil,
#   extensions = {
#     account: &quot;/accounts/1&quot;,
#     balance: 50
#   },
#   instance = nil,
#   status = 403,
#   title = &quot;Forbidden&quot;,
#   type = &quot;about:blank&quot;
# &amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Given the above, you can also check if an extension exists:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;payload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;extension?&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:account&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# true&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;payload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;extension?&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:bogus&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# false&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_json&quot;&gt;JSON&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Both serialization and deserialization of JSON is supported. For example, given the following payload:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;payload&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;RFC&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;API&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Problem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;type: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;https://demo.io/problem_details/out_of_credit&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;title: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;You do not have enough credit.&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;status: &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;403&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;detail: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Your current balance is 30, but that costs 50.&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;instance: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/accounts/1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;extensions: &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;ss&quot;&gt;balance: &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;30&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;ss&quot;&gt;accounts: &lt;/span&gt;&lt;span class=&quot;sx&quot;&gt;%w[/accounts/1 /accounts/10]&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This means you can serialize as follows:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;payload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_json&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# &quot;{\&quot;type\&quot;:\&quot;https://demo.io/problem_details/out_of_credit\&quot;,\&quot;title\&quot;:\&quot;You do not have enough credit.\&quot;,\&quot;status\&quot;:403,\&quot;detail\&quot;:\&quot;Your current balance is 30, but that costs 50.\&quot;,\&quot;instance\&quot;:\&quot;/accounts/1\&quot;,\&quot;balance\&quot;:30,\&quot;accounts\&quot;:[\&quot;/accounts/1\&quot;,\&quot;/accounts/10\&quot;]}&quot;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;payload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_json&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;indent: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;  &quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;space: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot; &quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;object_nl: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;array_nl: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# {&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   &quot;type&quot;: &quot;https://demo.io/problem_details/out_of_credit&quot;,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   &quot;title&quot;: &quot;You do not have enough credit.&quot;,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   &quot;status&quot;: 403,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   &quot;detail&quot;: &quot;Your current balance is 30, but that costs 50.&quot;,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   &quot;instance&quot;: &quot;/accounts/1&quot;,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   &quot;balance&quot;: 30,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   &quot;accounts&quot;: [&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#     &quot;/accounts/1&quot;,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#     &quot;/accounts/10&quot;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   ]&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;💡 All of the &lt;a href=&quot;https://docs.ruby-lang.org/en/master/JSON.html#module-JSON-label-Output+Options&quot;&gt;JSON&lt;/a&gt; output options are available to you when casting to JSON.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;You can also deserialize by taking the result of the above and turning the raw JSON back into a &lt;code&gt;RFC::API::Problem::Payload&lt;/code&gt;:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;no&quot;&gt;RFC&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;API&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Problem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;from_json&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;{&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;https://demo.io/problem_details/out_of_credit&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;You do not have enough credit.&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;status&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;:403,&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;detail&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Your current balance is 30, but that costs 50.&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;instance&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/accounts/1&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;balance&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;:30,&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;accounts&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;:[&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/accounts/1&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/accounts/10&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;]}&quot;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# #&amp;lt;data RFC::API::Problem::Payload:0x00002d10&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   detail = &quot;Your current balance is 30, but that costs 50.&quot;,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   extensions = {&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#      balance: 30,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#     accounts: [&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#       &quot;/accounts/1&quot;,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#       &quot;/accounts/10&quot;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#     ]&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   },&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   instance = &quot;/accounts/1&quot;,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   status = 403,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   title = &quot;You do not have enough credit.&quot;,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   type = &quot;https://demo.io/problem_details/out_of_credit&quot;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# &amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_xml&quot;&gt;XML&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;XML is supported too but isn&amp;#8217;t as robust as JSON support, at the moment. This is mostly due to the fact that extensions can be deeply nested so your mileage may vary. For example, given the following payload:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;payload&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;RFC&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;API&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Problem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;type: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;https://demo.io/problem_details/out_of_credit&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;title: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;You do not have enough credit.&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;status: &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;403&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;detail: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Your current balance is 30, but that costs 50.&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;instance: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/accounts/1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;extensions: &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;ss&quot;&gt;balance: &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;30&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;ss&quot;&gt;accounts: &lt;/span&gt;&lt;span class=&quot;sx&quot;&gt;%w[/accounts/1 /accounts/10]&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This means you can serialize as follows:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;payload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_xml&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# &quot;&amp;lt;?xml version=&#39;1.0&#39; encoding=&#39;UTF-8&#39;?&amp;gt;&amp;lt;problem xmlns=&#39;urn:ietf:rfc:7807&#39;&amp;gt;&amp;lt;type&amp;gt;https://demo.io/problem_details/out_of_credit&amp;lt;/type&amp;gt;&amp;lt;title&amp;gt;You do not have enough credit.&amp;lt;/title&amp;gt;&amp;lt;status&amp;gt;403&amp;lt;/status&amp;gt;&amp;lt;detail&amp;gt;Your current balance is 30, but that costs 50.&amp;lt;/detail&amp;gt;&amp;lt;instance&amp;gt;/accounts/1&amp;lt;/instance&amp;gt;&amp;lt;balance&amp;gt;30&amp;lt;/balance&amp;gt;&amp;lt;accounts&amp;gt;&amp;lt;i&amp;gt;/accounts/1&amp;lt;/i&amp;gt;&amp;lt;i&amp;gt;/accounts/10&amp;lt;/i&amp;gt;&amp;lt;/accounts&amp;gt;&amp;lt;/problem&amp;gt;&quot;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;payload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_xml&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;indent: &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# &amp;lt;?xml version=&#39;1.0&#39; encoding=&#39;UTF-8&#39;?&amp;gt;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# &amp;lt;problem xmlns=&#39;urn:ietf:rfc:7807&#39;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   &amp;lt;type&amp;gt;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#     https://demo.io/problem_details/out_of_credit&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   &amp;lt;/type&amp;gt;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   &amp;lt;title&amp;gt;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#     You do not have enough credit.&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   &amp;lt;/title&amp;gt;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   &amp;lt;status&amp;gt;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#     403&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   &amp;lt;/status&amp;gt;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   &amp;lt;detail&amp;gt;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#     Your current balance is 30, but that costs 50.&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   &amp;lt;/detail&amp;gt;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   &amp;lt;instance&amp;gt;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#     /accounts/1&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   &amp;lt;/instance&amp;gt;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   &amp;lt;balance&amp;gt;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#     30&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   &amp;lt;/balance&amp;gt;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   &amp;lt;accounts&amp;gt;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#     &amp;lt;i&amp;gt;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#       /accounts/1&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#     &amp;lt;/i&amp;gt;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#     &amp;lt;i&amp;gt;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#       /accounts/10&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#     &amp;lt;/i&amp;gt;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   &amp;lt;/accounts&amp;gt;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# &amp;lt;/problem&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;💡 All of the &lt;a href=&quot;https://ruby.github.io/rexml/REXML/Document.html#method-i-write&quot;&gt;REXML::Document.write&lt;/a&gt; output options are available to you when casting to XML.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;You can also deserialize by taking the result of the above and turning the raw JSON back into a &lt;code&gt;RFC::API::Problem::Payload&lt;/code&gt;:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;payload&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;RFC&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;API&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Problem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;from_xml&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;~&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;XML&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;
  &amp;lt;?xml version=&#39;1.0&#39; encoding=&#39;UTF-8&#39;?&amp;gt;
  &amp;lt;problem xmlns=&#39;urn:ietf:rfc:7807&#39;&amp;gt;
    &amp;lt;type&amp;gt;https://demo.io/problem_details/out_of_credit&amp;lt;/type&amp;gt;
    &amp;lt;title&amp;gt;You do not have enough credit.&amp;lt;/title&amp;gt;
    &amp;lt;status&amp;gt;403&amp;lt;/status&amp;gt;
    &amp;lt;detail&amp;gt;Your current balance is 30, but that costs 50.&amp;lt;/detail&amp;gt;
    &amp;lt;instance&amp;gt;/accounts/1&amp;lt;/instance&amp;gt;
    &amp;lt;balance&amp;gt;30&amp;lt;/balance&amp;gt;
    &amp;lt;accounts&amp;gt;
      &amp;lt;i&amp;gt;/accounts/1&amp;lt;/i&amp;gt;
      &amp;lt;i&amp;gt;/accounts/10&amp;lt;/i&amp;gt;
    &amp;lt;/accounts&amp;gt;
  &amp;lt;/problem&amp;gt;
&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;XML&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# #&amp;lt;data RFC::API::Problem::Payload:0x00000940&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   detail = &quot;Your current balance is 30, but that costs 50.&quot;,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   extensions = {&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#      balance: &quot;30&quot;,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#     accounts: [&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#       &quot;/accounts/1&quot;,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#       &quot;/accounts/10&quot;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#     ]&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   },&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   instance = &quot;/accounts/1&quot;,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   status = 403,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   title = &quot;You do not have enough credit.&quot;,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   type = &quot;https://demo.io/problem_details/out_of_credit&quot;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# &amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_examples&quot;&gt;Examples&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;There is a lot of useful information you can provide in your problem details depending on the context you are working in. Some have been shown above but here&amp;#8217;s a few more that might be of interest.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;sect3&quot;&gt;
&lt;h4 id=&quot;_hateoas&quot;&gt;HATEOAS&lt;/h4&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;With &lt;a href=&quot;https://nordicapis.com/tools-to-make-hateoas-compliance-easier&quot;&gt;HATEOAS&lt;/a&gt;, you can provide additional information and links for which the client can understand what next actions are available. The below example shows how you can provide additional resources for clients to adjust accordingly:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;no&quot;&gt;RFC&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;API&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Problem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;type: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;https://demo.io/problem_details/rate_limit&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;title: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Rate limit exceeded&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;status: &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;429&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;detail: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;You have exceeded your rate limit of 150 requests per minute&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;instance: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/articles&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;extensions: &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;ss&quot;&gt;retry_after: &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;ss&quot;&gt;links: &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;ss&quot;&gt;ref: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;self&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;ss&quot;&gt;href: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/articles&quot;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;ss&quot;&gt;rel: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;retry&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;ss&quot;&gt;href: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/articles&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;ss&quot;&gt;title: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Retry after five minutes&quot;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;ss&quot;&gt;rel: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;status&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;ss&quot;&gt;href: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/statuses/rate_limit&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;ss&quot;&gt;title: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Check current rate limit usage&quot;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect3&quot;&gt;
&lt;h4 id=&quot;_semantic_structure&quot;&gt;Semantic Structure&lt;/h4&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In other situations, you might need a different structure in order to aid clients that might be AI driven which needs a semantically structured response in order to course correct. Example:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;no&quot;&gt;RFC&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;API&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Problem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;type: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;https://demo.io/problem_details/invalid_field&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;title: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Invalid field value&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;status: &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;400&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;detail: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;The category requested doesn&#39;t exist&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;instance: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/categories&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;extensions: &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;ss&quot;&gt;parameters: &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;ss&quot;&gt;category_id: &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;123&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;ss&quot;&gt;suggestions: &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;s2&quot;&gt;&quot;ruby&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;s2&quot;&gt;&quot;git&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;s2&quot;&gt;&quot;htmx&quot;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;With the above, the client now knows what parameters where invalid along with relevant suggestions for proceeding. Even better, the suggestions implicitly show the types of IDs that are required.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_development&quot;&gt;Development&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;To contribute, run:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;bash&quot;&gt;git clone https://github.com/bkuhlmann/rfc-api-problem
&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;rfc-api-problem
bin/setup&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;You can also use the IRB console for direct access to all objects:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;bash&quot;&gt;bin/console&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_tests&quot;&gt;Tests&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;To test, run:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;bash&quot;&gt;bin/rake&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_resources&quot;&gt;Resources&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;You can find additional resources here:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://www.iana.org/assignments/http-problem-types/http-problem-types.xhtml&quot;&gt;IANA Hypertext Transfer Protocol (HTTP) Problem Types&lt;/a&gt;: A registered list of problem types you can use.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/protocol-registries/http-problem-types&quot;&gt;HTTP Problem Type Registration Requests&lt;/a&gt;: Where you can register new problem types.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_license&quot;&gt;&lt;a href=&quot;https://alchemists.io/policies/license&quot;&gt;License&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_security&quot;&gt;&lt;a href=&quot;https://alchemists.io/policies/security&quot;&gt;Security&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_code_of_conduct&quot;&gt;&lt;a href=&quot;https://alchemists.io/policies/code_of_conduct&quot;&gt;Code of Conduct&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_contributions&quot;&gt;&lt;a href=&quot;https://alchemists.io/policies/contributions&quot;&gt;Contributions&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_developer_certificate_of_origin&quot;&gt;&lt;a href=&quot;https://alchemists.io/policies/developer_certificate_of_origin&quot;&gt;Developer Certificate of Origin&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_versions&quot;&gt;&lt;a href=&quot;https://alchemists.io/projects/rfc-api-problem/versions&quot;&gt;Versions&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_community&quot;&gt;&lt;a href=&quot;https://alchemists.io/community&quot;&gt;Community&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_credits&quot;&gt;Credits&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Built with &lt;a href=&quot;https://alchemists.io/projects/gemsmith&quot;&gt;Gemsmith&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Engineered by &lt;a href=&quot;https://alchemists.io/team/brooke_kuhlmann&quot;&gt;Brooke Kuhlmann&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
</content>
    <id>https://alchemists.io/projects/rfc-api-problem</id>
    <link href="https://alchemists.io/projects/rfc-api-problem"/>
    <published>2026-08-22T20:29:24+00:00</published>
    <rights>2026</rights>
    <title>RFC API Problem Project</title>
    <updated>2026-10-14T23:32:15+00:00</updated>
    <dc:date>2026-10-14T23:32:15+00:00</dc:date>
  </entry>
  <entry>
    <author>
      <name>Brooke Kuhlmann</name>
      <uri>https://alchemists.io/team/brooke_kuhlmann</uri>
    </author>
    <category term="projects"
      label="Projects"/>
    <content type="html">&lt;div align=&quot;center&quot;&gt;
  &lt;a href=&quot;/projects/rfc-web-link&quot;&gt;
    &lt;img src=&quot;/images/projects/rfc-web-link/logo.png&quot; width=&quot;200&quot; height=&quot;200&quot;&gt;
  &lt;/a&gt;

  &lt;h1&gt;&lt;a href=&quot;/projects/rfc-web-link&quot;&gt;RFC Web Link&lt;/a&gt;&lt;/h1&gt;
&lt;/div&gt;

&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;RFC Web Link implements &lt;a href=&quot;https://www.rfc-editor.org/info/rfc8288&quot;&gt;RFC 8288&lt;/a&gt;: Web Linking. This allows you to process links via the HTTP &lt;code&gt;link&lt;/code&gt; header when processing HTTP responses. For example, the following demonstrates a HTTP link header which links to a previous and next article:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;link: &amp;lt;https://demo.io/articles?page=1&amp;gt;; rel=&quot;previous&quot;; title=&quot;Previous&quot;,
      &amp;lt;https://demo.io/articles?page=3&amp;gt;; rel=&quot;next&quot;; title=&quot;Next&quot;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The above parses each line, delimited by a comma (&lt;code&gt;,&lt;/code&gt;), and then each pair (attribute) in the line as delimited by a semicolon (&lt;code&gt;;&lt;/code&gt;). This is not something you want to reinvent for each application you maintain so this gem handles the parsing (and creation) of HTTP &lt;code&gt;link&lt;/code&gt; headers so you can stay focused on your own business logic.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&quot;toc&quot; class=&quot;toc&quot;&gt;
&lt;div id=&quot;toctitle&quot; class=&quot;title&quot;&gt;Table of Contents&lt;/div&gt;
&lt;ul class=&quot;sectlevel1&quot;&gt;
&lt;li&gt;&lt;a href=&quot;#_features&quot;&gt;Features&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_requirements&quot;&gt;Requirements&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_setup&quot;&gt;Setup&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_usage&quot;&gt;Usage&lt;/a&gt;
&lt;ul class=&quot;sectlevel2&quot;&gt;
&lt;li&gt;&lt;a href=&quot;#_root_uri&quot;&gt;Root URI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_delimiters&quot;&gt;Delimiters&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_attributes&quot;&gt;Attributes&lt;/a&gt;
&lt;ul class=&quot;sectlevel3&quot;&gt;
&lt;li&gt;&lt;a href=&quot;#_anchor&quot;&gt;anchor&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_hreflang&quot;&gt;hreflang&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_media&quot;&gt;media&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_rel&quot;&gt;rel&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_title&quot;&gt;title&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_type&quot;&gt;type&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_extensions&quot;&gt;Extensions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_models&quot;&gt;Models&lt;/a&gt;
&lt;ul class=&quot;sectlevel3&quot;&gt;
&lt;li&gt;&lt;a href=&quot;#_list&quot;&gt;List&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_link&quot;&gt;Link&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_pair&quot;&gt;Pair&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_error_handling&quot;&gt;Error Handling&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_development&quot;&gt;Development&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_tests&quot;&gt;Tests&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_license&quot;&gt;License&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_security&quot;&gt;Security&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_code_of_conduct&quot;&gt;Code of Conduct&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_contributions&quot;&gt;Contributions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_developer_certificate_of_origin&quot;&gt;Developer Certificate of Origin&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_versions&quot;&gt;Versions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_community&quot;&gt;Community&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_credits&quot;&gt;Credits&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_features&quot;&gt;Features&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Implements &lt;a href=&quot;https://www.rfc-editor.org/info/rfc8288&quot;&gt;RFC 8288&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Parses web link headers into whole value objects for processing and/or inspection.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Provides explicit or implicit casting of whole value objects into a web links.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_requirements&quot;&gt;Requirements&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;olist arabic&quot;&gt;
&lt;ol class=&quot;arabic&quot;&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://www.ruby-lang.org&quot;&gt;Ruby&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_setup&quot;&gt;Setup&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;To install &lt;em&gt;with&lt;/em&gt; security, run:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;c&quot;&gt;# 💡 Skip this line if you already have the public certificate installed.&lt;/span&gt;
gem cert &lt;span class=&quot;nt&quot;&gt;--add&lt;/span&gt; &amp;lt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;curl &lt;span class=&quot;nt&quot;&gt;--compressed&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--location&lt;/span&gt; https://alchemists.io/gems.pem&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
gem &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;rfc-web-link &lt;span class=&quot;nt&quot;&gt;--trust-policy&lt;/span&gt; HighSecurity&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;To install &lt;em&gt;without&lt;/em&gt; security, run:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;bash&quot;&gt;gem &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;rfc-web-link&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;You can also add the gem directly to your project:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;bash&quot;&gt;bundle add rfc-web-link&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Once the gem is installed, you only need to require it:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;rfc/web/link&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_usage&quot;&gt;Usage&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The fastest way to get started is to create a new instance of the parser that you can reuse upon each HTTP request. Example:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;parser&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;RFC&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Web&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Link&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;https://demo.io&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Then you can use the &lt;code&gt;parser&lt;/code&gt; instance to parse HTTP headers and build lists you can interact with:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;parser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;link&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&amp;lt;/articles&amp;gt;; rel=index&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The above will yield the following set of links (in this case, only with a single link):&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;c1&quot;&gt;#&amp;lt;data RFC::Web::Link::Models::List:0x00000900&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;links&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;#&amp;lt;data RFC::Web::Link::Models::Link:0x00000920&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;pairs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;                                                                                                                                                                                  &lt;span class=&quot;c1&quot;&gt;#&amp;lt;data RFC::Web::Link::Models::Pair:0x00000940&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;delimiter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;=&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;encoding&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;rel&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;language&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;index&quot;&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;uri&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;https://demo.io/articles&quot;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;As you can see, you get an immutable &lt;a href=&quot;https://alchemists.io/articles/ruby_data&quot;&gt;Data&lt;/a&gt; (whole value) object for which you can directly access all attributes.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_root_uri&quot;&gt;Root URI&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;A root URI (&lt;code&gt;root_uri&lt;/code&gt;) must be supplied in order to resolve all relative URIs as absolute URIs. Generally, the &lt;code&gt;root_uri&lt;/code&gt; is your host (i.e. primary domain). There are a few ways you can supply the root URI:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;strong&gt;Initialization&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The following sets the root URI globally so you only have to define it once:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;parser&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;RFC&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Web&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Link&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;https://demo.io&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;strong&gt;Call&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The following sets the root URI per call.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;parser&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;RFC&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Web&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Link&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;parser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;link&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&amp;lt;/articles&amp;gt;; rel=index&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;root_uri: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;https://demo.io&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;strong&gt;Call (override)&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The following sets the root URI globally but also allows you to override the global value with a custom value per call.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;parser&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;RFC&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Web&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Link&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;https://demo.io&quot;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;parser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;link&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&amp;lt;/articles&amp;gt;; rel=index&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;root_uri: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;https://alt.io&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_delimiters&quot;&gt;Delimiters&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Each delimiter provides the following behavior:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Semicolon&lt;/strong&gt; (&lt;code&gt;;&lt;/code&gt;): Delimits each pair associated with a line.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Comma&lt;/strong&gt; (&lt;code&gt;,&lt;/code&gt;): Delimits each line of a link.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;They must be quoted when not used as delimiters.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_attributes&quot;&gt;Attributes&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;There are six &lt;a href=&quot;https://www.rfc-editor.org/info/rfc8288&quot;&gt;RFC 8288&lt;/a&gt; registered target attributes:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;anchor&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;hreflang&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;media&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;rel&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;title&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;type&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Each is described in detail below.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;sect3&quot;&gt;
&lt;h4 id=&quot;_anchor&quot;&gt;anchor&lt;/h4&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Optional but, when supplied, can be a single string, quoted with special characters, a relative URI, or an absolute URI. Here&amp;#8217;s a few examples:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Fragment&lt;/strong&gt;: &lt;code&gt;#footer&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Quoted (special characters)&lt;/strong&gt;: &lt;code&gt;&quot;#overview,body,footer&quot;&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Relative URI&lt;/strong&gt;: &lt;code&gt;/policies&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Absolute URI&lt;/strong&gt;: &lt;code&gt;&lt;a href=&quot;https://demo.io/about&quot; class=&quot;bare&quot;&gt;https://demo.io/about&lt;/a&gt;&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Relative URIs will automatically be expanded into an absolute URIs when parsed. This means if the &lt;code&gt;root_uri&lt;/code&gt; is &lt;code&gt;&lt;a href=&quot;https://demo.io&quot; class=&quot;bare&quot;&gt;https://demo.io&lt;/a&gt;&lt;/code&gt; and the anchor&amp;#8217;s value is &lt;code&gt;/policies&lt;/code&gt; (relative), then the resulting URI will be: &lt;code&gt;&lt;a href=&quot;https://demo.io/polices&quot; class=&quot;bare&quot;&gt;https://demo.io/polices&lt;/a&gt;&lt;/code&gt;. Examples:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;strong&gt;Fragment&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;parser&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;RFC&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Web&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Link&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;https://demo.io&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;list&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;link&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&amp;lt;/articles&amp;gt;; anchor=#footer&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# #&amp;lt;data RFC::Web::Link::Models::List:0x000016f0&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   links = [&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#     #&amp;lt;data RFC::Web::Link::Models::Link:0x00001710&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#       pairs = [&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#         #&amp;lt;data RFC::Web::Link::Models::Pair:0x00001730&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           delimiter = &quot;=&quot;,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           encoding = nil,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           key = &quot;anchor&quot;,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           language = nil,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           value = &quot;#footer&quot;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#         &amp;gt;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#       ],&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#       uri = &quot;https://demo.io/articles&quot;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#     &amp;gt;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   ]&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# &quot;&amp;lt;https://demo.io/articles&amp;gt;; anchor=#footer&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;strong&gt;Quoted&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;parser&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;RFC&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Web&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Link&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;https://demo.io&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;list&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;link&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;sx&quot;&gt;%(&amp;lt;/articles&amp;gt;; anchor=&quot;#overview,body,footer&quot;)&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# #&amp;lt;data RFC::Web::Link::Models::List:0x00001660&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   links = [&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#     #&amp;lt;data RFC::Web::Link::Models::Link:0x00001680&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#       pairs = [&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#         #&amp;lt;data RFC::Web::Link::Models::Pair:0x000016a0&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           delimiter = &quot;=&quot;,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           encoding = nil,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           key = &quot;anchor&quot;,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           language = nil,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           value = &quot;\&quot;#overview,body,footer\&quot;&quot;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#         &amp;gt;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#       ],&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#       uri = &quot;https://demo.io/articles&quot;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#     &amp;gt;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   ]&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# &amp;gt;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# &quot;&amp;lt;https://demo.io/articles&amp;gt;; anchor=\&quot;#overview,body,footer\&quot;&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;strong&gt;Relative URI&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;parser&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;RFC&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Web&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Link&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;https://demo.io&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;list&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;link&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&amp;lt;/articles&amp;gt;; anchor=/policies&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# #&amp;lt;data RFC::Web::Link::Models::List:0x000017c0&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   links = [&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#     #&amp;lt;data RFC::Web::Link::Models::Link:0x000017e0&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#       pairs = [&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#         #&amp;lt;data RFC::Web::Link::Models::Pair:0x00001800&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           delimiter = &quot;=&quot;,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           encoding = nil,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           key = &quot;anchor&quot;,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           language = nil,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           value = &quot;https://demo.io/policies&quot;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#         &amp;gt;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#       ],&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#       uri = &quot;https://demo.io/articles&quot;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#     &amp;gt;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   ]&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# &amp;gt;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# &quot;&amp;lt;https://demo.io/articles&amp;gt;; anchor=https://demo.io/policies&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;strong&gt;Absolute URI&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;parser&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;RFC&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Web&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Link&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;https://demo.io&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;list&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;link&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&amp;lt;/articles&amp;gt;; anchor=https://demo.io/about&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# #&amp;lt;data RFC::Web::Link::Models::List:0x00001890&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   links = [&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#     #&amp;lt;data RFC::Web::Link::Models::Link:0x000018b0&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#       pairs = [&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#         #&amp;lt;data RFC::Web::Link::Models::Pair:0x000018d0&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           delimiter = &quot;=&quot;,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           encoding = nil,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           key = &quot;anchor&quot;,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           language = nil,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           value = &quot;https://demo.io/about&quot;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#         &amp;gt;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#       ],&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#       uri = &quot;https://demo.io/articles&quot;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#     &amp;gt;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   ]&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# &amp;gt;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# &quot;&amp;lt;https://demo.io/articles&amp;gt;; anchor=https://demo.io/about&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect3&quot;&gt;
&lt;h4 id=&quot;_hreflang&quot;&gt;hreflang&lt;/h4&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Optional but, when supplied, is a hint indicating the language of the associated link. This &lt;em&gt;does not&lt;/em&gt; override the value of the &lt;code&gt;content-language&lt;/code&gt; header. Example:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;strong&gt;Single&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;parser&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;RFC&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Web&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Link&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;https://demo.io&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;list&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;link&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&amp;lt;/articles&amp;gt;; hreflang=en&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# #&amp;lt;data RFC::Web::Link::Models::List:0x00000890&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   links = [&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#     #&amp;lt;data RFC::Web::Link::Models::Link:0x000008b0&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#       pairs = [&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#         #&amp;lt;data RFC::Web::Link::Models::Pair:0x000008d0&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           delimiter = &quot;=&quot;,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           encoding = nil,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           key = &quot;hreflang&quot;,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           language = nil,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           value = &quot;en&quot;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#         &amp;gt;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#       ],&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#       uri = &quot;https://demo.io/articles&quot;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#     &amp;gt;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   ]&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# &amp;gt;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# &quot;&amp;lt;https://demo.io/articles&amp;gt;; hreflang=en&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;strong&gt;Multiple&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;parser&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;RFC&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Web&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Link&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;https://demo.io&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;list&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;link&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&amp;lt;/articles&amp;gt;; hreflang=en; hreflang=de&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# #&amp;lt;data RFC::Web::Link::Models::List:0x000016c0&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   links = [&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#     #&amp;lt;data RFC::Web::Link::Models::Link:0x000016e0&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#       pairs = [&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#         #&amp;lt;data RFC::Web::Link::Models::Pair:0x00001700&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           delimiter = &quot;=&quot;,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           encoding = nil,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           key = &quot;hreflang&quot;,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           language = nil,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           value = &quot;en&quot;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#         &amp;gt;,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#         #&amp;lt;data RFC::Web::Link::Models::Pair:0x00001740&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           delimiter = &quot;=&quot;,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           encoding = nil,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           key = &quot;hreflang&quot;,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           language = nil,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           value = &quot;de&quot;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#         &amp;gt;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#       ],&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#       uri = &quot;https://demo.io/articles&quot;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#     &amp;gt;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   ]&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# &amp;gt;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# &quot;&amp;lt;https://demo.io/articles&amp;gt;; hreflang=en; hreflang=de&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect3&quot;&gt;
&lt;h4 id=&quot;_media&quot;&gt;media&lt;/h4&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Optional but, when supplied, is a hint indicating the kind of media associated with the link. Example:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;parser&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;RFC&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Web&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Link&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;https://demo.io&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;list&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;link&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&amp;lt;/articles&amp;gt;; media=print&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# #&amp;lt;data RFC::Web::Link::Models::List:0x000017d0&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   links = [&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#     #&amp;lt;data RFC::Web::Link::Models::Link:0x000017f0&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#       pairs = [&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#         #&amp;lt;data RFC::Web::Link::Models::Pair:0x00001810&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           delimiter = &quot;=&quot;,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           encoding = nil,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           key = &quot;media&quot;,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           language = nil,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           value = &quot;print&quot;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#         &amp;gt;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#       ],&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#       uri = &quot;https://demo.io/articles&quot;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#     &amp;gt;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   ]&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# &amp;gt;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# &quot;&amp;lt;https://demo.io/articles&amp;gt;; media=print&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect3&quot;&gt;
&lt;h4 id=&quot;_rel&quot;&gt;rel&lt;/h4&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Required and must be first defined. Example:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;strong&gt;Single&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;parser&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;RFC&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Web&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Link&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;https://demo.io&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;list&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;link&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&amp;lt;/articles&amp;gt;; rel=index&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# #&amp;lt;data RFC::Web::Link::Models::List:0x00000890&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   links = [&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#     #&amp;lt;data RFC::Web::Link::Models::Link:0x000008b0&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#       pairs = [&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#         #&amp;lt;data RFC::Web::Link::Models::Pair:0x000008d0&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           delimiter = &quot;=&quot;,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           encoding = nil,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           key = &quot;rel&quot;,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           language = nil,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           value = &quot;index&quot;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#         &amp;gt;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#       ],&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#       uri = &quot;https://demo.io/articles&quot;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#     &amp;gt;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   ]&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# &amp;gt;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# &quot;&amp;lt;https://demo.io/articles&amp;gt;; rel=index&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;strong&gt;Shorthand&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Short hand, for multiple relations, is supported as well. To use, each relation &lt;em&gt;must&lt;/em&gt; be delimited by a space within a single &lt;em&gt;quoted&lt;/em&gt; string. Example:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;parser&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;RFC&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Web&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Link&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;https://demo.io&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;list&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;link&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;sx&quot;&gt;%(&amp;lt;/articles&amp;gt;; rel=&quot;one two three&quot;)&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# #&amp;lt;data RFC::Web::Link::Models::List:0x00000960&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   links = [&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#     #&amp;lt;data RFC::Web::Link::Models::Link:0x00000980&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#       pairs = [&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#         #&amp;lt;data RFC::Web::Link::Models::Pair:0x000009a0&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           delimiter = &quot;=&quot;,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           encoding = nil,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           key = &quot;rel&quot;,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           language = nil,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           value = &quot;one&quot;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#         &amp;gt;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#       ],&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#       uri = &quot;https://demo.io/articles&quot;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#     &amp;gt;,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#     #&amp;lt;data RFC::Web::Link::Models::Link:0x000009f0&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#       pairs = [&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#         #&amp;lt;data RFC::Web::Link::Models::Pair:0x00000a10&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           delimiter = &quot;=&quot;,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           encoding = nil,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           key = &quot;rel&quot;,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           language = nil,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           value = &quot;two&quot;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#         &amp;gt;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#       ],&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#       uri = &quot;https://demo.io/articles&quot;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#     &amp;gt;,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#     #&amp;lt;data RFC::Web::Link::Models::Link:0x00000a60&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#       pairs = [&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#         #&amp;lt;data RFC::Web::Link::Models::Pair:0x00000a80&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           delimiter = &quot;=&quot;,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           encoding = nil,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           key = &quot;rel&quot;,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           language = nil,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           value = &quot;three&quot;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#         &amp;gt;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#       ],&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#       uri = &quot;https://demo.io/articles&quot;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#     &amp;gt;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   ]&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# &amp;gt;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# &quot;&amp;lt;https://demo.io/articles&amp;gt;; rel=one, &amp;lt;https://demo.io/articles&amp;gt;; rel=two, &amp;lt;https://demo.io/articles&amp;gt;; rel=three&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Notice that the original relation short hand of &lt;code&gt;&quot;one two three&quot;&lt;/code&gt; produced three unique links for each relation which allows you to type less while still producing three distinct links.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect3&quot;&gt;
&lt;h4 id=&quot;_title&quot;&gt;title&lt;/h4&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Optional but, when supplied, allows you to provide a human readable label for the associated link. This includes being able to encode and decode the value based on the delimiter used. For example, notice the difference in delimiters used below:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Plain&lt;/strong&gt; (&lt;code&gt;=&lt;/code&gt;): &lt;code&gt;title=Demo&lt;/code&gt; (example)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Encoded&lt;/strong&gt; (&lt;code&gt;*=&lt;/code&gt;): &lt;code&gt;title*=UTF-8&#39;en&#39;d%C3%A9j%C3%A0%20vu&lt;/code&gt; (example)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The title &lt;em&gt;must not&lt;/em&gt; appear more than once. If multiple occurrences are detected then only the first is honored. Also, if &lt;code&gt;=&lt;/code&gt; and &lt;code&gt;*=&lt;/code&gt; is used then &lt;code&gt;*=&lt;/code&gt; takes precedence. Examples:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;strong&gt;Without Encoding&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;parser&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;RFC&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Web&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Link&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;https://demo.io&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;list&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;link&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&amp;lt;/articles&amp;gt;; title=Demo&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# #&amp;lt;data RFC::Web::Link::Models::List:0x00000890&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   links = [&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#     #&amp;lt;data RFC::Web::Link::Models::Link:0x000008b0&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#       pairs = [&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#         #&amp;lt;data RFC::Web::Link::Models::Pair:0x000008d0&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           delimiter = &quot;=&quot;,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           encoding = nil,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           key = &quot;title&quot;,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           language = nil,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           value = &quot;Demo&quot;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#         &amp;gt;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#       ],&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#       uri = &quot;https://demo.io/articles&quot;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#     &amp;gt;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   ]&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# &amp;gt;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# &quot;&amp;lt;https://demo.io/articles&amp;gt;; title=Demo&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;strong&gt;With Encoding&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;parser&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;RFC&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Web&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Link&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;https://demo.io&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;list&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;link&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&amp;lt;/articles&amp;gt;; title*=UTF-8&#39;en&#39;d%C3%A9j%C3%A0%20vu&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# #&amp;lt;data RFC::Web::Link::Models::List:0x00000890&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   links = [&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#     #&amp;lt;data RFC::Web::Link::Models::Link:0x000008b0&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#       pairs = [&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#         #&amp;lt;data RFC::Web::Link::Models::Pair:0x000008d0&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           delimiter = &quot;*=&quot;,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           encoding = &quot;UTF-8&quot;,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           key = &quot;title&quot;,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           language = &quot;en&quot;,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           value = &quot;déjà vu&quot;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#         &amp;gt;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#       ],&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#       uri = &quot;https://demo.io/articles&quot;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#     &amp;gt;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   ]&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# &amp;gt;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# &quot;&amp;lt;https://demo.io/articles&amp;gt;; title*=UTF-8&#39;en&#39;d%C3%A9j%C3%A0%20vu&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect3&quot;&gt;
&lt;h4 id=&quot;_type&quot;&gt;type&lt;/h4&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Optional but, when supplied, is a hint indicating the MIME Type of the associated link. This &lt;em&gt;does not&lt;/em&gt; override the value of the &lt;code&gt;content-type&lt;/code&gt; header. Example:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;parser&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;RFC&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Web&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Link&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;https://demo.io&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;list&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;link&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&amp;lt;/articles&amp;gt;; type=text/html&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# #&amp;lt;data RFC::Web::Link::Models::List:0x00000890&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   links = [&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#     #&amp;lt;data RFC::Web::Link::Models::Link:0x000008b0&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#       pairs = [&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#         #&amp;lt;data RFC::Web::Link::Models::Pair:0x000008d0&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           delimiter = &quot;=&quot;,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           encoding = nil,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           key = &quot;type&quot;,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           language = nil,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           value = &quot;text/html&quot;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#         &amp;gt;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#       ],&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#       uri = &quot;https://demo.io/articles&quot;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#     &amp;gt;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   ]&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# &amp;gt;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# &quot;&amp;lt;https://demo.io/articles&amp;gt;; type=text/html&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_extensions&quot;&gt;Extensions&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Extensions allow you to extend your implementation beyond the registered target attributes, described above, with your own custom attributes. For example, maybe you want to use the following attributes which are specific to your application: hint, errata, copyright. You can do this as follows:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;parser&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;RFC&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Web&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Link&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;https://demo.io&quot;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;list&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;link&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;sx&quot;&gt;%(&amp;lt;/articles&amp;gt;; hint=&quot;A demo.&quot;; errata=&quot;For demonstration only.&quot;; copyright=2025)&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# #&amp;lt;data RFC::Web::Link::Models::List:0x00000980&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   links = [&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#     #&amp;lt;data RFC::Web::Link::Models::Link:0x000009a0&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#       pairs = [&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#         #&amp;lt;data RFC::Web::Link::Models::Pair:0x000009c0&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           delimiter = &quot;=&quot;,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           encoding = nil,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           key = &quot;hint&quot;,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           language = nil,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           value = &quot;\&quot;A demo.\&quot;&quot;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#         &amp;gt;,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#         #&amp;lt;data RFC::Web::Link::Models::Pair:0x00000a00&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           delimiter = &quot;=&quot;,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           encoding = nil,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           key = &quot;errata&quot;,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           language = nil,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           value = &quot;\&quot;For demonstration only.\&quot;&quot;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#         &amp;gt;,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#         #&amp;lt;data RFC::Web::Link::Models::Pair:0x00000a40&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           delimiter = &quot;=&quot;,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           encoding = nil,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           key = &quot;copyright&quot;,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           language = nil,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           value = &quot;2025&quot;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#         &amp;gt;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#       ],&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#       uri = &quot;https://demo.io/articles&quot;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#     &amp;gt;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   ]&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# &amp;gt;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# &quot;&amp;lt;https://demo.io/articles&amp;gt;; hint=\&quot;A demo.\&quot;; errata=\&quot;For demonstration only.\&quot;; copyright=2025&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;You can also encode your extensions by using the &lt;code&gt;*=&lt;/code&gt; delimiter. Example:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;parser&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;RFC&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Web&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Link&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;https://demo.io&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;list&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;link&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&amp;lt;/articles&amp;gt;; demo*=UTF-8&#39;en&#39;d%C3%A9j%C3%A0%20vu&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# #&amp;lt;data RFC::Web::Link::Models::List:0x00000ad0&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   links = [&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#     #&amp;lt;data RFC::Web::Link::Models::Link:0x00000af0&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#       pairs = [&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#         #&amp;lt;data RFC::Web::Link::Models::Pair:0x00000b10&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           delimiter = &quot;*=&quot;,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           encoding = &quot;UTF-8&quot;,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           key = &quot;demo&quot;,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           language = &quot;en&quot;,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           value = &quot;déjà vu&quot;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#         &amp;gt;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#       ],&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#       uri = &quot;https://demo.io/articles&quot;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#     &amp;gt;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   ]&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# &amp;gt;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# &quot;&amp;lt;https://demo.io/articles&amp;gt;; demo*=UTF-8&#39;en&#39;d%C3%A9j%C3%A0%20vu&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_models&quot;&gt;Models&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;You&amp;#8217;ve already seen all of the models (whole value objects) used in the examples above but this section details what you can do with each model individually.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;sect3&quot;&gt;
&lt;h4 id=&quot;_list&quot;&gt;List&lt;/h4&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This model has both &lt;a href=&quot;https://alchemists.io/articles/ruby_data&quot;&gt;Data&lt;/a&gt; and &lt;a href=&quot;https://docs.ruby-lang.org/en/master/Enumerable.html&quot;&gt;Enumerable&lt;/a&gt; behavior because it encapsulates the list of links parsed from an HTTP link header or created by you. A list can be created multiple ways:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;strong&gt;All At Once&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;list&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;RFC&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Web&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Link&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Models&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;links: &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;RFC&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Web&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Link&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Models&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Link&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;ss&quot;&gt;uri: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;https://demo.io&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;ss&quot;&gt;pairs: &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;no&quot;&gt;RFC&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Web&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Link&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Models&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Pair&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;key: :title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;value: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Demo&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;💡 Ensure you use a &lt;code&gt;Set&lt;/code&gt; when adding your links and pairs.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;strong&gt;Separately&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;pair&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;RFC&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Web&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Link&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Models&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Pair&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;key: :title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;value: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Demo&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;list&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;RFC&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Web&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Link&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Models&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Link&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;uri: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;https://demo.io&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pair&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;list&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;RFC&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Web&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Link&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Models&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;link&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Once you have a list, you can send the following messages including &lt;a href=&quot;https://alchemists.io/articles/ruby_data&quot;&gt;Data&lt;/a&gt; and &lt;a href=&quot;https://docs.ruby-lang.org/en/master/Enumerable.html&quot;&gt;Enumerable&lt;/a&gt; messages:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;add&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;line&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;clear&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;empty?&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;size&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_str&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;You&amp;#8217;ll notice you can explicitly and implicitly cast your list to a string. This makes the following quite handy:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;s2&quot;&gt;&quot;link: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# link: &amp;lt;https://demo.io&amp;gt;; title=Demo&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect3&quot;&gt;
&lt;h4 id=&quot;_link&quot;&gt;Link&lt;/h4&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This model encapsulates a single HTTP link header. A link can be created multiple ways:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;strong&gt;All At Once&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;link&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;RFC&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Web&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Link&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Models&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Link&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;uri: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;https://demo.io&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;pairs: &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;RFC&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Web&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Link&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Models&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Pair&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;key: :title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;value: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Demo&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;💡 Ensure you use a &lt;code&gt;Set&lt;/code&gt; when adding your pairs.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;strong&gt;Separately&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;pair&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;RFC&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Web&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Link&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Models&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Pair&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;key: :title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;value: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Demo&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;link&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;RFC&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Web&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Link&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Models&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Link&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;uri: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;https://demo.io&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pair&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Once you have a link, you can then send the following messages (including &lt;a href=&quot;https://alchemists.io/articles/ruby_data&quot;&gt;Data&lt;/a&gt; messages):&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;link&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;empty?&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;link&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;include?&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pair&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;link&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;add&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pair&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;link&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;append&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:relation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;index&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;link&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;append&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;s2&quot;&gt;&quot;déjà vu&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;ss&quot;&gt;delimiter: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;*=&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;ss&quot;&gt;encoding: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;UTF-8&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;ss&quot;&gt;language: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;en&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;link&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;find_pair&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;key: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;title&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;value: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Demo&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;link&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;find_pair&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;key: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;title&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;value: &lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/dem/i&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;link&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;find_pair&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;key: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;title&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;delimiter: &lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/\*=/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;value: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Demo&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;link&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;pair?&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;key: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;title&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;link&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;pair?&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;key: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;title&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;value: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Demo&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_str&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;You&amp;#8217;ll notice you can explicitly and implicitly cast your link to a string. This makes the following quite handy:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;s2&quot;&gt;&quot;link: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;link&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# link: &amp;lt;https://demo.io&amp;gt;; title=Demo&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect3&quot;&gt;
&lt;h4 id=&quot;_pair&quot;&gt;Pair&lt;/h4&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This models encapsulates a single HTTP link header pair (i.e. key/value). A pair can be created as follows:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;strong&gt;Basic&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;pair&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;RFC&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Web&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Link&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Models&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Pair&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;key: :title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;value: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Demo&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# #&amp;lt;data RFC::Web::Link::Models::Pair:0x00001e90&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   delimiter = &quot;=&quot;,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   encoding = nil,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   key = &quot;title&quot;,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   language = nil,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   value = &quot;Demo&quot;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# &amp;gt;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;pair&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;encoded?&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# false&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;strong&gt;Encoded&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;pair&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;RFC&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Web&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Link&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Models&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Pair&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;key: :title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;delimiter: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;*=&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;value: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Demo&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;encoding: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;UTF-8&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;language: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;en&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# #&amp;lt;data RFC::Web::Link::Models::Pair:0x00001ec0&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   delimiter = &quot;*=&quot;,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   encoding = &quot;UTF-8&quot;,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   key = &quot;title&quot;,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   language = &quot;en&quot;,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   value = &quot;Demo&quot;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# &amp;gt;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;pair&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;encoded?&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# true&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The key can be either a symbol or a string but is always stored as a string, internally. When using &lt;code&gt;=&lt;/code&gt; as your delimiter (default), &lt;code&gt;#encoded?&lt;/code&gt; will be &lt;code&gt;false&lt;/code&gt; but when using &lt;code&gt;*=&lt;/code&gt; as your delimiter, &lt;code&gt;#encoded?&lt;/code&gt; will be &lt;code&gt;true&lt;/code&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;As with &lt;code&gt;List&lt;/code&gt; and &lt;code&gt;Link&lt;/code&gt;, you have full access to all &lt;a href=&quot;https://alchemists.io/articles/ruby_data&quot;&gt;Data&lt;/a&gt; messages and can explicitly and implicitly cast to a string. Example:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Pair: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pair&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# Pair: title=Demo&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_error_handling&quot;&gt;Error Handling&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;As per &lt;a href=&quot;https://www.rfc-editor.org/info/rfc8288&quot;&gt;RFC 8288&lt;/a&gt;, this implementation is designed to safely ignore malformed web links. To illustrate, we&amp;#8217;ll start with an initialized parser:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;parser&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;RFC&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Web&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Link&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;https://demo.io&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The following examples show the result of parsing different malformed URIs:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;strong&gt;With Nil Value&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;parser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;link&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# #&amp;lt;data RFC::Web::Link::Models::List:0x00000880&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   links = []&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# &amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;strong&gt;With Empty Value&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;parser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;link&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# #&amp;lt;data RFC::Web::Link::Models::List:0x00000880&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   links = []&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# &amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;strong&gt;With No Leading Less Than Sign For URI&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;parser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;link&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;/articles; rel=index&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# #&amp;lt;data RFC::Web::Link::Models::List:0x00000880&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   links = []&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# &amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;strong&gt;Without Attributes&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;parser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;link&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&amp;lt;/articles&amp;gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# #&amp;lt;data RFC::Web::Link::Models::List:0x00000880&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   links = [&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#     #&amp;lt;data RFC::Web::Link::Models::Link:0x000008b0&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#       pairs = [],&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#       uri = &quot;https://demo.io/articles&quot;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#     &amp;gt;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   ]&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# &amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;strong&gt;With Missing Attribute Value&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;parser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;link&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&amp;lt;/articles&amp;gt;; rel&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# #&amp;lt;data RFC::Web::Link::Models::List:0x000008a0&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   links = [&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#     #&amp;lt;data RFC::Web::Link::Models::Link:0x00000910&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#       pairs = [&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#         #&amp;lt;data RFC::Web::Link::Models::Pair:0x00000930&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           delimiter = nil,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           encoding = nil,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           key = &quot;rel&quot;,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           language = nil,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#           value = nil&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#         &amp;gt;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#       ],&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#       uri = &quot;https://demo.io/articles&quot;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#     &amp;gt;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   ]&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# &amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_development&quot;&gt;Development&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;To contribute, run:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;bash&quot;&gt;git clone https://github.com/bkuhlmann/rfc-web-link
&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;rfc-web-link
bin/setup&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;You can also use the IRB console for direct access to all objects:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;bash&quot;&gt;bin/console&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_tests&quot;&gt;Tests&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;To test, run:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;bash&quot;&gt;bin/rake&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_license&quot;&gt;&lt;a href=&quot;https://alchemists.io/policies/license&quot;&gt;License&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_security&quot;&gt;&lt;a href=&quot;https://alchemists.io/policies/security&quot;&gt;Security&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_code_of_conduct&quot;&gt;&lt;a href=&quot;https://alchemists.io/policies/code_of_conduct&quot;&gt;Code of Conduct&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_contributions&quot;&gt;&lt;a href=&quot;https://alchemists.io/policies/contributions&quot;&gt;Contributions&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_developer_certificate_of_origin&quot;&gt;&lt;a href=&quot;https://alchemists.io/policies/developer_certificate_of_origin&quot;&gt;Developer Certificate of Origin&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_versions&quot;&gt;&lt;a href=&quot;https://alchemists.io/projects/rfc-web-link/versions&quot;&gt;Versions&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_community&quot;&gt;&lt;a href=&quot;https://alchemists.io/community&quot;&gt;Community&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_credits&quot;&gt;Credits&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Built with &lt;a href=&quot;https://alchemists.io/projects/gemsmith&quot;&gt;Gemsmith&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Engineered by &lt;a href=&quot;https://alchemists.io/team/brooke_kuhlmann&quot;&gt;Brooke Kuhlmann&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
</content>
    <id>https://alchemists.io/projects/rfc-web-link</id>
    <link href="https://alchemists.io/projects/rfc-web-link"/>
    <published>2026-08-22T17:22:35+00:00</published>
    <rights>2026</rights>
    <title>RFC Web Link Project</title>
    <updated>2026-10-14T23:32:23+00:00</updated>
    <dc:date>2026-10-14T23:32:23+00:00</dc:date>
  </entry>
  <entry>
    <author>
      <name>Brooke Kuhlmann</name>
      <uri>https://alchemists.io/team/brooke_kuhlmann</uri>
    </author>
    <category term="conference"
      label="Conference"/>
    <category term="htmx"
      label="htmx"/>
    <content type="html">&lt;div class=&quot;imageblock focal_point&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;a class=&quot;image&quot; href=&quot;https://bigskydevcon.com&quot;&gt;&lt;img src=&quot;/images/articles/big_sky_dev_con_2026/cover.png&quot; alt=&quot;Cover&quot; width=&quot;762&quot; height=&quot;362&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;div class=&quot;title&quot;&gt;Big Sky Dev Con 2026&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;After attending &lt;a href=&quot;/articles/big_sky_dev_con_2024&quot;&gt;Big Sky Dev Con 2024&lt;/a&gt;, a couple years ago, and meeting some of the &lt;a href=&quot;https://htmx.org&quot;&gt;htmx&lt;/a&gt; team, I became interested in the conference and was eager to return as a speaker. In 2025, I submitted my &lt;a href=&quot;/talks/milestones&quot;&gt;Milestones&lt;/a&gt; talk but, sadly, wasn&amp;#8217;t accepted. This is a shame because &lt;a href=&quot;/projects/milestoner&quot;&gt;Milestoner&lt;/a&gt; is used to fully generate all versions and corresponding release notes for all &lt;a href=&quot;/projects&quot;&gt;projects&lt;/a&gt;. The UI uses htmx which is perfect for statically generated content. Can&amp;#8217;t live without it! &amp;#8230;&amp;#8203;but I digress.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This year, thankfully, my &lt;a href=&quot;/talks/htmx_view_transitions&quot;&gt;htmx View Transitions&lt;/a&gt; talk was accepted and glad it was because I had a great time presenting, talking to folks, and enjoying the conference. The conference organizers have definitely stepped up their game in terms of quality of presentations and venues.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The following are a few notes and learnings captured from the conference that might be of interest.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&quot;toc&quot; class=&quot;toc&quot;&gt;
&lt;div id=&quot;toctitle&quot; class=&quot;title&quot;&gt;Table of Contents&lt;/div&gt;
&lt;ul class=&quot;sectlevel1&quot;&gt;
&lt;li&gt;&lt;a href=&quot;#_speakers_dinner&quot;&gt;Speakers Dinner&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_talks&quot;&gt;Talks&lt;/a&gt;
&lt;ul class=&quot;sectlevel2&quot;&gt;
&lt;li&gt;&lt;a href=&quot;#_day_1&quot;&gt;Day 1&lt;/a&gt;
&lt;ul class=&quot;sectlevel3&quot;&gt;
&lt;li&gt;&lt;a href=&quot;#_executor_orchestrator_leader_by_jaron_jones&quot;&gt;Executor, Orchestrator, Leader! by Jaron Jones&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_falling_in_love_with_sql_by_adam_rackis&quot;&gt;Falling in Love with SQL by Adam Rackis&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_htmx_view_transitions_by_brooke_kuhlmann&quot;&gt;htmx View Transitions by Brooke Kuhlmann&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_javascript_in_this_economy_a_love_letter_to_tailwind_and_modern_css_by_anthony_alaribe&quot;&gt;JavaScript? In This Economy? (A Love Letter to Tailwind and modern CSS) by Anthony Alaribe&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_html_is_not_just_for_the_web_by_lazarus_morrison&quot;&gt;HTML is not just for the web by Lazarus Morrison&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_day_2&quot;&gt;Day 2&lt;/a&gt;
&lt;ul class=&quot;sectlevel3&quot;&gt;
&lt;li&gt;&lt;a href=&quot;#_getting_off_the_modernization_treadmill_by_alexander_petros&quot;&gt;Getting off the Modernization Treadmill by Alexander Petros&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_agentic_engineering_for_jvm_developers_by_thomas_schilling&quot;&gt;Agentic Engineering for JVM Developers by Thomas Schilling&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_your_business_doesnt_fit_on_a_phone_neither_should_your_flutter_app_by_marcus_twichel&quot;&gt;Your Business Doesn&amp;#8217;t Fit on a Phone — Neither Should Your Flutter App by Marcus Twichel&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_i_have_no_idea_what_im_doing_by_ronan_berder&quot;&gt;I have no idea what I&amp;#8217;m doing by Ronan Berder&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_lessons_from_our_hardware_on_the_iss_running_a_linux_stack_beyond_the_clouds_by_mike_frandsen&quot;&gt;Lessons from our Hardware on the ISS: Running a Linux Stack Beyond the Cloud(s) by Mike Frandsen&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_cognitive_vandalism_what_i_learned_by_mutilating_a_gpt_by_barrett_breshears&quot;&gt;Cognitive Vandalism: What I Learned by Mutilating a GPT by Barrett Breshears&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_prompt_engineering_isnt_enough_building_ai_agents_you_can_steer_by_sandhya_subramani&quot;&gt;Prompt Engineering Isn’t Enough: Building AI Agents You Can Steer by Sandhya Subramani&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_orms_are_killing_your_performance_by_jerason_banes&quot;&gt;ORMs are Killing Your Performance by Jerason Banes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_intro_to_compression_techniques_by_lance_fisher&quot;&gt;Intro to Compression Techniques by Lance Fisher&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_real_time_hypermedia_the_htmx_way_by_christian_tanul&quot;&gt;Real-Time Hypermedia (the htmx way) by Christian Tanul&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_htmx_4_whats_new_by_carson_gross&quot;&gt;htmx 4: What&amp;#8217;s New by Carson Gross&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_speakers_dinner&quot;&gt;Speakers Dinner&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Originally scheduled for Wednesday, the night before the conference kicked off, the dinner ended up taking place after the conference ended on the first day.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock focal_point&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/images/articles/big_sky_dev_con_2026/speakers_dinner.png&quot; alt=&quot;Game&quot; width=&quot;800&quot; height=&quot;534&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Most impressive was the work Duncan put into this and the team behind this. The crew drives out, each year, from Utah with frozen BBQ, rents an AirBnB, and then spends a couple days cooking and prepping the food. Everything was delicious with a fantastic spread.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_talks&quot;&gt;Talks&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This year the conference consisted of a day and a half of talks with things kicking off at ~3pm on Friday at &lt;a href=&quot;https://www.tinworksart.org/rialto&quot;&gt;The Rialto&lt;/a&gt; and running all day on Saturday at &lt;a href=&quot;https://www.montana.edu&quot;&gt;Montana State University&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_day_1&quot;&gt;Day 1&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;As mentioned above, the first day was at the &lt;a href=&quot;https://www.tinworksart.org/rialto&quot;&gt;The Rialto&lt;/a&gt;. I arrived at 1pm to double check my display and portable WiFi router worked properly. This proved wise since the macOS display bug cropped up again which yielded a black screen. Thankfully the video crew had an extra video converter which resolved the problem.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;James Collins, Lazarus Morrison, and Carson Gross showed up shortly after. While chatting with Carson, I learned of &lt;a href=&quot;https://fil-c.org&quot;&gt;Fil-C&lt;/a&gt; which might be of interest to folks that might want modern&amp;#8201;&amp;#8212;&amp;#8201;and compatible&amp;#8201;&amp;#8212;&amp;#8201;C/C++ tooling that is memory safe.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;sect3&quot;&gt;
&lt;h4 id=&quot;_executor_orchestrator_leader_by_jaron_jones&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=BY2bpn4xvZo&amp;amp;list=PLLYO-P10l3y0&amp;amp;index=2&quot;&gt;Executor, Orchestrator, Leader!&lt;/a&gt; by Jaron Jones&lt;/h4&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Jones kicked off the conference by discussing how ownership and quality of your work is so important. You can&amp;#8217;t give up on the fundamentals and let the brain rot consume you in this Age of Slopware.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect3&quot;&gt;
&lt;h4 id=&quot;_falling_in_love_with_sql_by_adam_rackis&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=NQ0WmX-Dm24&amp;amp;list=PLLYO-P10l3y0&amp;amp;index=3&quot;&gt;Falling in Love with SQL&lt;/a&gt; by Adam Rackis&lt;/h4&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Rackis spent the core of the talk looking at execution plans. These are good skills to have so make sure to watch the video. This talk also pairs well with Jerason Banes talk on using pure SQL in general.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect3&quot;&gt;
&lt;h4 id=&quot;_htmx_view_transitions_by_brooke_kuhlmann&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=0JrHsHUErhk&amp;amp;list=PLLYO-P10l3y0&amp;amp;index=4&quot;&gt;htmx View Transitions&lt;/a&gt; by Brooke Kuhlmann&lt;/h4&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This was my talk which focused entirely on CSS View Transitions using htmx and Ruby. The slides and ePaper devices (passed out to the audience) were completely rendered live via &lt;a href=&quot;/projects/terminus&quot;&gt;Terminus&lt;/a&gt;. You can find the slides here: &lt;a href=&quot;/talks/htmx_view_transitions&quot;&gt;htmx View Transitions&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;At the end of the talk, I suggested an improvement to the htmx library where you could provide a callback into the View Transitions API for more granular control and Carson Gross mentioned this Michael West who folded the &lt;a href=&quot;https://github.com/bigskysoftware/htmx/pull/3918&quot;&gt;change&lt;/a&gt; into htmx 4.0.0!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect3&quot;&gt;
&lt;h4 id=&quot;_javascript_in_this_economy_a_love_letter_to_tailwind_and_modern_css_by_anthony_alaribe&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=bTURcTjmKBQ&amp;amp;list=PLLYO-P10l3y0&amp;amp;index=5&quot;&gt;JavaScript? In This Economy?&lt;/a&gt; (A Love Letter to Tailwind and modern CSS) by Anthony Alaribe&lt;/h4&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This is the second time seeing Anthony speak. This time he had interesting insights into how you can use Tailwind to programmatically control behavior by using the &lt;code&gt;:has&lt;/code&gt; and &lt;code&gt;:is&lt;/code&gt; pseudo-classes along with the &lt;code&gt;if()&lt;/code&gt; function.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I would never recommend Tailwind since the output always looks like someone barfed all over your source code. That said, using CSS to conditionally style a site based on which classes are present is worth knowing about. Alternative ways to tackle this would be via &lt;code&gt;data&lt;/code&gt; attributes, hidden check boxes, and so forth. For example, this site uses a hidden checkbox to toggle a collapsed main menu when viewing on smaller devices. All using CSS, no JavaScript!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect3&quot;&gt;
&lt;h4 id=&quot;_html_is_not_just_for_the_web_by_lazarus_morrison&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=XQl9Dq_14_g&amp;amp;list=PLLYO-P10l3y0&amp;amp;index=6&quot;&gt;HTML is not just for the web&lt;/a&gt; by Lazarus Morrison&lt;/h4&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Morrison closed out the day by discussing his &lt;a href=&quot;https://hypeapps.dev&quot;&gt;HypeApps&lt;/a&gt; project which provides enhanced HTML elements for building applications that can run on multiple platforms. Without having a chance to play with this more, this seems like a highly tailored, custom collection of web components without all of the JavaScript setup. The framework is built upon &lt;a href=&quot;https://flutter.dev&quot;&gt;Flutter&lt;/a&gt; and pairs well with Marcus Twichel&amp;#8217;s talk who also uses Flutter.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_day_2&quot;&gt;Day 2&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The second day was held in the Strand Union Building on the &lt;a href=&quot;https://www.montana.edu&quot;&gt;Montana State University&lt;/a&gt; campus. I found this to be more enjoyable than &lt;a href=&quot;https://www.tinworksart.org/rialto&quot;&gt;The Rialto&lt;/a&gt; because you had more space to setup your laptop, take notes, enjoy better lighting. Enjoyed being on the college campus as well.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;sect3&quot;&gt;
&lt;h4 id=&quot;_getting_off_the_modernization_treadmill_by_alexander_petros&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=vRJVw8Di-4s&amp;amp;list=PLLYO-P10l3y0&amp;amp;index=7&quot;&gt;Getting off the Modernization Treadmill&lt;/a&gt; by Alexander Petros&lt;/h4&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Alexander kicked off the day by first mentioning the book &lt;a href=&quot;https://www.recodingamerica.us&quot;&gt;Recoding America&lt;/a&gt; by Jennifer Pahlka which tied in well with the staggering numbers of government waste related to software development. Having tackled several government contracts in the past, I know this only too well. This is also a talk about software bloat and love that he emphasized the following:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Avoid JavaScript. Stick to pure HTML and CSS. Let the browsers upgrade for you in terms of performance and security fixes.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Avoid React entirely and lean in on native HTML and CSS support.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect3&quot;&gt;
&lt;h4 id=&quot;_agentic_engineering_for_jvm_developers_by_thomas_schilling&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=M4xK7b9nEhE&amp;amp;list=PLLYO-P10l3y0&amp;amp;index=8&quot;&gt;Agentic Engineering for JVM Developers&lt;/a&gt; by Thomas Schilling&lt;/h4&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Perhaps one of the only speakers who traveled the farthest distance by coming from Stuttgart, Germany to speak. This talk was entirely focused on AI automation via these four steps:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;olist arabic&quot;&gt;
&lt;ol class=&quot;arabic&quot;&gt;
&lt;li&gt;
&lt;p&gt;Tell, Watch, Steer&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;What To Do, How To Do It&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Behavior - User Interaction&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Sliced Loops&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;He also mentioned checking out &lt;a href=&quot;https://www.aihero.dev/grill-with-docs&quot;&gt;Grill with Docs&lt;/a&gt; for further tweaking of your agents. Check out his &lt;a href=&quot;https://tschuehly.de&quot;&gt;site&lt;/a&gt; and &lt;a href=&quot;https://jvmskills.com/big-sky-2026&quot;&gt;slides&lt;/a&gt; for further details.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect3&quot;&gt;
&lt;h4 id=&quot;_your_business_doesnt_fit_on_a_phone_neither_should_your_flutter_app_by_marcus_twichel&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=LT4touZOs2E&amp;amp;list=PLLYO-P10l3y0&amp;amp;index=9&quot;&gt;Your Business Doesn&amp;#8217;t Fit on a Phone — Neither Should Your Flutter App&lt;/a&gt; by Marcus Twichel&lt;/h4&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This talk was all about using &lt;a href=&quot;https://flutter.dev&quot;&gt;Flutter&lt;/a&gt; to run on iOS, macOS, Android, web, and other platforms with real-time communication and synchronization. This included a live demo which focused on a fake coffee store scenario where an audience member would order a beverage and we&amp;#8217;d watch the transaction process in real-time across multiple platforms.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This was a good demo and definitely can see why folks would be attracted to using Flutter. The problem is Flutter is Google&amp;#8217;s solution for this much like React is for Facebook and we all know how awful that has become especially for those that cargo cult these platforms&amp;#8201;&amp;#8212;&amp;#8201;without thinking through the ramifications&amp;#8201;&amp;#8212;&amp;#8201;by using a big hammer to solve the wrong problem.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This is why checking out Alexander Petros&#39; talk is well worth your time because focusing on modern HTML and CSS can get you a long way including leaning into &lt;a href=&quot;https://whatpwacando.today&quot;&gt;Progressive Web Apps&lt;/a&gt;. Minimizing your stack, reducing your dependencies, and avoiding complicated builds in order to release new versions of your software reduces your maintenance burdens. Not saying this is always the right solution but should definitely be the first thing you consider before going down the Flutter/React path.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect3&quot;&gt;
&lt;h4 id=&quot;_i_have_no_idea_what_im_doing_by_ronan_berder&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=c31UUvPk13Y&amp;amp;list=PLLYO-P10l3y0&amp;amp;index=10&quot;&gt;I have no idea what I&amp;#8217;m doing&lt;/a&gt; by Ronan Berder&lt;/h4&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;During the speakers dinner I ended up driving Ronan home despite both of us staying at opposite ends of the city so was a chance to chat. His talk ended up being a self deprecating talk on entrepreneurship especially the failures and mistakes. This makes the talk unique since people don&amp;#8217;t always share the missteps of success.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;A couple insights worth noting from his talk:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://news.ycombinator.com&quot;&gt;Hacker News&lt;/a&gt; has a section where you can post about open source. Each submission must be prefixed with &quot;Show HN: &quot; followed by the project name and a brief description. A landing page, repository, or demo of your work is what is preferred. Keep it short but technical, no marketing.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;&quot;&gt;Siddharta&lt;/a&gt; by Hermann Hesse might be worth a reading since it&amp;#8217;s about a spiritual journey of self-discovery.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Check out Ronan&amp;#8217;s &lt;a href=&quot;https://ronanberder.com&quot;&gt;writings&lt;/a&gt; and &lt;a href=&quot;https://github.com/hunvreus&quot;&gt;open source&lt;/a&gt; to learn more.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect3&quot;&gt;
&lt;h4 id=&quot;_lessons_from_our_hardware_on_the_iss_running_a_linux_stack_beyond_the_clouds_by_mike_frandsen&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=JdwQK9YI93w&amp;amp;list=PLLYO-P10l3y0&amp;amp;index=11&quot;&gt;Lessons from our Hardware on the ISS: Running a Linux Stack Beyond the Cloud(s)&lt;/a&gt; by Mike Frandsen&lt;/h4&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Insightful talk on running code in Space with limited hardware, resources, and connectivity. This talk focuses on the Cambrian Works Gig Router and lessons learned such as:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Review your defaults.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Ensure your systems are idempotent.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Use structured logging.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Ended up talking to Mike a bit afterwards because I was curious about the structured logging hurdles they faced especially since I maintain the &lt;a href=&quot;/projects/cogger&quot;&gt;Cogger&lt;/a&gt; gem which supports structured logging.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect3&quot;&gt;
&lt;h4 id=&quot;_cognitive_vandalism_what_i_learned_by_mutilating_a_gpt_by_barrett_breshears&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=EPmy1p06KHM&amp;amp;list=PLLYO-P10l3y0&amp;amp;index=12&quot;&gt;Cognitive Vandalism: What I Learned by Mutilating a GPT&lt;/a&gt; by Barrett Breshears&lt;/h4&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This was a humorous talk, plus clever engineering, which focused on messing with pre-trained models by removing layers, duplicating them, injecting gibberish, and more. The results were rendered live producing ridiculous results in order to illustrate how the models function.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Worth checking out when the video for more.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect3&quot;&gt;
&lt;h4 id=&quot;_prompt_engineering_isnt_enough_building_ai_agents_you_can_steer_by_sandhya_subramani&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=MO9GTwNgZzw&amp;amp;list=PLLYO-P10l3y0&amp;amp;index=13&quot;&gt;Prompt Engineering Isn’t Enough: Building AI Agents You Can Steer&lt;/a&gt; by Sandhya Subramani&lt;/h4&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This was the only talk that didn&amp;#8217;t land for me. The entire presentation was a lot like a marketing demo that had been given multiple times to companies and/or engineering teams. This would add up since Sandhya is a developer advocate which means traveling all over and talking about the same thing. Anyway, the talk was focused on using &lt;a href=&quot;https://github.com/strands-agents&quot;&gt;Strands Agents&lt;/a&gt; as an open source solution for building production agents.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect3&quot;&gt;
&lt;h4 id=&quot;_orms_are_killing_your_performance_by_jerason_banes&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=2DaRGRe4Ow4&amp;amp;list=PLLYO-P10l3y0&amp;amp;index=14&quot;&gt;ORMs are Killing Your Performance&lt;/a&gt; by Jerason Banes&lt;/h4&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This was a good talk about ditching the use of Object-Relational Mappers (ORMs), using functional transformer pipelines to manipulate key/value pars to produce the results you need, and streaming content from the database.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This also planted a seed for further exploration because I&amp;#8217;d like to rip out &lt;a href=&quot;https://hanakai.org/hanami&quot;&gt;Hanami&lt;/a&gt;&#39;s use of &lt;a href=&quot;https://hanakai.org/rom&quot;&gt;Ruby Object Mapper&lt;/a&gt; and explore pure SQL as well since there&amp;#8217;s been very little progress with the &lt;a href=&quot;https://hanakai.org/rom&quot;&gt;Ruby Object Mapper&lt;/a&gt; stack for years.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect3&quot;&gt;
&lt;h4 id=&quot;_intro_to_compression_techniques_by_lance_fisher&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=Kc8dXSgqqGE&amp;amp;list=PLLYO-P10l3y0&amp;amp;index=15&quot;&gt;Intro to Compression Techniques&lt;/a&gt; by Lance Fisher&lt;/h4&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Good talk&amp;#8201;&amp;#8212;&amp;#8201;along with helpful visuals&amp;#8201;&amp;#8212;&amp;#8201;on different compression techniques such as gzip, brotli and others. Worth checking out the video especially if you have an interest in the different compression algorithms.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect3&quot;&gt;
&lt;h4 id=&quot;_real_time_hypermedia_the_htmx_way_by_christian_tanul&quot;&gt;Real-Time Hypermedia (the htmx way) by Christian Tanul&lt;/h4&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Christian is a member of the htmx Core team and traveled from Romania to speak so was a bit jet lagged. The talk was also a bit discombobulated as a result. That said, I loved learning about the &lt;code&gt;multipart/mixed&lt;/code&gt; HTTP &lt;code&gt;Content-Type&lt;/code&gt; header which allows you to stream mixed data via a single connection! This has been part of the HTML spec since 1992 but I&amp;#8217;ve never seen anyone talk about this before.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Use of &lt;code&gt;multipart/mixed&lt;/code&gt; is also more versatile than &lt;a href=&quot;/articles/server_sent_events&quot;&gt;Server Sent Events&lt;/a&gt;, which I recently wrote about, so plan to explore and write about this more in the future.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;By the way, Christian&amp;#8217;s work is folded into the &lt;a href=&quot;https://four.htmx.org/extensions/hx-multipart&quot;&gt;hx-multipart&lt;/a&gt; extension which you can use in htmx 4.0.0.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect3&quot;&gt;
&lt;h4 id=&quot;_htmx_4_whats_new_by_carson_gross&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=SjUoc8R1dzQ&amp;amp;list=PLLYO-P10l3y0&amp;amp;index=16&quot;&gt;htmx 4: What&amp;#8217;s New&lt;/a&gt; by Carson Gross&lt;/h4&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Carson closed out the conference with an overview of htmx 4.0.0 features. Here&amp;#8217;s a few highlights:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;A strong focus and return to established web standards.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;As mentioned at &lt;a href=&quot;/articles/big_sky_dev_con_2024&quot;&gt;Big Sky Dev Con 2024&lt;/a&gt;, Carson continues using social media to play the game while staying true the cause.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;htmx 4.0.0&lt;/p&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Will include an upgrade helper.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Will support declarative partial updates via the new &lt;code&gt;hx-partial&lt;/code&gt; element (think &lt;code&gt;template&lt;/code&gt; but enhanced).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A new &lt;code&gt;hx-action&lt;/code&gt; and &lt;code&gt;hx-method&lt;/code&gt; methods which taps into Alexander Petros&#39; &lt;a href=&quot;https://triptychproject.org&quot;&gt;Triptych&lt;/a&gt; project. Super cool!&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A new &lt;code&gt;hx-alpine-compat&lt;/code&gt; attribute that smoothes out interaction with &lt;a href=&quot;https://alpinejs.dev&quot;&gt;Alpine.js&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Much more!&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The best part&amp;#8201;&amp;#8212;&amp;#8201;and epic ending to the entire conference&amp;#8201;&amp;#8212;&amp;#8201;was when Carson mentioned the Gameboy game for htmx 4.0.0 and then handed the mic to Stephen Mitchell to explain the development of the game, the design, levels, and access to the source code. Even better, as conference attendees, we all got a copy of the &lt;a href=&quot;https://swag.htmx.org/products/htmx-4-the-game&quot;&gt;game&lt;/a&gt;!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock focal_point&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/images/articles/big_sky_dev_con_2026/game.png&quot; alt=&quot;Game&quot; width=&quot;720&quot; height=&quot;658&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The only bad aspect of this is that the game is labeled as a &lt;em&gt;Golden Master&lt;/em&gt; but&amp;#8201;&amp;#8212;&amp;#8201;for all us that lived through that era and knows what this means&amp;#8201;&amp;#8212;&amp;#8201;this &lt;em&gt;isn&amp;#8217;t&lt;/em&gt; a Golden Master, only a Beta. Use of Golden Master is incorrect and misleading.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Both Carson and Stephen were channeling a Steve Jobs kind of vibe with the release of the htmx 4.0.0 and the corresponding game (&lt;a href=&quot;https://www.youtube.com/watch?v=M-GtT4-DgkI&amp;amp;list=PLLYO-P10l3y0&amp;amp;index=17&quot;&gt;watch&lt;/a&gt;). Loved it and definitely made the conference special.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Stephen closed with &quot;Don&amp;#8217;t stop caring and love your craft&quot;. This resonates deeply because this site and my entire career has been focused on the &lt;em&gt;Joy of the Craft&lt;/em&gt;. This also coincides with another great quote, above a bench, while walking the &lt;a href=&quot;https://www.montana.edu&quot;&gt;Montana State University&lt;/a&gt; campus:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;quoteblock&quot;&gt;
&lt;blockquote&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I want our graduates to leave here with the clear understanding that ethical purpose and pursuit of knowledge are higher life goals than the pursuit of profit.&lt;/p&gt;
&lt;/div&gt;
&lt;/blockquote&gt;
&lt;div class=&quot;attribution&quot;&gt;
&amp;#8212; Michael P. Malone
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock focal_point&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/images/articles/big_sky_dev_con_2026/bench.png&quot; alt=&quot;Bench&quot; width=&quot;1000&quot; height=&quot;707&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In the Age of Slopware, don&amp;#8217;t forget what it means to create high quality, well architected, and maintainable code. Sweating the details of good quality software&amp;#8201;&amp;#8212;&amp;#8201;both inside and outside&amp;#8201;&amp;#8212;&amp;#8201;is important. Don&amp;#8217;t lose that!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This, by far, has been the best conference of the year. Glad I was able to attend and speak. The entire team has stepped up their game since I was last here in 2024. Loved being on the college campus and being back in my home state. In some ways, this is a bit of a full circle for me by being able to share the joy of the craft with others that started several decades ago.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Looking forward to attending in 2027 and hope you consider this conference in the future as well!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</content>
    <id>https://alchemists.io/articles/big_sky_dev_con_2026</id>
    <link href="https://alchemists.io/articles/big_sky_dev_con_2026"/>
    <published>2026-08-01T16:10:18+00:00</published>
    <rights>2026</rights>
    <title>Big Sky Dev Con 2026</title>
    <updated>2026-09-11T16:06:01+00:00</updated>
    <dc:date>2026-09-11T16:06:01+00:00</dc:date>
  </entry>
  <entry>
    <author>
      <name>Brooke Kuhlmann</name>
      <uri>https://alchemists.io/team/brooke_kuhlmann</uri>
    </author>
    <category term="talks"
      label="Talks"/>
    <content type="html">&lt;p align=&quot;center&quot;&gt;
  &lt;a href=&quot;/talks/htmx_view_transitions&quot;&gt;
    &lt;img src=&quot;/images/talks/htmx_view_transitions/cover-original.png&quot;&gt;
  &lt;/a&gt;
&lt;/p&gt;

&lt;h2&gt;Summary&lt;/h2&gt;
&lt;p&gt;Learn about the power of CSS View Transitions using only HTML and CSS with a tiny amount of JavaScript to tie everything together while Ruby is used to render all slides in real-time both via the web UI and on ePaper devices. You&#39;ll learn the technical details of how all this works while gaining new knowledge to apply to your own tech stack!&lt;/p&gt;

&lt;h2&gt;Details&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;b&gt;Ratio&lt;/b&gt;: 16:9&lt;/li&gt;
  &lt;li&gt;&lt;b&gt;Slides&lt;/b&gt;: 60&lt;/li&gt;
&lt;/ul&gt;
</content>
    <id>https://alchemists.io/talks/htmx_view_transitions</id>
    <link href="https://alchemists.io/talks/htmx_view_transitions"/>
    <published>2026-07-24T16:13:09+00:00</published>
    <rights>2026</rights>
    <title>htmx View Transitions Talk</title>
    <updated>2026-08-23T16:05:28+00:00</updated>
    <dc:date>2026-08-23T16:05:28+00:00</dc:date>
  </entry>
  <entry>
    <author>
      <name>Brooke Kuhlmann</name>
      <uri>https://alchemists.io/team/brooke_kuhlmann</uri>
    </author>
    <category term="ruby"
      label="Ruby"/>
    <category term="rack"
      label="Rack"/>
    <category term="htmx"
      label="htmx"/>
    <content type="html">&lt;div class=&quot;imageblock focal_point&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/images/articles/server_sent_events/cover.png&quot; alt=&quot;Cover&quot; width=&quot;842&quot; height=&quot;280&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;title&quot;&gt;Server Sent Events&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Server Sent Events (SSE) allows a server to push data, one way, to a client over a long lived HTTP connection without the client needing to make multiple requests. Even better, the client will automatically reconnect if the connection drops. Here&amp;#8217;s a few use cases that SSE is great for:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Real-time notifications.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Live dashboards.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Live edits and rendering of updated content.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Progress updates of long running tasks.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Implementing SSE is fairly trivial in &lt;a href=&quot;https://www.ruby-lang.org&quot;&gt;Ruby&lt;/a&gt; especially when using &lt;a href=&quot;https://github.com/rack/rack&quot;&gt;Rack&lt;/a&gt; 3.0.0 middleware and &lt;a href=&quot;https://htmx.org&quot;&gt;htmx&lt;/a&gt; on the front end so let&amp;#8217;s explore further by diving into the code!&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&quot;toc&quot; class=&quot;toc&quot;&gt;
&lt;div id=&quot;toctitle&quot; class=&quot;title&quot;&gt;Table of Contents&lt;/div&gt;
&lt;ul class=&quot;sectlevel1&quot;&gt;
&lt;li&gt;&lt;a href=&quot;#_quick_start&quot;&gt;Quick Start&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_ruby&quot;&gt;Ruby&lt;/a&gt;
&lt;ul class=&quot;sectlevel2&quot;&gt;
&lt;li&gt;&lt;a href=&quot;#_gems&quot;&gt;Gems&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_dependencies&quot;&gt;Dependencies&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_event_source&quot;&gt;Event Source&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_middleware&quot;&gt;Middleware&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_rack&quot;&gt;Rack&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_html_htmx&quot;&gt;HTML (htmx)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_curl&quot;&gt;curl&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_falcon&quot;&gt;Falcon&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_running&quot;&gt;Running&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_specs&quot;&gt;Specs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_quick_start&quot;&gt;Quick Start&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;If you&amp;#8217;d prefer to have all of the code and start playing around, you only need these two files:&lt;/p&gt;
&lt;/div&gt;
&lt;details&gt;
&lt;summary class=&quot;title&quot;&gt;Ruby&lt;/summary&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Save as &lt;code&gt;demo&lt;/code&gt; and run &lt;code&gt;chmod 755 demo&lt;/code&gt; to make it executable.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;c1&quot;&gt;#! /usr/bin/env ruby&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# frozen_string_literal: true&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Save as `demo`, then `chmod 755 demo`, and run as `./demo`.&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;bundler/inline&quot;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;gemfile&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;source&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;https://rubygems.org&quot;&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;gem&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;amazing_print&quot;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;gem&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;cogger&quot;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;gem&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;containable&quot;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;gem&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;debug&quot;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;gem&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;infusible&quot;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;gem&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;initable&quot;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;gem&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;puma&quot;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;gem&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;rack&quot;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;gem&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;rackup&quot;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Container&lt;/span&gt;
  &lt;span class=&quot;kp&quot;&gt;extend&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Containable&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;register&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:logger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Cogger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;id: :demo&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;no&quot;&gt;Dependencies&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Infusible&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Container&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;EventSource&lt;/span&gt;
  &lt;span class=&quot;kp&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Dependencies&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:logger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;kp&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Initable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;sx&quot;&gt;%i[req id]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;kernel: &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Kernel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;stream&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;write&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;stream&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;rescue&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Errno&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;EPIPE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Errno&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;ECONNRESET&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;IOError&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;logger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;debug&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Event stream disconnected.&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;ensure&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;stream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;close&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

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

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;write&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;stream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;count: &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;kernel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;loop&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;stream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;write&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;~&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;CONTENT&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;
        event: demo
        data: Found: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;, Count: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;      CONTENT&lt;/span&gt;

      &lt;span class=&quot;n&quot;&gt;count&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;

      &lt;span class=&quot;nb&quot;&gt;sleep&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.5&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Middleware&lt;/span&gt;
  &lt;span class=&quot;kp&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Initable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;sx&quot;&gt;%i[req application]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;sx&quot;&gt;%i[keyreq pattern]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;ss&quot;&gt;headers: &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;s2&quot;&gt;&quot;Cache-Control&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;no-cache&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;s2&quot;&gt;&quot;Content-Type&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;text/event-stream&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;s2&quot;&gt;&quot;X-Accel-Buffering&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;no&quot;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;ss&quot;&gt;event_source: &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;EventSource&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;environment&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Rack&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;environment&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;path&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;path&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;match&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pattern&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;id: &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;event_source&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;application&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;environment&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;application&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Rack&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Middleware&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;pattern: &lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;%r(^/sse/(?&amp;lt;id&amp;gt;.+)$)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Rack&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Static&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;urls: &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;root: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;.&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;index: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;index.html&quot;&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;run&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;proc&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;content-type&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;text/plain&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Demonstration&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;no&quot;&gt;Rackup&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Server&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;start&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;app: &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;application&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/details&gt;
&lt;details&gt;
&lt;summary class=&quot;title&quot;&gt;HTML&lt;/summary&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Save as &lt;code&gt;index.html&lt;/code&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;html&quot;&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;

&lt;span class=&quot;nt&quot;&gt;&amp;lt;html&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;lang=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;en&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;meta&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;viewport&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;content=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;width=device-width,initial-scale=1,shrink-to-fit=no&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;

    &lt;span class=&quot;nt&quot;&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Demo&lt;span class=&quot;nt&quot;&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;

    &lt;span class=&quot;nt&quot;&gt;&amp;lt;meta&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;charset=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;utf-8&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;meta&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;description&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;content=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;A demo site.&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;meta&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;author&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;content=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Alchemists&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;

    &lt;span class=&quot;nt&quot;&gt;&amp;lt;style &lt;/span&gt;&lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;text/css&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;

    &lt;span class=&quot;nt&quot;&gt;&amp;lt;script &lt;/span&gt;&lt;span class=&quot;na&quot;&gt;src=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;https://unpkg.com/htmx.org@2.0.10&quot;&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;integrity=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;sha384-H5SrcfygHmAuTDZphMHqBJLc3FhssKjG7w/CeCpFReSfwBWDTKpkzPP8c+cLsK+V&quot;&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;crossorigin=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;anonymous&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

    &lt;span class=&quot;nt&quot;&gt;&amp;lt;script &lt;/span&gt;&lt;span class=&quot;na&quot;&gt;src=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;https://unpkg.com/htmx-ext-sse@2.2.4&quot;&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;integrity=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;sha384-A986SAtodyH8eg8x8irJnYUk7i9inVQqYigD6qZ9evobksGNIXfeFvDwLSHcp31N&quot;&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;crossorigin=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;anonymous&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;

  &lt;span class=&quot;nt&quot;&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;p&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;hx-ext=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;sse&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;sse-connect=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/sse/1&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;sse-swap=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;demo&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;Loading...&lt;span class=&quot;nt&quot;&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/details&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Once you&amp;#8217;ve saved the above to disk, you should have the following files:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;index.html
demo&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;To launch the application, run: &lt;code&gt;./demo&lt;/code&gt;. The open &lt;code&gt;&lt;a href=&quot;http://localhost:9292&quot; class=&quot;bare&quot;&gt;http://localhost:9292&lt;/a&gt;&lt;/code&gt; in your default web browser. The rest of this article will explain how all of this works.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_ruby&quot;&gt;Ruby&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;With the above, we are using a &lt;a href=&quot;/articles/ruby_bundler_inline&quot;&gt;Bundler Inline&lt;/a&gt; script for demonstration purposes. Normally, you&amp;#8217;d want to use &lt;a href=&quot;projects/rubysmith&quot;&gt;Rubysmith&lt;/a&gt; to split the implementation into separate files but keeping all of this together, for now, allows you to quickly experiment with the code.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_gems&quot;&gt;Gems&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;At the top of &lt;a href=&quot;/articles/ruby_bundler_inline&quot;&gt;Bundler Inline&lt;/a&gt; script, several gems are installed for you. The following breaks down why each is used:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://www.ruby-lang.org&quot;&gt;Ruby&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/amazing-print/amazing_print&quot;&gt;Amazing Print&lt;/a&gt;: For pretty printing of inspected objects.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;/projects/cogger&quot;&gt;Cogger&lt;/a&gt;: For logging.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;/projects/containable&quot;&gt;Containable&lt;/a&gt;: For dependency injection containers.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/ruby/debug&quot;&gt;Debug&lt;/a&gt;: For debugging code.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;/projects/infusible&quot;&gt;Infusible&lt;/a&gt;: For automatic dependency injection.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;/projects/initable&quot;&gt;Initable&lt;/a&gt;: For automatic initialization.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://puma.io&quot;&gt;Puma&lt;/a&gt;: For serving web content.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/rack/rack&quot;&gt;Rack&lt;/a&gt;: For building modular web applications.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/rack/rackup&quot;&gt;Rackup&lt;/a&gt;: For launching rack middleware.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://htmx.org&quot;&gt;htmx&lt;/a&gt;: For sending HTML fragments over the wire.&lt;/p&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://htmx.org/extensions/sse/&quot;&gt;htmx SSE Extension&lt;/a&gt;: For processing and rendering SSE.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_dependencies&quot;&gt;Dependencies&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Next, we register and prepare our dependencies for automatic injection:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Container&lt;/span&gt;
  &lt;span class=&quot;kp&quot;&gt;extend&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Containable&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;register&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:logger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Cogger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;id: :demo&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;no&quot;&gt;Dependencies&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Infusible&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Container&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This allows us to leverage dependency injection containers for dependency injection via &lt;a href=&quot;/projects/containable&quot;&gt;Containable&lt;/a&gt; and &lt;a href=&quot;/projects/infusible&quot;&gt;Infusible&lt;/a&gt; respectively so we can register and inject &lt;a href=&quot;/projects/cogger&quot;&gt;Cogger&lt;/a&gt; for logging purposes.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_event_source&quot;&gt;Event Source&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Next, we have our event source:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;EventSource&lt;/span&gt;
  &lt;span class=&quot;kp&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Dependencies&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:logger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;kp&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Initable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;sx&quot;&gt;%i[req id]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;kernel: &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Kernel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;stream&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;write&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;stream&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;rescue&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Errno&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;EPIPE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Errno&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;ECONNRESET&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;IOError&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;logger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;debug&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Event stream disconnected.&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;ensure&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;stream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;close&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

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

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;write&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;stream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;count: &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;kernel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;loop&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;stream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;write&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;~&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;CONTENT&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;
        event: demo
        data: Found: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;, Count: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;      CONTENT&lt;/span&gt;

      &lt;span class=&quot;n&quot;&gt;count&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;

      &lt;span class=&quot;nb&quot;&gt;sleep&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.5&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The &lt;code&gt;logger&lt;/code&gt; and &lt;code&gt;kernel&lt;/code&gt; are injected as dependencies while the &lt;code&gt;id&lt;/code&gt; is required for loading of a record associated with the ID. For demonstration purposes, we only print the ID to avoid setting up a persistence layer since you can do that on your own if you like.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In order to adhere to &lt;a href=&quot;https://github.com/rack/rack&quot;&gt;Rack&lt;/a&gt; 3.0.0 specification for event streaming, we only need make our event source callable by implementing the &lt;code&gt;#call&lt;/code&gt; method which does the following:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;olist arabic&quot;&gt;
&lt;ol class=&quot;arabic&quot;&gt;
&lt;li&gt;
&lt;p&gt;Writes to the given stream.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Gracefully handles errors by logging them.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Ensures the stream is always closed.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;You&amp;#8217;ll notice the private &lt;code&gt;#write&lt;/code&gt; method loops indefinitely on a &lt;code&gt;0.5&lt;/code&gt; second sleep schedule. In order to make the output interesting, a counter is incremented but, again, you&amp;#8217;d normally be loading or processing data to write to the stream instead of updating a simple counter.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;When writing to the stream, you always need the following keys:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;event&lt;/code&gt;: The event name (or identifier). In our case, &lt;code&gt;demo&lt;/code&gt; is our name. We&amp;#8217;ll look for this even in our &lt;a href=&quot;https://htmx.org&quot;&gt;htmx&lt;/a&gt; client shortly.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;data&lt;/code&gt;: The actual data we want to return.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Both the &lt;code&gt;event&lt;/code&gt; and &lt;code&gt;data&lt;/code&gt; data keys must be on separate lines followed by two new lines. Example (with new lines included for demonstration purposes:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;event: demo\n
data: Found 1, Count: 5\n
\n&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;It&amp;#8217;s &lt;em&gt;critical&lt;/em&gt; that you always adhere to this format or your events will be corrupted. It&amp;#8217;s important to note that you can use multiple data keys if necessary. Example:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;event: demo
data: Found 1
data: ,
data: Count: 5&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The above will be automatically concatenated for you and is identical to the following:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;event: demo
data: Found 1, Count: 5&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;If you need to keep writing to the stream in order to keep the stream alive, so-to-speak, you can drop the &lt;code&gt;data&lt;/code&gt; key to use a colon:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;event: demo
: A comment.&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Some call this a pulse or a heartbeat to prevent the stream from disconnecting especially when your writes to the stream are infrequent. All comments are ignored by your client (basically a no operation). Again, only useful if your updates are infrequent in order to keep the connection open.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_middleware&quot;&gt;Middleware&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In order to be compatible with &lt;a href=&quot;https://github.com/rack/rack&quot;&gt;Rack&lt;/a&gt;, our middleware must be callable:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Middleware&lt;/span&gt;
  &lt;span class=&quot;kp&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Initable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;sx&quot;&gt;%i[req application]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;sx&quot;&gt;%i[keyreq pattern]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;ss&quot;&gt;headers: &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;s2&quot;&gt;&quot;Cache-Control&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;no-cache&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;s2&quot;&gt;&quot;Content-Type&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;text/event-stream&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;s2&quot;&gt;&quot;X-Accel-Buffering&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;no&quot;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;ss&quot;&gt;event_source: &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;EventSource&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;environment&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Rack&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;environment&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;path&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;path&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;match&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pattern&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;id: &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;event_source&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;application&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;environment&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;We also need to require &lt;code&gt;application&lt;/code&gt; as the first positional parameter. Everything else is optional. Each, optional, keyword parameter is:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;pattern&lt;/code&gt;: This allows us to match the request path based on regular expression pattern. This also makes this middleware reusable for different routes that need shared behavior.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;headers&lt;/code&gt;: The first two headers are required for being in compliance with Server Sent Events. The &lt;code&gt;X-Accel-Buffering&lt;/code&gt; is optional but aids in being compatible with Nginx load balancers.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;event_source&lt;/code&gt;: This is our &lt;code&gt;EventSource&lt;/code&gt; object, as discussed earlier, which aids in swapping in different implementations if desired.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;It&amp;#8217;s worth pointing out, depending on your situation, that you might want to modify the &lt;code&gt;case&lt;/code&gt; statement as follows:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;match&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pattern&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;id:
    &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;puma.mark_as_io_bound&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;rack.session.options&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:skip&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;event_source&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;application&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;environment&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The first line allows you to make use of the &lt;a href=&quot;https://puma.io&quot;&gt;Puma&lt;/a&gt; feature that allows you to mark your Server Sent Event as I/0 bound so it can exceed the normal thread pool maximum for I/O operations that are usually slower. This pairs well with Puma&amp;#8217;s &lt;code&gt;max_io_threads&lt;/code&gt; configuration setting.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The second line allows you to skip sending your Rack session/authentication/cookie information with each event since you only need to send this once upon initial connection. Otherwise, you&amp;#8217;ll see duplicate sessions pile up with each response which is definitely &lt;em&gt;not&lt;/em&gt; what you want when streaming events.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_rack&quot;&gt;Rack&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The last part of our script uses &lt;code&gt;Rack::Builder&lt;/code&gt; to add our middleware, serve static assets (especially our index page), and run our demonstration application.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;application&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Rack&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Middleware&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;pattern: &lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;%r(^/sse/(?&amp;lt;id&amp;gt;.+)$)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Rack&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Static&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;urls: &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;root: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;.&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;index: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;index.html&quot;&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;run&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;proc&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;content-type&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;text/plain&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Demonstration&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;no&quot;&gt;Rackup&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Server&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;start&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;app: &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;application&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Again&amp;#8201;&amp;#8212;&amp;#8201;and as mentioned earlier&amp;#8201;&amp;#8212;&amp;#8201;you&amp;#8217;d split all objects out to separate files and use a &lt;code&gt;config.ru&lt;/code&gt; file to launch your Rack app but keeping all this logic in one file makes this easier to demonstrate.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;That&amp;#8217;s it for our Ruby code. Now let&amp;#8217;s look at our htmx client.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_html_htmx&quot;&gt;HTML (htmx)&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;a href=&quot;https://htmx.org&quot;&gt;htmx&lt;/a&gt; is great for having a simple client for consuming our Server Sent Events:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;html&quot;&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;

&lt;span class=&quot;nt&quot;&gt;&amp;lt;html&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;lang=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;en&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;meta&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;viewport&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;content=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;width=device-width,initial-scale=1,shrink-to-fit=no&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;

    &lt;span class=&quot;nt&quot;&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Demo&lt;span class=&quot;nt&quot;&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;

    &lt;span class=&quot;nt&quot;&gt;&amp;lt;meta&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;charset=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;utf-8&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;meta&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;description&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;content=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;A demo site.&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;meta&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;author&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;content=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Alchemists&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;

    &lt;span class=&quot;nt&quot;&gt;&amp;lt;style &lt;/span&gt;&lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;text/css&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;

    &lt;span class=&quot;nt&quot;&gt;&amp;lt;script &lt;/span&gt;&lt;span class=&quot;na&quot;&gt;src=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;https://unpkg.com/htmx.org@2.0.10&quot;&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;integrity=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;sha384-H5SrcfygHmAuTDZphMHqBJLc3FhssKjG7w/CeCpFReSfwBWDTKpkzPP8c+cLsK+V&quot;&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;crossorigin=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;anonymous&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

    &lt;span class=&quot;nt&quot;&gt;&amp;lt;script &lt;/span&gt;&lt;span class=&quot;na&quot;&gt;src=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;https://unpkg.com/htmx-ext-sse@2.2.4&quot;&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;integrity=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;sha384-A986SAtodyH8eg8x8irJnYUk7i9inVQqYigD6qZ9evobksGNIXfeFvDwLSHcp31N&quot;&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;crossorigin=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;anonymous&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;

  &lt;span class=&quot;nt&quot;&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;p&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;hx-ext=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;sse&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;sse-connect=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/sse/1&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;sse-swap=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;demo&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;Loading...&lt;span class=&quot;nt&quot;&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;With the above, we require the &lt;a href=&quot;https://htmx.org&quot;&gt;htmx&lt;/a&gt; library and associated &lt;a href=&quot;https://htmx.org/extensions/sse/&quot;&gt;htmx SSE Extension&lt;/a&gt; extension for consuming and rendering events. You&amp;#8217;ll notice that our path (&lt;code&gt;/sse/1&lt;/code&gt;) maps to the same path used to configure our middleware and the event name, &lt;code&gt;demo&lt;/code&gt;, also maps to the name used in our &lt;code&gt;EventSource&lt;/code&gt; implementation. This is what connects the client and server together.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_curl&quot;&gt;curl&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;You&amp;#8217;re not limited to viewing the output of your SSE via the web browser as you can use &lt;code&gt;curl&lt;/code&gt; as follows:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;bash&quot;&gt;curl &lt;span class=&quot;nt&quot;&gt;-v&lt;/span&gt; http://localhost:9292/sse/1&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The above should yield output similar to the following:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;* Host localhost:9292 was resolved.
* IPv6: ::1
* IPv4: 127.0.0.1
*   Trying [::1]:9292...
* Connected to localhost (::1) port 9292
&amp;gt; GET /sse/1 HTTP/1.1
&amp;gt; Host: localhost:9292
&amp;gt; User-Agent: curl/8.7.1
&amp;gt; Accept: */*
&amp;gt;
* Request completely sent off
&amp;lt; HTTP/1.1 200 OK
&amp;lt; cache-control: no-cache
&amp;lt; content-type: text/event-stream
&amp;lt; x-accel-buffering: no
&amp;lt;
* no chunk, no close, no size. Assume close to signal end
event: demo
data: Found: 1, Count: 1

event: demo
data: Found: 1, Count: 2

event: demo
data: Found: 1, Count: 3&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_falcon&quot;&gt;Falcon&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;If you&amp;#8217;d perfer &lt;a href=&quot;https://socketry.github.io/falcon/&quot;&gt;Falcon&lt;/a&gt;, instead of &lt;a href=&quot;https://puma.io&quot;&gt;Puma&lt;/a&gt;, you can definitely do this by requiring the gem and using &lt;code&gt;falcon&lt;/code&gt; as the server by changing the very last line of the &lt;a href=&quot;/articles/ruby_bundler_inline&quot;&gt;Bundler Inline&lt;/a&gt; script as follows:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;no&quot;&gt;Rackup&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Server&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;start&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;app: &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;application&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;server: :falcon&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_running&quot;&gt;Running&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;As mentioned in the &lt;em&gt;Quick Start&lt;/em&gt; section, to run the demonstration, you only need to run as follows:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;./demo
open http://localhost:9292&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;💡 You can then launch the same URL in multiple browser tabs to get multiple streams running at once.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_specs&quot;&gt;Specs&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;If using &lt;a href=&quot;https://puma.io&quot;&gt;Puma&lt;/a&gt;, ensure you use two minimum and two maximum threads since you&amp;#8217;ll need one thread for normal page requests and one for SSE connections since they are persisted and longer lived. Otherwise, you&amp;#8217;ll have random spec failures with fewer threads. Here&amp;#8217;s what you should have in your spec helper for your &lt;em&gt;feature&lt;/em&gt; specs to get started:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;no&quot;&gt;Capybara&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;server&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:puma&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Silent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Threads&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;2:2&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The threads value of &lt;code&gt;2:2&lt;/code&gt; means a minimum of two threads (first number before the colon) and a maximum of two threads (second value after the colon). You can definitely tweak these numbers by making them smaller or larger but do recommend keeping the maximum number of threads two or higher.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;As you can see, implementing SSE takes minimal effort. You only need an event stream, middleware, and a client to wire everything up. Even better, you&amp;#8217;ve learned how to make all of your objects reusable and configurable should you need to introduce different behavior without complicating or reducing the maintenance of your architecture.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Enjoy and may your applications be lively!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</content>
    <id>https://alchemists.io/articles/server_sent_events</id>
    <link href="https://alchemists.io/articles/server_sent_events"/>
    <published>2026-07-01T12:06:32+00:00</published>
    <rights>2026</rights>
    <title>Server Sent Events</title>
    <updated>2026-07-02T13:05:31+00:00</updated>
    <dc:date>2026-07-02T13:05:31+00:00</dc:date>
  </entry>
  <entry>
    <author>
      <name>Brooke Kuhlmann</name>
      <uri>https://alchemists.io/team/brooke_kuhlmann</uri>
    </author>
    <category term="projects"
      label="Projects"/>
    <content type="html">&lt;div align=&quot;center&quot;&gt;
  &lt;a href=&quot;/projects/docker-debian-ruby&quot;&gt;
    &lt;img src=&quot;/images/projects/docker-debian-ruby/logo.png&quot; width=&quot;200&quot; height=&quot;200&quot;&gt;
  &lt;/a&gt;

  &lt;h1&gt;&lt;a href=&quot;/projects/docker-debian-ruby&quot;&gt;Docker Debian Ruby&lt;/a&gt;&lt;/h1&gt;
&lt;/div&gt;

&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Provides a &lt;a href=&quot;https://www.ruby-lang.org&quot;&gt;Ruby&lt;/a&gt; focused &lt;a href=&quot;https://www.debian.org&quot;&gt;Debian&lt;/a&gt; Docker image with current tooling for development purposes. Great for local development and/or continuous integration builds using the most up-to-date tooling.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&quot;toc&quot; class=&quot;toc&quot;&gt;
&lt;div id=&quot;toctitle&quot; class=&quot;title&quot;&gt;Table of Contents&lt;/div&gt;
&lt;ul class=&quot;sectlevel1&quot;&gt;
&lt;li&gt;&lt;a href=&quot;#_features&quot;&gt;Features&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_requirements&quot;&gt;Requirements&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_setup&quot;&gt;Setup&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_usage&quot;&gt;Usage&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_development&quot;&gt;Development&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_tests&quot;&gt;Tests&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_license&quot;&gt;License&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_security&quot;&gt;Security&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_code_of_conduct&quot;&gt;Code of Conduct&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_contributions&quot;&gt;Contributions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_developer_certificate_of_origin&quot;&gt;Developer Certificate of Origin&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_versions&quot;&gt;Versions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_community&quot;&gt;Community&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_credits&quot;&gt;Credits&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_features&quot;&gt;Features&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Installs &lt;a href=&quot;https://jemalloc.net&quot;&gt;jemalloc&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Installs &lt;a href=&quot;https://www.ruby-lang.org&quot;&gt;Ruby&lt;/a&gt; with &lt;a href=&quot;https://speed.yjit.org&quot;&gt;YJIT&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Updates &lt;a href=&quot;https://rubygems.org&quot;&gt;RubyGems&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_requirements&quot;&gt;Requirements&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;olist arabic&quot;&gt;
&lt;ol class=&quot;arabic&quot;&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://www.docker.com&quot;&gt;Docker&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_setup&quot;&gt;Setup&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;To set up the project, run:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;bash&quot;&gt;git clone https://github.com/bkuhlmann/docker-debian-ruby.git
&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;docker-debian-ruby
git checkout:0.3.0&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_usage&quot;&gt;Usage&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;All versions of this image can be found on
&lt;a href=&quot;https://hub.docker.com/r/bkuhlmann/debian-ruby/tags&quot;&gt;Docker Hub&lt;/a&gt;. The image can be pulled as follows:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;bash&quot;&gt;docker pull bkuhlmann/debian-ruby:latest  &lt;span class=&quot;c&quot;&gt;# &amp;lt;= Pull latest version.&lt;/span&gt;
docker pull bkuhlmann/debian-ruby:0.3.0   &lt;span class=&quot;c&quot;&gt;# &amp;lt;= Pull specific version.&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;You can also build on top of this image via your &lt;code&gt;Dockerfile&lt;/code&gt;:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;dockerfile&quot;&gt;&lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; bkuhlmann/debian-ruby:latest  # &amp;lt;= Latest version.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; bkuhlmann/debian-ruby:0.3.0   # &amp;lt;= Specific version.&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_development&quot;&gt;Development&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;To contribute, run:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;bash&quot;&gt;git clone https://github.com/bkuhlmann/docker-debian-ruby.git
&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;docker-debian-ruby&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;To build, run:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;bash&quot;&gt;bin/build&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;To use the console, run:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;bash&quot;&gt;bin/console&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;To deploy the &lt;em&gt;latest&lt;/em&gt; version, run:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;bash&quot;&gt;bin/deploy&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;To automatically calculate the next logical version and deploy it, run:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;bash&quot;&gt;bin/deploy p&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Versions are calculated and created via the &lt;a href=&quot;https://alchemists.io/projects/milestoner&quot;&gt;Milestoner&lt;/a&gt; gem. Best practice is to deploy both the latest version and next version. Example:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;bash&quot;&gt;bin/deploy
bin/deploy p&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The above will ensure new images are created with the following tags:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;latest&lt;/code&gt;: This is the most recent stable version which may or may not be ahead of the last version released.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;major&amp;gt;.&amp;lt;minor&amp;gt;.&amp;lt;patch&amp;gt;&lt;/code&gt;: This the next logical version as calculated and created by &lt;a href=&quot;https://alchemists.io/projects/milestoner&quot;&gt;Milestoner&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_tests&quot;&gt;Tests&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;To test, run:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;rouge highlight&quot;&gt;&lt;code data-lang=&quot;bash&quot;&gt;bin/console
ruby &lt;span class=&quot;nt&quot;&gt;--version&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_license&quot;&gt;&lt;a href=&quot;https://alchemists.io/policies/license&quot;&gt;License&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_security&quot;&gt;&lt;a href=&quot;https://alchemists.io/policies/security&quot;&gt;Security&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_code_of_conduct&quot;&gt;&lt;a href=&quot;https://alchemists.io/policies/code_of_conduct&quot;&gt;Code of Conduct&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_contributions&quot;&gt;&lt;a href=&quot;https://alchemists.io/policies/contributions&quot;&gt;Contributions&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_developer_certificate_of_origin&quot;&gt;&lt;a href=&quot;https://alchemists.io/policies/developer_certificate_of_origin&quot;&gt;Developer Certificate of Origin&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_versions&quot;&gt;&lt;a href=&quot;https://alchemists.io/projects/docker-debian-ruby/versions&quot;&gt;Versions&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_community&quot;&gt;&lt;a href=&quot;https://alchemists.io/community&quot;&gt;Community&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_credits&quot;&gt;Credits&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Built with &lt;a href=&quot;https://alchemists.io/projects/rubysmith&quot;&gt;Rubysmith&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Engineered by &lt;a href=&quot;https://alchemists.io/team/brooke_kuhlmann&quot;&gt;Brooke Kuhlmann&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
</content>
    <id>https://alchemists.io/projects/docker-debian-ruby</id>
    <link href="https://alchemists.io/projects/docker-debian-ruby"/>
    <published>2026-06-14T23:06:10+00:00</published>
    <rights>2026</rights>
    <title>Docker Debian Ruby Project</title>
    <updated>2026-09-30T01:22:58+00:00</updated>
    <dc:date>2026-09-30T01:22:58+00:00</dc:date>
  </entry>
  <dc:date>2026-10-14T23:31:32+00:00</dc:date>
</feed>
