<?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: Matthew McGarvey</title>
    <description>The latest articles on DEV Community by Matthew McGarvey (@matthewmcgarvey).</description>
    <link>https://dev.to/matthewmcgarvey</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%2F228434%2Ff829e341-f722-496f-b342-e90be3aec696.jpg</url>
      <title>DEV Community: Matthew McGarvey</title>
      <link>https://dev.to/matthewmcgarvey</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/matthewmcgarvey"/>
    <language>en</language>
    <item>
      <title>Talk about Crystal &amp; Go Interfaces</title>
      <dc:creator>Matthew McGarvey</dc:creator>
      <pubDate>Mon, 15 Dec 2025 22:59:59 +0000</pubDate>
      <link>https://dev.to/matthewmcgarvey/talk-about-crystal-go-interfaces-lkd</link>
      <guid>https://dev.to/matthewmcgarvey/talk-about-crystal-go-interfaces-lkd</guid>
      <description>&lt;p&gt;Just a compilation of places where Golang-style interfaces were discussed in the context of Crystal.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://forum.crystal-lang.org/t/are-inferred-types-frozen-for-crystal-shards-and-the-standard-library/1434" rel="noopener noreferrer"&gt;https://forum.crystal-lang.org/t/are-inferred-types-frozen-for-crystal-shards-and-the-standard-library/1434&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://forum.crystal-lang.org/t/proposal-interfaces-for-more-generic-code/2103" rel="noopener noreferrer"&gt;https://forum.crystal-lang.org/t/proposal-interfaces-for-more-generic-code/2103&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/crystal-lang/crystal/issues/3489" rel="noopener noreferrer"&gt;https://github.com/crystal-lang/crystal/issues/3489&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://forum.crystal-lang.org/t/crystal-has-interfaces-in-java-sense/5105" rel="noopener noreferrer"&gt;https://forum.crystal-lang.org/t/crystal-has-interfaces-in-java-sense/5105&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://forum.crystal-lang.org/t/rfc-lazy-objects/8460" rel="noopener noreferrer"&gt;https://forum.crystal-lang.org/t/rfc-lazy-objects/8460&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://forum.crystal-lang.org/t/structural-typing-vs-interfaces/2086" rel="noopener noreferrer"&gt;https://forum.crystal-lang.org/t/structural-typing-vs-interfaces/2086&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Converting a nilable generic argument to its non-nil version</title>
      <dc:creator>Matthew McGarvey</dc:creator>
      <pubDate>Sat, 07 Jan 2023 18:38:42 +0000</pubDate>
      <link>https://dev.to/matthewmcgarvey/converting-a-nilable-generic-argument-to-its-non-nil-version-5gk4</link>
      <guid>https://dev.to/matthewmcgarvey/converting-a-nilable-generic-argument-to-its-non-nil-version-5gk4</guid>
      <description>&lt;p&gt;I have struggled a great deal in the past with making generic code that provides functionality to transform a generic argument from a nilable version to a non-nilable version. And I just learned something pretty cool today.&lt;/p&gt;

&lt;p&gt;Currently, I am working on a parsing and validation library and want to provide the ability to type-safely move from a nilable string input, to a non-nilable output without directly tying the library to only working with strings are optional inputs.&lt;/p&gt;

&lt;p&gt;Here's some simple example code&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Parser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kp"&gt;private&lt;/span&gt; &lt;span class="kp"&gt;getter&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;T&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vi"&gt;@input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;not_nil&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;temp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;temp&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
      &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="s2"&gt;"input was supposed to be present, but was nil"&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"raw_input"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;as&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;String&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt;
&lt;span class="no"&gt;Parser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;not_nil&lt;/span&gt; &lt;span class="c1"&gt;#=&amp;gt; "raw_input" : String&lt;/span&gt;

&lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;as&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;String&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt;
&lt;span class="no"&gt;Parser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;not_nil&lt;/span&gt; &lt;span class="c1"&gt;#=&amp;gt; runtime exception!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I'm hoping that code example is pretty straightforward. It shows a very basic &lt;code&gt;Parser&lt;/code&gt; class that has one method called &lt;code&gt;Parser#not_nil&lt;/code&gt;. It returns the non-nilable version of whatever you give it, otherwise it raises an exception if the input actually is nil. In the example, I gave it a nilable string and it returns a non-nilable string. If you are confused as to why I use a &lt;code&gt;temp&lt;/code&gt; variable, read more on that &lt;a href="https://crystal-lang.org/reference/1.6/syntax_and_semantics/if_var.html#limitations" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;One thing to notice about this code example, is that there is no way to express the return type of &lt;code&gt;Parser#not_nil&lt;/code&gt; so I am forced to let Crystal infer it. It works as expected but I am not overly fond of leaving off return types. It could easily infer something I didn't expect because there is a bug in the code and it also leaves the documentation lacking.&lt;/p&gt;

&lt;p&gt;This code is not very good, though. As I was saying, I'm working on a parsing &lt;em&gt;and validation&lt;/em&gt; library so instead of an exception, I'd prefer a way to express this so that it results in a value that I can return to the user.&lt;/p&gt;

&lt;p&gt;If your familiar with functional languages (or Rust), I'm talking about implementing a Result type of sorts. A Result type is a data structure that can only be represented as one of two options: an &lt;code&gt;Ok&lt;/code&gt; or an &lt;code&gt;Err&lt;/code&gt; (or Error to be more explicit). This is implemented generically to where the Result wraps the value contained in either the Ok or Err.&lt;br&gt;
For my purposes, I want the Ok to wrap any value &lt;code&gt;T&lt;/code&gt; and the Err to always wrap a String. With Crystal generics you'd write the Result as &lt;code&gt;Result(String, T)&lt;/code&gt; where the first item in the parens is the Err type and the second item is the Ok type. To not continue the article with two generics, and because it more closely matches my actual implementation, I will use a &lt;code&gt;Validated(T)&lt;/code&gt; type that is essentially equal to a  &lt;code&gt;Result(String, T)&lt;/code&gt; and has two implementing types of &lt;code&gt;Valid&lt;/code&gt; and &lt;code&gt;Invalid&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here's a real basic implementation of the Validated class.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="n"&gt;abstract&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Validated&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Valid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;Validated&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kp"&gt;getter&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;T&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vi"&gt;@value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Invalid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;Validated&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kp"&gt;getter&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;String&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vi"&gt;@value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There's very little code here, but it's the basic implementation that matter. I know it looks weird for &lt;code&gt;Validated::Invalid&lt;/code&gt; to also have the generic type on it since it only deals with string values (the error messages), but it relates to the code that is missing and it would be more difficult to illustrate what I'm talking about without it. In particular, the code that is missing, involves converting Valid to Invalid and vice-versa. You couldn't do that without keeping up with the valid type on the invalid classes.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;FINALLY&lt;/em&gt;, let's get to the problem code so that I can show off what I learned today.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Parser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kp"&gt;private&lt;/span&gt; &lt;span class="kp"&gt;getter&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;T&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vi"&gt;@input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;not_nil&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;temp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;
      &lt;span class="no"&gt;Validated&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Valid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;temp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
      &lt;span class="no"&gt;Validated&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Invalid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Expected input to be present, but was nil."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"raw_input"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;as&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;String&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt;
&lt;span class="no"&gt;Parser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;not_nil&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;value&lt;/span&gt; &lt;span class="c1"&gt;#=&amp;gt; compilation error!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you actually try to compile this, it fails. It fails because the compiler has no idea what the generic type is supposed to be for the Invalid class. The argument that we pass to create it, is the validation error message after all and we want it to be the not-nil type. We have finally reached the problem that I have run into multiple times and next step has time and again been to open up Discord, go to the Crystal channel, complain, then go do something else while wondering in the back of my mind whether or not I should give up on Crystal and use another language because I figured it was unsolvable. But I decided to do something differently today. I decided to look into where I knew Crystal did something similarly. Specifically, I know that in Crystal you can call &lt;code&gt;[1, 2, nil, 3].compact&lt;/code&gt; and get back the array &lt;code&gt;[1, 2, 3]&lt;/code&gt; with a type of &lt;code&gt;Array(Int32)&lt;/code&gt;. The compiler assures that there can't be nil with the type signature. If the core language is able to express a change from &lt;code&gt;T?&lt;/code&gt; to &lt;code&gt;T&lt;/code&gt;, I should be able to as well. So I opened up the core codebase and found that &lt;a href="https://github.com/crystal-lang/crystal/blob/5402f6a38f69e45d4c20fa0ee685ffb6f1aa416b/src/array.cr#L727-L729" rel="noopener noreferrer"&gt;&lt;code&gt;Array#compact&lt;/code&gt;&lt;/a&gt; delegates to &lt;a href="https://github.com/crystal-lang/crystal/blob/5402f6a38f69e45d4c20fa0ee685ffb6f1aa416b/src/enumerable.cr#L230-L239" rel="noopener noreferrer"&gt;&lt;code&gt;Enumerable#compact_map&lt;/code&gt;&lt;/a&gt;. Here's the code for that method&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;compact_map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;ary&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="n"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="no"&gt;Enumerable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;element_type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;not_nil!&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;
    &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;nil?&lt;/span&gt;
      &lt;span class="n"&gt;ary&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="n"&gt;ary&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This took me a while to understand. It's calling this &lt;code&gt;Enumerable.element_type&lt;/code&gt; function and yielding with it and I still don't understand that part, but the important piece is that it's calling &lt;code&gt;typeof((...).not_nil!)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;🤯🤯🤯🤯&lt;/p&gt;

&lt;p&gt;I had no idea that you could call &lt;code&gt;not_nil!&lt;/code&gt; inside &lt;code&gt;typeof&lt;/code&gt; without raising an error if the thing you are calling it on is actually nil.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;as&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;String&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt;
&lt;span class="n"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;not_nil!&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;#=&amp;gt; String : Class&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🤯🤯🤯🤯&lt;/p&gt;

&lt;p&gt;So &lt;code&gt;Enumerable#compact_map&lt;/code&gt; is able to let the compiler infer the return type by creating the return array with the non-nilable type.&lt;/p&gt;

&lt;p&gt;Now for the grand reveal of how I was able to use this in my own code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Parser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kp"&gt;private&lt;/span&gt; &lt;span class="kp"&gt;getter&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;T&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vi"&gt;@input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;not_nil&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;temp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;
      &lt;span class="no"&gt;Validated&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Valid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;temp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
      &lt;span class="no"&gt;Validated&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Invalid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;not_nil!&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Expected input to be present, but was nil."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"raw_input"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;as&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;String&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt;
&lt;span class="no"&gt;Parser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;not_nil&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;value&lt;/span&gt; &lt;span class="c1"&gt;#=&amp;gt; "raw_input" : String&lt;/span&gt;

&lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;as&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;String&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt;
&lt;span class="no"&gt;Parser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;not_nil&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;value&lt;/span&gt; &lt;span class="c1"&gt;#=&amp;gt; "Expected input to be present, but was nil." : String&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hey!! Look at that!! It works!!&lt;/p&gt;

&lt;p&gt;So while I use the &lt;code&gt;temp&lt;/code&gt; to allow the if-block to narrow the type down, I need to avoid doing that with the &lt;code&gt;typeof((...).not_nil!)&lt;/code&gt; trick so that it remains the original type. The compiler now understands that, while it doesn't have a reference to the not-nil value, Invalid has the same generic type as Valid.&lt;/p&gt;

&lt;p&gt;I love this, and I'm going to run with it in my code that does a whole lot more that's outside the scope of this post but I will hopefully have it ready soon to share. I hope this will be helpful to someone else and that your mind is as blown as mine is.&lt;/p&gt;

&lt;p&gt;By the way, I have noticed the core team refers to this hack in generic terms as &lt;code&gt;T -&amp;gt; T!&lt;/code&gt; and would love for this to be implemented in Crystal without the hacks.&lt;/p&gt;

</description>
      <category>gratitude</category>
    </item>
    <item>
      <title>Crystal View Context</title>
      <dc:creator>Matthew McGarvey</dc:creator>
      <pubDate>Fri, 25 Mar 2022 03:27:39 +0000</pubDate>
      <link>https://dev.to/matthewmcgarvey/crystal-view-context-5ghe</link>
      <guid>https://dev.to/matthewmcgarvey/crystal-view-context-5ghe</guid>
      <description>&lt;p&gt;This article is meant to be more of a public note than anything.&lt;/p&gt;

&lt;p&gt;I have found myself wondering why several Ruby gems that allowed you to create HTML in plain ruby still required you to have separate files instead of putting them in plain ol' ruby objects. As I'm working on my Crystal implementation of Roda, it finally occurred to me why. It's to be able to manage scope. All of those languages didn't require calling the methods &lt;em&gt;on&lt;/em&gt; anything, the methods were just there. It's because the file is run in the context of a class that provides those messages.&lt;/p&gt;

&lt;p&gt;Now why did I put Crystal in the title but only talk about Ruby? Well, we have a context issue in Crystal and we've struggled with it a fair amount. There's ECR which does some fancy macro things but ultimately just copy/pastes the ECR file directly into the place where &lt;code&gt;ECR.render&lt;/code&gt; is called. Over in Lucky, though, we make HTML through Crystal code and they are separate objects. One of the pains of that is passing in the HTTP context for things like link helpers and CSRF tokens. Buuuut, if the Crystal code was in a separate, non-Crystal file, we could still have all the functionality of Lucky's html building, but with the context control of ECR.&lt;/p&gt;

&lt;p&gt;I am sticking with ECR right now in my library, but I might experiment more in the future. One advantage of this over ECR is that I don't have to do any pre-processing to pull out the fancy tags for embedding crystal into regular HTML.&lt;/p&gt;

</description>
      <category>crystal</category>
      <category>html</category>
    </item>
    <item>
      <title>GitHub Pull Requests with Screenshots Tip</title>
      <dc:creator>Matthew McGarvey</dc:creator>
      <pubDate>Tue, 29 Jun 2021 18:51:10 +0000</pubDate>
      <link>https://dev.to/matthewmcgarvey/github-pull-requests-with-screenshots-tip-1cbb</link>
      <guid>https://dev.to/matthewmcgarvey/github-pull-requests-with-screenshots-tip-1cbb</guid>
      <description>&lt;p&gt;When you're making a pull request in GitHub and want to include screenshots in the description, you might be tempted to just throw the screenshots in with headings. I urge you, though, not to do that! Those screenshots take up a lot of room and there is a better way!&lt;/p&gt;

&lt;h2&gt;
  
  
  Dropdowns
&lt;/h2&gt;

&lt;p&gt;Dropdowns are truly the better way to add images to pull requests. By default they can be ignored and can be expanded if you want to look at them.&lt;/p&gt;

&lt;p&gt;Here's a picture of a pull request description without using dropdowns. Notice how much room is taken up. I had to zoom out to 60% just to get it all on my screen!&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--WFRw2O1V--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tyh8l0td0anndd1hgjl2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WFRw2O1V--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tyh8l0td0anndd1hgjl2.png" alt="PR description without dropdowns"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now here's a picture using dropdowns. It's so much simpler.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TRoaSe11--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gfrkc4s7zsrqy05436ff.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TRoaSe11--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gfrkc4s7zsrqy05436ff.png" alt="PR description with dropdowns"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Syntax
&lt;/h3&gt;

&lt;p&gt;I used to always google "github markdown dropdown" and used &lt;a href="https://gist.github.com/citrusui/07978f14b11adada364ff901e27c7f61"&gt;this link&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;They are created using markdown like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;details&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;How do I dropdown?&lt;span class="nt"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;br&amp;gt;&lt;/span&gt;
This is how you dropdown.
&lt;span class="nt"&gt;&amp;lt;/details&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Saved Replies
&lt;/h2&gt;

&lt;p&gt;Just so that you and I don't have to remember this article or that GitHub gist in the future, you can make it easy by creating a saved reply. Those are accessed in the bar above the text area when creating a pull request description.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--u3FAbZiR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jdjvrhjze1dhng5hyl2c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--u3FAbZiR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jdjvrhjze1dhng5hyl2c.png" alt="saved replies button"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can create a new saved reply through that button and make a dropdown saved reply. That's going to save me a bunch of time!&lt;/p&gt;

</description>
      <category>github</category>
    </item>
    <item>
      <title>Crystal - Plugin Pattern</title>
      <dc:creator>Matthew McGarvey</dc:creator>
      <pubDate>Tue, 12 Jan 2021 05:32:31 +0000</pubDate>
      <link>https://dev.to/matthewmcgarvey/crystal-plugin-pattern-3imj</link>
      <guid>https://dev.to/matthewmcgarvey/crystal-plugin-pattern-3imj</guid>
      <description>&lt;h2&gt;
  
  
  The Inspiration
&lt;/h2&gt;

&lt;p&gt;I recently &lt;a href="https://github.com/TechEmpower/FrameworkBenchmarks/pull/6069"&gt;added Lucky to TechEmpower benchmarks&lt;/a&gt; and was looking around for articles/videos about what other frameworks are doing to perform so well. I came across this really good talk by Jeremy Evans called &lt;a href="https://rubykaigi.org/2019/presentations/jeremyevans0.html"&gt;Optimization Techniques Used by the Benchmark Winners&lt;/a&gt;. Instead of carrying away a list of changes to make to Lucky, I came away with a fascination for how he designed his framework, &lt;a href="http://roda.jeremyevans.net/"&gt;Roda&lt;/a&gt;. Specifically, I loved the idea of entirely using plugins to extend and add behavior. If you ever get the chance to look at the source code for the framework you'll notice that the classes are almost empty. All the behavior is added in through plugins. I really wanted to see if this was possible in Crystal.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Challenge
&lt;/h2&gt;

&lt;p&gt;In Roda, when you add a plugin, it includes and extends nested modules.&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;plugin&lt;/span&gt; &lt;span class="no"&gt;CustomRender&lt;/span&gt;

&lt;span class="c1"&gt;# becomes...&lt;/span&gt;

&lt;span class="kp"&gt;include&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;CustomRender&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;InstanceMethods&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;defined?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;CustomRender&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;InstanceMethods&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kp"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;CustomRender&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;ClassMethods&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;defined?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;CustomRender&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;ClassMethods&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# and more...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It also adds modules to the request and response objects but that is enough code to convey the challenges with converting it to Crystal:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;modules can't be included at runtime&lt;/li&gt;
&lt;li&gt;there is no &lt;code&gt;defined?&lt;/code&gt; method&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Solution
&lt;/h2&gt;

&lt;p&gt;While Crystal can't include modules at runtime, we do have macros that can accomplish much of the same things. The original idea was to just have a macro like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="k"&gt;macro&lt;/span&gt; &lt;span class="nf"&gt;plugin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;InstanceMethods&lt;/span&gt;
  &lt;span class="kp"&gt;extend&lt;/span&gt; &lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;ClassMethods&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The only problem with that is the conditional aspect that Roda has. If the plugin doesn't need to add any class methods it shouldn't have to define that module and the framework should be able to handle it. The only solution I've found is to delegate to a second macro.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="k"&gt;macro&lt;/span&gt; &lt;span class="nf"&gt;extend_self&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;instance_methods&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;class_methods&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ims&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;instance_methods&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve?&lt;/span&gt; &lt;span class="p"&gt;%}&lt;/span&gt;
    &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="n"&gt;ims&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
  &lt;span class="p"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt; &lt;span class="p"&gt;%}&lt;/span&gt;
  &lt;span class="p"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cms&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;class_methods&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve?&lt;/span&gt; &lt;span class="p"&gt;%}&lt;/span&gt;
    &lt;span class="kp"&gt;extend&lt;/span&gt; &lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="n"&gt;cms&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
  &lt;span class="p"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt; &lt;span class="p"&gt;%}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;macro&lt;/span&gt; &lt;span class="nf"&gt;plugin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;extend_self&lt;/span&gt;&lt;span class="p"&gt;({{&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;::InstanceMethods"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;id&lt;/span&gt; &lt;span class="p"&gt;}},&lt;/span&gt; &lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;::ClassMethods"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;id&lt;/span&gt; &lt;span class="p"&gt;}})&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The reason for the second macro is that I need the &lt;a href="https://crystal-lang.org/api/0.35.1/Crystal/Macros/Path.html#resolve?:ASTNode%7CNilLiteral-instance-method"&gt;&lt;code&gt;Path#resolve?&lt;/code&gt; method&lt;/a&gt; in order to check if the module is defined and this is the only way I know to dynamically create a &lt;code&gt;Path&lt;/code&gt; object in a macro. Please let me know if you can think of a better way to do it!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="n"&gt;plugin&lt;/span&gt; &lt;span class="no"&gt;CustomRender&lt;/span&gt;

&lt;span class="c1"&gt;# becomes...&lt;/span&gt;

&lt;span class="n"&gt;extend_self&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;CustomerRender&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;InstanceMethods&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;CustomRender&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;ClassMethods&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# becomes...&lt;/span&gt;

&lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;CustomerRender&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;InstanceMethods&lt;/span&gt;
&lt;span class="kp"&gt;extend&lt;/span&gt; &lt;span class="no"&gt;CustomRender&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;ClassMethods&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I haven't gotten to actually converting Roda over to Crystal yet but I hope to. I also hope to make more posts about it along the way.&lt;/p&gt;

</description>
      <category>crystal</category>
    </item>
    <item>
      <title>Crystal Spec CLI Gotcha (--help)</title>
      <dc:creator>Matthew McGarvey</dc:creator>
      <pubDate>Fri, 01 Jan 2021 00:48:57 +0000</pubDate>
      <link>https://dev.to/matthewmcgarvey/crystal-spec-cli-gotcha-help-4l1g</link>
      <guid>https://dev.to/matthewmcgarvey/crystal-spec-cli-gotcha-help-4l1g</guid>
      <description>&lt;p&gt;When calling &lt;code&gt;crystal spec --help&lt;/code&gt; you actually get the spec description but the options list of the &lt;code&gt;crystal&lt;/code&gt; CLI instead of the specs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;❯ crystal spec &lt;span class="nt"&gt;--help&lt;/span&gt;
Usage: crystal spec &lt;span class="o"&gt;[&lt;/span&gt;options] &lt;span class="o"&gt;[&lt;/span&gt;files]

Options:
    &lt;span class="nt"&gt;-d&lt;/span&gt;, &lt;span class="nt"&gt;--debug&lt;/span&gt;                      Add full symbolic debug info
    &lt;span class="nt"&gt;--no-debug&lt;/span&gt;                       Skip any symbolic debug info
    &lt;span class="nt"&gt;-D&lt;/span&gt; FLAG, &lt;span class="nt"&gt;--define&lt;/span&gt; FLAG           Define a compile-time flag
    &lt;span class="nt"&gt;--error-trace&lt;/span&gt;                    Show full error trace
    &lt;span class="nt"&gt;--release&lt;/span&gt;                        Compile &lt;span class="k"&gt;in &lt;/span&gt;release mode
    &lt;span class="nt"&gt;-s&lt;/span&gt;, &lt;span class="nt"&gt;--stats&lt;/span&gt;                      Enable statistics output
    &lt;span class="nt"&gt;-p&lt;/span&gt;, &lt;span class="nt"&gt;--progress&lt;/span&gt;                   Enable progress output
    &lt;span class="nt"&gt;-t&lt;/span&gt;, &lt;span class="nt"&gt;--time&lt;/span&gt;                       Enable execution &lt;span class="nb"&gt;time &lt;/span&gt;output
    &lt;span class="nt"&gt;-h&lt;/span&gt;, &lt;span class="nt"&gt;--help&lt;/span&gt;                       Show this message
    &lt;span class="nt"&gt;--no-color&lt;/span&gt;                       Disable colored output
    &lt;span class="nt"&gt;--warnings&lt;/span&gt; all|none              Which warnings detect. &lt;span class="o"&gt;(&lt;/span&gt;default: all&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="nt"&gt;--error-on-warnings&lt;/span&gt;              Treat warnings as errors.
    &lt;span class="nt"&gt;--exclude-warnings&lt;/span&gt; &amp;lt;path&amp;gt;        Exclude warnings from path &lt;span class="o"&gt;(&lt;/span&gt;default: lib&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To get the options list for specs, run &lt;code&gt;crystal spec -- --help&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;❯ crystal spec &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nt"&gt;--help&lt;/span&gt;
crystal spec runner
    &lt;span class="nt"&gt;-e&lt;/span&gt; , &lt;span class="nt"&gt;--example&lt;/span&gt; STRING            run examples whose full nested names include STRING
    &lt;span class="nt"&gt;-l&lt;/span&gt; , &lt;span class="nt"&gt;--line&lt;/span&gt; LINE                 run examples whose line matches LINE
    &lt;span class="nt"&gt;-p&lt;/span&gt;, &lt;span class="nt"&gt;--profile&lt;/span&gt;                    Print the 10 slowest specs
    &lt;span class="nt"&gt;--fail-fast&lt;/span&gt;                      abort the run on first failure
    &lt;span class="nt"&gt;--location&lt;/span&gt; file:line             run example at line &lt;span class="s1"&gt;'line'&lt;/span&gt; &lt;span class="k"&gt;in &lt;/span&gt;file &lt;span class="s1"&gt;'file'&lt;/span&gt;, multiple allowed
    &lt;span class="nt"&gt;--tag&lt;/span&gt; TAG                        run examples with the specified TAG, or exclude examples by adding ~ before the TAG.
    &lt;span class="nt"&gt;--order&lt;/span&gt; MODE                     run examples &lt;span class="k"&gt;in &lt;/span&gt;random order by passing MODE as &lt;span class="s1"&gt;'random'&lt;/span&gt; or to a specific seed by passing MODE as the seed value
    &lt;span class="nt"&gt;--junit_output&lt;/span&gt; OUTPUT_PATH       generate JUnit XML output within the given OUTPUT_PATH
    &lt;span class="nt"&gt;-h&lt;/span&gt;, &lt;span class="nt"&gt;--help&lt;/span&gt;                       show this &lt;span class="nb"&gt;help&lt;/span&gt;
    &lt;span class="nt"&gt;-v&lt;/span&gt;, &lt;span class="nt"&gt;--verbose&lt;/span&gt;                    verbose output
    &lt;span class="nt"&gt;--tap&lt;/span&gt;                            Generate TAP output &lt;span class="o"&gt;(&lt;/span&gt;Test Anything Protocol&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="nt"&gt;--no-color&lt;/span&gt;                       Disable colored output
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Maybe this was obvious to everyone but I had no idea until I was told about it.&lt;/p&gt;

</description>
      <category>crystal</category>
      <category>testing</category>
    </item>
    <item>
      <title>Custom Spec Expectations</title>
      <dc:creator>Matthew McGarvey</dc:creator>
      <pubDate>Wed, 30 Dec 2020 20:24:12 +0000</pubDate>
      <link>https://dev.to/matthewmcgarvey/custom-spec-expectations-5d2j</link>
      <guid>https://dev.to/matthewmcgarvey/custom-spec-expectations-5d2j</guid>
      <description>&lt;p&gt;There are two parts to custom expectations:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The class that performs the expectation logic&lt;/li&gt;
&lt;li&gt;The method used in specs that initializes and returns the class&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Custom Expectation Class
&lt;/h2&gt;

&lt;p&gt;Methods to implement:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;#match&lt;/code&gt; - performs the expectation logic&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;#failure_message&lt;/code&gt; - the error message when &lt;code&gt;#match&lt;/code&gt; fails and &lt;code&gt;#should&lt;/code&gt; was used&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;#negative_failure_message&lt;/code&gt; - the error message when &lt;code&gt;#match&lt;/code&gt; fails and &lt;code&gt;#should_not&lt;/code&gt; was used&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;All three of these methods take in one argument, the object that &lt;code&gt;#should&lt;/code&gt; or &lt;code&gt;#should_not&lt;/code&gt; was called on. So if the expectation was &lt;code&gt;result.should be_nil&lt;/code&gt;, those methods would take &lt;code&gt;result&lt;/code&gt; as an argument. Here's an example that checks if an HTTP::Request has the expected path:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;HavePathExpectation&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vi"&gt;@expected_path&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;HTTP&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;path&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="vi"&gt;@expected_path&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;failure_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;HTTP&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&amp;lt;-&lt;/span&gt;&lt;span class="no"&gt;MSG&lt;/span&gt;&lt;span class="sh"&gt;
    Expected request to have path: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="vi"&gt;@expected_path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;
                           actual: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;
&lt;/span&gt;&lt;span class="no"&gt;    MSG&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;negative_failure_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;HTTP&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="s2"&gt;"Expected request to not have path: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Custom Expectation Method
&lt;/h2&gt;

&lt;p&gt;These are global methods and are the expectations that users will call. Libraries should put them in a single module for users to include in their &lt;code&gt;spec_helper.cr&lt;/code&gt;. To use the class from above:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;MyLibrary::Expectations&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;have_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;expected_path&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="no"&gt;HavePathExpectation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;expected_path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="c1"&gt;# in spec_helper.cr&lt;/span&gt;
&lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;MyLibrary&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Expectations&lt;/span&gt;

&lt;span class="c1"&gt;# in a spec&lt;/span&gt;
&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;should&lt;/span&gt; &lt;span class="n"&gt;have_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"/users"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All the method does is take in any arguments if they are necessary and returns the initialized expectation class.&lt;/p&gt;

&lt;p&gt;Types are really useful to specify with custom expectations. The types on the class method parameters limits when the expectations can be used. The class above is limited to only when &lt;code&gt;#should&lt;/code&gt; is called on an &lt;code&gt;HTTP::Request&lt;/code&gt; and the expectation method limits what can be passed in as the expected value.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fanciness
&lt;/h2&gt;

&lt;p&gt;I haven't had an opportunity to implement it yet, but since &lt;code&gt;#should&lt;/code&gt; only expects some object it can call those three methods on, you don't have to stop at just the one expectation method. Using method chaining where the methods always return &lt;code&gt;self&lt;/code&gt; at the end, you can make a really pleasant expectation DSL. Imagine, instead of a specific expectation class about the request path, it was a general request validation class that could be updated to check different parts of the request.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RequestExpectation&lt;/span&gt;
  &lt;span class="vi"&gt;@path&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;String&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;
  &lt;span class="vi"&gt;@request_method&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;String&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;
  &lt;span class="vi"&gt;@errors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="no"&gt;String&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;HTTP&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;expected_path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vi"&gt;@path&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;path&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;expected_path&lt;/span&gt;
      &lt;span class="vi"&gt;@errors&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s2"&gt;"Expected path to be &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;expected_path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; but was &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kp"&gt;false&lt;/span&gt; 
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;expected_method&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vi"&gt;@request_method&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;method&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;expected_method&lt;/span&gt;
      &lt;span class="vi"&gt;@errors&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s2"&gt;"Expected request method to be &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;expected_method&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; but was &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;method&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kp"&gt;false&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="kp"&gt;true&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;with_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;expected_path&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="vi"&gt;@path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;expected_path&lt;/span&gt;
    &lt;span class="nb"&gt;self&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;with_method&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;expected_method&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="vi"&gt;@request_method&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;expected_method&lt;/span&gt;
    &lt;span class="nb"&gt;self&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;failure_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;HTTP&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# not implemented for brevity&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;negative_failure_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;HTTP&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# not implemented for brevity&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and then the expectations would need to be updated accordingly&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;MyLibrary::Expectations&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;have_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;expected_path&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="no"&gt;HavePathExpectation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;with_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;expected_path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;have_method&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;expected_method&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="no"&gt;HavePathExpectation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;with_method&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;expected_method&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you can compose the expectation to validate the pieces you need.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;should&lt;/span&gt; &lt;span class="n"&gt;have_method&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"GET"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;should&lt;/span&gt; &lt;span class="n"&gt;have_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"/users/123"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;with_method&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"DELETE"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This might not have been the &lt;em&gt;best&lt;/em&gt; example because the expectations are very specific but imagine having a broader expectation with helper methods after to provide more specifics.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="no"&gt;EmailClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;should&lt;/span&gt; &lt;span class="n"&gt;have_sent_emails&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"foo@example.com"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;with_subject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Subscription Invoice"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;with_cc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"boss@example.com"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;with_email_template&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;SubscriptionInvoice&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It takes a bit of work but I think it's pretty cool!&lt;/p&gt;

</description>
      <category>crystal</category>
      <category>testing</category>
    </item>
    <item>
      <title>Macro Tips: Avoid nesting macros if possible</title>
      <dc:creator>Matthew McGarvey</dc:creator>
      <pubDate>Wed, 30 Dec 2020 05:46:01 +0000</pubDate>
      <link>https://dev.to/matthewmcgarvey/macro-tips-avoid-nesting-macros-if-possible-3i88</link>
      <guid>https://dev.to/matthewmcgarvey/macro-tips-avoid-nesting-macros-if-possible-3i88</guid>
      <description>&lt;p&gt;One issue that has come up recently is that error output for compilations errors only contains the place the error occurred and the place that called the offending code. It might not sound like a problem, but pair that with macros and it will all become clear. It's easiest to show, so here's some code that produces a compilation error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="k"&gt;macro&lt;/span&gt; &lt;span class="nf"&gt;compilation_error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="n"&gt;arg&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;compilation_error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"asdf"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;and the compilation error looks like:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Showing last frame. Use &lt;span class="nt"&gt;--error-trace&lt;/span&gt; &lt;span class="k"&gt;for &lt;/span&gt;full trace.

There was a problem expanding macro &lt;span class="s1"&gt;'compilation_error'&lt;/span&gt;

Code &lt;span class="k"&gt;in &lt;/span&gt;temp.cr:10:6

 10 | puts compilation_error&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"asdf"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
           ^
Called macro defined &lt;span class="k"&gt;in &lt;/span&gt;temp.cr:2:1

 2 | macro compilation_error&lt;span class="o"&gt;(&lt;/span&gt;arg&lt;span class="o"&gt;)&lt;/span&gt;

Which expanded to:

 &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; 1 | 1 &amp;lt; &lt;span class="s2"&gt;"asdf"&lt;/span&gt;
         ^
Error: no overload matches &lt;span class="s1"&gt;'Int32#&amp;lt;'&lt;/span&gt; with &lt;span class="nb"&gt;type &lt;/span&gt;String

Overloads are:
 ...cut &lt;span class="k"&gt;for &lt;/span&gt;brevity
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The error output for this compilation error is kind of nice. It states there's an issue and then the very first code reference is to where the macro was called. The next code reference points towards the macro-generated code that caused the error. If the user is not familiar with what code is generated by the macro they are using (and maybe they don't even know it's a macro), the first code reference is often way more helpful than when it dives into the macro code.&lt;/p&gt;

&lt;p&gt;Now, let's change how the macro works just a little bit and see what happens to the error output.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="k"&gt;macro&lt;/span&gt; &lt;span class="nf"&gt;inner_compilation_error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="n"&gt;arg&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;macro&lt;/span&gt; &lt;span class="nf"&gt;compilation_error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;inner_compilation_error&lt;/span&gt;&lt;span class="p"&gt;({{&lt;/span&gt; &lt;span class="n"&gt;arg&lt;/span&gt; &lt;span class="p"&gt;}})&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;compilation_error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"asdf"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And the new error output&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Showing last frame. Use &lt;span class="nt"&gt;--error-trace&lt;/span&gt; &lt;span class="k"&gt;for &lt;/span&gt;full trace.

There was a problem expanding macro &lt;span class="s1"&gt;'inner_compilation_error'&lt;/span&gt;

Code &lt;span class="k"&gt;in &lt;/span&gt;macro &lt;span class="s1"&gt;'compilation_error'&lt;/span&gt;

 1 | inner_compilation_error&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"asdf"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
     ^
Called macro defined &lt;span class="k"&gt;in &lt;/span&gt;&lt;span class="nb"&gt;eval&lt;/span&gt;:1:1

Which expanded to:

 &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; 1 | 1 &amp;lt; &lt;span class="s2"&gt;"asdf"&lt;/span&gt;
         ^
Error: no overload matches &lt;span class="s1"&gt;'Int32#&amp;lt;'&lt;/span&gt; with &lt;span class="nb"&gt;type &lt;/span&gt;String

Overloads are:
 ...cut &lt;span class="k"&gt;for &lt;/span&gt;brevity
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Can you notice the difference? Where in the error output does it point towards where the macro was called? The answer, it doesn't.&lt;/p&gt;

&lt;p&gt;The change to the code was adding another macro method that the original macro method now delegates to. This is very common when making macros since the code generation can become complicated. The downside is that error output only shows the compilation error and the code that called it, and in this case it means that it never makes it out of the macro code. Not so bad when you manage and call the macro, annoying and confusing when you are calling macros provided to you from libraries. At least in this code example you can kind of reference that the error is because you passed in a string, but what if the argument passed into the top-level macro is augmented in some way? What if the string is split into an array? I believe the error output becomes confusing and of little value. (I've written this article without talking about &lt;code&gt;--error-trace&lt;/code&gt; because I believe that errors should be helpful without it)&lt;/p&gt;
&lt;h2&gt;
  
  
  Story from Lucky-land
&lt;/h2&gt;

&lt;p&gt;In &lt;a href="https://luckyframework.org/"&gt;Lucky&lt;/a&gt; we generate URL helper methods to make it easier to create links in HTML, and we do this using macros called when users set up their actions (what we call controllers in a traditional MVC architecture). A common request for help in our Discord is to help figure out where users went wrong with their action setup. They copy and paste their action code and provide a picture of the stack-trace that looks something like this&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2QkLWSly--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/17329408/103235223-86cf4600-490f-11eb-8737-67033116207a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2QkLWSly--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/17329408/103235223-86cf4600-490f-11eb-8737-67033116207a.png" alt="Old stack-trace output"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You'll notice that the image of the stack-trace looks a little like the second example I laid out above. It talks about an error but the code references it points at are all in macro code. That's why user's end up staring at their action and are forced to ask for help. The awful thing about it is that the error isn't in their action at all. The user spends the most time staring at the action to see the error, but anyone who tries to help also has to spend time carefully reading the code. The annoying thing is that the real problem was with their usage of the generated URL helpers I mentioned, and not with the action implementation at all.&lt;/p&gt;

&lt;p&gt;Because I had experienced this issue myself and had helped people out with this often, I really wanted to figure out how to get the usage site (where they originally called into macro code) into the error output. Without going into the code, I looked at the macro and saw something very similar to the code example above where the main macro delegated to another but nowhere else was this second macro called. Moving the second macro code into the first was the solution and now the usage site shows up in the error output!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--VINvnjDW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/17329408/103235233-8a62cd00-490f-11eb-96ec-7282a352cb25.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VINvnjDW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/17329408/103235233-8a62cd00-490f-11eb-96ec-7282a352cb25.png" alt="New stack-trace output"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here's the pull request that made the change if you want to reference it &lt;/p&gt;
&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/luckyframework/lucky/pull/1373"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://res.cloudinary.com/practicaldev/image/fetch/s--vJ70wriM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/github-logo-ba8488d21cd8ee1fee097b8410db9deaa41d0ca30b004c0c63de0a479114156f.svg"&gt;
      &lt;span class="issue-title"&gt;
        Inline render_html_page to change compilation error
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#1373&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/matthewmcgarvey"&gt;
        &lt;img class="github-liquid-tag-img" src="https://res.cloudinary.com/practicaldev/image/fetch/s--u-pNoFXH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://avatars0.githubusercontent.com/u/17329408%3Fv%3D4" alt="matthewmcgarvey avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/matthewmcgarvey"&gt;matthewmcgarvey&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/luckyframework/lucky/pull/1373"&gt;&lt;time&gt;Dec 28, 2020&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;h2&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;Purpose&lt;/h2&gt;
&lt;p&gt;No connected issue&lt;/p&gt;
&lt;h2&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;Description&lt;/h2&gt;
&lt;h3&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;Before&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://user-images.githubusercontent.com/17329408/103235223-86cf4600-490f-11eb-8737-67033116207a.png" rel="nofollow"&gt;&lt;img width="849" alt="CleanShot 2020-12-28 at 13 20 01@2x" src="https://res.cloudinary.com/practicaldev/image/fetch/s--2QkLWSly--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/17329408/103235223-86cf4600-490f-11eb-8737-67033116207a.png"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;After&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://user-images.githubusercontent.com/17329408/103235233-8a62cd00-490f-11eb-96ec-7282a352cb25.png" rel="nofollow"&gt;&lt;img width="807" alt="CleanShot 2020-12-28 at 13 20 17@2x" src="https://res.cloudinary.com/practicaldev/image/fetch/s--VINvnjDW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/17329408/103235233-8a62cd00-490f-11eb-96ec-7282a352cb25.png"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Notice in the "Before" that the first code reference was a macro and not the usage site that caused the error. By removing the &lt;code&gt;render_html_page&lt;/code&gt; we actually see the usage site in the error which will help people track down issues.&lt;/p&gt;
&lt;p&gt;That macro was extracted &lt;a href="https://github.com/luckyframework/lucky/commit/3c1af65d46e6953c241c19232b74ed5cee424d58"&gt;here&lt;/a&gt; but you'll notice that this PR achieves the same level of DRY-ness without the separate macro.&lt;/p&gt;
&lt;h2&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;Checklist&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;[ ] - An issue already exists detailing the issue/or feature request that this PR fixes&lt;/li&gt;
&lt;li&gt;[x] - All specs are formatted with &lt;code&gt;crystal tool format spec src&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;[x] - Inline documentation has been added and/or updated&lt;/li&gt;
&lt;li&gt;[x] - Lucky builds on docker with &lt;code&gt;./script/setup&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;[x] - All builds and specs pass on docker with &lt;code&gt;./script/test&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/luckyframework/lucky/pull/1373"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;



</description>
      <category>crystal</category>
      <category>macros</category>
      <category>lucky</category>
    </item>
    <item>
      <title>LuckyFlow - The Basics</title>
      <dc:creator>Matthew McGarvey</dc:creator>
      <pubDate>Mon, 28 Dec 2020 06:02:40 +0000</pubDate>
      <link>https://dev.to/matthewmcgarvey/luckyflow-the-basics-20dn</link>
      <guid>https://dev.to/matthewmcgarvey/luckyflow-the-basics-20dn</guid>
      <description>&lt;p&gt;&lt;a href="https://github.com/luckyframework/lucky_flow"&gt;LuckyFlow&lt;/a&gt; is the browser-based testing library for &lt;a href="https://luckyframework.org/"&gt;Lucky&lt;/a&gt;. It uses headless Chrome to test your web-app as close to actual users would as possible.&lt;/p&gt;

&lt;h2&gt;
  
  
  Navigation
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="c1"&gt;# go to /users&lt;/span&gt;
&lt;span class="n"&gt;visit&lt;/span&gt; &lt;span class="no"&gt;Users&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Index&lt;/span&gt;

&lt;span class="c1"&gt;# go to /users/:user_id with user credentials&lt;/span&gt;
&lt;span class="n"&gt;visit&lt;/span&gt; &lt;span class="no"&gt;Users&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Show&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;current_user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="ss"&gt;as: &lt;/span&gt;&lt;span class="n"&gt;current_user&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Finding Elements on Page
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="c1"&gt;# `el` supports normal CSS selectors&lt;/span&gt;
&lt;span class="n"&gt;el&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;".class"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;el&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"#id"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also select elements by passing in text. This is helpful when there are multiple elements with the same selector but they are distinguished by their text.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="n"&gt;el&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;".list-item"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;text: &lt;/span&gt;&lt;span class="s2"&gt;"Item 123"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Keep in mind that &lt;code&gt;el&lt;/code&gt; is lazy so an error won't happen if you try to find an element that doesn't exist until you try to use the result.&lt;/p&gt;

&lt;h3&gt;
  
  
  Note: &lt;code&gt;flow-id&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Beyond CSS selectors, LuckyFlow and &lt;code&gt;el&lt;/code&gt; support a custom attribute called &lt;code&gt;flow-id&lt;/code&gt;. This is to allow selecting elements to be more specific and less susceptible to test breakage.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="c1"&gt;# notice the usage of `@` to reference a `flow-id`&lt;/span&gt;
&lt;span class="n"&gt;el&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"@custom-flow-id"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Clicking Links
&lt;/h2&gt;

&lt;p&gt;There are two ways to click an element. You can select it using &lt;code&gt;el&lt;/code&gt; or pass a CSS selector directly to &lt;code&gt;click&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="n"&gt;el&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"@my-link"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;
&lt;span class="n"&gt;click&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"@my-link"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Filling Out Forms
&lt;/h2&gt;

&lt;p&gt;LuckyFlow provides a nice integration with &lt;a href="https://github.com/luckyframework/avram"&gt;Avram&lt;/a&gt;, Lucky's ORM, to make filling out forms easy.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="n"&gt;fill_form&lt;/span&gt; &lt;span class="no"&gt;CreateUser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;name: &lt;/span&gt;&lt;span class="s2"&gt;"John Doe"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;email: &lt;/span&gt;&lt;span class="s2"&gt;"john@example.com"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Assertions
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="c1"&gt;# expect the element to be displayed on the page&lt;/span&gt;
&lt;span class="n"&gt;el&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"@custom-flow-id).should be_on_page

# expect the current path to match
# self is weird here because I have been showing
# all the code as if it was inside a Flow
# (more about that in a future post)
self.should have_current_path(Users::Index)

el("&lt;/span&gt;&lt;span class="vi"&gt;@custom&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;flow&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;should&lt;/span&gt; &lt;span class="n"&gt;have_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Hello, world!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In future posts, I want to go more in-depth on LuckyFlow and show how I use it to write clean specs.&lt;/p&gt;

</description>
      <category>crystal</category>
      <category>lucky</category>
      <category>testing</category>
    </item>
    <item>
      <title>Flash Messages with Lucky</title>
      <dc:creator>Matthew McGarvey</dc:creator>
      <pubDate>Sat, 26 Dec 2020 05:56:29 +0000</pubDate>
      <link>https://dev.to/matthewmcgarvey/flash-messages-with-lucky-3onp</link>
      <guid>https://dev.to/matthewmcgarvey/flash-messages-with-lucky-3onp</guid>
      <description>&lt;p&gt;There's often a need to show users some dynamic message based on some process of the app or action on their part. The most common scenario is usually around submitting forms. The user is trying to sign in to the app but use an incorrect password so the app sends them an error flash telling them to please try again. They subsequently sign in successfullyi so the app sends them a happy success flash welcoming them back 🌈🦄. But how might you do this in your Lucky app? Let's check it out.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding a flash message
&lt;/h2&gt;

&lt;p&gt;Going back to the form scenario, to add a flash message based on the outcome of a save operation it might look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Users&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Create&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;BrowserAction&lt;/span&gt;
  &lt;span class="n"&gt;post&lt;/span&gt; &lt;span class="s2"&gt;"/user"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="no"&gt;SaveUser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;saved?&lt;/span&gt;
        &lt;span class="n"&gt;flash&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;success&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"User created!"&lt;/span&gt;
        &lt;span class="n"&gt;redirect&lt;/span&gt; &lt;span class="ss"&gt;to: &lt;/span&gt;&lt;span class="no"&gt;Users&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Show&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;else&lt;/span&gt;
        &lt;span class="n"&gt;flash&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;failure&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Something went wrong..."&lt;/span&gt;
        &lt;span class="n"&gt;html&lt;/span&gt; &lt;span class="no"&gt;Users&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;NewPage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;operation: &lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This action is to create a new &lt;code&gt;User&lt;/code&gt; and renders a success flash message if it worked and a failure message if it failed to create the user. Besides &lt;code&gt;flash.success&lt;/code&gt; and &lt;code&gt;flash.failure&lt;/code&gt;, there is also &lt;code&gt;flash.info&lt;/code&gt; for general information to pass to the user. If you need a custom flash key and message you can call &lt;code&gt;flash.set(:some_key, "some value")&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Once a flash is set, it is accessible for the rest of the request or in the next one. The flash will be removed after that. It's so that, as in this example action, flashes can survive redirects. If you need the flash to survive longer than that, I will explain how to do it later in the post.&lt;/p&gt;
&lt;h2&gt;
  
  
  Accessing flash messages
&lt;/h2&gt;

&lt;p&gt;While flashes are a way to pass information across stateless requests, the most common use for them is for rendering HTML to notify users of events. Here's an example of something you might have in a component or a page to display flash messages if their are any:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="n"&gt;flash&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="n"&gt;div&lt;/span&gt; &lt;span class="ss"&gt;class: &lt;/span&gt;&lt;span class="s2"&gt;"alert alert-&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;role: &lt;/span&gt;&lt;span class="s2"&gt;"alert"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;para&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This iterates over every plash and displays the message to the user. When they refresh the page it will be gone. This is a nice and simple way to send the user short-lived informational messages. Much like we set them above, flashes can also be accessed individually. You can call &lt;code&gt;flash.get?(:any_key)&lt;/code&gt; to get a message if there is one. There is also helpers for the predefined message types so &lt;code&gt;flash.info?&lt;/code&gt; will work as well. This is useful if you display different flash message types in different ways.&lt;/p&gt;
&lt;h2&gt;
  
  
  Other Usefulness
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Persisting flash messages for multiple requests
&lt;/h3&gt;

&lt;p&gt;Flash messages are only kept for the request they were set in and the next one, but sometimes you need to persist them for longer. To do this, you can call &lt;code&gt;flash.keep&lt;/code&gt; to persist any flash messages given to the current request onto future ones. The most common use-case for this is when redirecting requests, but &lt;a href="https://github.com/luckyframework/lucky/blob/0b9be66ab1e0c238aa8715cdb3b195ceae59459b/src/lucky/redirectable.cr#L124"&gt;Lucky already handles this scenario for you&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It's important to remember to only call &lt;code&gt;flash.keep&lt;/code&gt; when you know you need to pass flash messages onto future requests. Calling it outside this scenario can lead to flash messages appearing to the user multiple times.&lt;/p&gt;
&lt;h3&gt;
  
  
  Clearing flash messages
&lt;/h3&gt;

&lt;p&gt;I think the heading says enough. Just call &lt;code&gt;flash.clear&lt;/code&gt; to immediately remove all existing flash messages.&lt;/p&gt;
&lt;h2&gt;
  
  
  One Warning
&lt;/h2&gt;

&lt;p&gt;It's important to remember that flash messages are accessible in the request they are set in &lt;strong&gt;AND&lt;/strong&gt; the next one. If you render all flash messages in HTML if there are any, setting flash messages on requests that don't redirect can also lead to them appearing to the user multiple times. For example, if you set a flash message on the user's profile page, they will see the flash message and then it will render again if they go to the home page.&lt;/p&gt;

&lt;p&gt;Unfortunately, there's not a solution for this problem right now but keep an eye on this issue to know when we have a working solution. &lt;/p&gt;
&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/luckyframework/lucky/issues/1271"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://res.cloudinary.com/practicaldev/image/fetch/s--vJ70wriM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/github-logo-ba8488d21cd8ee1fee097b8410db9deaa41d0ca30b004c0c63de0a479114156f.svg"&gt;
      &lt;span class="issue-title"&gt;
        Flash messages are always displayed for 2 requests
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#1271&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/odinhb"&gt;
        &lt;img class="github-liquid-tag-img" src="https://res.cloudinary.com/practicaldev/image/fetch/s--nsdD21VU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://avatars2.githubusercontent.com/u/49036561%3Fv%3D4" alt="odinhb avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/odinhb"&gt;odinhb&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/luckyframework/lucky/issues/1271"&gt;&lt;time&gt;Sep 26, 2020&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;I'm having trouble with the flash messages.&lt;/p&gt;
&lt;p&gt;I'm doing something similar to the generated browser sign_in endpoint:&lt;/p&gt;
&lt;div class="highlight highlight-source-crystal js-code-highlight"&gt;
&lt;pre&gt;get &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;/some_endpoint&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="pl-k"&gt;do&lt;/span&gt;
  flash.info &lt;span class="pl-k"&gt;=&lt;/span&gt; &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;here is a message&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;
  html &lt;span class="pl-c1"&gt;SomePage&lt;/span&gt;
&lt;span class="pl-k"&gt;end&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;It doesn't matter if I use &lt;code&gt;flash.keep&lt;/code&gt; or not. The flash message shows up in the response (as it should), but it doesn't go away if I refresh or trigger another request.&lt;/p&gt;
&lt;p&gt;I would expect it to disappear in the response to the second request.&lt;/p&gt;
&lt;p&gt;Lucky version: 0.24.0&lt;/p&gt;
&lt;p&gt;I noticed that in &lt;code&gt;Shared::FlashMessages&lt;/code&gt; we loop over flash keys using &lt;code&gt;#each&lt;/code&gt;, but in the implementation of &lt;code&gt;Lucky::FlashStore&lt;/code&gt; &lt;code&gt;#each&lt;/code&gt; is delegated to &lt;code&gt;#all&lt;/code&gt;, which means we are looping over both the &lt;code&gt;@next&lt;/code&gt; messages and the &lt;code&gt;@now&lt;/code&gt; messages.&lt;/p&gt;
&lt;p&gt;I also noticed that in &lt;code&gt;Lucky::FlashStore#set&lt;/code&gt; we modify &lt;code&gt;@next&lt;/code&gt; instead of &lt;code&gt;@now&lt;/code&gt;, meaning there is no difference between calling &lt;code&gt;flash.keep&lt;/code&gt; or not, as &lt;code&gt;@next&lt;/code&gt; gets put in a cookie (i assume thats why &lt;code&gt;#to_json&lt;/code&gt; is there), sent back by the client and put back in &lt;code&gt;@now&lt;/code&gt; for the next response, essentially always being "kept" and thus being displayed in both responses.&lt;/p&gt;
&lt;p&gt;I appended a monkey-patch in &lt;code&gt;src/app.cr&lt;/code&gt; which looks like this:&lt;/p&gt;
&lt;div class="highlight highlight-source-crystal js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-k"&gt;class&lt;/span&gt; &lt;span class="pl-en"&gt;Lucky::FlashStore&lt;/span&gt;
  &lt;span class="pl-k"&gt;def&lt;/span&gt; &lt;span class="pl-en"&gt;set&lt;/span&gt;(key : &lt;span class="pl-c1"&gt;Key&lt;/span&gt;, value : &lt;span class="pl-c1"&gt;String&lt;/span&gt;) : &lt;span class="pl-c1"&gt;String&lt;/span&gt;
    &lt;span class="pl-smi"&gt;@now&lt;/span&gt;[key.to_s] &lt;span class="pl-k"&gt;=&lt;/span&gt; value
  &lt;span class="pl-k"&gt;end&lt;/span&gt;
&lt;span class="pl-k"&gt;end&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;And it seems to work fine now, but this is not the correct implementation, is it? I'm finding the implications of the implementation a bit hard to hold in my head.&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/luckyframework/lucky/issues/1271"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;



</description>
      <category>lucky</category>
      <category>crystal</category>
    </item>
    <item>
      <title>Macro Tips: Method usage compilation errors</title>
      <dc:creator>Matthew McGarvey</dc:creator>
      <pubDate>Sat, 26 Dec 2020 04:22:49 +0000</pubDate>
      <link>https://dev.to/matthewmcgarvey/macro-tips-method-usage-compilation-errors-13ba</link>
      <guid>https://dev.to/matthewmcgarvey/macro-tips-method-usage-compilation-errors-13ba</guid>
      <description>&lt;p&gt;One cool feature of Crystal macros that I forget about is that they don't always have to be defined in a macro method. Where I've seen this be helpful is when you want to define a compile-time error in a method.&lt;/p&gt;

&lt;p&gt;One way to think about it is, say you have a method called &lt;code&gt;destroy&lt;/code&gt; and people keep mentioning that they keep forgetting and accidentally trying to call &lt;code&gt;delete&lt;/code&gt;. Sometimes Crystal gives you a recommendation of the method it thinks you wanted but that is not always the case. To be helpful to users, you could use macros to provide a better error.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyLibrary&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;destroy&lt;/span&gt;
    &lt;span class="c1"&gt;# pure destruction&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;delete&lt;/span&gt;
    &lt;span class="p"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="s2"&gt;"Woops! Did you mean to call destroy instead?"&lt;/span&gt; &lt;span class="p"&gt;%}&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;my_library&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;MyLibrary&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;
&lt;span class="n"&gt;my_library&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;delete&lt;/span&gt; &lt;span class="c1"&gt;#=&amp;gt; Helpful compilation error!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's a nice way to provide help to users who make mistakes from time to time. We use this in Lucky's ORM, Avram, to help users avoid making mistakes that would otherwise produce hard to understand compilation errors, or, even worse, runtime errors 🙀. One example is that in &lt;code&gt;Avram::Model&lt;/code&gt; you define a "belongs to" association by writing &lt;code&gt;belongs_to user : User&lt;/code&gt; but in a migration you can add a column with a foreign key relationship to a different table by writing &lt;code&gt;add_belongs_to user : User&lt;/code&gt;. Out of habit, I have accidentally used &lt;code&gt;belongs_to&lt;/code&gt; instead of &lt;code&gt;add_belongs_to&lt;/code&gt; in a migration and didn't get an understandable error. It took me several minutes to track it down and I felt dumb for making the mistake. Because of that experience, we added a compilation error using macros to catch that and point users towards the solution. Here's the code in Avram that can be found on GitHub &lt;a href="https://github.com/luckyframework/avram/blob/1e6f4edd4d49c518c858ee9ecc277a3b963051eb/src/avram/migrator/create_table_statement.cr#L137-L147"&gt;here&lt;/a&gt; (just a note that this is in a macro def but the same thing can be done in a regular def as well).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="k"&gt;macro&lt;/span&gt; &lt;span class="nf"&gt;belongs_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type_declaration&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;named_args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;-&lt;/span&gt;&lt;span class="no"&gt;ERROR&lt;/span&gt;&lt;span class="sh"&gt;
    Unexpected call to `belongs_to` in a migration.
    Found in &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;type_declaration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;:&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;type_declaration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;line_number&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;:&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;type_declaration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;column_number&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;.
    Did you mean to use 'add_belongs_to'?
    'add_belongs_to &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;type_declaration&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;, ...'
&lt;/span&gt;&lt;span class="no"&gt;    ERROR&lt;/span&gt;
  &lt;span class="p"&gt;%}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Caveat
&lt;/h3&gt;

&lt;p&gt;One problem we've had with this recently, though, is that we implemented this in the base method of a class that would be inherited and a module dynamically overrides it to provide the expected functionality. Because we were replacing existing code, some users were calling super in their method expecting to get the base functionality and were instead getting a compilation error. This is not a knock of the macro usage, just a note that it isn't always the perfect choice.&lt;/p&gt;

</description>
      <category>crystal</category>
      <category>macros</category>
    </item>
    <item>
      <title>Macro Tips: TypeDeclaration</title>
      <dc:creator>Matthew McGarvey</dc:creator>
      <pubDate>Tue, 08 Dec 2020 01:18:28 +0000</pubDate>
      <link>https://dev.to/matthewmcgarvey/macro-tips-typedeclaration-5hfo</link>
      <guid>https://dev.to/matthewmcgarvey/macro-tips-typedeclaration-5hfo</guid>
      <description>&lt;p&gt;When working with macros, you might have one that allows specifying a name, type, and an optional default value.&lt;/p&gt;

&lt;p&gt;It might look something like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="n"&gt;param&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;String&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"default query"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code for the macro will take in one parameter and that parameter will be a &lt;a href="https://crystal-lang.org/api/latest/Crystal/Macros/TypeDeclaration.html"&gt;&lt;code&gt;TypeDeclaration&lt;/code&gt;&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="n"&gt;macro&lt;/span&gt; &lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type_decl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="c1"&gt;# ...&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you imagine that this &lt;code&gt;param&lt;/code&gt; macro is for a web framework and used to define the query params for an endpoint, it makes sense that it would raise an error if the query is not nilable and no default value is given in the method that it defines.&lt;/p&gt;

&lt;p&gt;The code for that could be (forgive me for this mess)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="n"&gt;macro&lt;/span&gt; &lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type_decl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="n"&gt;type_decl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;var&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="n"&gt;type_decl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;type&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sx"&gt;% is_nilable_type &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;type_decl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;is_a?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Union&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get?&lt;/span&gt;&lt;span class="p"&gt;(:{{&lt;/span&gt; &lt;span class="n"&gt;type_declaration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;id&lt;/span&gt; &lt;span class="p"&gt;}})&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;nil?&lt;/span&gt;

    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sx"&gt;% if &lt;/span&gt;&lt;span class="n"&gt;is_nilable_type&lt;/span&gt; &lt;span class="sx"&gt;%}
      {{ type_declaration.value || nil }&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sx"&gt;% else &lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="n"&gt;default_or_nil&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="n"&gt;type_declaration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;value&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="kp"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;default_or_nil&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;nil?&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="no"&gt;MissingParamError&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"{{ type_declaration.var.id }}"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;else&lt;/span&gt;
        &lt;span class="n"&gt;default_or_nil&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sx"&gt;% end &lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Can you see the problem with this?&lt;/p&gt;

&lt;p&gt;What if a param was this instead &lt;code&gt;param show_deleted : Bool = false&lt;/code&gt;?&lt;/p&gt;

&lt;p&gt;The problem is the line &lt;code&gt;default_or_nil = {{ type_declaration.value || nil }}&lt;/code&gt;. It means that any time the value is not provided, it uses the default which is &lt;code&gt;false&lt;/code&gt; and is obviously falsey which means that &lt;code&gt;default_or_nil&lt;/code&gt; evaluates to nil and ends up raising the error.&lt;/p&gt;

&lt;p&gt;The solution is to check if the value is a &lt;a href="https://crystal-lang.org/api/latest/Crystal/Macros/Nop.html"&gt;&lt;code&gt;Nop&lt;/code&gt;&lt;/a&gt; instead of checking the truthiness of the default value since value is a &lt;code&gt;Nop&lt;/code&gt; when it isn't defined.&lt;/p&gt;

&lt;p&gt;Instead of&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="n"&gt;default_or_nil&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="n"&gt;type_declaration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;value&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="kp"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;it should be&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="n"&gt;default_or_nil&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="n"&gt;type_declaration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;is_a?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Nop&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="kp"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;type_declaration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;value&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://github.com/luckyframework/lucky/commit/49f1021a76c49ca7d14a3d636ebea0244671d97b"&gt;Here's the relevant PR&lt;/a&gt; for the fix made in Lucky. &lt;/p&gt;

</description>
      <category>crystal</category>
      <category>macros</category>
    </item>
  </channel>
</rss>
