<?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: Delon R. Newman</title>
    <description>The latest articles on DEV Community by Delon R. Newman (@delonnewman).</description>
    <link>https://dev.to/delonnewman</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%2F474158%2F42b3d4a5-0624-49e6-b056-d7dc46362fb5.jpg</url>
      <title>DEV Community: Delon R. Newman</title>
      <link>https://dev.to/delonnewman</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/delonnewman"/>
    <language>en</language>
    <item>
      <title>ruby -run, again</title>
      <dc:creator>Delon R. Newman</dc:creator>
      <pubDate>Wed, 15 Jan 2025 19:42:32 +0000</pubDate>
      <link>https://dev.to/delonnewman/ruby-run-again-2njc</link>
      <guid>https://dev.to/delonnewman/ruby-run-again-2njc</guid>
      <description>&lt;p&gt;Previously we learned about a tool in Ruby's standard library called &lt;a href="https://github.com/ruby/un" rel="noopener noreferrer"&gt;un&lt;/a&gt;. After some consideration it occurred to me some might wonder, "How does this work?"&lt;/p&gt;

&lt;p&gt;We learned that we can type something like &lt;code&gt;ruby -run -e httpd .&lt;/code&gt; to start a web server that will serve all the files in our current directory over HTTP. But we said the name of the library is "un"&lt;br&gt;
what's with &lt;code&gt;ruby -run&lt;/code&gt;?&lt;/p&gt;

&lt;p&gt;Well, why don't we try asking &lt;code&gt;ruby&lt;/code&gt;? We can do so by making use of its help flag. Just type &lt;code&gt;ruby -h&lt;/code&gt; and you should see something like this on your screen:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqsn2sagw8zpp39rrbxl8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqsn2sagw8zpp39rrbxl8.png" alt="Usage: /Users/delon/.asdf/installs/ruby/2.7.5/bin/ruby [switches] [--] [programfile] [arguments]&amp;lt;br&amp;gt;
  -0[octal]       specify record separator (\0, if no argument)&amp;lt;br&amp;gt;
  -a              autosplit mode with -n or -p (splits $_ into $F)&amp;lt;br&amp;gt;
  -c              check syntax only&amp;lt;br&amp;gt;
  -Cdirectory     cd to directory before executing your script&amp;lt;br&amp;gt;
  -d              set debugging flags (set $DEBUG to true)&amp;lt;br&amp;gt;
  -e 'command'    one line of script. Several -e's allowed. Omit [programfile]&amp;lt;br&amp;gt;
  -Eex[:in]       specify the default external and internal character encodings&amp;lt;br&amp;gt;
  -Fpattern       split() pattern for autosplit (-a)&amp;lt;br&amp;gt;
  -i[extension]   edit ARGV files in place (make backup if extension supplied)&amp;lt;br&amp;gt;
  -Idirectory     specify $LOAD_PATH directory (may be used more than once)&amp;lt;br&amp;gt;
  -l              enable line ending processing&amp;lt;br&amp;gt;
  -n              assume 'while gets(); ... end' loop around your script&amp;lt;br&amp;gt;
  -p              assume loop like -n but print line also like sed&amp;lt;br&amp;gt;
  -rlibrary       require the library before executing your script&amp;lt;br&amp;gt;
  -s              enable some switch parsing for switches after script name&amp;lt;br&amp;gt;
  -S              look for the script using PATH environment variable&amp;lt;br&amp;gt;
  -v              print the version number, then turn on verbose mode&amp;lt;br&amp;gt;
  -w              turn warnings on for your script&amp;lt;br&amp;gt;
  -W[level=2|:category]     set warning level; 0=silence, 1=medium, 2=verbose&amp;lt;br&amp;gt;
  -x[directory]   strip off text before #!ruby line and perhaps cd to directory&amp;lt;br&amp;gt;
  --jit           enable JIT with default options (experimental)&amp;lt;br&amp;gt;
  --jit-[option]  enable JIT with an option (experimental)&amp;lt;br&amp;gt;
  -h              show this message, --help for more info" width="800" height="561"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are a lot of options here, but if you squint you'll notice just past the middle an option called &lt;code&gt;-rlibrary&lt;/code&gt;. It says it's used to "require the library before executing your script". That's what we're using. "un" is the name of the library so when it's paired with &lt;code&gt;-r&lt;/code&gt; it spells &lt;code&gt;-run&lt;/code&gt;. That's clever!&lt;/p&gt;
&lt;h2&gt;
  
  
  View Source
&lt;/h2&gt;

&lt;p&gt;Let's not stop there. What else can we learn? Let's checkout the source code. We can find it in this repository on Github: &lt;a href="https://github.com/ruby/un" rel="noopener noreferrer"&gt;https://github.com/ruby/un&lt;/a&gt;. Let's check it out.&lt;/p&gt;

&lt;p&gt;When you do you'll notice that there's a &lt;a href="https://github.com/ruby/un/tree/master/lib" rel="noopener noreferrer"&gt;lib&lt;/a&gt; directory. That's usually were source code goes for Ruby libraries. Let's see what's in &lt;a href="https://github.com/ruby/un/tree/master/lib" rel="noopener noreferrer"&gt;there&lt;/a&gt;. It's a single file. Interesting.&lt;/p&gt;

&lt;p&gt;If you &lt;a href="https://github.com/ruby/un/blob/master/lib/un.rb#L37" rel="noopener noreferrer"&gt;open it&lt;/a&gt; and scan through it slowly to the bottom you'll notice that it just contains a few functions. Now scrolling back toward the top the first function is &lt;code&gt;setup&lt;/code&gt;. If you scroll down to the next function &lt;code&gt;cp&lt;/code&gt;. You'll notice that it &lt;em&gt;uses&lt;/em&gt; &lt;code&gt;setup&lt;/code&gt;. If you go back up to &lt;code&gt;setup&lt;/code&gt; you'll notice that it's parsing the command line flags that we've passed it using a class called &lt;a href="https://rubyapi.org/3.4/o/optionparser" rel="noopener noreferrer"&gt;OptionParser&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In the final line of &lt;code&gt;setup&lt;/code&gt; it uses the Ruby keyword &lt;code&gt;yield&lt;/code&gt; to pass the parsed arguments to a block that gets passed to it. Now when we look at each of the other functions &lt;code&gt;cp&lt;/code&gt;, &lt;code&gt;ln&lt;/code&gt;, &lt;code&gt;mv&lt;/code&gt;, etc. they each use &lt;code&gt;setup&lt;/code&gt; this way. That's a neat trick!&lt;/p&gt;
&lt;h2&gt;
  
  
  Come Together
&lt;/h2&gt;

&lt;p&gt;That's interesting and all but we still haven't quite explained how &lt;code&gt;ruby -run -e httpd .&lt;/code&gt; works. It seems like the missing piece is &lt;code&gt;-e&lt;/code&gt;. Let's ask &lt;code&gt;ruby&lt;/code&gt; again.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsve880g2oyz51spsn08l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsve880g2oyz51spsn08l.png" alt="Usage: /Users/delon/.asdf/installs/ruby/2.7.5/bin/ruby [switches] [--] [programfile] [arguments]&amp;lt;br&amp;gt;
  -0[octal]       specify record separator (\0, if no argument)&amp;lt;br&amp;gt;
  -a              autosplit mode with -n or -p (splits $_ into $F)&amp;lt;br&amp;gt;
  -c              check syntax only&amp;lt;br&amp;gt;
  -Cdirectory     cd to directory before executing your script&amp;lt;br&amp;gt;
  -d              set debugging flags (set $DEBUG to true)&amp;lt;br&amp;gt;
  -e 'command'    one line of script. Several -e's allowed. Omit [programfile]&amp;lt;br&amp;gt;
  -Eex[:in]       specify the default external and internal character encodings&amp;lt;br&amp;gt;
  -Fpattern       split() pattern for autosplit (-a)&amp;lt;br&amp;gt;
  -i[extension]   edit ARGV files in place (make backup if extension supplied)&amp;lt;br&amp;gt;
  -Idirectory     specify $LOAD_PATH directory (may be used more than once)&amp;lt;br&amp;gt;
  -l              enable line ending processing&amp;lt;br&amp;gt;
  -n              assume 'while gets(); ... end' loop around your script&amp;lt;br&amp;gt;
  -p              assume loop like -n but print line also like sed&amp;lt;br&amp;gt;
  -rlibrary       require the library before executing your script&amp;lt;br&amp;gt;
  -s              enable some switch parsing for switches after script name&amp;lt;br&amp;gt;
  -S              look for the script using PATH environment variable&amp;lt;br&amp;gt;
  -v              print the version number, then turn on verbose mode&amp;lt;br&amp;gt;
  -w              turn warnings on for your script&amp;lt;br&amp;gt;
  -W[level=2|:category]     set warning level; 0=silence, 1=medium, 2=verbose&amp;lt;br&amp;gt;
  -x[directory]   strip off text before #!ruby line and perhaps cd to directory&amp;lt;br&amp;gt;
  --jit           enable JIT with default options (experimental)&amp;lt;br&amp;gt;
  --jit-[option]  enable JIT with an option (experimental)&amp;lt;br&amp;gt;
  -h              show this message, --help for more info" width="800" height="561"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There it is, toward the top, &lt;code&gt;-e 'command'&lt;/code&gt;, "one line of script". Hmm. Let's try it out: &lt;code&gt;ruby -e "puts 'Hi'"&lt;/code&gt;. My console kindly greets me with "Hi". Is that what you see? Cool. So this allows us to execute arbitrary Ruby code....&lt;em&gt;I think I get it!&lt;/em&gt; When I load the library "un" with &lt;code&gt;-run&lt;/code&gt; I can call any of those functions in &lt;a href="https://github.com/ruby/un/blob/master/lib/un.rb" rel="noopener noreferrer"&gt;lib/un.rb&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;Let's test out this theory by doing something crazy.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ruby -run -e 'setup() { puts "Hi" }'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Did your console greet you like mine did? &lt;em&gt;That-is-cool&lt;/em&gt;. Now I get how &lt;code&gt;ruby -run -e httpd .&lt;/code&gt; works. Now I just need to understand the &lt;code&gt;httpd&lt;/code&gt; function. That'll have to wait. I could use a snack about now, but this was fun. Later!&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>tooling</category>
      <category>beginners</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>ruby -run</title>
      <dc:creator>Delon R. Newman</dc:creator>
      <pubDate>Wed, 15 Jan 2025 19:34:00 +0000</pubDate>
      <link>https://dev.to/delonnewman/ruby-run-56pk</link>
      <guid>https://dev.to/delonnewman/ruby-run-56pk</guid>
      <description>&lt;p&gt;Ruby is well known as a language that is easy to use from the surface but is very deep and complex underneath. That's what we know and love about it. Its standard library has a similar design and contains many hidden gems. One of the gems I've learned about recently is &lt;a href="https://github.com/ruby/un" rel="noopener noreferrer"&gt;un&lt;/a&gt;. It's designed to be a command line utility executed directly from &lt;code&gt;ruby&lt;/code&gt;. This is its usage description:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F497c98ag3g2ydcf48abd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F497c98ag3g2ydcf48abd.png" alt="ruby -run -e cp -- [OPTION] SOURCE DEST&amp;lt;br&amp;gt;
ruby -run -e ln -- [OPTION] TARGET LINK_NAME&amp;lt;br&amp;gt;
ruby -run -e mv -- [OPTION] SOURCE DEST&amp;lt;br&amp;gt;
ruby -run -e rm -- [OPTION] FILE&amp;lt;br&amp;gt;
ruby -run -e mkdir -- [OPTION] DIRS&amp;lt;br&amp;gt;
ruby -run -e rmdir -- [OPTION] DIRS&amp;lt;br&amp;gt;
ruby -run -e install -- [OPTION] SOURCE DEST&amp;lt;br&amp;gt;
ruby -run -e chmod -- [OPTION] OCTAL-MODE FILE&amp;lt;br&amp;gt;
ruby -run -e touch -- [OPTION] FILE&amp;lt;br&amp;gt;
ruby -run -e wait_writable -- [OPTION] FILE&amp;lt;br&amp;gt;
ruby -run -e mkmf -- [OPTION] EXTNAME [OPTION]&amp;lt;br&amp;gt;
ruby -run -e httpd -- [OPTION] [DocumentRoot]&amp;lt;br&amp;gt;
ruby -run -e colorize -- [FILE]&amp;lt;br&amp;gt;
ruby -run -e help [COMMAND]" width="800" height="569"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This means that if you type&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ruby -run -e help httpd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;you'll see a help message that will describe how that command works.&lt;/p&gt;

&lt;p&gt;Most of the commands have pretty limited utility.  They seem to be portable UNIX utilities for use when Ruby is present but a UNIX environment is not. In fact, the package is described as "Utilities to replace common UNIX commands in Makefiles etc." Perhaps they're useful in embedded systems (I understand that Ruby is commonly&lt;br&gt;
used for embedded systems in Japan).&lt;/p&gt;

&lt;p&gt;The two that stand out to me are &lt;code&gt;httpd&lt;/code&gt; and &lt;code&gt;colorize&lt;/code&gt;.  &lt;code&gt;httpd&lt;/code&gt; is very useful. It's become my go-to utility when I need to quickly serve files over HTTP.&lt;/p&gt;

&lt;p&gt;Just type&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ruby -run -e httpd .
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;press "Enter" and boom you're done! You should see something like this on your screen:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh2869zyh84ma2wzemysp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh2869zyh84ma2wzemysp.png" alt="[2025-01-12 13:43:26] INFO  WEBrick 1.6.1&amp;lt;br&amp;gt;
[2025-01-12 13:43:26] INFO  ruby 2.7.5 (2021-11-24) [arm64-darwin24]&amp;lt;br&amp;gt;
[2025-01-12 13:43:26] INFO  WEBrick::HTTPServer#start: pid=27808 port=8080" width="800" height="330"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now you can open &lt;code&gt;localhost:8080&lt;/code&gt; in your browser and see the files you've served.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;colorize&lt;/code&gt; prints out the Ruby code of any file you give it with syntax highlighting. I've not used it in a practical setting yet. But it might be useful when looking through Ruby files in a terminal as an alternative to &lt;code&gt;cat&lt;/code&gt;.&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>tooling</category>
      <category>beginners</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Emacs is More Like a Terminal Than an Editor</title>
      <dc:creator>Delon R. Newman</dc:creator>
      <pubDate>Thu, 23 Nov 2023 17:16:48 +0000</pubDate>
      <link>https://dev.to/delonnewman/emacs-is-more-like-a-terminal-than-an-editor-4g5j</link>
      <guid>https://dev.to/delonnewman/emacs-is-more-like-a-terminal-than-an-editor-4g5j</guid>
      <description>&lt;p&gt;I've long been a command-line nerd. It was, after all, my first computer interface starting with Apple II's in school and DOS at home when my mother bought our first computer when I was 10. While I was fascinated by graphical interfaces when I first encountered them, text-based interfaces continued to hold a certain mystique especially as I became familiar with the UNIX shell through my early experiences with Linux based systems when I was in my teens.&lt;/p&gt;

&lt;p&gt;As I continued to work at mastering the various skills of the programming trade, I decided to settle on a preferred text-editor&lt;sup id="fnref1"&gt;1&lt;/sup&gt;. At that point I settled on Vim for it's ubiquity and extensibility. Over time I came to embrace the idea of using &lt;a href="https://blog.sanctum.geek.nz/unix-as-ide-introduction/" rel="noopener noreferrer"&gt;the UNIX environment as my primary IDE&lt;/a&gt;&lt;sup id="fnref2"&gt;2&lt;/sup&gt;. From that standpoint the UNIX shell and it's various associated tools provide everything that you get from an IDE. I found that I was quite content with this as my default editing and programming environment with the exception of using IDEs for Java &amp;amp; C# when I used them.&lt;/p&gt;

&lt;p&gt;When I finally took the Lisp plunge&lt;sup id="fnref3"&gt;3&lt;/sup&gt; I started to wonder if I was missing something by not using Emacs.  First, I'd never gotten into writing my own Vim extensions because Vim script—well let's just say Vim script isn't Lisp, and second I was coming to realize that there was something different and at least equally powerful about the Lisp vs. the UNIX mindset&lt;sup id="fnref4"&gt;4&lt;/sup&gt;. Additionally, I'd gotten bitten by a bug&lt;sup id="fnref5"&gt;5&lt;/sup&gt;. I wanted to understand the state-of-the-art in tooling for the sake of trying to get a sense of how we could do better, and the world of Lisp and Smalltalk seemed like some of the ripest fruit to pick&lt;sup id="fnref6"&gt;6&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;So now I've been exploring Emacs for a few years. Early on I had the "Emacs is a computing environment" or "operating system", but definitely not an "editor" aha. As a result, I've found myself keeping an Emacs window open almost all the time to be ready for use whether I need a text editor, &lt;a href="https://orgmode.org" rel="noopener noreferrer"&gt;Org Mode&lt;/a&gt;, &lt;a href="https://magit.vc" rel="noopener noreferrer"&gt;Magit&lt;/a&gt;, &lt;a href="https://www.gnu.org/software/emacs/manual/html_node/tramp/Quick-Start-Guide.html" rel="noopener noreferrer"&gt;TRAMP&lt;/a&gt;, or a &lt;a href="https://www.gnu.org/software/emacs/manual/html_node/emacs/Lisp-Interaction.html" rel="noopener noreferrer"&gt;R&lt;/a&gt;&lt;a href="https://github.com/nonsequitur/inf-ruby" rel="noopener noreferrer"&gt;E&lt;/a&gt;&lt;a href="https://cider.mx" rel="noopener noreferrer"&gt;P&lt;/a&gt;&lt;a href="https://metacpan.org/pod/Sepia" rel="noopener noreferrer"&gt;L&lt;/a&gt;. But it wasn't until reading &lt;em&gt;&lt;a href="https://andreyor.st/posts/2023-10-27-you-dont-need-a-terminal-emulator/" rel="noopener noreferrer"&gt;You Don't Need a Terminal&lt;/a&gt;&lt;/em&gt; by &lt;a href="https://andreyor.st/about/" rel="noopener noreferrer"&gt;Andrey Listopadov&lt;/a&gt; that the full impact of this hit me. After trying out his suggestions I hardly find myself opening a terminal at all whether it's iTerm or vterm or the terminals integrated into RubyMine or VS Code.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Emacs is my terminal.&lt;/em&gt; Just as when I was primarily a Vim user I always had my terminal open and I would access my various tools from it. Now I always have Emacs an arm reach away. But there is a difference. And I think the difference speaks to the difference between the Lisp and the UNIX mindset. From a UNIX shell each of the tools are different&lt;sup id="fnref7"&gt;7&lt;/sup&gt;, whereas Emacs provides a uniform interface over lower-level tools&lt;sup id="fnref8"&gt;8&lt;/sup&gt;.  For example, if I want to access a remote server (or docker container) I use the same commands that I use to open files locally, and once I do connect all the commands I normally use now work on the remote server as well. This is a way of taking your configuration with you that Vim simply doesn't provide&lt;sup id="fnref9"&gt;9&lt;/sup&gt;. And more importantly, it's a way of empowering users through what is ultimately still a thin, but infinitely moldable layer of indirection.&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;Based on the advice I found in the wonderful book &lt;a href="https://pragprog.com/titles/tpp20/the-pragmatic-programmer-20th-anniversary-edition/" rel="noopener noreferrer"&gt;The Pragmatic Programmer&lt;/a&gt;. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;I even tried my best to replicate this experience on Windows (with mixed success) since I often used Windows machines in my work at the time. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn3"&gt;
&lt;p&gt;Using Clojure on a few projects in my work and digging into &lt;a href="https://mitpress.mit.edu/9780262510875/structure-and-interpretation-of-computer-programs/" rel="noopener noreferrer"&gt;SICP&lt;/a&gt; and the &lt;a href="https://mitpress.mit.edu/9780262560993/the-little-schemer/" rel="noopener noreferrer"&gt;Little Schemer&lt;/a&gt; series. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn4"&gt;
&lt;p&gt;For more on that read &lt;a href="https://www.dreamsongs.com/RiseOfWorseIsBetter.html" rel="noopener noreferrer"&gt;The Rise of Worse is Better&lt;/a&gt; and &lt;a href="https://www.dreamsongs.com/WorseIsBetter.html" rel="noopener noreferrer"&gt;Worse is Better&lt;/a&gt;. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn5"&gt;
&lt;p&gt;I'm sure I can thank &lt;a href="http://worrydream.com/#!/LearnableProgramming" rel="noopener noreferrer"&gt;Bret Victor&lt;/a&gt; for this. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn6"&gt;
&lt;p&gt;Having long been an IDE user of the C++, Java, and C# sort I'd always found them helpful, but ultimately disappointing. Though I have recently succumbed to using RubyMine and VS Code for my Ruby and JavaScript work, respectively. Though that is at least in part about gaining an intuition for the state-of-the-art in programmer tooling. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn7"&gt;
&lt;p&gt;UNIX command line arguments are infamously inconsistent, though we celebrate the openness of the system---that it's disparate parts can be tied together with the very thin, but powerful abstraction that the shell provides. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn8"&gt;
&lt;p&gt;Some of this uniformity is due to the way Emacs has been configured for me. Since I'm a Emacs newbie, I've resorted to using Doom Emacs, after initially trying to build my own configuration. But in the end, Emacs provides the uniform substrate that enables that experience. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn9"&gt;
&lt;p&gt;Although VS Code does now provide similar functionality. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>emacs</category>
      <category>editors</category>
      <category>ide</category>
      <category>lisp</category>
    </item>
    <item>
      <title>How to Generate Unique Names With a Plain Old Ruby Object</title>
      <dc:creator>Delon R. Newman</dc:creator>
      <pubDate>Thu, 16 Nov 2023 19:32:26 +0000</pubDate>
      <link>https://dev.to/delonnewman/tidy-code-unique-names-582g</link>
      <guid>https://dev.to/delonnewman/tidy-code-unique-names-582g</guid>
      <description>&lt;p&gt;I recently came accross something approximating the following in a&lt;br&gt;
client's code base.&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="c1"&gt;# app/model/user.rb&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;
  &lt;span class="c1"&gt;# ...more code&lt;/span&gt;
  &lt;span class="n"&gt;before_validation&lt;/span&gt; &lt;span class="ss"&gt;:set_username&lt;/span&gt;
  &lt;span class="c1"&gt;# ...more code&lt;/span&gt;

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

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;set_username&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;blank?&lt;/span&gt;

    &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;begin&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;present?&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;first_name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;present?&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;prefix&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;first_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;last_name&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;compact&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;presence&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'@'&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&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;username&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;prefix&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;positive?&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_s&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;else&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;username&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"user_&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="no"&gt;SecureRandom&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&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="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exists?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;username: &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;username&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;It's a fairly standard requirement for an application to have some named record that may need an automatically generated name that must be unique. This is a pretty standard (if not pretty) approach for a Rails application to take. I've taken a similar tack in the past myself.&lt;/p&gt;

&lt;p&gt;This time&lt;sup id="fnref1"&gt;1&lt;/sup&gt; it occurred to me that this could be a good opportunity to apply a little bit of Object-Oriented Design and make use of a &lt;a href="https://martinfowler.com/bliki/ValueObject.html" rel="noopener noreferrer"&gt;Value Object&lt;/a&gt;. As a starting place I envisioned something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# app/model/user/unique_name.rb&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User::UniqueName&lt;/span&gt;
  &lt;span class="n"&gt;delgegate&lt;/span&gt; &lt;span class="ss"&gt;:email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:first_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:last_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;to: :@user&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="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="vi"&gt;@user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;user&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;to_s&lt;/span&gt;
    &lt;span class="n"&gt;username&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;nil&lt;/span&gt;

    &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;begin&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;present?&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;first_name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;present?&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;prefix&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;first_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;last_name&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;compact&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;presence&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'@'&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;username&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;prefix&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;positive?&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_s&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;''&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;username&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"user_&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="no"&gt;SecureRandom&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&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="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exists?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;username: &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;username&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;username&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;# app/model/user.rb&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;
  &lt;span class="c1"&gt;# ...more code&lt;/span&gt;
  &lt;span class="n"&gt;before_validation&lt;/span&gt; &lt;span class="ss"&gt;:set_username&lt;/span&gt;
  &lt;span class="c1"&gt;# ...more code&lt;/span&gt;

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

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;set_username&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;blank?&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;username&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;UniqueName&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="nb"&gt;self&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;Although &lt;code&gt;User::UniqueName&lt;/code&gt; still isn't terribly pretty, it already has some useful properties. For one, in any testing I do, whether it's in the form of unit tests or experimenting in the REPL, it has the very desirable property that it can be tested on basis of simple input and output. Additionally, this can be done in relative isolation from the other properties I'd like to test about &lt;code&gt;User&lt;/code&gt;. This wouldn't stop me from testing the integration with &lt;code&gt;User&lt;/code&gt; either, but those tests can be few.&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="no"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;UniqueName&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="no"&gt;User&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;to_s&lt;/span&gt; &lt;span class="c1"&gt;# that's it!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All the essential behavior is encapsulated here. As a nice ergonomic bonus ActiveRecord will take care of calling &lt;code&gt;#to_s&lt;/code&gt; for us as it coerces our Value Object into a string.&lt;/p&gt;

&lt;p&gt;If this is the best we can do this is not a terrible place to be, but as it stands this code can be cleaned up, and it could be made more general. For example, on another project I'm working on there are &lt;em&gt;many&lt;/em&gt; models that require unique names to be generated. Some models also need to be unique within a certain scope. In that case the Value Object might take this form instead. Here we've also added logic that will return the name of the record if it's present removing the need for a condition in our callback.&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="c1"&gt;# app/models/unique_name.rb&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UniqueName&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="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;attribute: :name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;scope: &lt;/span&gt;&lt;span class="kp"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;root_name: &lt;/span&gt;&lt;span class="kp"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="vi"&gt;@record&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt;
    &lt;span class="vi"&gt;@attribute&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;attribute&lt;/span&gt;
    &lt;span class="vi"&gt;@root_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;root_name&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="s2"&gt;"New &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;model_name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;human&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="vi"&gt;@scope&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;scope&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;to_s&lt;/span&gt;
    &lt;span class="nb"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;record_name&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;name&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;present?&lt;/span&gt;

    &lt;span class="n"&gt;unique_name&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;record_name&lt;/span&gt;
    &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;public_send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attribute&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;record_scope_value&lt;/span&gt;
    &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;public_send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scope&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;unique_name&lt;/span&gt;
    &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;auto_named_count&lt;/span&gt;
    &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;zero?&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;root_name&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="n"&gt;root_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; (&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;n&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;def&lt;/span&gt; &lt;span class="nf"&gt;auto_named_count&lt;/span&gt;
    &lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attribute&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;root_name&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;or&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attribute&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;root_name&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;count&lt;/span&gt; &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="n"&gt;scope&lt;/span&gt;

    &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;or&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scope&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;record_scope_value&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;count&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;model&lt;/span&gt;
    &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;class&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

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

  &lt;span class="nb"&gt;attr_reader&lt;/span&gt; &lt;span class="ss"&gt;:record&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:attribute&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:root_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:scope&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="c1"&gt;# app/model/user.rb&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;
  &lt;span class="c1"&gt;# ...more code&lt;/span&gt;
  &lt;span class="n"&gt;before_validation&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;username&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;UniqueName&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="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="c1"&gt;# ...more code&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="c1"&gt;# app/model/survey.rb&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Survey&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;
  &lt;span class="c1"&gt;# ...more code&lt;/span&gt;
  &lt;span class="n"&gt;validates&lt;/span&gt; &lt;span class="ss"&gt;:name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;uniqueness: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;scope: :author&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="n"&gt;before_validation&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;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;UniqueName&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="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;scope: :author_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="c1"&gt;# ...more code&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;


&lt;span class="c1"&gt;# app/model/saved_report.rb&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SavedReport&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;
  &lt;span class="c1"&gt;# ...more code&lt;/span&gt;
  &lt;span class="n"&gt;validates&lt;/span&gt; &lt;span class="ss"&gt;:name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;uniqueness: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;scope: :author&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="n"&gt;before_validation&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;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;UniqueName&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="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;scope: :author_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="c1"&gt;# ...more code&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 we have a Value Object that is general enough to be used widely throughout a large project, and perhaps is on it's way to being a useful library.&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;Having long favored functional programming I've been exploring the complementary nature of object-oriented and functional programming (more on that later). ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
      <category>refactoring</category>
      <category>valueobject</category>
    </item>
    <item>
      <title>On Venerable Technology--Perl, Part 1</title>
      <dc:creator>Delon R. Newman</dc:creator>
      <pubDate>Wed, 08 Nov 2023 02:26:48 +0000</pubDate>
      <link>https://dev.to/delonnewman/on-venerable-technology-perl-part-1-4goi</link>
      <guid>https://dev.to/delonnewman/on-venerable-technology-perl-part-1-4goi</guid>
      <description>&lt;p&gt;It seems these days that I often find myself in the position of one of the elder programmers in team settings. This is unsettling for a variety of reasons, one of the more obvious being that I’m just over 40, and one of the most troubling being that there’s still so much to learn.  However, I do find that there’s some perspective that comes from being involved in the same industry for a while (27 years or so now—time waits for no one), and perspective, I’ve found, is always valuable. I often hear folks waxing nostalgic about PHP or the early days of JavaScript, but I hear very little about the wonder of a language that PHP and JavaScript, warts&lt;br&gt;
and all, could never have come to be without. That language is &lt;a href="https://perl.org" rel="noopener noreferrer"&gt;Perl&lt;/a&gt;. To understand its significance we have to do a little time traveling, but before&lt;br&gt;
we do that let’s talk a little about programming.&lt;/p&gt;

&lt;p&gt;Programming is a deep and strange art (not to start debates about whether programming is an art, for me there is no debate, programming is an art if for no other reason than because &lt;a href="http://www.paulgraham.com/knuth.html" rel="noopener noreferrer"&gt;Knuth said so&lt;/a&gt;, and if you don’t know who &lt;a href="https://www-cs-faculty.stanford.edu/~knuth/" rel="noopener noreferrer"&gt;Knuth&lt;/a&gt; is please get back to your studies). It’s linguistic, it’s mathematical, for many it’s mechanical. Now that teaching programming is becoming more of a focus there’s starting to be some actual science on the subject and it seems according to &lt;a href="https://news.mit.edu/2020/brain-reading-computer-code-1215" rel="noopener noreferrer"&gt;at least one study&lt;/a&gt; in our brains’ opinion it’s none of the above.&lt;/p&gt;

&lt;p&gt;Yet, each programming language, out of necessity, takes a stand on the matter. To C (old venerable C) programming is about helping the human communicate with the machine in a way that is portable (&lt;a href="https://queue.acm.org/detail.cfm?id=3212479" rel="noopener noreferrer"&gt;in the late 60’s sense of the word “portable”&lt;/a&gt;). To Lisp (my dear old friend) programming is a mathematical art, that is about the the creative artist communicating with themself (and others) then and only then with the machine. For COBOL programming is about getting the job done and in way that looks like English so hopefully, with a silent prayer to the saints, somebody who comes behind this guy will be able to understand his code.&lt;/p&gt;

&lt;p&gt;Most other languages take one of these positions or some combination thereof. Perl, however, takes a view of programming that is uniquely its own.  Yet, peridoxically, one of it’s most unique features is putting no effort into being unique. Rather all of its effort was thrown entirely in the opposite direction. That is, cannibalizing every good idea from every place else starting first with natural languages.&lt;/p&gt;

&lt;p&gt;Please don’t misunderstand, Perl is not linguistic in the sense that COBOL and Basic and SQL are linguistic.  These computer languages were linguistic in the shallow sense. Yes thanks to &lt;a href="https://en.wikipedia.org/wiki/Formal_language" rel="noopener noreferrer"&gt;Chomsky, et al.&lt;/a&gt; they all have a formal grammar, and that formal grammar “looks” like English, but these languages only steal the &lt;em&gt;appearance&lt;/em&gt; of natural languages.  They lack deeper features that have a profound effect on the usability (the user interface) of language. Now the programmer (a bit older than myself) that was forced to sling Perl code at her Web 1.0 startup cries foul, “I know this guy didn’t bring up usability while talking about Perl”.&lt;/p&gt;

&lt;p&gt;Yes, I said it, &lt;em&gt;usability&lt;/em&gt;.  Again, now there is actual science behind this and &lt;a href="http://www.wall.org/~larry/" rel="noopener noreferrer"&gt;Larry Wall&lt;/a&gt; (the father of Perl) was trained in linguistics. Many of those features that make languages like Perl or APL look strange and alien actually make them more usable once you’ve learned them.  The key is &lt;em&gt;once you’ve learned them&lt;/em&gt;.  Many of us who came to love Perl have had the experience of &lt;em&gt;truly thinking&lt;/em&gt; in Perl (much the way we do in our native tongue) an experience I don’t think I’ve had in any other language since (it seems APL hackers report similar experiences). And ultimately that seems to have been a part of Perl’s struggle like Lisp and Smalltalk it’s a deep language, like C++ it’s a big language. It’s power was that it was also&lt;br&gt;
easy to learn, that is, the basics were easy to learn, but the deeper parts that were necessary to know in order to understand it’s essential design and see how deeply coherent the language actually is was more like the process of having the code-as-data, “aha” from Lisp or the message passing, “aha” from Smalltalk, it took effort and that effort was only exerted by a relative few.&lt;/p&gt;

&lt;p&gt;In a later article I’ll endeavor to illuminate those usability features.  So for now, thank you for reading and in the meantime please enjoy these tasty links!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.perl.com/pub/1998/08/show/onion.html/" rel="noopener noreferrer"&gt;Larry Wall's, 2nd State of the Onion Address&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.perl.com/pub/1999/03/pm.html/" rel="noopener noreferrer"&gt;Perl, the first postmodern computer language&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.geoffreylitt.com/projects/ruby-family-history.html" rel="noopener noreferrer"&gt;Ruby: A Family History&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.perlmonks.org/?node_id=253714" rel="noopener noreferrer"&gt;"There are some stunningly novel ideas in Perl" -- Paul Graham&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=z8MVKianh54" rel="noopener noreferrer"&gt;Does APL Need a Type System?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>perl</category>
      <category>history</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
