    <rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:admin="http://webns.net/mvcb/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:content="http://purl.org/rss/1.0/modules/content/">
     <channel>
        <title>ACCU  :: Building C#/.NET, Go, and Ruby Programs with libCLImate â€“ Part 1: Ruby</title>
        <link>https://members.accu.org/index.php/articles/2653</link>
        <description>Professionalism in Programming</description>
        <dc:language>en-us</dc:language> 
        <dc:creator>Administrator</dc:creator> 
        <admin:generatorAgent rdf:resource="http://www.xaraya.org" /> 
        <admin:errorReportsTo rdf:resource="mailto:webeditor@accu.org" />
       <sy:updatePeriod>hourly</sy:updatePeriod>
       <sy:updateFrequency>1</sy:updateFrequency>
       <docs>http://backend.userland.com/rss</docs>




<div class="xar-mod-head"><span class="xar-mod-title">Programming Topics + CVu Journal Vol 31, #2 - May 2019</span></div>

<table border="0" cellpadding="1" cellspacing="0">
    <tbody>
    <tr>
        <td valign="top">
            Browse in :
       </td>
       <td valign="top">

                                            <a href="https://members.accu.org/index.php/articles/">All</a>

                     &gt;                         <a href="https://members.accu.org/index.php/articles/c13/">Topics</a>

                     &gt;                         <a href="https://members.accu.org/index.php/articles/c65/">Programming</a>
<br />

                                            <a href="https://members.accu.org/index.php/articles/">All</a>

                     &gt;                         <a href="https://members.accu.org/index.php/articles/c76/">Journals</a>

                     &gt;                         <a href="https://members.accu.org/index.php/articles/c77/">CVu</a>

                     &gt;                         <a href="https://members.accu.org/index.php/articles/c398/">312</a>
<br />

                                            <a href="https://members.accu.org/index.php/articles/c65-398/">Any of these categories</a>

                    -                        <a href="https://members.accu.org/index.php/articles/c65+398/">All of these categories</a>
<br />
</td>
   </tr>
   </tbody>
</table>




<div class="xar-error">
   <p>
 <strong>Note:</strong> when you create a new publication type,
the articles module will automatically use the templates
<em>user-display-[publicationtype].xt</em>
and <em>user-summary-[publicationtype].xt</em>.
If those templates do not exist when you try to preview or display a new article,
you'll get this warning :-)  Please place your own templates in themes/<em>yourtheme</em>/modules/articles . The templates will get the extension .xt there. </p>
</div>
<div class="xar-norm xar-standard-box-padding">
   <h1><strong>Title:</strong>&nbsp;Building C#/.NET, Go, and Ruby Programs with libCLImate â€“ Part 1: Ruby</h1>
<p><strong>Author:</strong>&nbsp;Bob Schmidt</p>
<p>
<strong>Date:</strong> 05 May 2019 23:33:51 +01:00 or Sun, 05 May 2019 23:33:51 +01:00</p>
<p><strong>Summary:</strong>&nbsp;Matthew Wilson demonstrates command-line processing.</p>
<p><strong>Body:</strong>&nbsp;<p>This article, the fourth in a series about software anatomy, describes some of my ongoing efforts to provide simple, succinct, easy, and, most importantly, consistent command-line argument processing across multiple languages. It, and the next one, build upon the observations of the first three articles, which pertained to building command-line interface (CLI) programs in C and C++, illustrating how the topic may be handled for the languages C#/.NET, Go, and Ruby, all of which have featured heavily in my career in the intervening years. As well as introducing readers to the respective Go, .NET and Ruby variants of the <strong>libCLImate</strong> and <strong>CLASP</strong> libraries, I will discuss how the features of these younger languages offer increased expressiveness and flexibility over C and C++, including how to work around some of their limitations.</p>

<h2>Introduction</h2>

<p>Command-line interface (CLI) programs often take arguments from the operating environment in order to control their behaviour. The shell breaks up the command-line (based on whitespace, except where quotes are operative) and presents this sequence of argument strings to the program. There are several, sometimes contradictory, conventions for how to classify arguments, including by the IEEE <a href="#[1]">[1]</a>, GNU <a href="#[2]">[2]</a>, Go <a href="#[3]">[3]</a>.</p>

<p>Consider the command-line:</p>

<pre class="programlisting">
  $ count_slocs &quot;C++ code&quot; -D --terse     --log-file=./log1 '*.cpp' '*.hpp'</pre>

<p>In this case, the program <code>count_slocs</code> would be passed six arguments, based primarily on the separating whitespace. Thereâ€™s a label argument <code>&quot;C++ code&quot;</code> which is enclosed within double-quotes, which instructs the shell to treat all characters within (but not including) the double-quotes as a single argument. There are two arguments containing wildcards â€“ <code>'*.cpp'</code> and <code>'*.hpp'</code> â€“ that are each enclosed within single quotes, in order to tell the shell not to expand them. Each of these three arguments is just a <em>value</em>.</p>

<p>The remaining three arguments are different, insofar as they are prefixed with hyphens. The arguments <code>-D</code> and <code>--terse</code> are <em>flag</em>s. The argument <code>--log-file=./log1</code> is an <em>option</em>.</p>

<p>The terms <em>flag</em>, <em>option</em>, and <em>value</em> are my names for these concepts, as described in my article â€˜An Introduction to CLASP, part 1: Câ€™ <a href="#[4]">[4]</a>. The basic rules are pretty simple:</p>

<ul>
	<li>if the argument does not begin with a hyphen (<code>-</code>) then it is a <em>value</em>; else</li>
	
	<li>if the argument contains an equals sign (<code>=</code>) then it is an <em>option</em> (and the parts before and after the equals sign are known as the <em>option name</em> and <em>option value</em>, respectively); else</li>
	
	<li>it is a <em>flag</em>.</li>
</ul>

<p>There are, of course, complications, including:</p>

<ul>
	<li>After the first occurrence of the special flag <code>--</code>, all arguments should be treated as values (regardless of any leading hyphen(s));</li>
	
	<li>Some program(mer)s prefer to be able to specify options separated by a space, e.g. the above option would alternatively be specified as <code>--log-file ./log1</code>. Naturally, for this to be recognised as two (separate argument) parts of a single option, something in the program has to know that <code>--log-file</code> is an option name, and that the next argument will the option value;</li>
	
	<li>Some program(mer)s prefer to be able to specify multiple flags (that have a single hyphen and a single letter) in combination so that, for example, the following command-line consisting of such flags:

		<pre class="programlisting">
  $ myprog -c -D -x</pre>
	
		<p>can be expressed alternately as</p>
		
		<pre class="programlisting">
  $ myprog -cDx</pre>

		<p>and obtain precisely the same behaviour.</p>
	</li>
</ul>

<p>(Thereâ€™s also a common convention to use the special flag <code>&quot;-&quot;</code> to mean standard-input, but that doesnâ€™t affect parsing so I wonâ€™t mention it further.)</p>

<h3>Obtaining command-line arguments</h3>

<p>Different languages have different mechanisms for obtaining command-line arguments:</p>

<ul>
	<li>C and C++ are provided the argument pair <code>argc : int , argv : char*[]</code> to the program entry point <code>main()</code>;</li>
	
	<li>C#/.NET are provided an array of <code>System.String</code> to the program entry point <code>Main()</code>;</li>
	
	<li>Python and Ruby do not have program entry points in the same way, and instead obtain the <code>sys.argv</code> property (a list) and global variable <code>ARGV</code> (an array), respectively;</li>
	
	<li>While Go does have a program entry point, it takes no arguments. The program-arguments are obtained from the exported array (<code>[]string</code>) <code>os.Argv</code>.</li>
</ul>

<h3>CLASP</h3>

<p>CLASP stands for Command-Line Argument Parsing and Sorting. In essence, CLASP libraries parse command-lines to recognise flags, options, and values, and then presents them in a convenient set of sequences as part of a data structure representing the command-line (along with other useful information, such as program-name, and so forth).</p>

<p>The CLASP library concept started out with a C/C++ library, cunningly called CLASP, which was introduced to the world in <a href="#[5]">[5]</a> and further discussed in the three preceding parts of this anatomies series <a href="#[4]">[4]</a> <a href="#[6]">[6]</a> <a href="#[7]">[7]</a>.</p>

<p>CLASP has subsequently been implemented in a number of different languages, including C#/.NET, Go, JavaScript, Python, and Ruby (all of which projects are available under <a href="https://github.com/synesissoftware">https://github.com/synesissoftware</a>).</p>

<p>As is the way of these things, different amounts of attention applied at different times, along with the strong influence of language limitations and conventions, have led to some differences, but fundamentally all perform the parsing and sorting (into flags, options, and values).</p>

<p>I found the use of CLASP to be a huge boon to productivity, not only because it provides often missing functionality, but also because having the same model in different languages means thinking time is kept to a useful minimum.</p>

<h3>libCLImate</h3>

<p>Despite the considerable advantages afforded by using CLASP, there are still tasks that one finds oneself performing again and again and again across projects. The most obvious ones are handling of the <em>de facto</em> standard <code>--help</code> and <code>--version</code>. But there are plenty of others, including:</p>

<ul>
	<li>checking whether any unrecognised flags/options are received;</li>
	<li>checking whether any required flags/options have been specified;</li>
	<li>checking whether too many, or too few, values have been specified;</li>
	<li>issuing contingent reports of a consistent form, in particular that they begin with <code>program-name :</code>;</li>
</ul>

<p>â€¦and many more.</p>

<p>The situation begged for a higher-level library, implemented in terms of CLASP, that provides most/all of this behaviour.</p>

<p>In the third part of this series, â€˜Building C &amp; C++ CLI Programs with the libCLImate Mini-frameworkâ€™ <a href="#[7]">[7]</a>, I described in detail the design and implementation of the original <strong>libCLImate</strong> library, which provide many of these extra facilities for C/C++. Since that time (2015), I have continued to use the notion of a library providing boilerplate facilities that it is implemented in terms of CLASP, and have so far built and released variants for Go, C#/.NET, and Ruby. (It is reasonably likely that that Python version will be released by the time youâ€™re reading this.)</p>

<p>(NOTE: after an exhaustive process of consultation with the esteemed members of the ACCU, the name <strong>libCLImate</strong> was accepted so that â€œ<em>every pull request will result in CLImate change</em>â€. Arf. Arf.)</p>

<p>As described in <a href="#[7]">[7]</a>, due to the limitations of the runtime libraries the C/C++ <strong>libCLImate</strong> includes additional features and dependencies for diagnostics. Furthermore, because of the inherent limitations of the language, and because the library supports both C and C++, setting up many elements for a given program are still quite verbose. I plan soon to use some C++-11/14/17 features to address the second problem, and am optimistic that it can all be made simpler and more succinct in client code. However, the dependencies on the diagnostic libraries will likely stay, because they solve a still-glaring omission of the C/C++ environment.</p>

<p>Conversely, with the other languages, the implementation of <strong>libCLImate</strong> is much simpler, and the use of the library in programs is very succinct indeed, as I will shortly demonstrate. I think this has been because <strong>libCLImate.Ruby</strong> was the first (after the original), and Iâ€™ve noticed that when I write libraries in Ruby that subsequently are ported to other  languages that the high expressiveness common in Ruby tends to get carried across.</p>

<h2>libCLImate.Ruby</h2>

<p>As mentioned above, since this is the oldest port, itâ€™s also the most fully featured (and widely tested). Letâ€™s consider how we might implement the notional program <code>count_slocs</code> from the introduction.</p>

<h3>Basic boilerplate</h3>

<p>The basic boilerplate of a libCLImate.Ruby program is as shown below:</p>

<pre class="programlisting">
  #! /usr/bin/env ruby
  require 'libclimate'
  options = {}
  climate = LibCLImate::Climate.new do |cl|
    # customise here
  end
  r = climate.parse ARGV</pre>
  
<p>Even without customising it in any way, we get a fair amount of useful functionality:</p>

<ul>
	<li>Support for <code>--help</code>:

		<pre class="programlisting">
$ ./count_slocs --help</pre>

		<p>yields the output:</p>

		<pre class="programlisting">
USAGE: count_slocs [... flags and options...]
flags/options:
--help
  shows this help and terminates
--version
  shows version and terminates</pre>
	</li>

	<li>Policing any unrecognised flags:

		<pre class="programlisting">
$ ./count_slocs -D</pre>

		<p>yields the contingent report (and non-0 exit code):</p>
		
		<pre class="programlisting">
count_slocs: unrecognised flag '-D'; use --help for usage</pre>
	</li>

	<li>Policing any unrecognised options:

		<pre class="programlisting">
$ ./count_slocs --log-file=./log1</pre>

		<p>yields the contingent report (and non-0 exit code):</p>
		
		<pre class="programlisting">
count_slocs: unrecognised option '--log-file=./log1'; use --help for usage</pre>
	</li>
</ul>

<h3>Specifying version</h3>

<p>However, if we run with <code>--version</code> we get a nasty surprise, as shown in Figure 1.</p>

<table class="sidebartable">
	<tr>
		<td>
			<pre class="programlisting"><span class="dimmed">
[...].../gems/clasp-ruby-0.16.0/lib/clasp/cli.rb:88:in</span>
`generate_version_string_': options must specify :version or :version_major [ + :version_minor [ + :version_revision [ + :version_build ]]] (ArgumentError)<span class="dimmed">
  from [...].../gems/clasp-ruby-0.16.0/lib/clasp/cli.rb:282:in
`show_version'
  from
[...]libCLImate/libCLImate.Ruby/trunk/lib/libclimate/climate.rb:179:in `show_version_'
  from
[...]libCLImate/libCLImate.Ruby/trunk/lib/libclimate/climate.rb:321:in `block in initialize'
  from
[...]libCLImate/libCLImate.Ruby/trunk/lib/libclimate/climate.rb:466:in `block in parse'
  from
[...]libCLImate/libCLImate.Ruby/trunk/lib/libclimate/climate.rb:438:in `each'
  from
[...]libCLImate/libCLImate.Ruby/trunk/lib/libclimate/climate.rb:438:in `parse'
  from ./count_slocs:9:in `&lt;main&gt;'</span>
			</pre>
		</td>
	</tr>
	<tr>
		<td class="title">Figure 1</td>
	</tr>
</table>

<p>This is because we havenâ€™t specified any version information. This can be done as a string, or an array of strings or integers (or mixed), as in:</p>

<pre class="programlisting"><span class="dimmed">
  climate = LibCLImate::Climate.new do |cl|
    # customise here</span>
    cl.version = [ 0, 0, 1 ]<span class="dimmed">
  end</span></pre>

<p>Now running with <code>--version</code> gives:</p>

<pre class="programlisting">
  count_slocs 0.0.1.alpha-1</pre>

<h3>Specifying program-specific flags</h3>

<p>Now letâ€™s add support for the flags <code>-D</code> and <code>--terse</code>. This is done via the <code>Climate#add_flag</code> method, which takes a name, an optional number of options, and an optional block to be executed if the flag is specified on the command-line (see Listing 1).</p>

<table class="sidebartable">
	<tr>
		<td>
			<pre class="programlisting"><span class="dimmed">
climate = LibCLImate::Climate.new do |cl|
  cl.version = [ 0, 0, 1, 'alpha-1' ]</span>
  cl.add_flag('-D', help: 'runs in debug mode') {
    options[:debug] = true }
  cl.add_flag('--terse', 
    help: 'minimal program output') { 
    options[:terse] = true }<span class="dimmed">
end</span>
			</pre>
		</td>
	</tr>
	<tr>
		<td class="title">Listing 1</td>
	</tr>
</table>

<p>When either of these flags is specified on the command-line its respective presence is recorded in the <code>options</code> hash, for consumption in the program proper. The <code>help</code> strings are used for the <code>--help</code> flag, which Iâ€™ll show in full later.</p>

<h3>Specifying program-specific options</h3>

<p>Adding support for the <code>--log-file</code> option follows in the same vein (see Listing 2).</p>

<table class="sidebartable">
	<tr>
		<td>
			<pre class="programlisting"><span class="dimmed">
climate = LibCLImate::Climate.new do |cl|
  ...
  cl.add_flag('--terse',
    help: 'minimal program output') {
    options[:terse] = true }</span>
  cl.add_option('--log-file',
    help: 'specifies the log-file') do |o|
    options[:log_file] = o.value or \
      cl.abort &quot;no log-file specified&quot;
  end<span class="dimmed">
end</span>
			</pre>
		</td>
	</tr>
	<tr>
		<td class="title">Listing 2</td>
	</tr>
</table>

<p>As you can see, this is very similar to adding a flag, except that the block takes a parameter of the actual parsed option, the value of which is placed into the <code>options</code> hash. If <code>o.value</code> is nil, which would happen if the last argument of the command-line is <code>--log-file</code> (without an <code>=</code>) an abort is executed, as in:</p>

<pre class="programlisting">
  $ count_slocs -D --terse --log-file</pre>
  
<p>which yields the contingent report (and non-0 exit code):</p>

<pre class="programlisting">
  count_slocs: no log-file specified</pre>
  
<p>If you also wished to reject an empty log-file (e.g. is passed <code>--log-file=</code>) then you could do:</p>

<pre class="programlisting">
  ( options[:log_file] = ( o.value ||'')).empty? 
  and cl.abort &quot;no log-file specified&quot;</pre>

<h3>Constraining values</h3>

<p>Letâ€™s now consider the values. In the example we had three values: the label, the implementation files filter, and the header files filter. Now obviously in the real world itâ€™s more likely that rather than two filters thereâ€™d be one or more filters, but for now letâ€™s pretend we want exactly two. As the program stands right now you can specify any number of values and it wonâ€™t care.</p>

<p>One way to do this is to obtain the values from the parse result, <code>r</code>, as in:</p>

<pre class="programlisting"><span class="dimmed">
  r = climate.parse_and_verify ARGV</span>
  unless 3 == r.values.size
    climate.abort &quot;must specify three values; use    --h-help for usage&quot;
  end</pre>
  
<p>But thatâ€™s just a generic message, and youâ€™re having to manually check. Instead, you can constrain the values, and give meaningful names to the values by customising the <code>Climate</code> instance (see Listing 3).</p>

<table class="sidebartable">
	<tr>
		<td>
			<pre class="programlisting"><span class="dimmed">
climate = LibCLImate::Climate.new do |cl|
  ...
  cl.add_option('--log-file', help: 'specifies
    the log-file') do |o|
    options[:log_file] = o.value or \
      cl.abort &quot;no log-file specified&quot;
  end</span>
  cl.constrain_values = 3
  cl.value_names = [
    'label',
    'implementation files filter',
    'header files filter',
  ]
  cl.usage_values = '&lt;label&gt; &lt;impl-filter&gt;
  &lt;hdr-filter&gt;'<span class="dimmed">
end</span>
			</pre>
		</td>
	</tr>
	<tr>
		<td class="title">Listing 3</td>
	</tr>
</table>

<p>Now, if you run with, say, one argument:</p>

<pre class="programlisting">
  $ ./count_slocs &quot;C++ code&quot;</pre>
  
<p>Youâ€™ll get the contingent report (and non-0 exit code):</p>

<pre class="programlisting">
  count_slocs: implementation files filter not
  specified; use --help for usage</pre>
  
<p>And with two:</p>

<pre class="programlisting">
  $ ./count_slocs &quot;C++ code&quot; '*.cpp'</pre>
  
<p>Youâ€™ll get the contingent report (and non-0 exit code):</p>

<pre class="programlisting">
  count_slocs: header files filter not specified;
  use --help for usage</pre>

<h3>Enhancing usage</h3>

<p>If you take the advice and specify <code>--help</code> then youâ€™ll get the output shown in Figure 2.</p>

<table class="sidebartable">
	<tr>
		<td>
			<pre class="programlisting">
USAGE: count_slocs [ ... flags and options ... ]
&lt;label&gt; &lt;impl-filter&gt; &lt;hdr-filter&gt;

flags/options:
  --help
    shows this help and terminates
  --version
    shows version and terminates
  -D
    runs in debug mode
  --terse
    minimal program output
  --log-file=&lt;value&gt;
    specifies the log-file
			</pre>
		</td>
	</tr>
	<tr>
		<td class="title">Figure 2</td>
	</tr>
</table>

<p>This is reasonably good, but it can be better. We can specify some informational lines as shown in Listing 4.</p>

<table class="sidebartable">
	<tr>
		<td>
			<pre class="programlisting"><span class="dimmed">
climate = LibCLImate::Climate.new do |cl|
  ...
  cl.usage_values = '&lt;label&gt; &lt;impl-filter&gt;
    &lt;hdr-filter&gt;'</span>
  cl.info_lines = [
    'libCLImate.Ruby example for CVu',
    nil,
    :version,
    nil,
  ]<span class="dimmed">
end</span>
			</pre>
		</td>
	</tr>
	<tr>
		<td class="title">Listing 4</td>
	</tr>
</table>

<p>Now <code>--help</code> gives the output shown in Figure 3.</p>

<table class="sidebartable">
	<tr>
		<td>
			<pre class="programlisting">
libCLImate.Ruby example for CVu
count_slocs 0.0.1.alpha-1
USAGE: count_slocs [ ... flags and options ... ]
  &lt;label&gt; &lt;impl-filter&gt; &lt;hdr-filter&gt;
flags/options:
  --help
    shows this help and terminates
  --version
    shows version and terminates
  -D
    runs in debug mode
  --terse
    minimal program output
  --log-file=&lt;value&gt;
    specifies the log-file
			</pre>
		</td>
	</tr>
	<tr>
		<td class="title">Figure 3</td>
	</tr>
</table>

<h3>Flag aliases</h3>

<p>With the current definitions, we have to specify <code>-D</code> and <code>--terse</code> separately. However, CLASP (in all its guises) allows the combination of single-hyphen single-letter flags. This can be easily achieved by adding an alias property <code>-t</code> for <code>--terse</code>, as in:</p>

<pre class="programlisting"><span class="dimmed">
  climate = LibCLImate::Climate.new do |cl|
  cl.version = [ 0, 0, 1, 'alpha-1' ]
  cl.add_flag('--terse',</span> alias: '-t'<span class="dimmed">, help:
  'minimal program output') {
    options[:terse] = true }
  end</span></pre>

<p>Now the two can be combined, as in:</p>

<pre class="programlisting">
  $ ./count_slocs -Dt ... other args ...</pre>
  
<p>And this acts exactly as if theyâ€™d been supplied separately.</p>

<h3>Option aliases</h3>

<p>Options can have aliases two. For example, we could add an alias for <code>--log-file</code> to, say, <code>-f</code>, just in the same way as done for the flag above. This would allow for the long form expression seen already, as well as for a short(er) form as in:</p>

<pre class="programlisting">
  $ ./count_slocs -l ./log1 ... other args ...</pre>
  
<p>But thereâ€™s a much more interesting way of using aliases with options. Consider that we change the flag <code>--terse</code> to an option <code>--verbosity</code> that can take a set of verbosity values and that, further, we have the flag <code>-t</code> instead be equivalent to specifying <code>--verbosity=terse</code>. This is supported by all versions of CLASP, and that filters through to use in <strong>libCLImate.Ruby </strong>(see Listing 5).</p>

<table class="sidebartable">
	<tr>
		<td>
			<pre class="programlisting">
VERBOSITIES = %w{ silent terse normal chatty
  verbose }<span class="dimmed">
climate = LibCLImate::Climate.new do |cl|
  ...
  cl.add_flag('-D', help: 'runs in debug mode') {
    options[:debug] = true }</span>
  cl.add_option('--verbosity', help: 'specifies
    verbosity of program output', 
    values: VERBOSITIES) do |o|
      options[:verbosity] and \
        cl.abort 'already specified verbosity'
      options[:verbosity] = o.value
  end
  VERBOSITIES.each do |v|
    # === cl.add_alias('--verbosity=terse', '-t')
    cl.add_alias(&quot;--verbosity=#{v}&quot;, &quot;-#{v[0]}&quot;)
  end<span class="dimmed">
  ...
end</span>
			</pre>
		</td>
	</tr>
	<tr>
		<td class="title">Listing 5</td>
	</tr>
</table>

<p>This code specifies an option, <code>--verbosity</code>, along with description string, a values list, and several combinable flag aliases, which would mean that the <code>-Dt</code> (and so forth) argument is still valid. And all this information is useful for the usage when applying <code>--help</code> (see Figure 4).</p>

<table class="sidebartable">
	<tr>
		<td>
			<pre class="programlisting">
libCLImate.Ruby example for CVu
count_slocs 0.0.1.alpha-1
USAGE: count_slocs [ ... flags and options ... ]
   &lt;label&gt; &lt;impl-filter&gt; &lt;hdr-filter&gt;
flags/options:
  --help
    shows this help and terminates
  --version
    shows version and terminates
  -D
    runs in debug mode
  -s --verbosity=silent
  -t --verbosity=terse
  -n --verbosity=normal
  -c --verbosity=chatty
  -v --verbosity=verbose
  --verbosity=&lt;value&gt;
    specifies verbosity of program output
    where &lt;value&gt; one of:
      silent
      terse
      normal
      chatty
      verbose
  --log-file=&lt;value&gt;
    specifies the log-file
			</pre>
		</td>
	</tr>
	<tr>
		<td class="title">Figure 4</td>
	</tr>
</table>

<h3>Obtaining results</h3>

<p>In a real program, you will likely use blocks for flags and options as Iâ€™ve shown. But if you prefer, you can instead process them from the collections supplied in the parse result. For now, weâ€™ll just print them out thusly:</p>

<pre class="programlisting">
  puts &quot;flags (#{r.flags.size}):&quot;
  r.flags.each { |f| puts &quot;\t#{f}&quot; }
  puts &quot;options (#{r.options.size}):&quot;
  r.options.each { |o| puts &quot;\t#{o}&quot; }
  puts &quot;values (#{r.values.size}):&quot;
  r.values.each { |v| puts &quot;\t#{v}&quot; }</pre>
  
<p>With the command-line</p>

<pre class="programlisting">
  $ ./count_slocs -Dt --log-file=./log1 &quot;C++ code&quot;  '*.cpp' '*.hpp'</pre>
  
<p>This yields the output:</p>

<pre class="programlisting">
  flags (1):
    -D
  options (2):
    --verbosity=terse
    --log-file=./log1
  values (3):
    C++ code
    *.cpp
    *.hpp</pre>

<h3>Final code</h3>

<p>All, up all this code (excluding the printing of the flags/options/values collections) comes in at under 45 lines of code, as shown in full in Listing 6.</p>

<table class="sidebartable">
	<tr>
		<td>
			<pre class="programlisting">
#! /usr/bin/env ruby
require 'libclimate'
VERBOSITIES = %w{ silent terse normal chatty
  verbose }
options = {}
climate = LibCLImate::Climate.new do |cl|

  # customise here
  cl.version = [ 0, 0, 1, 'alpha-1' ]
  cl.add_flag('-D', help: 'runs in debug mode') {
    options[:debug] = true }
  cl.add_option('--verbosity', help: 'specifies
    verbosity of program output',
    values: VERBOSITIES) do |o|
      options[:verbosity] and \
        cl.abort 'already specified verbosity'
      options[:verbosity] = o.value
  end

  VERBOSITIES.each do |v|
    cl.add_alias(&quot;--verbosity=#{v}&quot;, &quot;-#{v[0]}&quot;)
  end

  cl.add_option('--log-file', required: true,
    help: 'specifies the log-file') do |o|
      options[:log_file] = o.value or \
        cl.abort &quot;no log-file specified&quot;
  end

  cl.constrain_values = 3
  cl.value_names = [
    'label',
    'implementation files filter',
    'header files filter',
  ]
  cl.usage_values = '&lt;label&gt; &lt;impl-filter&gt; 
    &lt;hdr-filter&gt;'

  cl.info_lines = [
    'libCLImate.Ruby example for CVu',
    nil,
    :version,
    nil,
  ]
end
r = climate.parse_and_verify ARGV

			</pre>
		</td>
	</tr>
	<tr>
		<td class="title">Listing 6</td>
	</tr>
</table>

<h2>Next time</h2>

<p>In the next instalment Iâ€™ll provide a much more chopped down presentation of equivalent programs in C# using libCLImate.NET and Go using libCLImate.Go, and then will go into details about the different facilities in the respective languages that help with the expressiveness and flexibility of such libraries. More importantly, perhaps, I will also go into those aspects in the languages that impede such, and how I have gone about addressing them with somewhat advanced features - anonymous structures and reflection in C#; extensions and monkey-patching in Ruby; strong typedefs and type-switches in Go - in order to have a consistent programmer and user experience across the different technologies.</p>

<p>For now, hereâ€™re three teaser trailers for next time.</p>

<h3>More powerful option value processing in Ruby</h3>

<p>As a little teaser for next time, permit me to illustrate how the verbosity values can be made even than bit more useable, to both user and programmer, by allow option value initials to be specified on the command-line and then automatically tested and converted into Ruby symbols in the code. Consider the changes in Listing 7.</p>

<table class="sidebartable">
	<tr>
		<td>
			<pre class="programlisting"><span class="dimmed">
require 'libclimate'</span>
require 'xqsr3/extensions/string/
  map_option_string'
...

VERBOSITIES = %w{ [s]ilent [t]erse [n]ormal
  [c]hatty [v]erbose }<span class="dimmed">
...
  cl.add_option('--verbosity', help: 'specifies
    verbosity of program output',
    values: VERBOSITIES) do |o|
      options[:verbosity] and cl.abort 'already
        specified verbosity'
      options[:verbosity] = 
        o.value</span> .map_option_string(VERBOSITIES)
        or \
        cl.abort &quot;invalid verbosity '#{o.value}';
        use --help for usage&quot;<span class="dimmed">
  end
  VERBOSITIES.each do |v|</span>
    v = v.gsub /[\[\]]/, ''<span class="dimmed">
    cl.add_alias(&quot;--verbosity=#{v}&quot;, &quot;-#{v[0]}&quot;)
  end
  ...</span>
			</pre>
		</td>
	</tr>
	<tr>
		<td class="title">Listing 7</td>
	</tr>
</table>

<p>This uses one of the <code>String</code> class extensions provided by the <strong>Xqsr3</strong> library (another of mine - https://github.com/synesissoftware/xqsr3) to allow string values to be interpreted in full or via a contraction (the part inside the square brackets) against a known set of values such as <code>VERBOSITIES</code>, obtaining as the result a Ruby symbol. If not matched, <code>nil</code> is obtained, and the <code>abort</code> is fired. For example, the command-line</p>

<pre class="programlisting">
  $ ./count_slocs --verbosity=s ... other args ...</pre>
  
<p>cause the <code>options[:verbosity]</code> value to be <code>:silent</code>, whereas the command-line</p>

<pre class="programlisting">
  $ ./count_slocs --verbosity=j ... other args ...</pre>
  
<p>precipitates the contingent report (and a non-0 exit code):</p>

<pre class="programlisting">
  count_slocs: invalid verbosity 'j'; use --help
  for usage</pre>

<h3>count_slocs in Go</h3>

<p>Listing 8 contains the equivalent program in Go (written in terms of libCLImate.Go and CLASP.Go).</p>

<table class="sidebartable">
	<tr>
		<td>
			<pre class="programlisting">
package main
import (
  clasp &quot;github.com/synesissoftware/CLASP.Go&quot;
  libclimate &quot;github.com/synesissoftware/
    libCLImate.Go&quot;
  &quot;fmt&quot;
  &quot;os&quot;
  &quot;strings&quot;
)
const (
  verbosities =
   &quot;silent|terse|normal|chatty|verbose&quot;
)

func main() {
  debug := false
  verbosity := &quot;&quot;
  fl_Debug := clasp.Flag(&quot;-D&quot;).
    SetHelp(&quot;runs in debug mode&quot;)
  opt_Verb := clasp.Option(&quot;--verbosity&quot;).
    SetHelp(&quot;specifies verbosity of program
    output&quot;).
    SetValues(strings.Split(verbosities, &quot;|&quot;)...)
  climate, err := libclimate.Init(func 
      (cl *libclimate.Climate) (error) {
    cl.AddFlagFunc(fl_Debug, func () {
      debug = true })
    cl.AddOptionFunc(opt_Verb, func 
      (o *clasp.Argument, a *clasp.Alias) {
        verbosity = o.Value
    })
    for _, v := range(strings.Split(verbosities,
      &quot;|&quot;)) {
        cl.AddAlias(&quot;--verbosity=&quot; + v,
          &quot;-&quot; + v[0:1])
    }
    return nil
  })
  if err != nil {
    fmt.Fprintf(os.Stderr, 
      &quot;failed to create CLI parser: %v\n&quot;, err)
  }
  _, _ = climate.ParseAndVerify(os.Args)
  
  // Program-specific processing of flags/options
  if 0 != len(verbosity) {
    fmt.Printf(&quot;verbosity is specified as: %s\n&quot;,
    verbosity)
  }
  if debug {
    fmt.Printf(&quot;Debug mode is specified\n&quot;)
  }
  // Finish normal processing
  return
}
			</pre>
		</td>
	</tr>
	<tr>
		<td class="title">Listing 8</td>
	</tr>
</table>

<h3>count_slocs in C#</h3>

<p>Listing 9 contains the C# version.</p>

<table class="sidebartable">
	<tr>
		<td>
			<pre class="programlisting">
namespace CVu_example
{
  using global::LibCLImate;
  using Clasp =
    global::SynesisSoftware.SystemTools.Clasp;
  using System;
  static class Program
  {
    static int Main(string[] args)
    {
      bool debug = false;
      string verbosity = null;
      Climate climate = Climate.Init((cl) =&gt; {
        cl.AddFlag(&quot;--debug&quot;
        , new { 
          Alias = &quot;-d&quot;,
          Help = &quot;runs in Debug mode&quot; }
        , (f, a) =&gt; {debug = true;}
      );

        cl.AddOption(&quot;--verbosity&quot;
        , new
        {
          Alias = &quot;-v&quot;,
          Help = &quot;specifies the verbosity&quot;,
          Values = new string[] { &quot;silent&quot;,
            &quot;terse&quot;, &quot;normal&quot;, &quot;chatty&quot;,
            &quot;verbose&quot; },
          Default = &quot;chatty&quot;,
          Required = true,
        }, (o, a) =&gt;
        {
          verbosity = o.Value;
        });
        cl.AddAlias(&quot;--verbosity=chatty&quot;, &quot;-c&quot;);

        cl.SetInfoLines(
          &quot;libCLImate.NET examples&quot;,
          null,
          &quot;:version:&quot;,
          null
        );
        cl.SetUsageValues(&quot;&lt;path&gt;&quot;);
      });

      var r = climate.ParseAndVerify(args);

      if(null != verbosity)
      {
        Console.WriteLine(
          &quot;verbosity is specified as: {0}&quot;,
          verbosity);
      }

      if(debug)
      {
        Console.WriteLine(
          &quot;Debug mode is specified&quot;);
      }
      return 0;
    }
  }
}
			</pre>
		</td>
	</tr>
	<tr>
		<td class="title">Listing 9</td>
	</tr>
</table>

<h2>References</h2>

<p class="bibliomixed"><a id="[1]"></a>[1]	The Open Group Base Specifications Issue 7, 2018 edition, section 12: Utility conventions, at <a href="http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap12.html">http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap12.html</a></p>

<p class="bibliomixed"><a id="[2]"></a>[2]	GNU manual: <a href="http://www.gnu.org/software/libc/manual/html_node/Getopt-Long-Options.html">http://www.gnu.org/software/libc/manual/html_node/Getopt-Long-Options.html</a></p>

<p class="bibliomixed"><a id="[3]"></a>[3]	The Go Programming Language: <a href="https://golang.org/pkg/flag">https://golang.org/pkg/flag</a></p>

<p class="bibliomixed"><a id="[4]"></a>[4]	Anatomy of a CLI Program written in C, Matthew Wilson, <em>CVu </em>24.4, September 2012.</p>

<p class="bibliomixed"><a id="[5]"></a>[5]	An introduction to CLASP, part 1: C, Matthew Wilson, <em>CVu </em>23.6, January 2012</p>

<p class="bibliomixed"><a id="[6]"></a>[6]	Anatomy of a CLI Program written in C++, Matthew Wilson, <em>CVu</em> 27.4, September 2015.</p>

<p class="bibliomixed"><a id="[7]"></a>[7]	Building C &amp; C++ Programs with the libCLImate Mini-framework , Matthew Wilson, <em>CVu </em>27.5, November 2015</p>

<p class="bio"><span class="author"><b>Matthew Wilson</b></span> Matthew is a software development consultant and trainer for Synesis Software who helps clients to build high-performance software that does not break, and an author of articles and books that attempt to do the same.</p>
</p>
<p><strong>Notes:</strong>&nbsp;</p>
<p><em>More fields may be available via dynamicdata ..</em></p>
</div>
</channel>
</rss>
