<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Andrew Bohush</title>
    <description>The latest articles on DEV Community by Andrew Bohush (@abohush).</description>
    <link>https://dev.to/abohush</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F748160%2Fc37d6870-ca35-428c-846b-ad1c0fef2aa3.jpg</url>
      <title>DEV Community: Andrew Bohush</title>
      <link>https://dev.to/abohush</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/abohush"/>
    <language>en</language>
    <item>
      <title>Convert a Hash to a Struct-like object</title>
      <dc:creator>Andrew Bohush</dc:creator>
      <pubDate>Mon, 21 Feb 2022 08:40:25 +0000</pubDate>
      <link>https://dev.to/abohush/convert-a-hash-to-a-struct-like-object-100p</link>
      <guid>https://dev.to/abohush/convert-a-hash-to-a-struct-like-object-100p</guid>
      <description>&lt;h2&gt;
  
  
  &lt;strong&gt;TL;DR&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Stop thinking about symbols &lt;em&gt;vs&lt;/em&gt; strings when accessing values in your hash. Simply call a method. Convert your hash to a struct-like object with &lt;a href="https://github.com/a-bohush/hash_to_struct"&gt;hash_to_struct&lt;/a&gt; gem. It is built on top of standard &lt;code&gt;Struct&lt;/code&gt; and &lt;code&gt;OpenStruct&lt;/code&gt;, with the ability to handle nested hashes/arrays and a few more convenient features.&lt;/p&gt;

&lt;h2&gt;
  
  
  Motivation
&lt;/h2&gt;

&lt;p&gt;Working with a ruby &lt;code&gt;Hash&lt;/code&gt; can sometimes be tricky. Hash's ability to hold almost any object as a key may be a source of frustration when using strings and symbols as hash keys.&lt;/p&gt;

&lt;p&gt;Often, when we use a hash to represent some data, we also have to pick &lt;code&gt;String&lt;/code&gt; or &lt;code&gt;Symbol&lt;/code&gt; type for the hash keys while in fact we do not really care about the key type. From a human perspective keys &lt;code&gt;'foo'&lt;/code&gt; and &lt;code&gt;:foo&lt;/code&gt; in a hash should point to the same value.&lt;/p&gt;

&lt;p&gt;And while it may not matter to you, it certainly does for a ruby interpreter. So it is common to get a &lt;code&gt;nil&lt;/code&gt; in the place where you are expecting &lt;code&gt;hash[:foo]&lt;/code&gt; to return a value but the hash happen to be &lt;code&gt;{'foo' =&amp;gt; value}&lt;/code&gt; for some reason.&lt;/p&gt;

&lt;p&gt;This typically happens around hash serialization actions. For example, at one point you had a hash with symbol keys and saved it to Redis, then later got the hash back from Redis, but keys are strings now.&lt;/p&gt;

&lt;p&gt;There is an Active Support Core Extensions class called &lt;code&gt;ActiveSupport::HashWithIndifferentAccess&lt;/code&gt;, solving precisely this problem. It extends a ruby &lt;code&gt;Hash&lt;/code&gt;, making it handle keys like &lt;code&gt;'foo'&lt;/code&gt; and &lt;code&gt;:foo&lt;/code&gt; as if they were the same.&lt;/p&gt;

&lt;p&gt;However, I would not consider this as a go-to approach whenever you don't want to care about a key type. I think the best case for the &lt;code&gt;ActiveSupport::HashWithIndifferentAccess&lt;/code&gt; is when you work with an API that explicitly expects a hash, but you don't know or don't care what key type the API relies on.&lt;/p&gt;

&lt;p&gt;When working with regular serializable data I prefer to use structs (e.g., &lt;code&gt;Struct&lt;/code&gt;, &lt;code&gt;OpenStruct&lt;/code&gt;). Unlike hashes, structs represent data in the form of value objects, which is more convenient to me, because I do not have to rely on hash specifics like brackets (&lt;code&gt;[]&lt;/code&gt;) as accessor method with the whole string vs symbols dilemma. I expect my data to be an object with values accessible through regular method calls, so I can rely on duck typing if needed.&lt;/p&gt;

&lt;p&gt;Ruby's standard struct classes are a good fit for this case, but you will need some extra "glue" to make this all work together. There is no easy way to convert &lt;code&gt;Hash&lt;/code&gt; to &lt;code&gt;Struct&lt;/code&gt; or &lt;code&gt;OpenStruct&lt;/code&gt;. While &lt;code&gt;OpenStrcut&lt;/code&gt; does accept a hash as a constructor argument, &lt;code&gt;Struct&lt;/code&gt; expects a list of keys first to be mapped to values later. And both &lt;code&gt;Struct&lt;/code&gt; and &lt;code&gt;OpenStruct&lt;/code&gt; are not able to perform recursive conversion of a nested hash.&lt;/p&gt;

&lt;p&gt;To facilitate this, I've built the &lt;a href="https://github.com/a-bohush/hash_to_struct"&gt;hash_to_struct&lt;/a&gt; gem, which defines a unified interface for creating objects based on &lt;code&gt;Struct&lt;/code&gt; or &lt;code&gt;OpenStruct&lt;/code&gt; out of &lt;code&gt;Hash&lt;/code&gt; objects, with an ability to use nested hashes and a few other convenient features. It is a simple gem under 100 lines of code, with no external dependencies.&lt;/p&gt;

&lt;p&gt;With this library you can, for example, create a Struct-based value object like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;struct&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;HashToStruct&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;struct&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="ss"&gt;q: &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;w: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;e: &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;}})&lt;/span&gt;
&lt;span class="n"&gt;struct&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;w&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;e&lt;/span&gt; &lt;span class="c1"&gt;# =&amp;gt; 2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check out the full API description &lt;a href="https://github.com/a-bohush/hash_to_struct/blob/main/README.md"&gt;here&lt;/a&gt;. &lt;/p&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
      <category>gem</category>
    </item>
  </channel>
</rss>
