<?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: Keith Bennett</title>
    <description>The latest articles on DEV Community by Keith Bennett (@keithrbennett).</description>
    <link>https://dev.to/keithrbennett</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%2F1783%2F28410.jpeg</url>
      <title>DEV Community: Keith Bennett</title>
      <link>https://dev.to/keithrbennett</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/keithrbennett"/>
    <language>en</language>
    <item>
      <title>AutoPilot, CoPilot, or AI Assistant?</title>
      <dc:creator>Keith Bennett</dc:creator>
      <pubDate>Sat, 03 Feb 2024 00:47:00 +0000</pubDate>
      <link>https://dev.to/keithrbennett/autopilot-copilot-or-ai-assistant-2moj</link>
      <guid>https://dev.to/keithrbennett/autopilot-copilot-or-ai-assistant-2moj</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftmovxd7o3jijofguu9ow.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftmovxd7o3jijofguu9ow.png" alt="Image description" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  AI Downsides
&lt;/h3&gt;

&lt;p&gt;In &lt;a href="https://visualstudiomagazine.com/articles/2024/01/25/copilot-research.aspx"&gt;New GitHub Copilot Research Finds 'Downward Pressure on Code Quality'&lt;/a&gt;, Visual Studio magazine cites a &lt;a href="https://www.gitclear.com/coding_on_copilot_data_shows_ais_downward_pressure_on_code_quality"&gt;GitClear study&lt;/a&gt; that points out that AI for coding results in less maintainable (and therefore costlier) code.&lt;/p&gt;

&lt;p&gt;They point out, for example, that copying and pasting code in multiple locations where it is needed, rather than moving it to a single location and referring to it there, is prone to producing repetitive code, that is, code that is not &lt;a href="https://en.wikipedia.org/wiki/Don't_repeat_yourself"&gt;DRY&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In addition, at the time of this writing (January 2024), AI still makes &lt;em&gt;plenty&lt;/em&gt; of mistakes; that is, a) misunderstandings of intent, b) hallucinations, and c) downright errors.&lt;/p&gt;

&lt;h3&gt;
  
  
  Resisting Oversimplification
&lt;/h3&gt;

&lt;p&gt;While the study describes in great detail the pitfalls it found in AI-assisted coding, we must not succumb to the oversimplification so prevalent in these times and generalize that "AI is 100% bad". We need to realize that the positive or negative value of AI depends on this crucial nuance: the extent to which the developer &lt;em&gt;relies on&lt;/em&gt; and &lt;em&gt;defers to&lt;/em&gt; AI, rather than &lt;em&gt;supervising&lt;/em&gt; it with a critical eye.&lt;/p&gt;

&lt;p&gt;The name "Copilot" is apt. It must not be "Autopilot". However, even "Copilot" may not sufficiently express the subservient position that AI should take; "AI Assistant" would probably be more accurate, and is exactly &lt;a href="https://www.jetbrains.com/help/idea/ai-assistant.html"&gt;the name used by JetBrains&lt;/a&gt;, the company that produces outstanding IDE's.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Optimum Balance
&lt;/h3&gt;

&lt;p&gt;An organization that mandates excessive reliance on AI to quickly reduce labor costs will have a rude awakening when, over time, the poor code quality reveals itself in the form of reduced quality and increased cost.&lt;/p&gt;

&lt;p&gt;On the other hand, an organization that completely ignores the immense productivity boost that coding AI offers will "leave money on the table" and fall behind the competition.&lt;/p&gt;

&lt;h3&gt;
  
  
  Organizational Responsibility
&lt;/h3&gt;

&lt;p&gt;To quote my favorite paragraph in the study:&lt;/p&gt;

&lt;p&gt;"If there isn't a CTO or VP of Engineering who actively schedules time to reduce tech debt, you can add "executive-driven time pressures" to the list of reasons that newly added copy/paste code will never be consolidated into the component libraries that underpin long-term development velocity."&lt;/p&gt;

&lt;p&gt;In other words, resisting the temptation to build working code quickly in the short term at the expense of the medium and long term requires will power and effort, plus initiative or at minimum support from the highest levels of the organization. Those organizations that are not able or willing to delay gratification will suffer the consequences.&lt;/p&gt;

&lt;p&gt;Investing in code quality pays off well, but does have an initial cost. In the case of AI, this will be especially important.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;The bottom line is that we still need expert software developers to know how to use the tool, appreciating its knowledge and assistance, but taking the lead to verify and integrate it correctly. The AI landscape is changing at astonishing speed. Organizations and their developers need to reevaluate tools and policies frequently to ensure they are making optimal use of this game changing technology.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>githubcopilot</category>
      <category>github</category>
      <category>codequality</category>
    </item>
    <item>
      <title>Installing International Language Keyboard Input Methods on Linux Mint 20 Cinnamon &amp; Mate</title>
      <dc:creator>Keith Bennett</dc:creator>
      <pubDate>Mon, 24 Aug 2020 16:39:31 +0000</pubDate>
      <link>https://dev.to/keithrbennett/installing-international-language-keyboard-input-methods-on-linux-mint-20-cinnamon-mate-3d6d</link>
      <guid>https://dev.to/keithrbennett/installing-international-language-keyboard-input-methods-on-linux-mint-20-cinnamon-mate-3d6d</guid>
      <description>&lt;p&gt;I just started using a desktop system using Linux Mint 20 Cinnamon, and wanted to make sure that keyboard input methods worked for Thai and Korean. This took me down a long road, consulting several blog articles, questions, and answers, so I decided to document it to save others (and future me!) this effort.&lt;/p&gt;

&lt;p&gt;I've also briefly tested that this procedure works with Arabic, French, Hebrew, Russian, and Swedish, so I'm fairly confident that it will work for any supported language and input method.&lt;/p&gt;

&lt;p&gt;Below are the instructions for Linux Mint Cinnamon; I believe they will be identical for Mate.&lt;/p&gt;

&lt;h3&gt;
  
  
  Language Support
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Press the {Super} key, start typing &lt;code&gt;Languages&lt;/code&gt;, and select the "Languages" application.&lt;/li&gt;
&lt;li&gt;Click "Install/Remove Languages" at the bottom right.&lt;/li&gt;
&lt;li&gt;If requested, enter your login password to grant superuser rights to "Languages".&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For each language you want to add:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Click "Add"&lt;/li&gt;
&lt;li&gt;Start typing the name of the language, select the language you want, and then click the "Install" button. 
There may not be any confirmation that it has completed.&lt;/li&gt;
&lt;li&gt;Find the newly installed language in the list (again, you can start to type it to find it), select it,
and click the "Install Language Packs" button.&lt;/li&gt;
&lt;li&gt;Confirm any confirmation dialogs as necessary.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  If...
&lt;/h3&gt;

&lt;p&gt;The remainder of work to be done involves the IBus input method framework.&lt;/p&gt;

&lt;p&gt;If at any point during this procedure, you see a dialog saying "The IBus daemon is not running. Do you wish to start it?", click "Yes".&lt;/p&gt;

&lt;p&gt;Also, if you encounter a dialog saying "IBus has been started! If you cannot use IBus, add the following lines...", just click OK. I have seen this happen but have never needed the information displayed in the dialog.&lt;/p&gt;

&lt;h3&gt;
  
  
  Install IBus
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Install the IBus keyboard input management framework and the Hangul (native Korean alphabet) support:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sudo apt install -y ibus-m17n ibus-hangul&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Add IBus to the Startup Applications List
&lt;/h3&gt;

&lt;p&gt;Press the {Super} (Windows/Mac) key, type &lt;code&gt;startup&lt;/code&gt; and select "Startup Applications".&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Click the "+" button.&lt;/li&gt;
&lt;li&gt;Select "Custom command".&lt;/li&gt;
&lt;li&gt;For Name: &lt;code&gt;IBus&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;For Command: &lt;code&gt;ibus-daemon&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Click "Add".&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Configure IBus
&lt;/h3&gt;

&lt;p&gt;Press the {Super} key and type &lt;code&gt;ibus&lt;/code&gt;. Select "IBus Preferences".&lt;/p&gt;

&lt;h4&gt;
  
  
  Add a keyboard shortcut
&lt;/h4&gt;

&lt;p&gt;Cinnamon uses {Super}{Space} to navigate panel entries, and I have not found a way to disable that, so I assign another shortcut for language switching, {Ctrl}{Super}{Alt}-k ("k" for keyboard). Here's how:&lt;/p&gt;

&lt;p&gt;On the "General" tab:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;click the button labelled "..." to the right of the "Next Input Method" text field&lt;/li&gt;
&lt;li&gt;with "{Super}" selected, click the "Delete" button&lt;/li&gt;
&lt;li&gt;Replace any text in the "Key code" input field with "k"&lt;/li&gt;
&lt;li&gt;check "Control", "Alt", and "Super"&lt;/li&gt;
&lt;li&gt;click the "Add" button&lt;/li&gt;
&lt;li&gt;click the "OK" button&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You may not need to do this if you are using Mate and the {Super}{Space} key combination is available for IBus to use.&lt;/p&gt;

&lt;p&gt;Also, I found that {Ctrl}{Super}{Alt}-k &lt;em&gt;did not work&lt;/em&gt; when pressed while certain input methods were active. I briefly researched how to disable Cinnamon's use of {Super}{Space} but could not find an answer. Anyone? Assigning multiple key combinations to this action is supported, so that is another approach.&lt;/p&gt;

&lt;h4&gt;
  
  
  Add input methods
&lt;/h4&gt;

&lt;p&gt;On the "Input Method" tab, click "Add".&lt;/p&gt;

&lt;p&gt;For each desired input method, click your desired language, or if it is not listed (as with Korean and Thai), click the three vertical dots entry, click the text field to give it focus, and type the language into the text field, then select the entry below the language name that you want. In the case of Korean, there is only one ("Hangul"). Click "Add".&lt;/p&gt;

&lt;h3&gt;
  
  
  Reboot and Test
&lt;/h3&gt;

&lt;p&gt;Reboot the system. (If you want to save time, you could log out and then in again instead of rebooting, but that will not verify that IBus was started on system startup.)&lt;/p&gt;

&lt;p&gt;Test switching input methods with {Ctrl}{Super}{Alt}-k, and typing text into an application that can accept it. &lt;/p&gt;

&lt;h3&gt;
  
  
  The Language Panel Applet
&lt;/h3&gt;

&lt;p&gt;There are two methods for invoking input method selection:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the keyboard shortcut ({Ctrl}{Super}{Alt}-k, {Super}{Space}, etc.)&lt;/li&gt;
&lt;li&gt;the panel applet&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The panel applet is on the system panel, and will display the currently selected language. Clicking it will display a list of languages from which you can select a different one. This applet can be used as a fallback mechanism for changing language if the keyboard shortcut does not work.&lt;/p&gt;

&lt;p&gt;Unfortunately, the text on this indicator is displayed in a dark blue text that is difficult to see against the black background, so it may take some effort to find. The Korean language setting deals with this by showing a colorful icon instead of text.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cautions
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Invoking Input Method Selection&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As mentioned, if the keyboard shortcut for selecting an input method does not work, remember the panel applet and use that instead.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Know Your Input Methods&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The Korean input method uses a {Shift}{Space} toggle key combination to toggle between Hangul and English character input. When you switch into Korean input mode from another language, it will initially be in English mode, so it may not be obvious that you have successfully switched to Korean. Press {Shift}{Space} to toggle to Hangul input mode.&lt;/li&gt;
&lt;li&gt;If you're new to a language, there may be things to learn about that language's computer input methods that are not taught in school or otherwise obvious. If the input does not appear to work correctly, make sure you're not overlooking a feature of that input method.&lt;/li&gt;
&lt;li&gt;Some languages have many input methods from which to choose, and some may be much better than others for your purposes. For example, some are Dvorak layouts of interest only to the hardiest of souls.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Language-Specific Configuration&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There may be language specific requirements with other languages like the need to install the ibus-hangul package for Korean.&lt;/p&gt;

&lt;h3&gt;
  
  
  You're done!
&lt;/h3&gt;

&lt;p&gt;Thanks for reading, and let me know in a comment on the &lt;a href="https://dev.to/keithrbennett/installing-international-language-keyboard-input-methods-on-linux-mint-20-cinnamon-mate-3d6d"&gt;dev.to article page&lt;/a&gt; if you have any corrections or improvements to offer.&lt;/p&gt;

</description>
      <category>linux</category>
      <category>mint</category>
      <category>i18n</category>
      <category>internationalization</category>
    </item>
    <item>
      <title>Using Lambdas to Simplify Varying Behaviors in Your Code</title>
      <dc:creator>Keith Bennett</dc:creator>
      <pubDate>Tue, 12 May 2020 18:37:42 +0000</pubDate>
      <link>https://dev.to/keithrbennett/using-lambdas-to-simplify-varying-behaviors-in-your-code-1lbi</link>
      <guid>https://dev.to/keithrbennett/using-lambdas-to-simplify-varying-behaviors-in-your-code-1lbi</guid>
      <description>&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Anonymous_function"&gt;Lambdas&lt;/a&gt; are anonymous (unnamed) functions. Unlike &lt;em&gt;methods&lt;/em&gt; in &lt;a href="https://en.wikipedia.org/wiki/Object-oriented_programming"&gt;object oriented programming&lt;/a&gt; languages, lambdas are not bound to any object. Although they are best known in the context of &lt;a href="https://en.wikipedia.org/wiki/Functional_languages"&gt;functional programming&lt;/a&gt; languages, object oriented programming languages that support lambdas, such as Ruby, can greatly benefit from their use. This is especially true when it comes to implementing varying behaviors(1).&lt;/p&gt;

&lt;p&gt;By varying behaviors, I mean situations where the code that needs to run is not fixed, but rather specified, using parameters, subclassing, or configuration. Examples would include cases for which you would use the &lt;a href="https://en.wikipedia.org/wiki/Command_pattern"&gt;Command&lt;/a&gt; and &lt;a href="https://en.wikipedia.org/wiki/Strategy_pattern"&gt;Strategy&lt;/a&gt; design patterns.&lt;/p&gt;

&lt;p&gt;Many developers are already familiar with using lambdas for &lt;em&gt;event handling&lt;/em&gt; (implemented with the  &lt;code&gt;function&lt;/code&gt; keyword in JavaScript and also as arrow functions in ES6) , but there are many other cases in which they are helpful, a couple of which I will describe below.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Problem with Non-Lambda Approaches
&lt;/h3&gt;

&lt;p&gt;The procedural &lt;code&gt;if-elsif-end&lt;/code&gt; or &lt;code&gt;case&lt;/code&gt; clauses work when you have a small number of conditions and actions that are known in advance, but if you don't, they're pretty useless.&lt;/p&gt;

&lt;p&gt;And although the object oriented approach of &lt;a href="https://en.wikipedia.org/wiki/Polymorphism_(computer_science)"&gt;polymorphism&lt;/a&gt; by inheritance (2) can produce a correct result, in many cases it is unnecessarily verbose, ceremonial, and awkward.&lt;/p&gt;

&lt;p&gt;To further embellish on this point, &lt;a href="https://twitter.com/KayEss"&gt;@kayess&lt;/a&gt; pointed me to a &lt;a href="http://okmij.org/ftp/Scheme/oop-in-fp.txt"&gt;discussion&lt;/a&gt; on a Scheme forum where Anton van Straaten said about closures (lambdas are closures): "A closure's  simplicity can be an asset: classes and interfaces can get in the way of simple parameterization of behavior.  Anyone who's tried functional programming in Java or C++ has encountered this - it can be done, but it's more tedious." Anton goes on to provide an entertaining koan about the subject.&lt;/p&gt;

&lt;p&gt;Furthermore, though we're accustomed to thinking about this problem in the context of a &lt;em&gt;single&lt;/em&gt; customizable behavior, what if there are &lt;em&gt;several&lt;/em&gt;?&lt;/p&gt;

&lt;p&gt;Let's say we have a class that contains 3 varying behaviors. As an admittedly contrived example, let's say we have classes for each of hundreds of different species of animals, and they each have a &lt;code&gt;move&lt;/code&gt;, &lt;code&gt;sleep&lt;/code&gt;, and &lt;code&gt;vocalize&lt;/code&gt; behavior. As a simplifying assumption, let's say that each of these behaviors has 7 possible variations, each of which is shared by many species. If we were to write a class to implement each possible set of the 3 behaviors, we would need the &lt;a href="https://en.wikipedia.org/wiki/Cartesian_product"&gt;Cartesian product&lt;/a&gt; of classes, (7 * 7 * 7), or 343 classes! That would be a silly monstrosity for several reasons of course, one of which being we could simplify the design by providing a class hierarchy for each of the three kinds of behavior, and plug those into the larger class -- but then we would still need (7 + 7 + 7), or 21 classes! (Probably 24 really, as pure design would dictate an additional class as an abstract superclass for each set of 7 implementations).&lt;/p&gt;

&lt;p&gt;If these behaviors are truly complex enough to justify a class of their own, this is not a problem. However, often they are not, and the solution is many times as verbose and complex as it needs to be.&lt;/p&gt;

&lt;p&gt;A better solution is using &lt;em&gt;callables&lt;/em&gt; such as lambdas.&lt;/p&gt;




&lt;h4&gt;
  
  
  Callables as a Superset of Lambdas
&lt;/h4&gt;

&lt;p&gt;In traditional object oriented languages such as Java and C++, polymorphism is (in general) implemented by inheritance. Ruby does this also (3), but in addition, Ruby uses &lt;em&gt;duck typing&lt;/em&gt;, meaning that &lt;em&gt;any&lt;/em&gt; object that responds to the method name can be used, regardless of its position in the class hierarchy.&lt;/p&gt;

&lt;h5&gt;
  
  
  This means that in Ruby, since the method used to call a lambda is &lt;code&gt;call&lt;/code&gt;, &lt;em&gt;any&lt;/em&gt; object that responds to &lt;code&gt;call&lt;/code&gt; can be used in place of a lambda.
&lt;/h5&gt;

&lt;p&gt;It could be a lambda, an instance of a class, or even a class or module. This provides great flexibility in implementing varying behavior. You can choose what kind of object to use based on your situation. For complex behaviors you may want modules or classes, and for simpler behaviors a lambda will work just fine.&lt;/p&gt;

&lt;p&gt;Since any object responding to &lt;code&gt;call&lt;/code&gt; can be used in place of a lambda, I will use the term &lt;em&gt;callable&lt;/em&gt; instead of &lt;em&gt;lambda&lt;/em&gt; where applicable.&lt;/p&gt;




&lt;h3&gt;
  
  
  The Buffered Enumerable
&lt;/h3&gt;

&lt;p&gt;I once worked on a project where I needed to implement buffering of multiple kinds of things received over network connections. I started writing the first one, and noticed how the code could be cleanly divided into two kinds of tasks: 1) knowing &lt;em&gt;when&lt;/em&gt; to fetch objects into the buffer and other buffer management tasks, and 2) knowing &lt;em&gt;how&lt;/em&gt; to fetch each block of objects and what &lt;em&gt;else&lt;/em&gt; to do each time that fetch is performed (e.g. logging, displaying a message to the user, updating some external state).&lt;/p&gt;

&lt;p&gt;Realizing that #1 would be common and identical to all cases, and only #2 would vary, I thought about how wasteful it would be to implement #1 separately in all cases. I thought about the admonition about high cohesion / low coupling, and the Unix axiom "do one thing well", and decided to separate the two.&lt;/p&gt;

&lt;p&gt;The most natural way to design this functionality in Ruby is with an &lt;a href="https://ruby-doc.org/core-2.5.1/Enumerable.html"&gt;&lt;em&gt;Enumerable&lt;/em&gt;&lt;/a&gt;, which will have access to all kinds of functional wizardry thanks to the methods it gets for free by including the &lt;code&gt;Enumerable&lt;/code&gt; module. In addition, it can easily be used to generate an array by calling its &lt;code&gt;to_a&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;This is the origin of the  &lt;a href="https://github.com/keithrbennett/trick_bag/blob/master/lib/trick_bag/enumerables/buffered_enumerable.rb"&gt;&lt;em&gt;BufferedEnumerable&lt;/em&gt;&lt;/a&gt; class in my &lt;a href="https://github.com/keithrbennett/trick_bag/"&gt;&lt;em&gt;trick_bag&lt;/em&gt;&lt;/a&gt; gem. This class manages buffering but has no idea how to fetch chunks of data, nor what else to do at each such fetch; for that, the caller provides callables such as lambdas. (Upon user request, the ability to subclass it and override its methods was also added.) The result is a dramatic simplification, where the logic of buffering is defined in only one place, and the places it is used need not be concerned with its implementation (or its testing!).&lt;/p&gt;

&lt;p&gt;To create an instance of this with callables, we call the &lt;code&gt;BufferedEnumerable&lt;/code&gt; class method &lt;code&gt;create_with_callables&lt;/code&gt;, which is defined as follows(4):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_with_callables&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chunk_size&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fetcher&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fetch_notifier&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="n"&gt;instance&lt;/span&gt; &lt;span class="o"&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;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chunk_size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetcher&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fetcher&lt;/span&gt;
    &lt;span class="n"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetch_notifier&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fetch_notifier&lt;/span&gt;
    &lt;span class="n"&gt;instance&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;When a fetcher callable has been defined (as opposed to the use of the subclassing approach, where an overriding method is used), it is called with the empty data buffer and the number of objects requested as shown below whenever the buffer needs to be filled, as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;fetcher&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;chunk_size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;(In Ruby, &lt;code&gt;.(&lt;/code&gt; is an abbreviation for &lt;code&gt;.call(&lt;/code&gt;.)&lt;/p&gt;

&lt;p&gt;A trivial fetcher that merely fills the array of the requested chunk size with random numbers could look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;fetcher&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;chunk_size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;chunk_size&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;times&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rand&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;Below is a &lt;code&gt;pry&lt;/code&gt; example that illustrates the call to that fetcher, and its effect on the passed array:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[7] pry("")&amp;gt; a = []; fetcher.(a, 2)
2
[8] pry("")&amp;gt; a
[
    [0] 0.4885287976297428,
    [1] 0.5493143769524284
]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;After the buffer is filled, if a fetch notifier callable has been defined (unlike the fetcher, this is optional), it too is called, with the data buffer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;fetch_notifier&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;A trivial fetch notifier might look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="no"&gt;Time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; Fetched &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;size&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; objects"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;(&lt;code&gt;data.size&lt;/code&gt; will not necessarily be equal to &lt;code&gt;chunk_size&lt;/code&gt;, especially on the last fetch.)&lt;/p&gt;

&lt;p&gt;This notifier might produce something looking like this:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;2018-07-26 17:19:47 +0700 Fetched 1000 objects&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;After defining the &lt;code&gt;fetcher&lt;/code&gt; and &lt;code&gt;fetch_notifier&lt;/code&gt; lambdas, we could call the class method for creating a BufferedEnumerable shown above as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;buffered_enumerable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;BufferedEnumerable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_with_callables&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;\&lt;/span&gt;
    &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fetcher&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fetch_notifier&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This enumerable can be used to call &lt;code&gt;each&lt;/code&gt; or any other of the rich set of methods available on the &lt;a href="https://ruby-doc.org/core-2.5.1/Enumerable.html"&gt;&lt;em&gt;Enumerable&lt;/em&gt;&lt;/a&gt; module.&lt;/p&gt;

&lt;p&gt;By parameterizing the behaviors with callables, we have increased the simplicity of the implementation by separating the two orthogonal tasks into separate code areas, and avoided the unnecessary overhead of the inheritance approach, which would have packaged these functions in classes.&lt;/p&gt;




&lt;h3&gt;
  
  
  Using Predicate Callables to Implement Filters
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;Predicates&lt;/em&gt; are functions that return a Boolean value, that is, either true or false. There are many uses for predicates in software: filters, boundaries, triggers, authentication results...again, anything that produces a true or false value.&lt;/p&gt;

&lt;p&gt;Configurable predicates are another natural fit for using callables.&lt;/p&gt;

&lt;p&gt;I once had to write a &lt;a href="https://github.com/keithrbennett/mock_dns_server"&gt;DNS mock server&lt;/a&gt; for network testing  that could be configured to respond with specific behaviors based on the characteristics of the incoming request. In another situation more recently, I was writing some accounting software and wanted to be able to filter the working set of transactions based on date, category, etc.&lt;/p&gt;

&lt;p&gt;Both cases were an excellent fit for using callables as filters.&lt;/p&gt;

&lt;p&gt;In the case of the mock DNS server, there were multiple criteria for the DNS request filters, such as &lt;em&gt;protocol&lt;/em&gt; (TCP vs. UDP), &lt;em&gt;qtype&lt;/em&gt; (question type), &lt;em&gt;qclass&lt;/em&gt; (question class), and &lt;em&gt;qname&lt;/em&gt; (question name). I provided methods that return lambdas that filter for specific values for those attributes; for example, to create a filter that will return true only for the qname &lt;code&gt;example.com&lt;/code&gt;, you would do the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;MockDnsServer&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;PredicateFactory&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;qname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'example.com'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;qname&lt;/code&gt; method (i.e. the method that returns a filter for exactly one qname value) is defined as (roughly):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;qname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qname&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_protocol&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;do&lt;/span&gt;
    &lt;span class="n"&gt;eq_case_insensitive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;qname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;qname&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;If you view the method body from left to right, you will notice the prominent &lt;code&gt;-&amp;gt;&lt;/code&gt; and its corresponding &lt;code&gt;end&lt;/code&gt; two lines beneath it, which tell you that the value returned by this method is a lambda. The leading underscore of the &lt;code&gt;_protocol&lt;/code&gt; parameter is a convention that indicates that that parameter is unused by the lambda.&lt;/p&gt;

&lt;p&gt;Notice that the &lt;code&gt;qname&lt;/code&gt; parameter's value (e.g. "example.com") is effectively stored in the lambda that the method returns? This technique is called &lt;em&gt;partial application&lt;/em&gt;, and is extremely useful when working with lambdas.&lt;/p&gt;

&lt;p&gt;Does storing state in the lambda make it any less &lt;em&gt;functional&lt;/em&gt;? Not really; the state is immutable and used only for comparison.&lt;/p&gt;

&lt;p&gt;If we were to refine the filter by adding the requirement that the qtype be 'A' and the protocol be 'TCP', then we could call methods to return those filters as well, and combine all three using the &lt;code&gt;all&lt;/code&gt; compound filter. (Other compound filters are &lt;code&gt;any&lt;/code&gt; and &lt;code&gt;none&lt;/code&gt;.) Here is what that would look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;pf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;MockDnsServer&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;PredicateFactory&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;filter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;pf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;qtype&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'A'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;pf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;qname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'example.com'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;pf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_tcp&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;all&lt;/code&gt; compound filter is nothing more than a simple wrapper around Ruby's Enumerable's &lt;code&gt;all?&lt;/code&gt; method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;predicates&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;protocol&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;do&lt;/span&gt;
      &lt;span class="n"&gt;predicates&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all?&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nb"&gt;p&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nb"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;protocol&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="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Why does all this work? The filters are interchangeable because they all have uniform inputs and outputs. That is, they take the same parameter list (&lt;code&gt;[message, protocol]&lt;/code&gt; in this example), and they all return a value usable by the caller (&lt;code&gt;true&lt;/code&gt; or &lt;code&gt;false&lt;/code&gt; in this example). We've already seen one implementation, the lambda returned by the &lt;code&gt;qname&lt;/code&gt; method shown above. Here is another one; this one returns true if and only if the message was sent over TCP:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;from_tcp&lt;/span&gt;
  &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;protocol&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;protocol&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="ss"&gt;:tcp&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;In this case, we only care about the protocol so we can ignore the first (&lt;code&gt;message&lt;/code&gt;) parameter.&lt;/p&gt;




&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;I hope I have been successful in persuading you to consider using callables for implementing variable predicates and actions.&lt;/p&gt;

&lt;p&gt;These are just two examples. I will stop here for the sake of brevity, but if you have any questions or suggestions for elaboration, please contact me.&lt;/p&gt;

&lt;p&gt;You can find me on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/keithrbennett"&gt;Github&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.linkedin.com/in/keithrbennett/"&gt;LinkedIn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://stackoverflow.com/users/501266/keith-bennett"&gt;StackOverflow&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/keithrbennett"&gt;Twitter&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Also, for more information about lambdas, feel free to check out my Ruby lambdas presentation (&lt;a href="https://speakerdeck.com/keithrbennett/ruby-lambdas-functional-conf-bangalore-oct-2014"&gt;Speakerdeck slideshow&lt;/a&gt; and &lt;a href="https://www.youtube.com/watch?v=nGEy-vFJCSE"&gt;YouTube video&lt;/a&gt;).&lt;/p&gt;




&lt;h3&gt;
  
  
  Footnotes
&lt;/h3&gt;

&lt;p&gt;(1) One might ask what else &lt;em&gt;is&lt;/em&gt; there about lambdas other than varying behavior, but there &lt;em&gt;are&lt;/em&gt; other reasons to use them in Ruby. For example, they can be used:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;as nested functions&lt;/li&gt;
&lt;li&gt;as truly private functions (which, unlike private methods, cannot be accessed with &lt;code&gt;send&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;for self invoking anonymous functions, to hide variables&lt;/li&gt;
&lt;li&gt;for defining functions where methods cannot be defined (e.g. in some RSpec code)&lt;/li&gt;
&lt;li&gt;for defining classes dynamically with the &lt;code&gt;class...end&lt;/code&gt; notation which may be easier to understand than the &lt;code&gt;Class.new&lt;/code&gt; approach.&lt;/li&gt;
&lt;li&gt;for chaining operations, as in an array of lambdas&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;(2) Polymorphism by inheritance is a key characteristic of object oriented design whereby, by virtue of having a common ancestor in the class hierarchy that contains the method in question, objects of different classes can respond to the same message (typically identified by a method or function name) differently. This can be a nice design in some cases, but in others it is an overly heavy handed solution to a simple problem, as it forces the developer to create multiple classes in a class hierarchy.&lt;/p&gt;

&lt;p&gt;(2 (cont'd)) &lt;a href="https://twitter.com/KayEss"&gt;@kayess&lt;/a&gt; points out that the more precise terms in software engineering are &lt;a href="https://en.wikipedia.org/wiki/Nominal_type_system"&gt;nominal typing&lt;/a&gt; for polymorphism by inheritance, and &lt;a href="https://en.wikipedia.org/wiki/Structural_type_system"&gt;structural typing&lt;/a&gt; for duck typing.&lt;/p&gt;

&lt;p&gt;(3) To be more precise, Ruby supports polymorphism by inheritance, but not by checking the class hierarchy like most OO languages do. Instead, it is using duck typing, and merely calls the method by name; since a subclass will be able to call its superclass' method by default, it works.&lt;/p&gt;

&lt;p&gt;(4) The omission of the &lt;code&gt;fetcher&lt;/code&gt; and &lt;code&gt;fetch_notifier&lt;/code&gt; parameters from the constructor is intentional. The constructor is intended to be used directly by the caller only when the subclassing approach is used; for lambdas the static method &lt;code&gt;create_with_callables&lt;/code&gt; should be used.&lt;/p&gt;




&lt;p&gt;This article may be improved over time. To see its revisions you can go to its &lt;a href="https://github.com/keithrbennett/keithrbennett.github.io/commits/master/_posts/2018-08-04-using-lambdas-to-simplify-varying-behaviors-in-your-code.md"&gt;Github commit history&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>lambda</category>
    </item>
    <item>
      <title>Add Bootstrap to Rails 6 with Two Shell Commands</title>
      <dc:creator>Keith Bennett</dc:creator>
      <pubDate>Thu, 07 May 2020 21:15:18 +0000</pubDate>
      <link>https://dev.to/keithrbennett/adding-bootstrap-to-your-rails-6-application-a17</link>
      <guid>https://dev.to/keithrbennett/adding-bootstrap-to-your-rails-6-application-a17</guid>
      <description>&lt;h3&gt;
  
  
  Introduction
&lt;/h3&gt;

&lt;p&gt;In this article I will discuss a very simple approach to configuring your Rails 6 application to work with &lt;a href="https://getbootstrap.com/"&gt;Bootstrap&lt;/a&gt;. An &lt;a href="https://github.com/keithrbennett/rails-bootstrap-example"&gt;entire Rails repo&lt;/a&gt; is provided, including commit history, but this might be all you need:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl https://raw.githubusercontent.com/keithrbennett/rails-bootstrap-example/master/0001-Add-Bootstrap-configuration.patch | git apply -
yarn add bootstrap jquery popper.js
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;I recently wanted to add Bootstrap to a new Rails 6 application, but even after reading the &lt;a href="https://getbootstrap.com/docs/4.4/getting-started/introduction/"&gt;documentation&lt;/a&gt; and several blog articles, success eluded me.&lt;/p&gt;

&lt;p&gt;What finally worked was to follow along with &lt;a href="https://gorails.com/episodes/how-to-use-bootstrap-with-webpack-and-rails"&gt;this article&lt;/a&gt; by &lt;a href="https://twitter.com/excid3"&gt;Chris Oliver&lt;/a&gt; -- well, more precicely, the &lt;a href="https://www.youtube.com/watch?v=bn9arlhfaXc"&gt;&lt;em&gt;video&lt;/em&gt;&lt;/a&gt; linked to in the article. In it, he shows exactly what to do -- and doing what he said to do worked for me.&lt;/p&gt;

&lt;h3&gt;
  
  
  Even Simpler -- A Patch
&lt;/h3&gt;

&lt;p&gt;In order to even further simplify the process for future developers, I generated a &lt;a href="https://github.com/keithrbennett/rails-bootstrap-example/blob/master/0001-Add-Bootstrap-configuration.patch"&gt;patch file&lt;/a&gt; to make the changes needed to provide the correct configuration. (These changes do assume a new Rails application, so it's possible that some modification to the changes would be required for existing projects.)&lt;/p&gt;

&lt;p&gt;You can make the changes to your existing project or a fresh one generated with &lt;code&gt;rails new&lt;/code&gt;. Here's how to do it:&lt;/p&gt;

&lt;p&gt;Change directory to your project root.&lt;/p&gt;

&lt;p&gt;I suggest you have a "clean working tree" (no git-relevant changes since the most recent commit) before you apply the patch; this will make it easier to revert the change or limit your next commit to only the Bootstrap configuration change.&lt;/p&gt;

&lt;p&gt;You can download the patch in its &lt;a href="https://raw.githubusercontent.com/keithrbennett/rails-bootstrap-example/master/0001-Add-Bootstrap-configuration.patch"&gt;raw format&lt;/a&gt; (i.e. only the unadorned text and not the HTML web page displaying it) to your local filesystem with the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl -o bootstrap.patch https://raw.githubusercontent.com/keithrbennett/rails-bootstrap-example/master/0001-Add-Bootstrap-configuration.patch
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Then apply the patch:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git apply bootstrap.patch
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Alternatively, you can combine the above two steps into one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl https://raw.githubusercontent.com/keithrbennett/rails-bootstrap-example/master/0001-Add-Bootstrap-configuration.patch | git apply -
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;You can see the changes with a &lt;code&gt;git diff&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding the JavaScript Libraries
&lt;/h3&gt;

&lt;p&gt;At some point (either before or after the patch) you will need to add the necessary JavaScript libraries:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn add bootstrap jquery popper.js
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This will make changes to &lt;code&gt;package.json&lt;/code&gt; and &lt;code&gt;yarn.lock&lt;/code&gt; that will need to be committed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Testing that Bootstrap Works
&lt;/h3&gt;

&lt;p&gt;We'll want to exercise Bootstrap to verify that it is working correctly. &lt;/p&gt;

&lt;p&gt;The &lt;code&gt;index.html.erb&lt;/code&gt; &lt;a href="https://github.com/keithrbennett/rails-bootstrap-example/blob/master/app/views/home/index.html.erb"&gt;file in the repo&lt;/a&gt; uses Bootstrap colored border spinners requiring both CSS and JavaScript provided by Bootstrap, and is a good test. Of course, you can find many other components to use in the Bootstrap &lt;a href="https://getbootstrap.com/docs/4.4/getting-started/introduction/"&gt;docs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The rest of this section discusses setting up a sample app using the patches provided. Here is a list of all the patches:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# already used above, to configure Bootstrap
0001-Add-Bootstrap-configuration.patch                       

# These next 3 can be used to put something in the
# home page to test that Bootstrap is working:
0002-rails-g-controller-home-index.patch
0003-Change-root-route-to-go-to-new-page.patch
0004-Add-Bootstrap-color-border-spinners-to-page.patch
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;These patches are in the &lt;a href="https://github.com/keithrbennett/rails-bootstrap-example"&gt;project root of the sample repo&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Applying patches #2 through #4 will set up the sample code to show that Bootstrap is working. Here are commands that will apply the patches directly from Github (without creating patch files on your local filesystem):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl https://raw.githubusercontent.com/keithrbennett/rails-bootstrap-example/master/0002-rails-g-controller-home-index.patch | git apply -
curl https://raw.githubusercontent.com/keithrbennett/rails-bootstrap-example/master/0003-Change-root-route-to-go-to-new-page.patch | git apply -
curl https://raw.githubusercontent.com/keithrbennett/rails-bootstrap-example/master/0004-Add-Bootstrap-color-border-spinners-to-page.patch | git apply -
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This is all you should need to do! At this point you can run &lt;code&gt;rails s&lt;/code&gt; and connect to it in your browser. If all goes well you will see something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--C1lwJl-d--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/0d3a74vcsdj1cktwcq9n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--C1lwJl-d--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/0d3a74vcsdj1cktwcq9n.png" alt="successful Bootstrap page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Git's Patch Support
&lt;/h3&gt;

&lt;p&gt;You may have noticed that the patch file names were numbered and contained the first part of the commit messages in the names. This was not something I did myself, this was done automatically by git. Git has great patch support, and all I needed to do to generate the patches was issue this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ git format-patch HEAD~4
0001-rails-g-controller-home-index.patch
0002-Change-root-route-to-go-to-new-page.patch
0003-Add-Bootstrap-color-border-spinners-to-page.patch
0004-Add-patch-files-git-format-patch-HEAD-4.patch
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;HEAD~4&lt;/code&gt; told git how far back I wanted to start (4 commits).&lt;/p&gt;

&lt;p&gt;As you saw above, applying a patch to a code base is as simple as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git apply something.patch
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;






&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;I hope that the time I invested in creating and documenting this simplifying procedure will pay off in the form of time saved for you. If you think I could be useful on your project, or would just like to say hello, please give me a holler at &lt;a href="//mailto:kbennett@bbs-software.com"&gt;kbennett@bbs-software.com&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;This article may be improved over time. To see its revisions you can go to its &lt;a href="https://github.com/keithrbennett/keithrbennett.github.io/commits/master/blog/_posts/2020-05-07-adding-bootstrap-to-rails-6.md"&gt;Github commit history&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;Note: The patch (#1) originally published with this article did not include some configuration code needed to expose JQuery and Popper, which could have been a problem implementing customizations. It was fixed on 2020-05-12. You can see the changes &lt;a href="https://gist.github.com/keithrbennett/1ee95d21ab9597602184ab689ca0a6f1/revisions"&gt;here&lt;/a&gt;. &lt;/p&gt;

</description>
      <category>rails</category>
      <category>bootstrap</category>
      <category>web</category>
    </item>
    <item>
      <title>Clinics in Your Meetups</title>
      <dc:creator>Keith Bennett</dc:creator>
      <pubDate>Mon, 03 Feb 2020 10:47:52 +0000</pubDate>
      <link>https://dev.to/keithrbennett/clinics-in-your-meetups-2pa0</link>
      <guid>https://dev.to/keithrbennett/clinics-in-your-meetups-2pa0</guid>
      <description>&lt;p&gt;Information sharing at technical meetings (aka "meetups") consists almost exclusively of presentations. Although we all understand the value of having an expert share expertise with the rest of us, our cultural bias towards one-to-many communication results in many lost opportunities for cross-fertilization of knowledge and cultivation of connections among the group.&lt;/p&gt;

&lt;p&gt;In contrast, a many-to-many medium of communication such as a discussion or clinic provides an environment in which knowledge, ideas, and solutions can emanate from, and be received by, anyone.&lt;/p&gt;

&lt;p&gt;I am not advocating &lt;em&gt;replacing&lt;/em&gt; presentations with discussions. Rather, I am advocating an optimal balance of the two. Where this optimal point falls will depend on the group.&lt;/p&gt;

&lt;p&gt;We are all familiar with presentations, so I will mainly talk about discussions and clinics here, and what they offer that presentations do not. First I will talk about discussions in general, and then clinics in particular.&lt;/p&gt;

&lt;h4&gt;
  
  
  Multiple Sources of Information
&lt;/h4&gt;

&lt;p&gt;It's rare that a single person possesses all the knowledge in the room. When &lt;em&gt;anyone&lt;/em&gt; can speak, we are more likely to get more high quality information. (Of course, we are also more likely to get more low quality information but the group can usually recognize and neutralize it.)&lt;/p&gt;

&lt;h4&gt;
  
  
  Dialog vs. Monologue
&lt;/h4&gt;

&lt;p&gt;In a presentation, the information is assumed to be flowing in one direction, from the speaker to everyone else. Any discussion is normally for clarification of that unidirectional information flow.&lt;/p&gt;

&lt;p&gt;In contrast, in a more &lt;em&gt;conversational&lt;/em&gt; medium, people &lt;br&gt;
are more likely to participate, resulting in greater depth and breadth of the information flow, as ideas bounce from person to person.&lt;/p&gt;

&lt;h4&gt;
  
  
  Synergy
&lt;/h4&gt;

&lt;p&gt;There is a synergy in discussions that is absent in presentations. In discussions, one person's contribution can raise other questions or responses that can provide better information or lead the discussion to a valuable place that would not have otherwise been visited.&lt;/p&gt;

&lt;h4&gt;
  
  
  Greater Variety of Subject Matter
&lt;/h4&gt;

&lt;p&gt;Even if a meetup includes two presentations, the topics covered are narrow. Including discussions even for, say, fifteen minutes, makes it more likely that people will find something in the meetup that is more relevant, and therefore more interesting, to them. Imagine, for example, the beginner who attends their first meetup, encounters specialized presentations that they do not understand, and then never returns, concluding that the meetings are "not for them".&lt;/p&gt;

&lt;h4&gt;
  
  
  Community Development
&lt;/h4&gt;

&lt;p&gt;People who may have not uttered a word in months of presentations may feel more comfortable doing so in a discussion. They should be actively encouraged, even if it's to ask a question. &lt;/p&gt;

&lt;p&gt;There will likely be "wizards" in the group, members who are recognizably much more knowledgeable than the others. It is natural for the others to feel intimidated and refrain from speaking. Wizards should step out of the way frequently, and the facilitator should encourage everyone to take part.&lt;/p&gt;

&lt;p&gt;From discussion springs familiarity, and from familiarity springs friendship and community (not to mention jobs sometimes). It even enhances productivity, in that a relationship has formed such that people will feel more comfortable consulting each other outside of the discussions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Clinics, in Particular
&lt;/h2&gt;

&lt;p&gt;The &lt;em&gt;clinic&lt;/em&gt; is a specialized form of discussion where people share their problems, challenges, and discoveries.&lt;/p&gt;

&lt;p&gt;The key benefit of the clinic is that participants are likely to receive the information that is most valuable and helpful to them &lt;em&gt;at the time&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;In addition, the entire group is involved in finding the solution. Everyone is "on call". This can result in greater engagement and energy.&lt;/p&gt;

&lt;p&gt;I describe at the bottom of this article my experience facilitating an internal organization Ruby clinic.&lt;sup id="a1"&gt;[1]&lt;/sup&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Structure
&lt;/h4&gt;

&lt;p&gt;The clinic can be totally free form, but I recommend a meta-discussion at the beginning where people describe the topics they would like to discuss, and the group plans the discussion schedule. This is kind of like the opening of an open space conference but on a micro scale.&lt;/p&gt;

&lt;h4&gt;
  
  
  Advance Notice of Topics
&lt;/h4&gt;

&lt;p&gt;It can be helpful for the group to propose topics in advance of the meetup. This has the following benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ambiguities can be resolved before the meetup&lt;/li&gt;
&lt;li&gt;some of the session planning can be done in advance&lt;/li&gt;
&lt;li&gt;people can research the topics in advance&lt;/li&gt;
&lt;li&gt;opportunities to refine or combine topics would be identified earlier&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Infrastructure
&lt;/h4&gt;

&lt;p&gt;It's helpful to have a shared screen. This is automatic if you are using collaboration software, but if you're in a physical room together, you'll need a projector or large shared monitor to be most productive.&lt;/p&gt;

&lt;p&gt;Whether you have a single machine which will be shared by everyone, or everyone uses their own computer, I recommend bringing a wireless keyboard and mouse to the clinic; it lowers the barrier for &lt;em&gt;other&lt;/em&gt; people to take the driver seat.&lt;/p&gt;

&lt;h4&gt;
  
  
  Level of Effort
&lt;/h4&gt;

&lt;p&gt;One of many great things about clinics is that they require zero preparation. The group may want to propose topics in advance, but it's not absolutely necessary.&lt;/p&gt;

&lt;h4&gt;
  
  
  Frequency
&lt;/h4&gt;

&lt;p&gt;At minimum, clinics can be used as a fallback activity when unable to find a speaker. However, I would argue that having a clinic for part of every meeting would be valuable and interesting for most groups.&lt;/p&gt;

&lt;h4&gt;
  
  
  Duration
&lt;/h4&gt;

&lt;p&gt;There is no real minimum time, nor a need for its own sake that the time be consistent from meeting to meeting. For example, if a meeting normally has two presentations, the clinic could be limited to fifteen minutes. If there is only one presentation, the clinic could be expanded to fill that missing speaker's time slot.&lt;/p&gt;

&lt;h4&gt;
  
  
  Clinics for Dev Teams
&lt;/h4&gt;

&lt;p&gt;Clinics aren't good only for meetups -- they can be even more valuable for development teams, where in addition to the shared languages and frameworks, they work with the same organizational code base and environment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cautions and Counterpoints
&lt;/h2&gt;

&lt;p&gt;There is a risk that the clinics would gravitate towards beginner issues that would bore the more advanced users, or advanced subjects that would be incomprehensible to the more beginning users. Facilitators need to keep a close eye on this. If it's a short clinic this might be fine, but if it's a substantial portion of the meeting, it could drive people away. Other options could partially replace the clinic, such as a supplemental beginners meeting once a month. &lt;/p&gt;

&lt;p&gt;The topics chosen (if there are enough to select from among them) could be selected to balance against the presentation. For example, if the presentation is very advanced, then the the more beginning clinic topics might be selected for discussion.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://twitter.com/darinwilson"&gt;Darin Wilson&lt;/a&gt; points out: "The Q&amp;amp;A format can be good, but I think you have to put some effort into managing group dynamics.&lt;br&gt;
The trouble with any Q&amp;amp;A session is that they self-select for folks who are comfortable speaking out loud in a group setting. The larger the group, the more pronounced this effect will be. Also, if you have one or two individuals who really like to hear themselves talk, they can end up dominating the discussion.&lt;br&gt;
If you have a smallish group that already knows each other, this can be easier to manage. But if you have a larger group and/or folks don’t know each other very well, the moderator will probably need to make some extra effort to make sure that everyone feels welcome to participate, and that the discussion isn’t dominated by the over-talkers."&lt;/p&gt;

&lt;p&gt;I agree that this is definitely something to look out for, but more applicable to general discussions than clinics. If the goal is to provide solutions, then there may indeed be a couple of experts who possess most of the relevant information. The facilitator needs to balance the need for solutions with the need to cultivate universal participation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://twitter.com/JosephHGlass"&gt;Joseph Glass&lt;/a&gt; says: "I’ve found clinics to be very engaging but they also require more “crowd management”. With a well-prepared presentation, the quality largely depends on the speaker, and will be pretty much the same wherever it's presented.&lt;/p&gt;

&lt;p&gt;"Clinics on the other hand depend on the quality of the participants. It might turn out to be a fantastic conversation of people sharing expertise and forming connections. Or maybe one over-talkative participant will hijack the conversation into irrelevant tangents. It can be a bit of a gamble unless you know the community you’re working with or have a really good moderator."&lt;/p&gt;

&lt;p&gt;Indeed, a really good moderator is the key. Perhaps that is a whole 'nother article. Anyone want to write it? :)&lt;/p&gt;

&lt;h2&gt;
  
  
  Philippines Ruby Meetup, January 2020
&lt;/h2&gt;

&lt;p&gt;I suggested experimenting with this clinic format to the organizers of the &lt;a href="https://www.meetup.com/ruby-phil"&gt;Philippines Ruby Users Group&lt;/a&gt;. They agreed, and roughly half the &lt;a href="https://www.meetup.com/ruby-phil/events/267773265/"&gt;meetup&lt;/a&gt; was allocated for it.&lt;/p&gt;

&lt;p&gt;It turned out that only one person had a question, and several people answered it in complementary ways. Then there were no more questions. What to do? We morphed it into a general discussion. It was all engaging and interesting. Sometimes things don't go the way we expect. That's ok, we can adapt.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;I describe in this article a formula that has worked for me, but of course there is an infinite number of combinations of attributes of a clinic, and your optimal mix may differ from mine. Any discussion can be engaging and informative, but for me the essentials of a &lt;em&gt;clinic&lt;/em&gt; are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;help people get the information they most need at the time&lt;/li&gt;
&lt;li&gt;strive for universal and balanced participation&lt;/li&gt;
&lt;li&gt;balance the mix of levels of expertise for the questions within the clinic, and with the presentations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Presentations definitely have their place. There really &lt;em&gt;is&lt;/em&gt; value in someone who has deeply researched a topic sharing their knowledge with the group. However, meetups can be improved when the one-to-many information flow is supplemented by the many-to-many flow provided by discussions in general, and clinics in particular.&lt;/p&gt;




&lt;h4&gt;
  
  
  Footnotes:
&lt;/h4&gt;

&lt;p&gt;&lt;b id="f1"&gt;[1]&lt;/b&gt;A few years ago I was working at a network services company. At the time, they were automating their software testing to use Ruby and Cucumber. There were whole teams of software testers new to those technologies, and even programming in general. They were provided training, but after that training they were on their own. In addition to my own assignments to write software, one of my tasks was to help them get more productive in their programming.&lt;/p&gt;

&lt;p&gt;They would sometimes come to me when stuck, and when they did, I dropped what I was doing. It felt great to help them, but I knew they needed more than just firefighting to be really productive. I was unable to get authorization for us to devote the time we needed for more intensive collaboration, so I scheduled weekly Ruby lunchtime "clinics" on our own time. People shared their challenges, questions, and conquests. We met in a meeting room with a large shared monitor. I brought an external keyboard and mouse with me for use by whomever was "driving". At the beginning we had a discussion of topics to cover. That gave me the information I needed to optimize the use of our hour together.&lt;/p&gt;

&lt;p&gt;I encouraged them to show things they had learned, and to help each other. As time went on, their knowledge grew, and to my delight this happened more and more often. These sessions were my fondest memories of working there.&lt;/p&gt;




&lt;p&gt;This article may be improved over time. To see its revisions you can go to its &lt;a href="https://github.com/techhumans-com/techhumans-com.github.io/commits/master/_posts/2020-02-03-clinics-in-your-meetups.md"&gt;Github commit history&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>community</category>
      <category>discuss</category>
      <category>meetups</category>
      <category>meetings</category>
    </item>
    <item>
      <title>The Case for Stabby Lambda Notation</title>
      <dc:creator>Keith Bennett</dc:creator>
      <pubDate>Mon, 02 Dec 2019 14:45:32 +0000</pubDate>
      <link>https://dev.to/keithrbennett/why-i-prefer-stabby-lambda-notation-5gcj</link>
      <guid>https://dev.to/keithrbennett/why-i-prefer-stabby-lambda-notation-5gcj</guid>
      <description>&lt;h3&gt;
  
  
  The Stabby Lambda (&lt;code&gt;-&amp;gt;&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;Although the &lt;code&gt;-&amp;gt;&lt;/code&gt; "stabby lambda" notation has been available for creating lambdas since Ruby version 1.9, old habits die hard and acceptance and adoption has been slow. In this article I will explain why I recommend using it instead of the &lt;code&gt;lambda&lt;/code&gt; notation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Stabby Notation as an Indicator of Preferred and Default Proc Type
&lt;/h3&gt;

&lt;p&gt;In a previous article, "&lt;a href="https://dev.to/keithrbennett/lambdas-are-better-than-procs-52a1"&gt;lambdas Are Better Than procs&lt;/a&gt;", I proposed that lambdas should be used rather than procs in almost all cases, given that they are safer in terms of argument count checking and return behavior.&lt;/p&gt;

&lt;p&gt;So it makes sense that &lt;code&gt;-&amp;gt;&lt;/code&gt; should create a lambda and not a proc. (As an aside, it always puzzles me when people use the term stabby &lt;em&gt;proc&lt;/em&gt;, when it creates a lambda.)&lt;/p&gt;

&lt;p&gt;One way to look at it is, by using the stabby lambda notation, we are&lt;br&gt;
saying "make me Ruby's implementation of an objectless function". This is at a level higher than "make me a lambda" or "make me a proc", and is probably a better interface to the programmer, especially the newer Rubyist.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;-&amp;gt;&lt;/code&gt;'s Picture-Like Notation
&lt;/h3&gt;

&lt;p&gt;The picture-like notation &lt;code&gt;-&amp;gt;&lt;/code&gt; is quite different from the &lt;code&gt;lambda&lt;/code&gt; and &lt;code&gt;proc&lt;/code&gt; forms, because although all result in method calls that create &lt;code&gt;Proc&lt;/code&gt; instances, &lt;code&gt;lambda&lt;/code&gt; and &lt;code&gt;proc&lt;/code&gt; &lt;em&gt;look like&lt;/em&gt; method calls, while &lt;code&gt;-&amp;gt;&lt;/code&gt; does not, instead appearing more like a &lt;em&gt;language construct&lt;/em&gt;. On the higher level, it really &lt;em&gt;is&lt;/em&gt; a language construct, and the fact that a method needs to be called to create a lambda is an implementation detail that should not matter to the programmer.&lt;/p&gt;

&lt;p&gt;The striking appearance of &lt;code&gt;-&amp;gt;&lt;/code&gt; says to the reader "take note, something different is happening here, this marks the beginning of a definition of executable code that will probably be called somewhere &lt;em&gt;else&lt;/em&gt;". If a picture is worth a thousand words, then a text picture like &lt;code&gt;-&amp;gt;&lt;/code&gt; is worth, well, at least ten.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Need for Visual Differentiation
&lt;/h3&gt;

&lt;p&gt;Unlike other code in a method, a lambda's code is not called in sequence (unless it is immediately called as a self invoking anonymous function, but this is rare). Also, sometimes a lambda can be used as if it were a nested method, containing lower level code that may be called multiple times in the method in which it was defined. For these reasons, a pictorial indication setting it apart from other code in the method is especially helpful.&lt;/p&gt;

&lt;h3&gt;
  
  
  Rubocop
&lt;/h3&gt;

&lt;p&gt;Rubocop is a very useful tool for normalizing code style. For better or worse though, Rubocop's defaults constitute implicit recommendations, and deviating from the defaults can require lengthy and contentious team discussions. Because of this potentially high cost of overriding the defaults, it is important that the basis in reasoning for the selection of the default be sound.&lt;/p&gt;

&lt;p&gt;Rubocop's &lt;a href="https://www.rubydoc.info/gems/rubocop/RuboCop/Cop/Style/Lambda"&gt;default setting for lambdas&lt;/a&gt; is to use &lt;code&gt;-&amp;gt;&lt;/code&gt; with lambda one-liners but &lt;code&gt;lambda&lt;/code&gt; for multiline lambdas. While this is not a matter of monumental importance, I believe it's misguided and should be changed.&lt;/p&gt;

&lt;p&gt;My guess is that it is intended to mirror the Ruby code block notation convention of &lt;code&gt;{..}&lt;/code&gt; for single line blocks and &lt;code&gt;do...end&lt;/code&gt; for multi-line blocks. However, the code block case is different because the &lt;code&gt;do&lt;/code&gt; and &lt;code&gt;end&lt;/code&gt; are at the end and beginning of the line, respectively (though it is true that if there are arguments they will appear after the &lt;code&gt;do&lt;/code&gt;). Although the indentation of the code block within the &lt;code&gt;lambda do...end&lt;/code&gt; makes it easy to see that &lt;em&gt;something&lt;/em&gt; is going on, it is easy to miss the &lt;code&gt;lambda&lt;/code&gt; and assume it is a normal code block. The pictorial nature of &lt;code&gt;-&amp;gt;&lt;/code&gt; reduces this risk.&lt;/p&gt;

&lt;p&gt;I believe that the Rubocop default should be changed to prefer (or at minimum permit) &lt;code&gt;-&amp;gt;&lt;/code&gt; in all cases.&lt;/p&gt;

&lt;p&gt;Note: Since writing this article I posted an issue on the Rubocop project site &lt;a href="https://github.com/rubocop-hq/rubocop/issues/7566"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Lambdas are, thankfully, first class objects in Ruby. That is, they can be passed to and returned from methods, and can be assigned to variables. This is a pretty major construct, and I believe a special notation (&lt;code&gt;-&amp;gt;&lt;/code&gt;), rather than a method name (&lt;code&gt;lambda&lt;/code&gt;) is justified and helpful. While it is true that &lt;code&gt;class&lt;/code&gt;, &lt;code&gt;module&lt;/code&gt;, and &lt;code&gt;def&lt;/code&gt; also mark the beginning of major language constructs, they are likely to be the first token on a line, whereas lambdas are usually assigned to variables or passed to methods or other lambdas, and are not.&lt;/p&gt;

&lt;p&gt;The conciseness and pictorial nature of &lt;code&gt;-&amp;gt;&lt;/code&gt; encourage the use of lambdas, and in my opinion, that is a Good Thing. Lambdas are underused in the Ruby community, and many opportunities for cleaner and clearer code are missed.&lt;/p&gt;




&lt;p&gt;This article may be improved over time. To see its revisions you can go to its &lt;a href="https://github.com/keithrbennett/keithrbennett.github.io/commits/master/blog/_posts/2019-11-30-why-i-prefer-stabby-lambda-notation.md"&gt;Github commit history&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>functional</category>
      <category>lambda</category>
    </item>
    <item>
      <title>lambdas Are Better Than procs</title>
      <dc:creator>Keith Bennett</dc:creator>
      <pubDate>Wed, 20 Nov 2019 09:53:12 +0000</pubDate>
      <link>https://dev.to/keithrbennett/lambdas-are-better-than-procs-52a1</link>
      <guid>https://dev.to/keithrbennett/lambdas-are-better-than-procs-52a1</guid>
      <description>&lt;p&gt;Many Rubyists believe that lambda and nonlambda Procs are pretty much the same and that choosing which one to use is a subjective preference. This is an unfortunate fallacy.&lt;/p&gt;

&lt;p&gt;This article will attempt to achieve two purposes:&lt;/p&gt;

&lt;p&gt;1) to explain the difference between lambdas and procs&lt;/p&gt;

&lt;p&gt;2) to persuade you to use lambdas unless there is a compelling reason not to&lt;/p&gt;

&lt;p&gt;There are many resources available that explain lambdas and procs &lt;sup id="a1"&gt;[1]&lt;/sup&gt;, and I will assume you know at least a little about them.&lt;/p&gt;

&lt;p&gt;Before we look at some examples, here are some characteristics of lambdas and procs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a &lt;code&gt;Proc&lt;/code&gt; instance can be either lambda or a proc &lt;sup id="a2"&gt;[2]&lt;/sup&gt;
&lt;/li&gt;
&lt;li&gt;all &lt;code&gt;lambda&lt;/code&gt;s are &lt;code&gt;Proc&lt;/code&gt;s&lt;/li&gt;
&lt;li&gt;all &lt;code&gt;proc&lt;/code&gt;s are &lt;code&gt;Proc&lt;/code&gt;s&lt;/li&gt;
&lt;li&gt;code blocks behave like &lt;code&gt;proc&lt;/code&gt;s&lt;/li&gt;
&lt;li&gt;you can determine the kind of Proc by calling &lt;code&gt;lambda?&lt;/code&gt; on it&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Arity (Argument Count) Checking Behavior Differences
&lt;/h3&gt;

&lt;p&gt;A &lt;code&gt;lambda&lt;/code&gt;, like a method, strictly enforces its argument count, but a &lt;code&gt;proc&lt;/code&gt; does not. When we call a &lt;code&gt;proc&lt;/code&gt; with the wrong number of arguments, there are no complaints by the Ruby runtime &lt;sup id="a3"&gt;[3]&lt;/sup&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="mf"&gt;2.6&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mo"&gt;006&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;pfn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;proc&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="c1"&gt;#&amp;lt;Proc:0x00007f93828bd298@(irb):6&amp;gt;&lt;/span&gt;
&lt;span class="mf"&gt;2.6&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mo"&gt;007&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;pfn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;
 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kp"&gt;nil&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In contrast, when we do the same with a lambda, we get an error &lt;sup id="a4"&gt;[4]&lt;/sup&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="mf"&gt;2.6&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mo"&gt;002&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;lfn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&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="p"&gt;{}&lt;/span&gt;
    &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="c1"&gt;#&amp;lt;Proc:0x00007f9383118ed8@(irb):2 (lambda)&amp;gt;&lt;/span&gt;
   &lt;span class="mf"&gt;2.6&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mo"&gt;003&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;lfn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;
   &lt;span class="o"&gt;...&lt;/span&gt;
   &lt;span class="no"&gt;ArgumentError&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;wrong&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="n"&gt;arguments&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;given&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;expected&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Which behavior would &lt;em&gt;you&lt;/em&gt; prefer?&lt;/p&gt;

&lt;p&gt;Clearly, arity checking is helpful, and we abandon it at our peril.&lt;/p&gt;




&lt;h3&gt;
  
  
  Return Behavior Differences
&lt;/h3&gt;

&lt;p&gt;What happens when you pass a code block somewhere, and it executes a &lt;code&gt;return&lt;/code&gt;? Does it return from the block? Well, yes, but it does much more than that; it returns from the method that &lt;em&gt;yielded&lt;/em&gt; to the block. &lt;code&gt;proc&lt;/code&gt;s behave the same way; in addition to returning from themselves, they will return from the method in which they were called:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;using_proc&lt;/span&gt;
  &lt;span class="n"&gt;pfn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;proc&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"Before calling"&lt;/span&gt;
  &lt;span class="n"&gt;pfn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"After calling"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="c1"&gt;# ...&lt;/span&gt;
&lt;span class="mf"&gt;2.6&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mo"&gt;015&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;using_proc&lt;/span&gt;
&lt;span class="no"&gt;Before&lt;/span&gt; &lt;span class="n"&gt;calling&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Before proceeding to the lambda behavior, I'd like to point out that this &lt;code&gt;proc&lt;/code&gt; behavior is such that implicit and explicit returns do very different things. An implicit return will return from the proc, but an explicit return will return from the context that called it! Weird, eh? Here is the same code, but without the explicit return; the proc will end and exit naturally:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;using_proc_without_return&lt;/span&gt;
  &lt;span class="n"&gt;pfn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;proc&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"Before calling"&lt;/span&gt;
  &lt;span class="n"&gt;pfn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"After calling"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="c1"&gt;# ...&lt;/span&gt;
&lt;span class="mf"&gt;2.6&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mo"&gt;007&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;using_proc_without_return&lt;/span&gt;
&lt;span class="no"&gt;Before&lt;/span&gt; &lt;span class="n"&gt;calling&lt;/span&gt;
&lt;span class="no"&gt;After&lt;/span&gt; &lt;span class="n"&gt;calling&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;When we first learn Ruby, we learn that a &lt;code&gt;return&lt;/code&gt; at the end of a method is redundant (it &lt;em&gt;is&lt;/em&gt;, of course), but in the case of the &lt;code&gt;proc&lt;/code&gt; (and code block) it is not!&lt;/p&gt;

&lt;p&gt;In contrast, a &lt;code&gt;lambda&lt;/code&gt;'s &lt;code&gt;return&lt;/code&gt; returns from itself to the context that called it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;using_lambda&lt;/span&gt;
  &lt;span class="n"&gt;lfn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"Before calling"&lt;/span&gt;
  &lt;span class="n"&gt;lfn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"After calling"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="c1"&gt;# ...&lt;/span&gt;
&lt;span class="mf"&gt;2.6&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mo"&gt;00&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;using_lambda&lt;/span&gt;
&lt;span class="no"&gt;Before&lt;/span&gt; &lt;span class="n"&gt;calling&lt;/span&gt;
&lt;span class="no"&gt;After&lt;/span&gt; &lt;span class="n"&gt;calling&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;






&lt;h3&gt;
  
  
  A &lt;code&gt;lambda&lt;/code&gt; is More Method-Like Than a &lt;code&gt;proc&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;In both of the above cases, the lambda behaves more like a method than a proc does. The newer &lt;code&gt;-&amp;gt;(args)&lt;/code&gt; notation for creating a lambda reveals that intent by defining the arguments as a method does, in a parenthesized list, and is therefore preferable to the older &lt;code&gt;lambda&lt;/code&gt; notation:&lt;/p&gt;

&lt;p&gt;New:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;fn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg2&lt;/span&gt;&lt;span class="p"&gt;)&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Old:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;fn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;lambda&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;arg1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg2&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;






&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Here are some principles I've learned to code by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;prefer simplicity to complexity&lt;/li&gt;
&lt;li&gt;limit things to the narrowest possible scope&lt;/li&gt;
&lt;li&gt;specify things with minimal ambiguity&lt;/li&gt;
&lt;li&gt;use language features that minimize the risk of errors&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Regarding everything said so far, the lambda wins over the proc. There is no reason to use a proc unless you specifically need the odd and potentially hazardous behaviors described above.&lt;/p&gt;

&lt;p&gt;You may think it will never matter in your case. Maybe you're never calling the lambda yourself, but passing it to a framework such as Rails that is doing all the calling. Nevertheless, if given the added protection for free, why would you &lt;em&gt;not&lt;/em&gt; want it? Especially since the &lt;code&gt;-&amp;gt;&lt;/code&gt; notation is somewhat pictorial and more concise?&lt;/p&gt;




&lt;h3&gt;
  
  
  Footnotes
&lt;/h3&gt;

&lt;p&gt;&lt;b id="f1"&gt;[1]&lt;/b&gt; There are many good resources; here are some that I have produced (articles and a conference talk):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/keithrbennett/using-lambdas-to-simplify-varying-behaviors-in-your-code-1d5ff"&gt;Using Lambdas to Simplify Varying Behaviors in Your Code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/keithrbennett/ruby-enumerables-make-your-code-short-and-sweet-2nl0"&gt;Ruby Enumerables Make Your Code Short and Sweet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.youtube.com/watch?v=nGEy-vFJCSE"&gt;Functional Programming in Ruby&lt;/a&gt;, video of a talk given at Functional Conf in Bangalore, India in 2014&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;↩&lt;/p&gt;

&lt;p&gt;&lt;b id="f2"&gt;[2]&lt;/b&gt; This terminology is unfortunate, as &lt;code&gt;Proc&lt;/code&gt; and &lt;code&gt;proc&lt;/code&gt;, when spoken, sound identical.&lt;br&gt;
↩&lt;/p&gt;

&lt;p&gt;&lt;b id="f3"&gt;[3]&lt;/b&gt; In this article I've used the &lt;code&gt;.call&lt;/code&gt; variant of calling a Proc because it is the most obvious for the reader, but in practice I prefer the shorthand notation &lt;code&gt;.()&lt;/code&gt;.&lt;br&gt;
↩&lt;/p&gt;

&lt;p&gt;&lt;b id="f4"&gt;[4]&lt;/b&gt; The shorthand &lt;code&gt;-&amp;gt;&lt;/code&gt; can be used in place of the &lt;code&gt;lambda&lt;/code&gt; keyword to more succinctly define a lambda.&lt;br&gt;
↩&lt;/p&gt;




&lt;p&gt;This article may be improved over time. To see its revisions you can go to its &lt;a href="https://github.com/keithrbennett/keithrbennett.github.io/commits/master/blog/_posts/2019-11-19-lambdas-are-better-than-procs.md"&gt;Github commit history&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>functional</category>
      <category>lambda</category>
    </item>
    <item>
      <title>Using Lambdas to Simplify Varying Behaviors in Your Code</title>
      <dc:creator>Keith Bennett</dc:creator>
      <pubDate>Mon, 18 Nov 2019 10:10:45 +0000</pubDate>
      <link>https://dev.to/keithrbennett/using-lambdas-to-simplify-varying-behaviors-in-your-code-1d5f</link>
      <guid>https://dev.to/keithrbennett/using-lambdas-to-simplify-varying-behaviors-in-your-code-1d5f</guid>
      <description>&lt;p&gt;&lt;small&gt;(This article was first posted on my personal blog on 2018-08-04 at &lt;a href="https://bbs-software.com/blog/2018/08/04/using-lambdas-to-simplify-varying-behaviors-in-your-code.html"&gt;https://bbs-software.com/blog/2018/08/04/using-lambdas-to-simplify-varying-behaviors-in-your-code.html&lt;/a&gt;.)&lt;/small&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Anonymous_function"&gt;Lambdas&lt;/a&gt; are anonymous (unnamed) functions. Unlike &lt;em&gt;methods&lt;/em&gt; in &lt;a href="https://en.wikipedia.org/wiki/Object-oriented_programming"&gt;object oriented programming&lt;/a&gt; languages, lambdas are not bound to any object. Although they are best known in the context of &lt;a href="https://en.wikipedia.org/wiki/Functional_languages"&gt;functional programming&lt;/a&gt; languages, object oriented programming languages that support lambdas, such as Ruby, can greatly benefit from their use. This is especially true when it comes to implementing varying behaviors(1).&lt;/p&gt;

&lt;p&gt;By varying behaviors, I mean situations where the code that needs to run is not fixed, but rather specified, using parameters, subclassing, or configuration. Examples would include cases for which you would use the &lt;a href="https://en.wikipedia.org/wiki/Command_pattern"&gt;Command&lt;/a&gt; and &lt;a href="https://en.wikipedia.org/wiki/Strategy_pattern"&gt;Strategy&lt;/a&gt; design patterns.&lt;/p&gt;

&lt;p&gt;Many developers are already familiar with using lambdas for &lt;em&gt;event handling&lt;/em&gt; (implemented with the  &lt;code&gt;function&lt;/code&gt; keyword in JavaScript and also as arrow functions in ES6) , but there are many other cases in which they are helpful, a couple of which I will describe below.&lt;/p&gt;




&lt;h3&gt;
  
  
  The Problem with Non-Lambda Approaches
&lt;/h3&gt;

&lt;p&gt;The procedural &lt;code&gt;if-elsif-end&lt;/code&gt; or &lt;code&gt;case&lt;/code&gt; clauses work when you have a small number of conditions and actions that are known in advance, but if you don't, they're pretty useless.&lt;/p&gt;

&lt;p&gt;And although the object oriented approach of &lt;a href="https://en.wikipedia.org/wiki/Polymorphism_(computer_science)"&gt;polymorphism&lt;/a&gt; by inheritance (2) can produce a correct result, in many cases it is unnecessarily verbose, ceremonial, and awkward.&lt;/p&gt;

&lt;p&gt;To further embellish on this point, &lt;a href="https://twitter.com/KayEss"&gt;@kayess&lt;/a&gt; pointed me to a &lt;a href="http://okmij.org/ftp/Scheme/oop-in-fp.txt"&gt;discussion&lt;/a&gt; on a Scheme forum where Anton van Straaten said about closures (lambdas are closures): "A closure's  simplicity can be an asset: classes and interfaces can get in the way of simple parameterization of behavior.  Anyone who's tried functional programming in Java or C++ has encountered this - it can be done, but it's more tedious." Anton goes on to provide an entertaining koan about the subject.&lt;/p&gt;

&lt;p&gt;Furthermore, though we're accustomed to thinking about this problem in the context of a &lt;em&gt;single&lt;/em&gt; customizable behavior, what if there are &lt;em&gt;several&lt;/em&gt;?&lt;/p&gt;

&lt;p&gt;Let's say we have a class that contains 3 varying behaviors. As an admittedly contrived example, let's say we have classes for each of hundreds of different species of animals, and they each have a &lt;code&gt;move&lt;/code&gt;, &lt;code&gt;sleep&lt;/code&gt;, and &lt;code&gt;vocalize&lt;/code&gt; behavior. As a simplifying assumption, let's say that each of these behaviors has 7 possible variations, each of which is shared by many species. If we were to write a class to implement each possible set of the 3 behaviors, we would need the &lt;a href="https://en.wikipedia.org/wiki/Cartesian_product"&gt;Cartesian product&lt;/a&gt; of classes, (7 * 7 * 7), or 343 classes! That would be a silly monstrosity for several reasons of course, one of which being we could simplify the design by providing a class hierarchy for each of the three kinds of behavior, and plug those into the larger class -- but then we would still need (7 + 7 + 7), or 21 classes! (Probably 24 really, as pure design would dictate an additional class as an abstract superclass for each set of 7 implementations).&lt;/p&gt;

&lt;p&gt;If these behaviors are truly complex enough to justify a class of their own, this is not a problem. However, often they are not, and the solution is many times as verbose and complex as it needs to be.&lt;/p&gt;

&lt;p&gt;A better solution is using &lt;em&gt;callables&lt;/em&gt; such as lambdas.&lt;/p&gt;




&lt;h3&gt;
  
  
  Callables as a Superset of Lambdas
&lt;/h3&gt;

&lt;p&gt;In traditional object oriented languages such as Java and C++, polymorphism is (in general) implemented by inheritance. Ruby does this also (3), but in addition, Ruby uses &lt;em&gt;duck typing&lt;/em&gt;, meaning that &lt;em&gt;any&lt;/em&gt; object that responds to the method name can be used, regardless of its position in the class hierarchy.&lt;/p&gt;

&lt;h5&gt;
  
  
  This means that in Ruby, since the method used to call a lambda is &lt;code&gt;call&lt;/code&gt;, &lt;em&gt;any&lt;/em&gt; object that responds to &lt;code&gt;call&lt;/code&gt; can be used in place of a lambda.
&lt;/h5&gt;

&lt;p&gt;It could be a lambda, an instance of a class, or even a class or module. This provides great flexibility in implementing varying behavior. You can choose what kind of object to use based on your situation. For complex behaviors you may want modules or classes, and for simpler behaviors a lambda will work just fine.&lt;/p&gt;

&lt;p&gt;Since any object responding to &lt;code&gt;call&lt;/code&gt; can be used in place of a lambda, I will use the term &lt;em&gt;callable&lt;/em&gt; instead of &lt;em&gt;lambda&lt;/em&gt; where applicable.&lt;/p&gt;




&lt;h3&gt;
  
  
  The Buffered Enumerable
&lt;/h3&gt;

&lt;p&gt;I once worked on a project where I needed to implement buffering of multiple kinds of things received over network connections. I started writing the first one, and noticed how the code could be cleanly divided into two kinds of tasks: 1) knowing &lt;em&gt;when&lt;/em&gt; to fetch objects into the buffer and other buffer management tasks, and 2) knowing &lt;em&gt;how&lt;/em&gt; to fetch each block of objects and what &lt;em&gt;else&lt;/em&gt; to do each time that fetch is performed (e.g. logging, displaying a message to the user, updating some external state).&lt;/p&gt;

&lt;p&gt;Realizing that #1 would be common and identical to all cases, and only #2 would vary, I thought about how wasteful it would be to implement #1 separately in all cases. I thought about the admonition about high cohesion / low coupling, and the Unix axiom "do one thing well", and decided to separate the two.&lt;/p&gt;

&lt;p&gt;The most natural way to design this functionality in Ruby is with an &lt;a href="https://ruby-doc.org/core-2.5.1/Enumerable.html"&gt;&lt;em&gt;Enumerable&lt;/em&gt;&lt;/a&gt;, which will have access to all kinds of functional wizardry thanks to the methods it gets for free by including the &lt;code&gt;Enumerable&lt;/code&gt; module. In addition, it can easily be used to generate an array by calling its &lt;code&gt;to_a&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;This is the origin of the  &lt;a href="https://github.com/keithrbennett/trick_bag/blob/master/lib/trick_bag/enumerables/buffered_enumerable.rb"&gt;&lt;em&gt;BufferedEnumerable&lt;/em&gt;&lt;/a&gt; class in my &lt;a href="https://github.com/keithrbennett/trick_bag/"&gt;&lt;em&gt;trick_bag&lt;/em&gt;&lt;/a&gt; gem. This class manages buffering but has no idea how to fetch chunks of data, nor what else to do at each such fetch; for that, the caller provides callables such as lambdas. (Upon user request, the ability to subclass it and override its methods was also added.) The result is a dramatic simplification, where the logic of buffering is defined in only one place, and the places it is used need not be concerned with its implementation (or its testing!).&lt;/p&gt;

&lt;p&gt;To create an instance of this with callables, we call the &lt;code&gt;BufferedEnumerable&lt;/code&gt; class method &lt;code&gt;create_with_callables&lt;/code&gt;, which is defined as follows(4):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_with_callables&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chunk_size&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fetcher&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fetch_notifier&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="n"&gt;instance&lt;/span&gt; &lt;span class="o"&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;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chunk_size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetcher&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fetcher&lt;/span&gt;
    &lt;span class="n"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetch_notifier&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fetch_notifier&lt;/span&gt;
    &lt;span class="n"&gt;instance&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;When a fetcher callable has been defined (as opposed to the use of the subclassing approach, where an overriding method is used), it is called with the empty data buffer and the number of objects requested as shown below whenever the buffer needs to be filled, as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;fetcher&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;chunk_size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;(In Ruby, &lt;code&gt;.(&lt;/code&gt; is an abbreviation for &lt;code&gt;.call(&lt;/code&gt;.)&lt;/p&gt;

&lt;p&gt;A trivial fetcher that merely fills the array of the requested chunk size with random numbers could look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;fetcher&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;chunk_size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;chunk_size&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;times&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rand&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;Below is a &lt;code&gt;pry&lt;/code&gt; example that illustrates the call to that fetcher, and its effect on the passed array:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[7] pry("")&amp;gt; a = []; fetcher.(a, 2)
2
[8] pry("")&amp;gt; a
[
    [0] 0.4885287976297428,
    [1] 0.5493143769524284
]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;After the buffer is filled, if a fetch notifier callable has been defined (unlike the fetcher, this is optional), it too is called, with the data buffer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;fetch_notifier&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;A trivial fetch notifier might look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="no"&gt;Time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; Fetched &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;size&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; objects"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;(&lt;code&gt;data.size&lt;/code&gt; will not necessarily be equal to &lt;code&gt;chunk_size&lt;/code&gt;, especially on the last fetch.)&lt;/p&gt;

&lt;p&gt;This notifier might produce something looking like this:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;2018-07-26 17:19:47 +0700 Fetched 1000 objects&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;After defining the &lt;code&gt;fetcher&lt;/code&gt; and &lt;code&gt;fetch_notifier&lt;/code&gt; lambdas, we could call the class method for creating a BufferedEnumerable shown above as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;buffered_enumerable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;BufferedEnumerable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_with_callables&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;\&lt;/span&gt;
    &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fetcher&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fetch_notifier&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This enumerable can be used to call &lt;code&gt;each&lt;/code&gt; or any other of the rich set of methods available on the &lt;a href="https://ruby-doc.org/core-2.5.1/Enumerable.html"&gt;&lt;em&gt;Enumerable&lt;/em&gt;&lt;/a&gt; module.&lt;/p&gt;

&lt;p&gt;By parameterizing the behaviors with callables, we have increased the simplicity of the implementation by separating the two orthogonal tasks into separate code areas, and avoided the unnecessary overhead of the inheritance approach, which would have packaged these functions in classes.&lt;/p&gt;




&lt;h3&gt;
  
  
  Using Predicate Callables to Implement Filters
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;Predicates&lt;/em&gt; are functions that return a Boolean value, that is, either true or false. There are many uses for predicates in software: filters, boundaries, triggers, authentication results...again, anything that produces a true or false value.&lt;/p&gt;

&lt;p&gt;Configurable predicates are another natural fit for using callables.&lt;/p&gt;

&lt;p&gt;I once had to write a &lt;a href="https://github.com/keithrbennett/mock_dns_server"&gt;DNS mock server&lt;/a&gt; for network testing  that could be configured to respond with specific behaviors based on the characteristics of the incoming request. In another situation more recently, I was writing some accounting software and wanted to be able to filter the working set of transactions based on date, category, etc.&lt;/p&gt;

&lt;p&gt;Both cases were an excellent fit for using callables as filters.&lt;/p&gt;

&lt;p&gt;In the case of the mock DNS server, there were multiple criteria for the DNS request filters, such as &lt;em&gt;protocol&lt;/em&gt; (TCP vs. UDP), &lt;em&gt;qtype&lt;/em&gt; (question type), &lt;em&gt;qclass&lt;/em&gt; (question class), and &lt;em&gt;qname&lt;/em&gt; (question name). I provided methods that return lambdas that filter for specific values for those attributes; for example, to create a filter that will return true only for the qname &lt;code&gt;example.com&lt;/code&gt;, you would do the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;MockDnsServer&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;PredicateFactory&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;qname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'example.com'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;qname&lt;/code&gt; method (i.e. the method that returns a filter for exactly one qname value) is defined as (roughly):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;qname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qname&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_protocol&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;do&lt;/span&gt;
    &lt;span class="n"&gt;eq_case_insensitive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;qname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;qname&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;If you view the method body from left to right, you will notice the prominent &lt;code&gt;-&amp;gt;&lt;/code&gt; and its corresponding &lt;code&gt;end&lt;/code&gt; two lines beneath it, which tell you that the value returned by this method is a lambda. The leading underscore of the &lt;code&gt;_protocol&lt;/code&gt; parameter is a convention that indicates that that parameter is unused by the lambda.&lt;/p&gt;

&lt;p&gt;Notice that the &lt;code&gt;qname&lt;/code&gt; parameter's value (e.g. "example.com") is effectively stored in the lambda that the method returns? This technique is called &lt;em&gt;partial application&lt;/em&gt;, and is extremely useful when working with lambdas.&lt;/p&gt;

&lt;p&gt;Does storing state in the lambda make it any less &lt;em&gt;functional&lt;/em&gt;? Not really; the state is immutable and used only for comparison.&lt;/p&gt;

&lt;p&gt;If we were to refine the filter by adding the requirement that the qtype be 'A' and the protocol be 'TCP', then we could call methods to return those filters as well, and combine all three using the &lt;code&gt;all&lt;/code&gt; compound filter. (Other compound filters are &lt;code&gt;any&lt;/code&gt; and &lt;code&gt;none&lt;/code&gt;.) Here is what that would look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;pf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;MockDnsServer&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;PredicateFactory&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;filter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;pf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;qtype&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'A'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;pf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;qname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'example.com'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;pf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_tcp&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;all&lt;/code&gt; compound filter is nothing more than a simple wrapper around Ruby's Enumerable's &lt;code&gt;all?&lt;/code&gt; method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;predicates&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;protocol&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;do&lt;/span&gt;
      &lt;span class="n"&gt;predicates&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all?&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nb"&gt;p&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nb"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;protocol&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="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Why does all this work? The filters are interchangeable because they all have uniform inputs and outputs. That is, they take the same parameter list (&lt;code&gt;[message, protocol]&lt;/code&gt; in this example), and they all return a value usable by the caller (&lt;code&gt;true&lt;/code&gt; or &lt;code&gt;false&lt;/code&gt; in this example). We've already seen one implementation, the lambda returned by the &lt;code&gt;qname&lt;/code&gt; method shown above. Here is another one; this one returns true if and only if the message was sent over TCP:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;from_tcp&lt;/span&gt;
  &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;protocol&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;protocol&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="ss"&gt;:tcp&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;In this case, we only care about the protocol so we can ignore the first (&lt;code&gt;message&lt;/code&gt;) parameter.&lt;/p&gt;




&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;I hope I have been successful in persuading you to consider using callables for implementing variable predicates and actions.&lt;/p&gt;

&lt;p&gt;These are just two examples. I will stop here for the sake of brevity, but if you have any questions or suggestions for elaboration, please contact me.&lt;/p&gt;

&lt;p&gt;You can find me on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/keithrbennett"&gt;Github&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.linkedin.com/in/keithrbennett/"&gt;LinkedIn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://stackoverflow.com/users/501266/keith-bennett"&gt;StackOverflow&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/keithrbennett"&gt;Twitter&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Also, for more information about lambdas, feel free to check out my Ruby lambdas presentation (&lt;a href="https://speakerdeck.com/keithrbennett/ruby-lambdas-functional-conf-bangalore-oct-2014"&gt;Speakerdeck slideshow&lt;/a&gt; and &lt;a href="https://www.youtube.com/watch?v=nGEy-vFJCSE"&gt;YouTube video&lt;/a&gt;).&lt;/p&gt;




&lt;h3&gt;
  
  
  Footnotes
&lt;/h3&gt;

&lt;p&gt;(1) One might ask what else &lt;em&gt;is&lt;/em&gt; there about lambdas other than varying behavior, but there &lt;em&gt;are&lt;/em&gt; other reasons to use them in Ruby. For example, they can be used:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;as nested functions&lt;/li&gt;
&lt;li&gt;as truly private functions (which, unlike private methods, cannot be accessed with &lt;code&gt;send&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;for self invoking anonymous functions, to hide variables&lt;/li&gt;
&lt;li&gt;for defining functions where methods cannot be defined (e.g. in some RSpec code)&lt;/li&gt;
&lt;li&gt;for defining classes dynamically with the &lt;code&gt;class...end&lt;/code&gt; notation which may be easier to understand than the &lt;code&gt;Class.new&lt;/code&gt; approach.&lt;/li&gt;
&lt;li&gt;for chaining operations, as in an array of lambdas&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;(2) Polymorphism by inheritance is a key characteristic of object oriented design whereby, by virtue of having a common ancestor in the class hierarchy that contains the method in question, objects of different classes can respond to the same message (typically identified by a method or function name) differently. This can be a nice design in some cases, but in others it is an overly heavy handed solution to a simple problem, as it forces the developer to create multiple classes in a class hierarchy.&lt;/p&gt;

&lt;p&gt;(2 (cont'd)) &lt;a href="https://twitter.com/KayEss"&gt;@kayess&lt;/a&gt; points out that the more precise terms in software engineering are &lt;a href="https://en.wikipedia.org/wiki/Nominal_type_system"&gt;nominal typing&lt;/a&gt; for polymorphism by inheritance, and &lt;a href="https://en.wikipedia.org/wiki/Structural_type_system"&gt;structural typing&lt;/a&gt; for duck typing.&lt;/p&gt;

&lt;p&gt;(3) To be more precise, Ruby supports polymorphism by inheritance, but not by checking the class hierarchy like most OO languages do. Instead, it is using duck typing, and merely calls the method by name; since a subclass will be able to call its superclass' method by default, it works.&lt;/p&gt;

&lt;p&gt;(4) The omission of the &lt;code&gt;fetcher&lt;/code&gt; and &lt;code&gt;fetch_notifier&lt;/code&gt; parameters from the constructor is intentional. The constructor is intended to be used directly by the caller only when the subclassing approach is used; for lambdas the static method &lt;code&gt;create_with_callables&lt;/code&gt; should be used.&lt;/p&gt;




&lt;p&gt;This article may be improved over time. To see its revisions you can go to its &lt;a href="https://github.com/keithrbennett/keithrbennett.github.io/commits/master/_posts/2018-08-04-using-lambdas-to-simplify-varying-behaviors-in-your-code.md"&gt;Github commit history&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>functional</category>
      <category>lambda</category>
    </item>
    <item>
      <title>Ruby Enumerables Make Your Code Short and Sweet</title>
      <dc:creator>Keith Bennett</dc:creator>
      <pubDate>Wed, 13 Nov 2019 13:52:20 +0000</pubDate>
      <link>https://dev.to/keithrbennett/ruby-enumerables-make-your-code-short-and-sweet-2nl0</link>
      <guid>https://dev.to/keithrbennett/ruby-enumerables-make-your-code-short-and-sweet-2nl0</guid>
      <description>&lt;p&gt;One of the most amazing things about Ruby is the richness of its &lt;code&gt;Enumerable&lt;/code&gt; library; there are &lt;em&gt;so many&lt;/em&gt; things it can do. Another is Ruby's ability to express intent with the utmost conciseness and clarity. However, out in the wild I very often see code that fails to take full advantage of these qualities.&lt;/p&gt;

&lt;p&gt;As a contrived example, let's say we're keeping track of letter frequencies in a document. We define a class to contain them as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;LetterFrequency&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Struct&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="ss"&gt;:letter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:frequency&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:vowel?&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;I've seen a lot code that looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;filtered_and_transformed_records_1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;records&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

  &lt;span class="n"&gt;records&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="n"&gt;record&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="k"&gt;next&lt;/span&gt; &lt;span class="k"&gt;unless&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;vowel?&lt;/span&gt;
    &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&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="nf"&gt;letter&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="nf"&gt;frequency&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="n"&gt;results&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In more primitive languages one must use these approaches, but in Ruby we have some major refactorings that can make this code much, much simpler.&lt;/p&gt;

&lt;p&gt;First, we can use &lt;code&gt;each_with_object&lt;/code&gt; to eliminate the need for the explicit initialization of the function-local variable containing the array and its explicit return, on the first and last lines of the method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;filtered_and_transformed_records_2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;records&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;records&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each_with_object&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;record&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="k"&gt;next&lt;/span&gt; &lt;span class="k"&gt;unless&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;vowel?&lt;/span&gt;
    &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&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="nf"&gt;letter&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="nf"&gt;frequency&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;I say &lt;em&gt;function-local&lt;/em&gt; because we do need the &lt;em&gt;block-local&lt;/em&gt; variable &lt;code&gt;results&lt;/code&gt; inside the &lt;code&gt;each_with_object&lt;/code&gt; block. However, we've narrowed the scope of the &lt;code&gt;results&lt;/code&gt; variable, and that's always a good thing.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;each_with_object&lt;/code&gt; is like &lt;code&gt;each&lt;/code&gt; except that it will pass &lt;em&gt;two&lt;/em&gt; variables to the block instead of one. In addition to the object from the Enumerable that &lt;code&gt;each&lt;/code&gt; passes, it passes the object you are using to accumulate results. You initialize the accumulator by passing its initial value to the &lt;code&gt;each_with_object&lt;/code&gt; method. In this case we are passing a newly created empty array.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;each_with_object&lt;/code&gt;'s return value is the accumulator object, so you don't need to specify the accumulator explicitly for it to be the value returned by the method.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;each_with_object&lt;/code&gt; usage may not feel natural at first, but once you've seen it a few times your mind will parse it with almost zero effort. (By the way, I always had trouble remembering the order of its arguments until I realized that they were in the same order as in the method name itself; &lt;code&gt;each&lt;/code&gt; for the enumerated object and &lt;code&gt;object&lt;/code&gt; for the accumulator object.)&lt;/p&gt;

&lt;p&gt;The second refactoring is instead of using control flow constructs like &lt;code&gt;next&lt;/code&gt;, we can use the &lt;code&gt;Enumerable&lt;/code&gt; methods &lt;code&gt;select&lt;/code&gt; or &lt;code&gt;reject&lt;/code&gt;. We could refactor the code further into:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;filtered_and_transformed_records_3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;records&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;records&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="ss"&gt;:vowel?&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;each_with_object&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;record&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&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="nf"&gt;letter&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="nf"&gt;frequency&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;After this refactoring, we see the filter where it is more appropriate and helpful. Instead of it being on a line inside the block, it's just a few characters immediately after the input array (&lt;code&gt;records.select...&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;We've already simplified this method quite a bit, but there's even more we can do. Because &lt;code&gt;select&lt;/code&gt; returns the filtered array, we can simplify even further by using &lt;code&gt;map&lt;/code&gt; instead of &lt;code&gt;each_with_object&lt;/code&gt;!:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;filtered_and_transformed_records_4&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;records&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;records&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="ss"&gt;:vowel?&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="o"&gt;|&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="nf"&gt;letter&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="nf"&gt;frequency&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Although as software developers our mission is to deliver functionality, the other side of that coin is to do so as simply as possible. Put otherwise, we need to remove &lt;em&gt;accidental complexity&lt;/em&gt; (a.k.a. &lt;em&gt;incidental complexity&lt;/em&gt;) so that only the &lt;em&gt;essential complexity&lt;/em&gt; remains. The functional approaches described here are extremely effective at doing this. We've ended up with a simple one-liner.&lt;/p&gt;




&lt;p&gt;Whenever you start feeling that your code is getting verbose or awkward, ask yourself "could I improve this code with &lt;code&gt;Enumerable&lt;/code&gt;?" The answer may well be &lt;em&gt;yes&lt;/em&gt;.&lt;/p&gt;




&lt;p&gt;For your reference, &lt;a href="https://github.com/keithrbennett/keithrbennett.github.io/blob/master/source-code/short_sweet.rb"&gt;here&lt;/a&gt; is a file that contains the methods in the article, and verifies that they all produce the same result.&lt;/p&gt;




&lt;p&gt;[Note: This article may occasionally be improved. Its commit history is &lt;a href="https://github.com/keithrbennett/keithrbennett.github.io/commits/master/blog/_posts/2019-11-13-enumerables-short-and-sweet.md"&gt;here&lt;/a&gt;.]&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>enumerable</category>
      <category>functional</category>
    </item>
    <item>
      <title>Automate the Little Things Too</title>
      <dc:creator>Keith Bennett</dc:creator>
      <pubDate>Tue, 12 Nov 2019 10:46:08 +0000</pubDate>
      <link>https://dev.to/keithrbennett/automate-the-little-things-too-26n3</link>
      <guid>https://dev.to/keithrbennett/automate-the-little-things-too-26n3</guid>
      <description>&lt;p&gt;&lt;small&gt;(This article was originally published at on 2019-09-24 at:&lt;br&gt;
&lt;a href="https://bbs-software.com/blog/2019/09/24/automate-the-little-things-too.html"&gt;https://bbs-software.com/blog/2019/09/24/automate-the-little-things-too.html&lt;/a&gt;)&lt;/small&gt;&lt;/p&gt;

&lt;p&gt;We developers automate highly complex tasks, but when it comes to the smaller repetitive tasks, we tend to do things manually, or fail to do them at all. By combining Ruby with robust and richly functional command line tools such as MPlayer, we can save ourselves lots of time and have fun in the process.&lt;/p&gt;

&lt;p&gt;I recently decided that it would be nice to trim my collection of many video files downloaded from my phones over the years. Realizing this would be quite tedious, I asked myself "would this be easier with Ruby?" The answer, of course, was &lt;em&gt;Yes!&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Integrating MPlayer and Ruby
&lt;/h3&gt;

&lt;p&gt;&lt;a href="http://www.mplayerhq.hu/"&gt;MPlayer&lt;/a&gt; is a Unix &lt;em&gt;command line&lt;/em&gt; multimedia player that can be installed with your favorite package manager (e.g. &lt;code&gt;brew&lt;/code&gt;, &lt;code&gt;apt&lt;/code&gt;, or &lt;code&gt;yum&lt;/code&gt;). By driving MPlayer from Ruby, we can create a workflow that will enable you to view and decide about video files with a minimum of keystrokes, &lt;em&gt;without needing to use the mouse&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Files to process are specified on the command line. Multiple arguments can be specified, either absolute or relative, and either with or without wildcards. All filespecs are normalized to their absolute form so that duplicates can be eliminated.&lt;/p&gt;

&lt;p&gt;MPlayer plays each file for the user, responding to cursor keys to move forward and backward in time, change the speed, etc. I recommend viewing the man page (&lt;code&gt;man mplayer&lt;/code&gt;), but here are the most relevant options:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;keyboard control
      LEFT and RIGHT
           Seek backward/forward 10 seconds.
      UP and DOWN
           Seek forward/backward 1 minute.
      PGUP and PGDWN
           Seek forward/backward 10 minutes.
      [ and ]
           Decrease/increase current playback speed by 10%.
      { and }
           Halve/double current playback speed.
      BACKSPACE
           Reset playback speed to normal.

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;When the user has seen enough to make a decision, &lt;code&gt;q&lt;/code&gt; or &lt;code&gt;[ESC]&lt;/code&gt; can be pressed, and MPlayer returns control to the Ruby script, which accepts a one character response to mark it to be saved (&lt;code&gt;s&lt;/code&gt;), deleted (&lt;code&gt;d&lt;/code&gt;), or marked as undecided (&lt;code&gt;u&lt;/code&gt;) for future reprocessing; or &lt;code&gt;q&lt;/code&gt; to quit the application.&lt;/p&gt;

&lt;h3&gt;
  
  
  The High Level View
&lt;/h3&gt;

&lt;p&gt;Here is the highest level method in the script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;
  &lt;span class="n"&gt;check_presence_of_mplayer&lt;/span&gt;
  &lt;span class="n"&gt;create_dirs&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;greeting&lt;/span&gt;
  &lt;span class="n"&gt;files_to_process&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="n"&gt;filespec&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="n"&gt;play_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filespec&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="n"&gt;disposition_prompt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filespec&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;destination_subdir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_disposition_from_user&lt;/span&gt;
    &lt;span class="sb"&gt;`mv &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;filespec&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt; &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;destination_subdir&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filespec&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;destination_subdir&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;h3&gt;
  
  
  Using Subdirectories
&lt;/h3&gt;

&lt;p&gt;For simplicity of implementation and added safety, the application "marks" each multimedia file by moving it to one of the three subdirectories it has created, based on the user's choice. The user selects &lt;code&gt;d&lt;/code&gt; for deletes, &lt;code&gt;s&lt;/code&gt; for saves, or  &lt;code&gt;u&lt;/code&gt; for undecideds. &lt;code&gt;create_dirs&lt;/code&gt; creates the three subdirectories:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create_dirs&lt;/span&gt;
  &lt;span class="sx"&gt;%w{deletes  saves  undecideds}&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;dir&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="no"&gt;FileUtils&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mkdir_p&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dir&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;When the user is finished processing all files, they will probably want to move any files that have been moved to &lt;code&gt;./undecided&lt;/code&gt; back to &lt;code&gt;.&lt;/code&gt; and run the program again.&lt;/p&gt;

&lt;p&gt;Finally, when there are no files left in &lt;code&gt;undecided&lt;/code&gt;, one will probably want to do something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;rmdir undecideds
rm -rf deletes
mv saves/* .
rmdir saves
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  An Example
&lt;/h3&gt;

&lt;p&gt;For example, let's say you run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;organize-av-files 'video/*mp4' 'audio/*mp3'
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;MPlayer will begin playing the first file. When you are ready to finish viewing it, you will press &lt;code&gt;q&lt;/code&gt; or &lt;code&gt;ESC&lt;/code&gt;, and be presented with a prompt like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/Users/kbennett/android/video/20160102_234426.mp4:
s = save, d = delete, u = undecided, q = quit:
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Type your response choice and then &lt;code&gt;[Enter]&lt;/code&gt;. The program will move the file as appropriate, and immediately start playing the next file.&lt;/p&gt;

&lt;h3&gt;
  
  
  Shell vs. Ruby Wildcard Expansion
&lt;/h3&gt;

&lt;p&gt;Be careful when using wildcards. If you enter &lt;code&gt;*mp4&lt;/code&gt; in a directory with 10,000 MP4 files, the shell will try to expand it into 10,000 arguments, which might exceed the maximum command line size and result in an error. You can instead quote the filemask (as &lt;code&gt;'*mp4'&lt;/code&gt;), and it will then be passed to Ruby as a single argument, and Ruby will perform the expansion. You can usually use double quotes, but be aware that the single and double quotes behavior differs (see &lt;a href="https://stackoverflow.com/questions/6697753/difference-between-single-and-double-quotes-in-bash"&gt;this helpful StackOverflow article&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;One case where the shell's expansion would be preferable is with the use of environment variables in the filespec (&lt;code&gt;$FOO&lt;/code&gt; is more concise than &lt;code&gt;ENV['FOO']&lt;/code&gt;), and in the case of using &lt;code&gt;~&lt;/code&gt; for users other than the current user (e.g. &lt;code&gt;~someoneelse&lt;/code&gt;).&lt;/p&gt;

&lt;h3&gt;
  
  
  Also...
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;This workflow can be used with any multimedia files recognized by MPlayer, and that includes audio files.&lt;/li&gt;
&lt;li&gt;There are many, many nice-to-have features that have not been implemented, since speed of implementation was a high priority. Feel free to add your own!&lt;/li&gt;
&lt;li&gt;Although using Ruby probably enables writing the most concise and intention-revealing code, other languages such as Python would do fine as well.&lt;/li&gt;
&lt;li&gt;The code for this script ("organize-av-files") is currently at &lt;a href="https://gist.github.com/keithrbennett/4d9953e66ea35e2c52abae52650ebb1b"&gt;https://gist.github.com/keithrbennett/4d9953e66ea35e2c52abae52650ebb1b&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;I hope you can see that with a modest amount of code you can build a highly useful (albeit not fancy) automation tool. The amount of expected use and the benefit per use determines the optimum amount of effort, and you have the freedom to choose any point in that continuum. The notion that all applications need to be feature-rich is not a useful one, and often results in inaction altogether.&lt;/p&gt;

&lt;p&gt;Ruby is a great tool for this sort of thing. Why not use it?&lt;/p&gt;

&lt;p&gt;--- The End ---&lt;/p&gt;




&lt;p&gt;[Note: This article is occasionally improved. Its commit history is &lt;a href="https://github.com/keithrbennett/keithrbennett.github.io/commits/master/blog/_posts/2019-09-24-automate-the-little-things-too.md"&gt;here&lt;/a&gt;.]&lt;/p&gt;




&lt;p&gt;For your convenience, the script is displayed below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;#!/usr/bin/env ruby&lt;/span&gt;

&lt;span class="c1"&gt;# organize-av-files - Organizes files playable by mplayer&lt;/span&gt;
&lt;span class="c1"&gt;# into 'saves', 'deletes', and 'undecideds' subdirectories&lt;/span&gt;
&lt;span class="c1"&gt;# of the current working directory.&lt;/span&gt;
&lt;span class="c1"&gt;#&lt;/span&gt;
&lt;span class="c1"&gt;# Be careful, if you specify files to process in multiple directories,&lt;/span&gt;
&lt;span class="c1"&gt;# they will all be moved to the same subdirectories, so they will no&lt;/span&gt;
&lt;span class="c1"&gt;# longer be organized by directory, and if there are multiple files&lt;/span&gt;
&lt;span class="c1"&gt;# of the same name, some may be lost if overwritten.&lt;/span&gt;
&lt;span class="c1"&gt;#&lt;/span&gt;
&lt;span class="c1"&gt;# stored at:&lt;/span&gt;
&lt;span class="c1"&gt;# https://gist.github.com/keithrbennett/4d9953e66ea35e2c52abae52650ebb1b&lt;/span&gt;


&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'date'&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'fileutils'&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'set'&lt;/span&gt;

&lt;span class="no"&gt;LOG_FILESPEC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'organize-av-files.log'&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create_dirs&lt;/span&gt;
  &lt;span class="sx"&gt;%w{deletes  saves  undecideds}&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;dir&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="no"&gt;FileUtils&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mkdir_p&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dir&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="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;check_presence_of_mplayer&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="sb"&gt;`which mplayer`&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;chomp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;size&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;raise&lt;/span&gt; &lt;span class="s2"&gt;"mplayer not detected. "&lt;/span&gt;
        &lt;span class="s2"&gt;"Please install it (with apt, brew, yum, etc.)"&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;# Takes all ARGV elements, expands any wildcards,&lt;/span&gt;
&lt;span class="c1"&gt;# converts to normalized (absolute) form,&lt;/span&gt;
&lt;span class="c1"&gt;# and eliminates duplicates.&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;files_to_process&lt;/span&gt;

  &lt;span class="c1"&gt;# Dir[] does not understand ~, need to process it ourselves.&lt;/span&gt;
  &lt;span class="c1"&gt;# This does *not* handle the `~username` form.&lt;/span&gt;
  &lt;span class="n"&gt;replace_tilde_if_needed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filespec&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;filespec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start_with?&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="p"&gt;\&lt;/span&gt;
        &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="no"&gt;File&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="no"&gt;ENV&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'HOME'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;filespec&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&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;filespec&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="c1"&gt;# When Dir[] gets a directory it returns no files.&lt;/span&gt;
  &lt;span class="c1"&gt;# Need to add '/*' to it.&lt;/span&gt;
  &lt;span class="n"&gt;add_star_to_dirspec_if_needed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filespec&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;directory?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filespec&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="no"&gt;File&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="n"&gt;filespec&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="p"&gt;\&lt;/span&gt;
        &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;filespec&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="c1"&gt;# Default to all nonhidden files in current directory&lt;/span&gt;
  &lt;span class="c1"&gt;# but not its subdirectories.&lt;/span&gt;
  &lt;span class="no"&gt;ARGV&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="o"&gt;||=&lt;/span&gt; &lt;span class="s1"&gt;'*'&lt;/span&gt;

  &lt;span class="n"&gt;all_filespecs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;ARGV&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each_with_object&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Set&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="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;filemask&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;all_filespecs&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="n"&gt;filemask&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;replace_tilde_if_needed&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filemask&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;filemask&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;add_star_to_dirspec_if_needed&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filemask&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="no"&gt;Dir&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;filemask&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="nf"&gt;map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;absolute_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&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="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;file?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&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="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="n"&gt;filespec&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="n"&gt;all_filespecs&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;filespec&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;all_filespecs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sort&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;greeting&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;~&lt;/span&gt;&lt;span class="no"&gt;GREETING&lt;/span&gt;&lt;span class="sh"&gt;
      organize-av-files

      Enables the vetting of audio and video files. 

      For each file, plays it with mplayer, and prompts for what you would like to do 
      with that file, moving the file to one of the following subdirectories:

      * deletes
      * saves
      * undecideds

      This software uses mplayer to play audio files. Use cursor keys to move forwards/backwards in time.
      Press 'q' or 'ESC' to abort playback and specify disposition of that file.

      Run `man mplayer` for more on mplayer.

      Assumes all files specified are playable by mplayer.
      Creates subdirectories in the current directory: deletes, saves, undecideds.
      Logs to file '&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="no"&gt;LOG_FILESPEC&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;'

&lt;/span&gt;&lt;span class="no"&gt;  GREETING&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;play_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filespec&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="c1"&gt;# If you have mplayer problems, remove the redirection ("2&amp;gt; /dev/null")&lt;/span&gt;
  &lt;span class="c1"&gt;# to see any errors.&lt;/span&gt;
  &lt;span class="sb"&gt;`mplayer &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;filespec&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt; 2&amp;gt; /dev/null`&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;disposition_prompt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filespec&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;filespec&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;s = save, d = delete, u = undecided, q = quit: "&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;get_disposition_from_user&lt;/span&gt;
  &lt;span class="kp"&gt;loop&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vg"&gt;$stdin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;gets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;chomp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;downcase&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;'q'&lt;/span&gt;
      &lt;span class="nb"&gt;exit&lt;/span&gt;
    &lt;span class="k"&gt;elsif&lt;/span&gt; &lt;span class="sx"&gt;%w(s d u)&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;include?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="s1"&gt;'s'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'saves'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="s1"&gt;'d'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'deletes'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="s1"&gt;'u'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'undecideds'&lt;/span&gt;
      &lt;span class="p"&gt;}[&lt;/span&gt;&lt;span class="n"&gt;response&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;print&lt;/span&gt; &lt;span class="s2"&gt;"s = save, d = delete, u = undecided, q = quit: "&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;def&lt;/span&gt; &lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filespec&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;destination_subdir&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;dest_abbrev&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;destination_subdir&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="nf"&gt;upcase&lt;/span&gt; &lt;span class="c1"&gt;# 'S' for saves, etc.&lt;/span&gt;
  &lt;span class="n"&gt;log_message&lt;/span&gt; &lt;span class="o"&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;dest_abbrev&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="no"&gt;Time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&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;filespec&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="sb"&gt;`echo &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;log_message&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt; &amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="no"&gt;LOG_FILESPEC&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&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;main&lt;/span&gt;
  &lt;span class="n"&gt;check_presence_of_mplayer&lt;/span&gt;
  &lt;span class="n"&gt;create_dirs&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;greeting&lt;/span&gt;
  &lt;span class="n"&gt;files_to_process&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="n"&gt;filespec&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="n"&gt;play_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filespec&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="n"&gt;disposition_prompt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filespec&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;destination_subdir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_disposition_from_user&lt;/span&gt;
    &lt;span class="sb"&gt;`mv &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;filespec&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt; &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;destination_subdir&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filespec&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;destination_subdir&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;main&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



</description>
      <category>ruby</category>
      <category>shell</category>
      <category>script</category>
    </item>
    <item>
      <title>Boost Your Shell Scripting with Ruby and Rexe</title>
      <dc:creator>Keith Bennett</dc:creator>
      <pubDate>Mon, 15 Apr 2019 06:11:54 +0000</pubDate>
      <link>https://dev.to/keithrbennett/boost-your-shell-scripting-with-ruby-and-rexe-54pb</link>
      <guid>https://dev.to/keithrbennett/boost-your-shell-scripting-with-ruby-and-rexe-54pb</guid>
      <description>&lt;p&gt;[Caution: This is a long article! &lt;br&gt;
Sections are mostly self contained, so feel free to skim or skip them.]&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;Rexe&lt;/strong&gt; is a Ruby script and gem that multiplies Ruby's usefulness and conciseness on the command line by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;automating parsing and formatting using JSON, YAML, Ruby marshalling, Awesome Print, and others&lt;/li&gt;
&lt;li&gt;simplifying the use of Ruby as a shell filter, optionally predigesting input as lines, an enumerator, or one big string&lt;/li&gt;
&lt;li&gt;extracting the plumbing from the command line; requires and other options can be set in an environment variable&lt;/li&gt;
&lt;li&gt;enabling the loading of Ruby helper files to keep your code DRY and your command line code high level&lt;/li&gt;
&lt;li&gt;reading and evaluating a ~/.rexerc file on startup for your shared custom code and common requires&lt;/li&gt;
&lt;/ul&gt;



&lt;p&gt;Shell scripting is great for simple tasks but for anything nontrivial it can easily get cryptic and awkward (pun intended!).&lt;/p&gt;

&lt;p&gt;This problem can often be solved by writing a Ruby script instead. Ruby provides fine grained control in a language that is all about clarity, conciseness, and expressiveness.&lt;/p&gt;

&lt;p&gt;Unfortunately, when there are multiple OS commands to be called, then Ruby can be awkward too.&lt;/p&gt;

&lt;p&gt;Sometimes a good solution is to combine Ruby and shell scripting on the same command line. Rexe multiplies your power to do so.&lt;/p&gt;
&lt;h3&gt;
  
  
  Using the Ruby Interpreter on the Command Line
&lt;/h3&gt;

&lt;p&gt;Let's start by seeing what the Ruby interpreter already provides. Here we use &lt;code&gt;ruby&lt;/code&gt; on the command line, using an intermediate environment variable to simplify the logic and save the data for use by future commands. An excerpt of the output follows the code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;➜  ~   &lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;EUR_RATES_JSON&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;curl https://api.exchangeratesapi.io/latest&lt;span class="sb"&gt;`&lt;/span&gt;
➜  ~   &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$EUR_RATES_JSON&lt;/span&gt; | ruby &lt;span class="nt"&gt;-r&lt;/span&gt; json &lt;span class="nt"&gt;-r&lt;/span&gt; yaml &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'puts JSON.parse(STDIN.read).to_yaml'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;rates&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;MXN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;21.96&lt;/span&gt;
  &lt;span class="na"&gt;AUD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.5964&lt;/span&gt;
  &lt;span class="na"&gt;HKD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8.8092&lt;/span&gt;
  &lt;span class="s"&gt;...&lt;/span&gt;
&lt;span class="na"&gt;base&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;EUR&lt;/span&gt;
&lt;span class="na"&gt;date&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;2019-03-08'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Unfortunately, the configuration setup (the &lt;code&gt;require&lt;/code&gt;s) along with the reading, parsing, and formatting make the command long and tedious, discouraging this approach.&lt;/p&gt;

&lt;h3&gt;
  
  
  Rexe
&lt;/h3&gt;

&lt;p&gt;Rexe [see footnote ^1 regarding its origin] can simplify such commands. Among other things, rexe provides switch-activated input parsing and output formatting so that converting from one format to another is trivial. The previous &lt;code&gt;ruby&lt;/code&gt; command can be expressed in &lt;code&gt;rexe&lt;/code&gt; as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;➜  ~   &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$EUR_RATES_JSON&lt;/span&gt; | rexe &lt;span class="nt"&gt;-mb&lt;/span&gt; &lt;span class="nt"&gt;-ij&lt;/span&gt; &lt;span class="nt"&gt;-oy&lt;/span&gt; self
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Or, even more concisely (&lt;code&gt;self&lt;/code&gt; is the default Ruby source code for rexe commands):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;➜  ~   &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$EUR_RATES_JSON&lt;/span&gt; | rexe &lt;span class="nt"&gt;-mb&lt;/span&gt; &lt;span class="nt"&gt;-ij&lt;/span&gt; &lt;span class="nt"&gt;-oy&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The command options may seem cryptic, but they're logical so it shouldn't take long to learn them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;-mb&lt;/code&gt; - &lt;strong&gt;mode&lt;/strong&gt; to consume all standard input as a single &lt;strong&gt;big&lt;/strong&gt; string&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-ij&lt;/code&gt; - parse that &lt;strong&gt;input&lt;/strong&gt; with &lt;strong&gt;JSON&lt;/strong&gt;; &lt;code&gt;self&lt;/code&gt; will be the parsed object&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-oy&lt;/code&gt; - &lt;strong&gt;output&lt;/strong&gt; the final value as &lt;strong&gt;YAML&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If input comes from a JSON or YAML file, rexe determines the input format from the file's extension, and it's even simpler:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;➜  ~   rexe &lt;span class="nt"&gt;-f&lt;/span&gt; eur_rates.json &lt;span class="nt"&gt;-oy&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Rexe is at &lt;a href="https://github.com/keithrbennett/rexe"&gt;https://github.com/keithrbennett/rexe&lt;/a&gt; and can be installed with &lt;code&gt;gem install rexe&lt;/code&gt;. Rexe provides several ways to simplify Ruby on the command line, tipping the scale so that it is practical to do it more often.&lt;/p&gt;




&lt;p&gt;Here is rexe's help text as of the time of this writing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;rexe -- Ruby Command Line Executor/Filter -- v1.0.1 -- https://github.com/keithrbennett/rexe

Executes Ruby code on the command line, 
optionally automating management of standard input and standard output,
and optionally parsing input and formatting output with YAML, JSON, etc.

rexe [options] [Ruby source code]

Options:

-c  --clear_options        Clear all previous command line options specified up to now
-f  --input_file           Use this file instead of stdin for preprocessed input; 
                           if filespec has a YAML and JSON file extension,
                           sets input format accordingly and sets input mode to -mb
-g  --log_format FORMAT    Log format, logs to stderr, defaults to none
                           (see -o for format options)
-h, --help                 Print help and exit
-i, --input_format FORMAT  Input format
                             -ij  JSON
                             -im  Marshal
                             -in  None (default)
                             -iy  YAML
-l, --load RUBY_FILE(S)    Ruby file(s) to load, comma separated;
                             ! to clear all, or precede a name with '-' to remove
-m, --input_mode MODE      Input preprocessing mode (determines what `self` will be):
                             -ml  line; each line is ingested as a separate string
                             -me  enumerator (each_line on STDIN or File)
                             -mb  big string; all lines combined into one string
                             -mn  none (default); no input preprocessing; 
                                  self is an Object.new 
-n, --[no-]noop            Do not execute the code (useful with -g);
                           For true: yes, true, y, +; for false: no, false, n
-o, --output_format FORMAT Output format (defaults to puts):
                             -oi  Inspect
                             -oj  JSON
                             -oJ  Pretty JSON
                             -om  Marshal
                             -on  No Output (default)
                             -op  Puts
                             -os  to_s
                             -oy  YAML
-r, --require REQUIRE(S)   Gems and built-in libraries to require, comma separated;
                             ! to clear all, or precede a name with '-' to remove

---------------------------------------------------------------------------------------

In many cases you will need to enclose your source code in single or double quotes.

If source code is not specified, it will default to 'self', 
which is most likely useful only in a filter mode (-ml, -me, -mb).

If there is a .rexerc file in your home directory, it will be run as Ruby code 
before processing the input.

If there is a REXE_OPTIONS environment variable, its content will be prepended
to the command line so that you can specify options implicitly 
(e.g. `export REXE_OPTIONS="-r awesome_print,yaml"`)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Simplifying the Rexe Invocation
&lt;/h3&gt;

&lt;p&gt;There are two main ways we can make the rexe command line even more concise:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;by extracting configuration into the &lt;code&gt;REXE_OPTIONS&lt;/code&gt; environment variable&lt;/li&gt;
&lt;li&gt;by extracting low level and/or shared code into helper files that are loaded using &lt;code&gt;-l&lt;/code&gt;,
or implicitly with &lt;code&gt;~/.rexerc&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The REXE_OPTIONS Environment Variable
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;REXE_OPTIONS&lt;/code&gt; environment variable can contain command line options that would otherwise be specified on the rexe command line:&lt;/p&gt;

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

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;➜  ~   rexe &lt;span class="nt"&gt;-r&lt;/span&gt; wifi-wand &lt;span class="nt"&gt;-oa&lt;/span&gt; WifiWand::MacOsModel.new.wifi_info
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;you can do this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;➜  ~   &lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;REXE_OPTIONS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"-r wifi-wand -oa"&lt;/span&gt;
➜  ~   rexe WifiWand::MacOsModel.new.wifi_info
➜  ~   &lt;span class="c"&gt;# [more rexe commands with the same options]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Putting configuration options in &lt;code&gt;REXE_OPTIONS&lt;/code&gt; effectively creates custom defaults, and is useful when you use the same options in most or all of your commands. Any options specified on the rexe command line will override the environment variable options.&lt;/p&gt;

&lt;p&gt;Like any environment variable, &lt;code&gt;REXE_OPTIONS&lt;/code&gt; could also be set in your startup script, input on a command line using &lt;code&gt;export&lt;/code&gt;, or in another script loaded with &lt;code&gt;source&lt;/code&gt; or &lt;code&gt;.&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Loading Files
&lt;/h3&gt;

&lt;p&gt;The environment variable approach works well for command line &lt;em&gt;options&lt;/em&gt;, but what if we want to specify Ruby &lt;em&gt;code&lt;/em&gt; (e.g. methods) that can be used by your rexe code?&lt;/p&gt;

&lt;p&gt;For this, rexe lets you &lt;em&gt;load&lt;/em&gt; Ruby files, using the &lt;code&gt;-l&lt;/code&gt; option, or implicitly (without your specifying it) in the case of the &lt;code&gt;~/.rexerc&lt;/code&gt; file. Here is an example of something you might include in such a file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Open YouTube to Wagner's "Ride of the Valkyries"&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;valkyries&lt;/span&gt;
  &lt;span class="sb"&gt;`open "http://www.youtube.com/watch?v=P73Z6291Pt8&amp;amp;t=0m28s"`&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;To digress a bit, why would you want this? You might want to be able to go to another room until a long job completes, and be notified when it is done.  The &lt;code&gt;valkyries&lt;/code&gt; method will launch a browser window pointed to Richard Wagner's "Ride of the Valkyries" starting at a lively point in the music [see footnote ^2 regarding autoplay]. (The &lt;code&gt;open&lt;/code&gt; command is Mac specific and could be replaced with &lt;code&gt;start&lt;/code&gt; on Windows, a browser command name, etc.) [see footnote ^3 regarding OS portability].&lt;/p&gt;

&lt;p&gt;If you like this kind of audio notification, you could download public domain audio files and use a command like player like &lt;code&gt;afplay&lt;/code&gt; on Mac OS, or &lt;code&gt;mpg123&lt;/code&gt; or &lt;code&gt;ogg123&lt;/code&gt; on Linux. This approach is lighter weight, requires no network access, and will not leave an open browser window for you to close.&lt;/p&gt;

&lt;p&gt;Here is an example of how you might use the &lt;code&gt;valkyries&lt;/code&gt; method, assuming the above configuration is loaded from your &lt;code&gt;~/.rexerc&lt;/code&gt; file or an explicitly loaded file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;➜  ~   &lt;span class="nb"&gt;tar &lt;/span&gt;czf /tmp/my-whole-user-space.tar.gz ~ &lt;span class="p"&gt;;&lt;/span&gt; rexe valkyries
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;(Note that &lt;code&gt;;&lt;/code&gt; is used rather than &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt; because we want to hear the music whether or not the command succeeds.)&lt;/p&gt;

&lt;p&gt;You might be thinking that creating an alias or a minimal shell script (instead of a Ruby script) for this &lt;code&gt;open&lt;/code&gt; would be a simpler and more natural approach, and I would agree with you. However, over time the number of these could become unmanageable, whereas using Ruby you could build a pretty extensive and well organized library of functionality. Moreover, that functionality could be made available to &lt;em&gt;all&lt;/em&gt; your Ruby code (for example, by putting it in a gem), and not just command line one liners.&lt;/p&gt;

&lt;p&gt;For example, you could have something like this in a gem or loaded file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;play&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;piece_code&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;pieces&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="ss"&gt;hallelujah: &lt;/span&gt;&lt;span class="s2"&gt;"https://www.youtube.com/watch?v=IUZEtVbJT5c&amp;amp;t=0m20s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="ss"&gt;valkyries:  &lt;/span&gt;&lt;span class="s2"&gt;"http://www.youtube.com/watch?v=P73Z6291Pt8&amp;amp;t=0m28s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="ss"&gt;wm_tell:    &lt;/span&gt;&lt;span class="s2"&gt;"https://www.youtube.com/watch?v=j3T8-aeOrbg&amp;amp;t=0m1s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;# ... and many, many more&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="sb"&gt;`open &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="no"&gt;Shellwords&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;escape&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pieces&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;piece_code&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&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;...which you could then call like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;➜  ~   &lt;span class="nb"&gt;tar &lt;/span&gt;czf /tmp/my-whole-user-space.tar.gz ~ &lt;span class="p"&gt;;&lt;/span&gt; rexe &lt;span class="s1"&gt;'play(:hallelujah)'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;(You need to quote the &lt;code&gt;play&lt;/code&gt; call because otherwise the shell will process and remove the parentheses. Alternatively you could escape the parentheses with backslashes.)&lt;/p&gt;

&lt;p&gt;One of the examples at the end of this articles shows how you could have different music play for success and failure.&lt;/p&gt;

&lt;h3&gt;
  
  
  Logging
&lt;/h3&gt;

&lt;p&gt;A log entry is optionally output to standard error after completion of the code. This entry is a hash representation (to be precise, &lt;code&gt;to_h&lt;/code&gt;) of the &lt;code&gt;$RC&lt;/code&gt; OpenStruct described in the $RC section below. It contains the version, date/time of execution, source code to be evaluated, options (after parsing both the &lt;code&gt;REXE_OPTIONS&lt;/code&gt; environment variable and the command line), and the execution time of your Ruby code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;➜  ~   &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$EUR_RATES_JSON&lt;/span&gt; | rexe &lt;span class="nt"&gt;-gy&lt;/span&gt; &lt;span class="nt"&gt;-ij&lt;/span&gt; &lt;span class="nt"&gt;-mb&lt;/span&gt; &lt;span class="nt"&gt;-oa&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; self
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="s"&gt;:count: &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
&lt;span class="s"&gt;:rexe_version: 1.0.0&lt;/span&gt;
&lt;span class="s"&gt;:start_time: '2019-04-15T13:12:15+08:00'&lt;/span&gt;
&lt;span class="s"&gt;:source_code: self&lt;/span&gt;
&lt;span class="s"&gt;:options:&lt;/span&gt;
  &lt;span class="s"&gt;:input_filespec:&lt;/span&gt;
  &lt;span class="s"&gt;:input_format: :json&lt;/span&gt;
  &lt;span class="s"&gt;:input_mode: :one_big_string&lt;/span&gt;
  &lt;span class="s"&gt;:loads: []&lt;/span&gt;
  &lt;span class="s"&gt;:output_format: :awesome_print&lt;/span&gt;
  &lt;span class="s"&gt;:requires:&lt;/span&gt;
  &lt;span class="s"&gt;- awesome_print&lt;/span&gt;
  &lt;span class="s"&gt;- json&lt;/span&gt;
  &lt;span class="s"&gt;- yaml&lt;/span&gt;
  &lt;span class="s"&gt;:log_format: :yaml&lt;/span&gt;
  &lt;span class="s"&gt;:noop: &lt;/span&gt;&lt;span class="no"&gt;true&lt;/span&gt;
&lt;span class="s"&gt;:duration_secs: &lt;/span&gt;&lt;span class="m"&gt;0.050326&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We specified &lt;code&gt;-gy&lt;/code&gt; for YAML format; there are other formats as well (see the help output or this document) and the default is &lt;code&gt;-gn&lt;/code&gt;, which means don't output the log entry at all.&lt;/p&gt;

&lt;p&gt;The requires you see were not explicitly specified but were automatically added because Rexe will add any requires needed for automatic parsing and formatting, and we specified those formats in the command line options &lt;code&gt;-gy -ij -oa&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This extra output is sent to standard error (&lt;em&gt;stderr&lt;/em&gt;) instead of standard output (&lt;em&gt;stdout&lt;/em&gt;) so that it will not pollute the "real" data when stdout is piped to another command.&lt;/p&gt;

&lt;p&gt;If you would like to append this informational output to a file(e.g. &lt;code&gt;rexe.log&lt;/code&gt;), you could do something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;➜  ~   rexe ... &lt;span class="nt"&gt;-gy&lt;/span&gt; 2&amp;gt;&amp;gt;rexe.log
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Input Modes
&lt;/h3&gt;

&lt;p&gt;Rexe tries to make it simple and convenient for you to handle standard input, and in different ways. Here is the help text relating to input modes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-m, --input_mode MODE      Input preprocessing mode (determines what `self` will be):
                             -ml  line; each line is ingested as a separate string
                             -me  enumerator (each_line on STDIN or File)
                             -mb  big string; all lines combined into one string
                             -mn  none (default); no input preprocessing; 
                                  self is an Object.new 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The first three are &lt;em&gt;filter&lt;/em&gt; modes; they make standard input available to your code as &lt;code&gt;self&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The last (and default) is the &lt;em&gt;executor&lt;/em&gt; mode. It merely assists you in executing the code you provide without any special implicit handling of standard input. Here is more detail on these modes:&lt;/p&gt;

&lt;h4&gt;
  
  
  -ml "Line" Filter Mode
&lt;/h4&gt;

&lt;p&gt;In this mode, your code would be called once per line of input, and in each call, &lt;code&gt;self&lt;/code&gt; would evaluate to each line of text:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;➜  ~   &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"hello&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;goodbye"&lt;/span&gt; | rexe &lt;span class="nt"&gt;-ml&lt;/span&gt; puts reverse
olleh
eybdoog
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;code&gt;reverse&lt;/code&gt; is implicitly called on each line of standard input.  &lt;code&gt;self&lt;/code&gt; is the input line in each call (we could also have used &lt;code&gt;self.reverse&lt;/code&gt; but the &lt;code&gt;self.&lt;/code&gt; would have been redundant).&lt;/p&gt;

&lt;p&gt;Be aware that, in this mode, if you are using an automatic output mode (anything other than the default &lt;code&gt;-on&lt;/code&gt; no output mode), although you can control the &lt;em&gt;content&lt;/em&gt; of output records, there is no way to selectively &lt;em&gt;exclude&lt;/em&gt; records from being output. Even if the result of the code is nil or the empty string, a newline will be output. To prevent this, you can do one of the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;use &lt;code&gt;-me&lt;/code&gt; Enumerator mode instead and call &lt;code&gt;select&lt;/code&gt;, &lt;code&gt;filter&lt;/code&gt;, &lt;code&gt;reject&lt;/code&gt;, etc.&lt;/li&gt;
&lt;li&gt;use the (default) &lt;code&gt;-on&lt;/code&gt; &lt;em&gt;no output&lt;/em&gt; mode and call &lt;code&gt;puts&lt;/code&gt; explicitly for the output you &lt;em&gt;do&lt;/em&gt; want&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  -me "Enumerator" Filter Mode
&lt;/h4&gt;

&lt;p&gt;In this mode, your code is called only once, and &lt;code&gt;self&lt;/code&gt; is an enumerator dispensing all lines of standard input. To be more precise, it is the enumerator returned by the &lt;code&gt;each_line&lt;/code&gt; method, on &lt;code&gt;$stdin&lt;/code&gt; or the input file, whichever is applicable.&lt;/p&gt;

&lt;p&gt;Dealing with input as an enumerator enables you to use the wealth of &lt;code&gt;Enumerable&lt;/code&gt; methods such as &lt;code&gt;select&lt;/code&gt;, &lt;code&gt;to_a&lt;/code&gt;, &lt;code&gt;map&lt;/code&gt;, etc.&lt;/p&gt;

&lt;p&gt;Here is an example of using &lt;code&gt;-me&lt;/code&gt; to add line numbers to the first 3 files in the directory listing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;➜  ~   &lt;span class="nb"&gt;ls&lt;/span&gt; / | rexe &lt;span class="nt"&gt;-me&lt;/span&gt; &lt;span class="s2"&gt;"first(3).each_with_index { |ln,i| puts '%5d  %s' % [i, ln] }"&lt;/span&gt;

    0  AndroidStudioProjects
    1  Applications
    2  Desktop
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Since &lt;code&gt;self&lt;/code&gt; is an enumerable, we can call &lt;code&gt;first&lt;/code&gt; on it. We've used the default output mode &lt;code&gt;-on&lt;/code&gt; (&lt;em&gt;no output&lt;/em&gt; mode), which says don't do any automatic output, just the output explicitly specified by &lt;code&gt;puts&lt;/code&gt; in the source code.&lt;/p&gt;

&lt;h4&gt;
  
  
  -mb "Big String" Filter Mode
&lt;/h4&gt;

&lt;p&gt;In this mode, all standard input is combined into a single (possibly large and possibly multiline) string.&lt;/p&gt;

&lt;p&gt;A good example of when you would use this is when you need to parse a multiline JSON or YAML representation of an object; you need to pass all the standard input to the parse method. This is the mode that was used in the first rexe example in this article.&lt;/p&gt;

&lt;h4&gt;
  
  
  -mn "No Input" Executor Mode -- The Default
&lt;/h4&gt;

&lt;p&gt;In this mode, no special handling of standard input is done at all; if you want standard input you need to code it yourself (e.g. with &lt;code&gt;STDIN.read&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;&lt;code&gt;self&lt;/code&gt; evaluates to a new instance of &lt;code&gt;Object&lt;/code&gt;, which would be used if you defined methods, constants, instance variables, etc., in your code.&lt;/p&gt;

&lt;h4&gt;
  
  
  Filter Input Mode Memory Considerations
&lt;/h4&gt;

&lt;p&gt;If you are using one of the filter modes, and may have more input than would fit in memory, you can do one of the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;use &lt;code&gt;-ml&lt;/code&gt; (line) mode so you are fed only 1 line at a time&lt;/li&gt;
&lt;li&gt;use an Enumerator, either by a) specifying the &lt;code&gt;-me&lt;/code&gt; (enumerator) mode option,
or b) using &lt;code&gt;-mn&lt;/code&gt; (no input) mode in conjunction with something like &lt;code&gt;STDIN.each_line&lt;/code&gt;. Then: 

&lt;ul&gt;
&lt;li&gt;Make sure not to call any methods (e.g. &lt;code&gt;map&lt;/code&gt;, &lt;code&gt;select&lt;/code&gt;)
that will produce an array of all the input because that will pull all the records into memory, or:&lt;/li&gt;
&lt;li&gt;use &lt;a href="https://www.honeybadger.io/blog/using-lazy-enumerators-to-work-with-large-files-in-ruby/"&gt;lazy enumerators&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Input Formats
&lt;/h3&gt;

&lt;p&gt;Rexe can parse your input in any of several formats if you like. You would request this in the &lt;em&gt;input format&lt;/em&gt; (&lt;code&gt;-i&lt;/code&gt;) option. Legal values are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;-ij&lt;/code&gt; - JSON&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-im&lt;/code&gt; - Marshal&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-in&lt;/code&gt; - &lt;a href="https://dev.todefault"&gt;None&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-iy&lt;/code&gt; - YAML&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Except for &lt;code&gt;-in&lt;/code&gt;, which passes the text to your code untouched, your input will be parsed in the specified format, and the resulting object passed into your code as &lt;code&gt;self&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The input format option is ignored if the input &lt;em&gt;mode&lt;/em&gt; is &lt;code&gt;-mn&lt;/code&gt; ("no input" executor mode, the default), since there is no preprocessing of standard input in that mode.&lt;/p&gt;

&lt;h3&gt;
  
  
  Output Formats
&lt;/h3&gt;

&lt;p&gt;Several output formats are provided for your convenience:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;-oa&lt;/code&gt; - Awesome Print - calls &lt;code&gt;.ai&lt;/code&gt; on the object to get the string that &lt;code&gt;ap&lt;/code&gt; would print&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-oi&lt;/code&gt; - Inspect - calls &lt;code&gt;inspect&lt;/code&gt; on the object&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-oj&lt;/code&gt; - JSON - calls &lt;code&gt;to_json&lt;/code&gt; on the object&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-oJ&lt;/code&gt; - Pretty JSON calls &lt;code&gt;JSON.pretty_generate&lt;/code&gt; with the object&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-on&lt;/code&gt; - (default) No Output - output is suppressed&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-op&lt;/code&gt; - Puts - produces what &lt;code&gt;puts&lt;/code&gt; would output&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-os&lt;/code&gt; - To String - calls &lt;code&gt;to_s&lt;/code&gt; on the object&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-oy&lt;/code&gt; - YAML - calls &lt;code&gt;to_yaml&lt;/code&gt; on the object&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All formats will implicitly &lt;code&gt;require&lt;/code&gt; anything needed to accomplish their task (e.g. &lt;code&gt;require 'yaml'&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;The default is &lt;code&gt;-on&lt;/code&gt; to produce no output at all (unless explicitly coded to do so). If you prefer a different default such as &lt;code&gt;-op&lt;/code&gt; for &lt;em&gt;puts&lt;/em&gt; mode, you can specify that in your &lt;code&gt;REXE_OPTIONS&lt;/code&gt; environment variable.&lt;/p&gt;

&lt;p&gt;If two letters are provided, the first will be used for tty devices (e.g. the terminal when not redirected or piped), and the second for block devices (e.g. when redirected or piped to another process).&lt;/p&gt;

&lt;p&gt;You may wonder why these formats are provided, given that their functionality could be included in the custom code instead. Here's why:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The savings in command line length goes a long way to making these commands more readable and feasible.&lt;/li&gt;
&lt;li&gt;It's much simpler to switch formats, as there is no need to change the code itself.&lt;/li&gt;
&lt;li&gt;This approach enables parameterization of the output format.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Reading Input from a File
&lt;/h3&gt;

&lt;p&gt;Rexe also simplifies getting input from a file rather than standard input. The &lt;code&gt;-f&lt;/code&gt; option takes a filespec and does with its content exactly what it would have done with standard input. This shortens:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;➜  ~   &lt;span class="nb"&gt;cat &lt;/span&gt;filename.ext | rexe ...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;...to...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;➜  ~   rexe &lt;span class="nt"&gt;-f&lt;/span&gt; filename.ext ...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This becomes even more useful if you are using files whose extensions are &lt;code&gt;.yml&lt;/code&gt;, &lt;code&gt;.yaml&lt;/code&gt;, or &lt;code&gt;.json&lt;/code&gt; (case insensitively). In this case the input format and mode will be set automatically for you to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;-iy&lt;/code&gt; (YAML) or &lt;code&gt;-ij&lt;/code&gt; (JSON) depending on the file extension&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-mb&lt;/code&gt; (one big string mode), which assumes that the most common use case will be to parse the entire file at once&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So the example we gave above:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;➜  ~   &lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;EUR_RATES_JSON&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;curl https://api.exchangeratesapi.io/latest&lt;span class="sb"&gt;`&lt;/span&gt;
➜  ~   &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$EUR_RATES_JSON&lt;/span&gt; | rexe &lt;span class="nt"&gt;-mb&lt;/span&gt; &lt;span class="nt"&gt;-ij&lt;/span&gt; &lt;span class="nt"&gt;-oy&lt;/span&gt; self
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;...could be changed to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;➜  ~   curl https://api.exchangeratesapi.io/latest &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; eur_rates.json
➜  ~   rexe &lt;span class="nt"&gt;-f&lt;/span&gt; eur_rates.json &lt;span class="nt"&gt;-oy&lt;/span&gt; self
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Another possible win for using &lt;code&gt;-f&lt;/code&gt; is that since it is a command line option, it could be specified in &lt;code&gt;REXE_OPTIONS&lt;/code&gt;. This could be useful if you are doing many operations on the same file.&lt;/p&gt;

&lt;p&gt;If you need to override the input mode and format automatically configured for file input, you can simply specify the desired options on the command line &lt;em&gt;after&lt;/em&gt; the &lt;code&gt;-f&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;➜  ~   rexe &lt;span class="nt"&gt;-f&lt;/span&gt; eur_rates.json &lt;span class="nt"&gt;-mb&lt;/span&gt; &lt;span class="nt"&gt;-in&lt;/span&gt; &lt;span class="s1"&gt;'puts self.class, self[0..20]'&lt;/span&gt;
String
&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"base"&lt;/span&gt;:&lt;span class="s2"&gt;"EUR"&lt;/span&gt;,&lt;span class="s2"&gt;"rates"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  'self' as Default Source Code
&lt;/h3&gt;

&lt;p&gt;To make rexe even more concise, you do not need to specify any source code when you want that source code to be &lt;code&gt;self&lt;/code&gt;. This would be the case for simple format conversions, as in JSON to YAML conversion mentioned above:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;➜ ~  rexe &lt;span class="nt"&gt;-f&lt;/span&gt; eur_rates.json &lt;span class="nt"&gt;-oy&lt;/span&gt;
&lt;span class="c"&gt;# or&lt;/span&gt;
➜ ~  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$EUR_RATES_JSON&lt;/span&gt; | rexe &lt;span class="nt"&gt;-mb&lt;/span&gt; &lt;span class="nt"&gt;-ij&lt;/span&gt; &lt;span class="nt"&gt;-oy&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;rates&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;JPY&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;126.63&lt;/span&gt;
  &lt;span class="na"&gt;BRL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;4.3012&lt;/span&gt;
  &lt;span class="na"&gt;NOK&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;9.6915&lt;/span&gt;
  &lt;span class="s"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This feature is probably only useful in the filter modes, since in the executor mode (&lt;code&gt;-mn&lt;/code&gt;) self is a new instance of &lt;code&gt;Object&lt;/code&gt; and hardly ever useful as an output value.&lt;/p&gt;

&lt;h3&gt;
  
  
  The $RC Global OpenStruct
&lt;/h3&gt;

&lt;p&gt;For your convenience, the information displayed in verbose mode is available to your code at runtime by accessing the &lt;code&gt;$RC&lt;/code&gt; global variable, which contains an OpenStruct. Let's print out its contents using YAML:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;➜  ~   rexe &lt;span class="nt"&gt;-oy&lt;/span&gt; &lt;span class="s1"&gt;'$RC'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt; &lt;span class="kt"&gt;!ruby/object:OpenStruct&lt;/span&gt;
&lt;span class="na"&gt;table&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="s"&gt;:count: &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
  &lt;span class="s"&gt;:rexe_version: 1.0.0&lt;/span&gt;
  &lt;span class="s"&gt;:start_time: '2019-04-15T13:25:56+08:00'&lt;/span&gt;
  &lt;span class="s"&gt;:source_code: "$RC"&lt;/span&gt;
  &lt;span class="s"&gt;:options:&lt;/span&gt;
    &lt;span class="s"&gt;:input_filespec:&lt;/span&gt;
    &lt;span class="s"&gt;:input_format: :none&lt;/span&gt;
    &lt;span class="s"&gt;:input_mode: :none&lt;/span&gt;
    &lt;span class="s"&gt;:loads: []&lt;/span&gt;
    &lt;span class="s"&gt;:output_format: :yaml&lt;/span&gt;
    &lt;span class="s"&gt;:requires:&lt;/span&gt;
    &lt;span class="s"&gt;- yaml&lt;/span&gt;
    &lt;span class="s"&gt;:log_format: :none&lt;/span&gt;
    &lt;span class="s"&gt;:noop: &lt;/span&gt;&lt;span class="no"&gt;false&lt;/span&gt;
&lt;span class="na"&gt;modifiable&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Probably most useful in that object at runtime is the record count, accessible with both &lt;code&gt;$RC.count&lt;/code&gt; and &lt;code&gt;$RC.i&lt;/code&gt;. This is only really useful in line mode, because in the others it will always be 0 or 1. Here is an example of how you might use it as a kind of progress indicator:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;➜  ~   find / | rexe &lt;span class="nt"&gt;-ml&lt;/span&gt; &lt;span class="nt"&gt;-on&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="s1"&gt;'if $RC.i % 1000 == 0; puts %Q{File entry ##{$RC.i} is #{self}}; end'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
File entry #106000 is /usr/local/Cellar/go/1.11.5/libexec/src/cmd/vendor/github.com/google/pprof/internal/driver/driver_test.go
File entry #107000 is /usr/local/Cellar/go/1.11.5/libexec/src/go/types/testdata/cycles1.src
File entry #108000 is /usr/local/Cellar/go/1.11.5/libexec/src/runtime/os_linux_novdso.go
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Note that a single quote was used for the Ruby code here; if a double quote were used, the &lt;code&gt;$RC&lt;/code&gt; would have been interpreted and removed by the shell.&lt;/p&gt;

&lt;h3&gt;
  
  
  Implementing Domain Specific Languages (DSL's)
&lt;/h3&gt;

&lt;p&gt;Defining methods in your loaded files enables you to effectively define a &lt;a href="https://en.wikipedia.org/wiki/Domain-specific_language"&gt;DSL&lt;/a&gt; for your command line use. You could use different load files for different projects, domains, or contexts, and define aliases or one line scripts to give them meaningful names. For example, if you had Ansible helper code in &lt;code&gt;~/projects/ansible-tools/rexe-ansible.rb&lt;/code&gt;, you could define an alias in your startup script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;➜  ~   &lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;rxans&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"rexe -l ~/projects/ansible-tools/rexe-ansible.rb &lt;/span&gt;&lt;span class="nv"&gt;$*&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;...and then you would have an Ansible DSL available for me to use by calling &lt;code&gt;rxans&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In addition, since you can also call &lt;code&gt;pry&lt;/code&gt; on the context of any object, you can provide a DSL in a &lt;a href="https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop"&gt;REPL&lt;/a&gt; (shell) trivially easily. Just to illustrate, here's how you would open a REPL on the File class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;➜  ~   ruby &lt;span class="nt"&gt;-r&lt;/span&gt; pry &lt;span class="nt"&gt;-e&lt;/span&gt; File.pry
&lt;span class="c"&gt;# or&lt;/span&gt;
➜  ~   rexe &lt;span class="nt"&gt;-r&lt;/span&gt; pry File.pry
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;code&gt;self&lt;/code&gt; would evaluate to the &lt;code&gt;File&lt;/code&gt; class, so you could call class methods using only their names:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;➜  ~   rexe &lt;span class="nt"&gt;-r&lt;/span&gt; pry File.pry
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[6] pry(File)&amp;gt; size '/etc/passwd'
6804
[7] pry(File)&amp;gt; directory? '.'
true
[8] pry(File)&amp;gt; file?('/etc/passwd')
true
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This could be really handy if you call &lt;code&gt;pry&lt;/code&gt; on a custom object that has methods especially suited to your task:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;➜  ~   rexe &lt;span class="nt"&gt;-r&lt;/span&gt; wifi-wand,pry  WifiWand::MacOsModel.new.pry
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[1] pry(#&amp;lt;WifiWand::MacOsModel&amp;gt;)&amp;gt; random_mac_address
"a1:ea:69:d9:ca:05"
[2] pry(#&amp;lt;WifiWand::MacOsModel&amp;gt;)&amp;gt; connected_network_name
"My WiFi"
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Ruby is supremely well suited for DSL's since it does not require parentheses for method calls, so calls to your custom methods &lt;em&gt;look&lt;/em&gt; like built in language commands and keywords. &lt;/p&gt;

&lt;h3&gt;
  
  
  Quotation Marks and Quoting Strings in Your Ruby Code
&lt;/h3&gt;

&lt;p&gt;One complication of using utilities like rexe where Ruby code is specified on the command line is that you need to be careful about the shell's special treatment of certain characters. For this reason, it is often necessary to quote the Ruby code. You can use single or double quotes to have the shell treat your source code as a single argument. An excellent reference for how they differ is on StackOverflow at &lt;a href="https://stackoverflow.com/questions/6697753/difference-between-single-and-double-quotes-in-bash"&gt;https://stackoverflow.com/questions/6697753/difference-between-single-and-double-quotes-in-bash&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Personally, I find single quotes more useful since I usually don't want special characters in my Ruby code like &lt;code&gt;$&lt;/code&gt; to be processed by the shell.&lt;/p&gt;

&lt;p&gt;Sometimes it doesn't matter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;➜  ~   rexe &lt;span class="s1"&gt;'puts "hello"'&lt;/span&gt;
hello
➜  ~   rexe &lt;span class="s2"&gt;"puts 'hello'"&lt;/span&gt;
hello
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We can also use &lt;code&gt;%q&lt;/code&gt; or &lt;code&gt;%Q&lt;/code&gt;, and sometimes this eliminates the needs for the outer quotes altogether:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;➜  ~   rexe puts %q&lt;span class="o"&gt;{&lt;/span&gt;hello&lt;span class="o"&gt;}&lt;/span&gt;
hello
➜  ~   rexe puts %Q&lt;span class="o"&gt;{&lt;/span&gt;hello&lt;span class="o"&gt;}&lt;/span&gt;
hello
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Sometimes the quotes to use on the outside (quoting your command in the shell) need to be chosen based on which quotes are needed on the inside. For example, in the following command, we need double quotes in Ruby in order for interpolation to work, so we use single quotes on the outside:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;➜  ~   rexe puts &lt;span class="s1"&gt;'"The time is now #{Time.now}"'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The time is now 2019-03-29 16:41:26 +0800
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In this case we also need to use single quotes on the outside, because we need literal double quotes in a &lt;code&gt;%Q{}&lt;/code&gt; expression:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;➜  ~   rexe &lt;span class="s1"&gt;'puts %Q{The operating system name is "#{`uname`.chomp}".}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The operating system name is "Darwin".
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We can eliminate the need for any quotes in the Ruby code using &lt;code&gt;%Q{}&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;➜  ~   rexe puts &lt;span class="s1"&gt;'%Q{The time is now #{Time.now}}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The time is now 2019-03-29 17:06:13 +0800
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Of course you can always escape the quotes with backslashes instead, but that is probably more difficult to read.&lt;/p&gt;

&lt;h3&gt;
  
  
  No Op Mode
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;-n&lt;/code&gt; no-op mode will result in the specified source code &lt;em&gt;not&lt;/em&gt; being executed. This can sometimes be handy in conjunction with a &lt;code&gt;-g&lt;/code&gt; (logging) option, if you have are building a rexe command and want to inspect the configuration options before executing the Ruby code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Mimicking Method Arguments
&lt;/h3&gt;

&lt;p&gt;You may want to support arguments in your rexe commands. It's a little kludgy, but you could do this by piping in the arguments as rexe's stdin.&lt;/p&gt;

&lt;p&gt;One of the previous examples downloaded currency conversion rates. To prepare for an example of how to do this, let's find out the available currency codes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;➜  /   &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$EUR_RATES_JSON&lt;/span&gt; | &lt;span class="se"&gt;\&lt;/span&gt;
rexe &lt;span class="nt"&gt;-ij&lt;/span&gt; &lt;span class="nt"&gt;-mb&lt;/span&gt; &lt;span class="nt"&gt;-op&lt;/span&gt; &lt;span class="s2"&gt;"self['rates'].keys.sort.join(' ')"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AUD BGN BRL CAD CHF CNY CZK DKK GBP HKD HRK HUF IDR ILS INR ISK JPY KRW MXN MYR NOK NZD PHP PLN RON RUB SEK SGD THB TRY USD ZAR
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The codes output are the legal arguments that could be sent to rexe's stdin as an argument in the command below. Let's find out the Euro exchange rate for &lt;em&gt;PHP&lt;/em&gt;, Philippine Pesos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;➜  ~   &lt;span class="nb"&gt;echo &lt;/span&gt;PHP | rexe &lt;span class="nt"&gt;-ml&lt;/span&gt; &lt;span class="nt"&gt;-op&lt;/span&gt; &lt;span class="nt"&gt;-rjson&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="s2"&gt;"rate = JSON.parse(ENV['EUR_RATES_JSON'])['rates'][self];&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
        %Q{1 EUR = #{rate} #{self}}"&lt;/span&gt;

1 EUR &lt;span class="o"&gt;=&lt;/span&gt; 58.986 PHP
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In this code, &lt;code&gt;self&lt;/code&gt; is the currency code &lt;code&gt;PHP&lt;/code&gt; (Philippine Peso). We have accessed the JSON text to parse from the environment variable we previously populated.&lt;/p&gt;

&lt;p&gt;Because we "used up" stdin for the &lt;code&gt;PHP&lt;/code&gt; argument, we needed to read the JSON data explicitly from the environment variable, and that made the command more complex. A regular Ruby script would handle this more nicely.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using the Clipboard for Text Processing
&lt;/h3&gt;

&lt;p&gt;For editing text in an editor, rexe can be used for text transformations that would otherwise need to be done manually.&lt;/p&gt;

&lt;p&gt;The system's commands for pasting to and copying from the clipboard can handle the moving of the text between the editor and rexe. On the Mac, we have the following commands:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;pbcopy&lt;/code&gt; - copies the content of its stdin &lt;em&gt;to&lt;/em&gt; the clipboard&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;pbpaste&lt;/code&gt; - copies the content &lt;em&gt;from&lt;/em&gt; the clipboard to its stdout&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's say we have the following currency codes displayed on the screen (data abridged for brevity):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AUD BGN BRL PHP TRY USD ZAR
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;...and we want to turn them into Ruby symbols for inclusion in Ruby source code as keys in a hash whose values will be the display names of the currencies, e.g "Australian Dollar").&lt;/p&gt;

&lt;p&gt;We could manually select that text and use system menu commands or keys to copy it to the clipboard, or we could do this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;➜  ~   &lt;span class="nb"&gt;echo &lt;/span&gt;AUD BGN BRL PHP TRY USD ZAR | pbcopy
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;After copying this line to the clipboard, we could run this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;➜  ~   pbpaste | rexe &lt;span class="nt"&gt;-ml&lt;/span&gt; &lt;span class="nt"&gt;-op&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="s2"&gt;"split.map(&amp;amp;:downcase).map { |s| %Q{    #{s}: '',} }.join(%Q{&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;})"&lt;/span&gt;
    aud: &lt;span class="s1"&gt;''&lt;/span&gt;,
    bgn: &lt;span class="s1"&gt;''&lt;/span&gt;,
    brl: &lt;span class="s1"&gt;''&lt;/span&gt;,
    &lt;span class="c"&gt;# ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;If I add &lt;code&gt;| pbcopy&lt;/code&gt; to the rexe command, then that output text would be copied into the clipboard instead of displayed in the terminal, and I could then paste it into my editor.&lt;/p&gt;

&lt;p&gt;Using the clipboard in manual operations is handy, but using it in automated scripts is a very bad idea, since there is only one clipboard per user session. If you use the clipboard in an automated script you risk an error situation if its content is changed by another process, or, conversely, you could mess up another process when you change the content of the clipboard. &lt;/p&gt;

&lt;h3&gt;
  
  
  Multiline Ruby Commands
&lt;/h3&gt;

&lt;p&gt;Although rexe is cleanest with short one liners, you may want to use it to include nontrivial Ruby code in your shell script as well. If you do this, you may need to add trailing backslashes to the lines of Ruby code.&lt;/p&gt;

&lt;p&gt;What might not be so obvious is that you will often need to use semicolons as statement separators. For example, here is an example without a semicolon:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;➜  ~   cowsay hello | rexe &lt;span class="nt"&gt;-me&lt;/span&gt; &lt;span class="s2"&gt;"print %Q{&lt;/span&gt;&lt;span class="se"&gt;\u&lt;/span&gt;&lt;span class="s2"&gt;001b[33m} &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
puts to_a"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;rexe: (eval):1: syntax error, unexpected tIDENTIFIER, expecting '}'
...new { print %Q{\u001b[33m} puts to_a }
...                           ^~~~
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The shell combines all backslash terminated lines into a single line of text, so when the Ruby interpreter sees your code, it's all in a single line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;➜  ~   cowsay hello | rexe &lt;span class="nt"&gt;-me&lt;/span&gt; &lt;span class="s2"&gt;"print %Q{&lt;/span&gt;&lt;span class="se"&gt;\u&lt;/span&gt;&lt;span class="s2"&gt;001b[33m} puts to_a"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Adding the semicolon fixes the problem:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;➜  ~   cowsay hello | rexe &lt;span class="nt"&gt;-me&lt;/span&gt; &lt;span class="s2"&gt;"print %Q{&lt;/span&gt;&lt;span class="se"&gt;\u&lt;/span&gt;&lt;span class="s2"&gt;001b[33m}; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
puts to_a"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt; _______
&amp;lt; hello &amp;gt;
 -------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Clearing the Require and Load Lists
&lt;/h3&gt;

&lt;p&gt;There may be times when you have specified a load or require on the command line or in the &lt;code&gt;REXE_OPTIONS&lt;/code&gt; environment variable, but you want to override it for a single invocation. Here are your options:&lt;/p&gt;

&lt;p&gt;1) Unspecify &lt;em&gt;all&lt;/em&gt; the requires or loads with the &lt;code&gt;-r!&lt;/code&gt; and &lt;code&gt;-l!&lt;/code&gt; command line options, respectively.&lt;/p&gt;

&lt;p&gt;2) Unspecify individual requires or loads by preceding the name with &lt;code&gt;-&lt;/code&gt;, e.g. &lt;code&gt;-r -rails&lt;/code&gt;. Array subtraction is used, and array subtraction removes &lt;em&gt;all&lt;/em&gt; occurrences of each element of the subtracted (subtrahend) array, so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;➜  ~   rexe &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; rails,rails,rails,-rails &lt;span class="nt"&gt;-gP&lt;/span&gt;
...
   :requires&lt;span class="o"&gt;=&amp;gt;[&lt;/span&gt;&lt;span class="s2"&gt;"pp"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;,
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;...would show that the final &lt;code&gt;-rails&lt;/code&gt; cancelled all the previous &lt;code&gt;rails&lt;/code&gt; specifications.&lt;/p&gt;

&lt;p&gt;We could have also extracted the requires list programmatically using &lt;code&gt;$RC&lt;/code&gt; (described above) by doing this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;➜  ~   rexe &lt;span class="nt"&gt;-oP&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; rails,rails,rails,-rails &lt;span class="s1"&gt;'$RC[:options][:requires]'&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"pp"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Clearing &lt;em&gt;All&lt;/em&gt; Options
&lt;/h3&gt;

&lt;p&gt;You can also clear &lt;em&gt;all&lt;/em&gt; options specified up to a certain point in time with the &lt;em&gt;clear options&lt;/em&gt; option (&lt;code&gt;-c&lt;/code&gt;). This is especially useful if you have specified options in the &lt;code&gt;REXE_OPTIONS&lt;/code&gt; environment variable, and want to ignore all of them.&lt;/p&gt;

&lt;h3&gt;
  
  
  Comma Separated Requires and Loads
&lt;/h3&gt;

&lt;p&gt;For consistency with the &lt;code&gt;ruby&lt;/code&gt; interpreter, rexe supports requires with the &lt;code&gt;-r&lt;/code&gt; option, but also allows grouping them together using commas:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;                                    vvvvvvvvvvvvvvvvvvvvv
➜  ~   &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$EUR_RATES_JSON&lt;/span&gt; | rexe &lt;span class="nt"&gt;-r&lt;/span&gt; json,awesome_print &lt;span class="s1"&gt;'ap JSON.parse(STDIN.read)'&lt;/span&gt;
                                    ^^^^^^^^^^^^^^^^^^^^^
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Files loaded with the &lt;code&gt;-l&lt;/code&gt; option are treated the same way.&lt;/p&gt;

&lt;h3&gt;
  
  
  Beware of Configured Requires
&lt;/h3&gt;

&lt;p&gt;Requiring gems and modules for &lt;em&gt;all&lt;/em&gt; invocations of rexe will make your commands simpler and more concise, but will be a waste of execution time if they are not needed. You can inspect the execution times to see just how much time is being consumed. For example, we can find out that rails takes about 0.63 seconds to load on one system by observing and comparing the execution times with and without the require (output has been abbreviated using &lt;code&gt;grep&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;➜  ~   rexe &lt;span class="nt"&gt;-gy&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; rails 2&amp;gt;&amp;amp;1 | &lt;span class="nb"&gt;grep &lt;/span&gt;duration
:duration_secs: 0.660138
➜  ~   rexe &lt;span class="nt"&gt;-gy&lt;/span&gt;          2&amp;gt;&amp;amp;1 | &lt;span class="nb"&gt;grep &lt;/span&gt;duration
:duration_secs: 0.027781
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;(For the above to work, the &lt;code&gt;rails&lt;/code&gt; gem and its dependencies need to be installed.)&lt;/p&gt;

&lt;h3&gt;
  
  
  Operating System Support
&lt;/h3&gt;

&lt;p&gt;Rexe has been tested successfully on Mac OS, Linux, and Windows Subsystem for Linux (WSL). It is intended as a tool for the Unix shell, and, as such, no attempt is made to support Windows non-Unix shells.&lt;/p&gt;

&lt;h3&gt;
  
  
  More Examples
&lt;/h3&gt;

&lt;p&gt;Here are some more examples to illustrate the use of rexe.&lt;/p&gt;




&lt;h4&gt;
  
  
  Using Rexe as a Simple Calculator
&lt;/h4&gt;

&lt;p&gt;To output the result to stdout, you can either call &lt;code&gt;puts&lt;/code&gt; or specify the &lt;code&gt;-op&lt;/code&gt; option:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;➜  ~   rexe puts 1 / 3.0
0.3333333333333333
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;or:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;➜  ~   rexe &lt;span class="nt"&gt;-op&lt;/span&gt; 1 / 3.0
0.3333333333333333
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Since &lt;code&gt;*&lt;/code&gt; is interpreted by the shell, if we do multiplication, we need to quote the expression:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;➜  ~   rexe &lt;span class="nt"&gt;-op&lt;/span&gt; &lt;span class="s1"&gt;'2 * 7'&lt;/span&gt;
14
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Of course, if you put the &lt;code&gt;-op&lt;/code&gt; in the &lt;code&gt;REXE_OPTIONS&lt;/code&gt; environment variable, you don't need to be explicit about the output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;➜  ~   &lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;REXE_OPTIONS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nt"&gt;-op&lt;/span&gt;
➜  ~   rexe &lt;span class="s1"&gt;'2 * 7'&lt;/span&gt;
14
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;






&lt;h4&gt;
  
  
  Outputting ENV
&lt;/h4&gt;

&lt;p&gt;Output the contents of &lt;code&gt;ENV&lt;/code&gt; using AwesomePrint [see footnote ^4 regarding ENV.to_s]:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;➜  ~   rexe &lt;span class="nt"&gt;-oa&lt;/span&gt; ENV
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
...
  "LANG" =&amp;gt; "en_US.UTF-8",
   "PWD" =&amp;gt; "/Users/kbennett/work/rexe",
 "SHELL" =&amp;gt; "/bin/zsh",
...
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;






&lt;h4&gt;
  
  
  Reformatting a Command's Output
&lt;/h4&gt;

&lt;p&gt;Show disk space used/free on a Mac's main hard drive's main partition:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;➜  ~   &lt;span class="nb"&gt;df&lt;/span&gt; &lt;span class="nt"&gt;-h&lt;/span&gt; | &lt;span class="nb"&gt;grep &lt;/span&gt;disk1s1 | rexe &lt;span class="nt"&gt;-ml&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="s2"&gt;"x = split; puts %Q{#{x[4]} Used: #{x[2]}, Avail: #{x[3]}}"&lt;/span&gt;
91% Used: 412Gi, Avail: 44Gi
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;(Note that &lt;code&gt;split&lt;/code&gt; is equivalent to &lt;code&gt;self.split&lt;/code&gt;, and because the &lt;code&gt;-ml&lt;/code&gt; option is used, &lt;code&gt;self&lt;/code&gt; is the line of text.&lt;/p&gt;




&lt;h4&gt;
  
  
  Formatting for Numeric Sort
&lt;/h4&gt;

&lt;p&gt;Show the 3 longest file names of the current directory, with their lengths, in descending order:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;➜  ~   &lt;span class="nb"&gt;ls&lt;/span&gt;  | rexe &lt;span class="nt"&gt;-ml&lt;/span&gt; &lt;span class="nt"&gt;-op&lt;/span&gt; &lt;span class="s2"&gt;"%Q{[%4d] %s} % [length, self]"&lt;/span&gt; | &lt;span class="nb"&gt;sort&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; | &lt;span class="nb"&gt;head&lt;/span&gt; &lt;span class="nt"&gt;-3&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;  50] Agoda_Booking_ID_9999999 49_–_RECEIPT_enclosed.pdf
&lt;span class="o"&gt;[&lt;/span&gt;  40] 679a5c034994544aab4635ecbd50ab73-big.jpg
&lt;span class="o"&gt;[&lt;/span&gt;  28] 2018-abc-2019-01-16-2340.zip
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;When you right align numbers using printf formatting, sorting the lines alphabetically will result in sorting them numerically as well.&lt;/p&gt;




&lt;h4&gt;
  
  
  Print yellow (trust me!):
&lt;/h4&gt;

&lt;p&gt;This uses an &lt;a href="https://en.wikipedia.org/wiki/ANSI_escape_code"&gt;ANSI escape code&lt;/a&gt; to output text to the terminal in yellow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;➜  ~   cowsay hello | rexe &lt;span class="nt"&gt;-me&lt;/span&gt; &lt;span class="s2"&gt;"print %Q{&lt;/span&gt;&lt;span class="se"&gt;\u&lt;/span&gt;&lt;span class="s2"&gt;001b[33m}; puts to_a"&lt;/span&gt;
➜  ~     &lt;span class="c"&gt;# or&lt;/span&gt;
➜  ~   cowsay hello | rexe &lt;span class="nt"&gt;-mb&lt;/span&gt; &lt;span class="s2"&gt;"print %Q{&lt;/span&gt;&lt;span class="se"&gt;\u&lt;/span&gt;&lt;span class="s2"&gt;001b[33m}; puts self"&lt;/span&gt;
➜  ~     &lt;span class="c"&gt;# or&lt;/span&gt;
➜  ~   cowsay hello | rexe &lt;span class="s2"&gt;"print %Q{&lt;/span&gt;&lt;span class="se"&gt;\u&lt;/span&gt;&lt;span class="s2"&gt;001b[33m}; puts STDIN.read"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  _______
 &amp;lt; hello &amp;gt;
  -------
         \   ^__^
          \  (oo)\_______
             (__)\       )\/\
                 ||----w |
                 ||     ||`
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;






&lt;h4&gt;
  
  
  More YouTube: Differentiating Success and Failure
&lt;/h4&gt;

&lt;p&gt;Let's take the YouTube example from the "Loading Files" section further. Let's have the video that loads be different for the success or failure of the command.&lt;/p&gt;

&lt;p&gt;If we put this in a load file (such as ~/.rexerc):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;play&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;piece_code&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;pieces&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="ss"&gt;hallelujah: &lt;/span&gt;&lt;span class="s2"&gt;"https://www.youtube.com/watch?v=IUZEtVbJT5c&amp;amp;t=0m20s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="ss"&gt;rick_roll:  &lt;/span&gt;&lt;span class="s2"&gt;"https://www.youtube.com/watch?v=dQw4w9WgXcQ&amp;amp;t=0m43s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="ss"&gt;valkyries:  &lt;/span&gt;&lt;span class="s2"&gt;"http://www.youtube.com/watch?v=P73Z6291Pt8&amp;amp;t=0m28s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="ss"&gt;wm_tell:    &lt;/span&gt;&lt;span class="s2"&gt;"https://www.youtube.com/watch?v=j3T8-aeOrbg"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="sb"&gt;`open &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="no"&gt;Shellwords&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;escape&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pieces&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;piece_code&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&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;play_result&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;success&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;play&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;success&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="ss"&gt;:hallelujah&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="ss"&gt;:rick_roll&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;


&lt;span class="c1"&gt;# Must pipe the exit code into this Ruby process, &lt;/span&gt;
&lt;span class="c1"&gt;# e.g. using `echo $? | rexe play_result_by_exit_code`&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;play_result_by_exit_code&lt;/span&gt;
  &lt;span class="n"&gt;play_result&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;STDIN&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;chomp&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;'0'&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;Then when we issue a command that succeeds, the Hallelujah Chorus is played [see footnote ^2]:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;➜  ~   &lt;span class="nb"&gt;uname&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$?&lt;/span&gt; | rexe play_result_by_exit_code
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;...but when the command fails, in this case, with an executable which is not found, it plays Rick Astley's "Never Gonna Give You Up":&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;➜  ~   uuuuu&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$?&lt;/span&gt; | rexe play_result_by_exit_code
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;






&lt;h4&gt;
  
  
  Reformatting Source Code for Help Text
&lt;/h4&gt;

&lt;p&gt;Another formatting example...I wanted to reformat this source code...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;         &lt;span class="s1"&gt;'i'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Inspect&lt;/span&gt;
         &lt;span class="s1"&gt;'j'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;JSON&lt;/span&gt;
         &lt;span class="s1"&gt;'J'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Pretty&lt;/span&gt; &lt;span class="no"&gt;JSON&lt;/span&gt;
         &lt;span class="s1"&gt;'n'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;No&lt;/span&gt; &lt;span class="no"&gt;Output&lt;/span&gt;
         &lt;span class="s1"&gt;'p'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Puts&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
         &lt;span class="s1"&gt;'s'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;to_s&lt;/span&gt;
         &lt;span class="s1"&gt;'y'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;YAML&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;...into something more suitable for my help text. Admittedly, the time it took to do this with rexe probably exceeded the time to do it manually, but it was an interesting exercise and made it easy to try different formats. Here it is, after copying the original text to the clipboard:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;➜  ~   pbpaste | rexe &lt;span class="nt"&gt;-ml&lt;/span&gt; &lt;span class="nt"&gt;-op&lt;/span&gt; &lt;span class="s2"&gt;"sub(%q{'}, '-o').sub(%q{' =&amp;gt;}, %q{ })"&lt;/span&gt;
         &lt;span class="nt"&gt;-oi&lt;/span&gt;  Inspect
         &lt;span class="nt"&gt;-oj&lt;/span&gt;  JSON
         &lt;span class="nt"&gt;-oJ&lt;/span&gt;  Pretty JSON
         &lt;span class="nt"&gt;-on&lt;/span&gt;  No Output
         &lt;span class="nt"&gt;-op&lt;/span&gt;  Puts &lt;span class="o"&gt;(&lt;/span&gt;default&lt;span class="o"&gt;)&lt;/span&gt;
         &lt;span class="nt"&gt;-os&lt;/span&gt;  to_s
         &lt;span class="nt"&gt;-oy&lt;/span&gt;  YAML
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;






&lt;h4&gt;
  
  
  Currency Conversion
&lt;/h4&gt;

&lt;p&gt;I travel a lot, and when I visit a country for the first time I often get confused by the exchange rate. I put this in my &lt;code&gt;~/.rexerc&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Conversion rate to US Dollars&lt;/span&gt;
&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Curr&lt;/span&gt;
  &lt;span class="kp"&gt;module_function&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;myr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;      &lt;span class="mf"&gt;4.08&lt;/span&gt;  &lt;span class="k"&gt;end&lt;/span&gt;  &lt;span class="c1"&gt;# Malaysian Ringits&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;thb&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;     &lt;span class="mf"&gt;31.72&lt;/span&gt;  &lt;span class="k"&gt;end&lt;/span&gt;  &lt;span class="c1"&gt;# Thai Baht&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;usd&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;      &lt;span class="mf"&gt;1.00&lt;/span&gt;  &lt;span class="k"&gt;end&lt;/span&gt;  &lt;span class="c1"&gt;# US Dollars&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;vnd&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="mf"&gt;23199.50&lt;/span&gt;  &lt;span class="k"&gt;end&lt;/span&gt;  &lt;span class="c1"&gt;# Vietnamese Dong&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 I'm lucky enough to be at my computer when I need to do a conversion, for example, to find the value of 150 Malaysian ringits in US dollars, I can do this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;➜  rexe git:&lt;span class="o"&gt;(&lt;/span&gt;master&lt;span class="o"&gt;)&lt;/span&gt; ✗   rexe puts 150 / Curr.myr
36.76470588235294
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Obviously rates will change over time, but this will give me a general idea, which is usually all I need.&lt;/p&gt;




&lt;h4&gt;
  
  
  Reformatting Grep Output
&lt;/h4&gt;

&lt;p&gt;I was recently asked to provide a schema for the data in my &lt;code&gt;rock_books&lt;/code&gt; accounting gem. &lt;code&gt;rock_books&lt;/code&gt; data is intended to be very small in size, and no data base is used. Instead, the input data is parsed on every run, and reports generated on demand. However, there are data structures (actually class instances) in memory at runtime, and their classes inherit from &lt;code&gt;Struct&lt;/code&gt;. The definition lines look like this one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;JournalEntry&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;Struct&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="ss"&gt;:date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:acct_amounts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:doc_short_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:description&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:receipts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;grep&lt;/code&gt; command line utility prepends each of these matches with a string like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;lib/rock_books/documents/journal_entry.rb:
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;So this is what worked well for me:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;➜  ~   &lt;span class="nb"&gt;grep &lt;/span&gt;Struct &lt;span class="k"&gt;**&lt;/span&gt;/&lt;span class="k"&gt;*&lt;/span&gt;.rb | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; OpenStruct | rexe &lt;span class="nt"&gt;-ml&lt;/span&gt; &lt;span class="nt"&gt;-op&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="s2"&gt;"a =                            &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
 gsub('lib/rock_books/', '')    &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
.gsub('&amp;lt; Struct.new',    '')    &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
.gsub('; end',           '')    &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
.split('.rb:')                  &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
.map(&amp;amp;:strip);                  &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
                                &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
%q{%-40s %-s} % [a[0] + %q{.rb}, a[1]]"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;...which produced this output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cmd_line/command_line_interface.rb       class Command (:min_string, :max_string, :action)
documents/book_set.rb                    class BookSet (:run_options, :chart_of_accounts, :journals)
documents/journal.rb                     class Entry (:date, :amount, :acct_amounts, :description)
documents/journal_entry.rb               class JournalEntry (:date, :acct_amounts, :doc_short_name, :description, :receipts)
documents/journal_entry_builder.rb       class JournalEntryBuilder (:journal_entry_context)
reports/report_context.rb                class ReportContext (:chart_of_accounts, :journals, :page_width)
types/account.rb                         class Account (:code, :type, :name)
types/account_type.rb                    class AccountType (:symbol, :singular_name, :plural_name)
types/acct_amount.rb                     class AcctAmount (:date, :code, :amount, :journal_entry_context)
types/journal_entry_context.rb           class JournalEntryContext (:journal, :linenum, :line)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Although there's a lot going on in this code, the vertical and horizontal alignments and spacing make the code straightforward to follow. Here's what it does:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;grep the code base for &lt;code&gt;"Struct"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;exclude references to &lt;code&gt;"OpenStruct"&lt;/code&gt; with &lt;code&gt;grep -v&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;remove unwanted text with &lt;code&gt;gsub&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;split the line into 1) a filespec relative to &lt;code&gt;lib/rockbooks&lt;/code&gt;, and 2) the class definition&lt;/li&gt;
&lt;li&gt;strip unwanted space because that will mess up the horizontal alignment of the output.&lt;/li&gt;
&lt;li&gt;use C-style printf formatting to align the text into two columns&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Rexe is not revolutionary technology, it's just plumbing that removes parsing, formatting, and low level configuration from your command line so that you can focus on the high level task at hand.&lt;/p&gt;

&lt;p&gt;When we consider a new piece of software, we usually think "what would this be helpful with now?". However, for me, the power of rexe is not so much what I can do with it in a single use case now, but rather what will I be able to do over time as I accumulate more experience and expertise with it.&lt;/p&gt;

&lt;p&gt;I suggest starting to use rexe even for modest improvements in workflow, even if it doesn't seem compelling. There's a good chance that as you use it over time, new ideas will come to you and the workflow improvements will increase exponentially.&lt;/p&gt;

&lt;p&gt;A word of caution though -- the complexity and difficulty of &lt;em&gt;sharing&lt;/em&gt; your rexe scripts across systems will be proportional to the extent to which you use environment variables and loaded files for configuration and shared code. Be responsible and disciplined in making this configuration and code as clean and organized as possible.&lt;/p&gt;




&lt;h4&gt;
  
  
  Footnotes
&lt;/h4&gt;

&lt;p&gt;[1]: Rexe is an embellishment of the minimal but excellent &lt;code&gt;rb&lt;/code&gt; script at &lt;a href="https://github.com/thisredone/rb"&gt;https://github.com/thisredone/rb&lt;/a&gt;. I started using &lt;code&gt;rb&lt;/code&gt; and thought of lots of other features I would like to have, so I started working on rexe.&lt;/p&gt;

&lt;p&gt;[2]: It's possible that when this page opens in your browser it will not play automatically. You may need to change your default browser, or change the code that opens the URL. Firefox's new (as of March 2019) version 66 suppresses autoplay; you can register exceptions to this policy: open Firefox Preferences, search for "autoplay" and add "&lt;a href="https://www.youtube.com"&gt;https://www.youtube.com&lt;/a&gt;".&lt;/p&gt;

&lt;p&gt;[3]: Making this truly OS-portable is a lot more complex than it looks on the surface. On Linux, &lt;code&gt;xdg-open&lt;/code&gt; may not be installed by default. Also, Windows Subsystem for Linux (WSL) out of the box is not able to launch graphical applications.&lt;/p&gt;

&lt;p&gt;Here is a &lt;em&gt;start&lt;/em&gt; at a method that opens a resource portably across operating systems:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;open_resource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resource_identifier&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;command&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sb"&gt;`uname`&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;chomp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="s1"&gt;'Darwin'&lt;/span&gt;
      &lt;span class="s1"&gt;'open'&lt;/span&gt;
    &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="s1"&gt;'Linux'&lt;/span&gt;
      &lt;span class="s1"&gt;'xdg-open'&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
      &lt;span class="s1"&gt;'start'&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt; &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;resource_identifier&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&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;[4]: It is an interesting quirk of the Ruby language that &lt;code&gt;ENV.to_s&lt;/code&gt; returns &lt;code&gt;"ENV"&lt;/code&gt; and not the contents of the &lt;code&gt;ENV&lt;/code&gt; object. As a result, many of the other output formats will also return some form of &lt;code&gt;"ENV"&lt;/code&gt;. You can handle this by specifying &lt;code&gt;ENV.to_h&lt;/code&gt;.&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>shell</category>
      <category>script</category>
    </item>
  </channel>
</rss>
