Wednesday, April 10, 2019

CLASP & libCLImate : different language implementations converging

I'm working on CLASP and libCLImate for Ruby, Go, .NET at the moment, and they're getting close to a 1.0 release, particularly CLASP.

There've been two recent releases of CLASP.Ruby:

  • 0.17 adds a CLASP::Arguments.load() method, which takes a Hash or YAML-containing file (actually an IO type), containing definitions of the flag/option/alias specifications;
  • 0.18 changes the name of the concept from alias to specification, removing the ambiguity that's been bugging me for years.
The same changes will be made in the Go and .NET versions shortly. The Python and Node versions will change in the medium term.

Once all the other variants are done, the original C/C++ library will be done.

Friday, March 29, 2019

Lots of new things to Go at ...

The Go work is marching on, with the occasionally publicly publishable parts, the most recent of which are:

  • ANGoLS (Algorithms Not found in Go Language Standard library) first release to the world;
  • STEGoL (Simple Testing Enhancements for Go Language) first release to the world;
  • CLASP.Go v0.14.2, much improved and working seamlessly with libCLImate.Go, of which:
  • libCLImate.Go v0.4.1, again much improved.
ANGoLS and STEGoL are new, and so are suffering from the Matt Wilson-disease of poor/missing documentation, but CLASP.Go and libCLImate.Go are now replete with information and examples. Checkout them out. Feedback welcomed.

Watch this space - and the Synesis Twitter and Synesis GitHub accounts - for more Go stuff in the coming weeks. libpath.Go and recls.Go are imminent. Pantheios.Go will be released by mid-year. (And there'll likely be plenty of webservice-related libraries, too, given that's the current focus of Go development here ...)

Monday, March 18, 2019

A bunch of CLASPs

CLASP - Command-Line Argument Sorting and Parsing - is a suite of libraries for sophisticated parsing of command-line arguments and presenting the parsed elements - flags, options, values - in a usable form. The original C/C++ library was released in 2011; variants for other languages have been released from time to time since.

Of necessity (but also enjoying it), currently I'm building systems in a bunch of different technologies, including GoJavascript (NodeB), Python, and Ruby. As such, I have new/updated versions of the CLASP variants for these languages:


Each of the newly-released projects - Go, js, Python - contains  (on GitHub) an EXAMPLES.md file, with links to examples. CLASP.Ruby will provide examples in a forthcoming release.

Friday, February 15, 2019

Simple cat in CoffeeScript

Further to the post "Simple cat in Node", here's a version in CoffeeScript.

#! /usr/bin/env coffee

fs = require('fs')
readline = require('readline')
paths = process.argv.slice(2)

cat = (path) ->

stm = if path then fs.createReadStream(path) else process.stdin

readline.createInterface(
input: stm
).on 'line', (line) ->

process.stdout.write line + '\n'

return

  return

if 0 == paths.length

cat null

return
else

  // process each one at a time
paths.forEach (path) ->

cat path

return


As you can see, it's very simple in structure to the JavaScript version; just simpler and with fewer parentheses. It can be further simplified by removing all the return statements, as every one is redundant in this case:

#! /usr/bin/env coffee

fs = require('fs')
readline = require('readline')
paths = process.argv.slice(2)

cat = (path) ->

stm = if path then fs.createReadStream(path) else process.stdin

readline.createInterface(
input: stm
).on 'line', (line) ->

process.stdout.write line + '\n'

if 0 == paths.length

cat null
else

  // process each one at a time
paths.forEach (path) ->

cat path




Saturday, June 18, 2016

The Strobl Interjection

The other day I was giving a Ruby programming tutorial to the team at Razor Risk, since we're introducing a suite of tools to effect automated wholesale code transmogrification of our codebase, in part to bring up-to-date the very large C++ codebase with C++ 11 / C++ 14. The element in question resides within a chunk of Ruby code that is a pattern I've been using for well over a decade, involving two loops:

  • An outer loop, that searches a given directory for a given set of patterns, using the recls.Ruby library; and
  • An inner loop, that processes the contents of a given file on a per-line basis.
In each case, we're applying each.

I've been applying this pattern for almost as long as I've been using Ruby, and it looks something like this:

Recls::FileSearch.new(root_dir, patterns, Recls::RECURSIVE | Recls::FILE).each do |fe|

  IO::readlines(fe.path).each_with_index do |line, index0|

    index = 1 + index0
    line = line.chomp

    if line =~ / . . . some regex that finds something interesting .../

      . . . do something interesting to log or change the line, ...
    end
  end
end

The first two lines of the inner-loop have been part of my idiom forever, and are explained thusly:

  • Since humans and IDEs use 1-based numbering, I always obtain a 1-based index from the 0-based one, which I name index0, obtained as the second parameter to each_with_index()'s block. So far, so good;
  • Since lines come with their end-of-line sequence - usually "\n" - this needs to be chomped off. Since it's bad practice to change objects that are held by other objects (in this case it doesn't matter, but making a habit of good practice is, er, good practice) I don't call chomp! to change the actual line, but instead obtain a chomped copy from it.
All seems quiet on the western front. Alas, as I was showing this to the team, little did I know I was about to be hoist on my own petard.

Some of the things I'm always banging on about wrt the C++ codebase include being totally unambiguous and making absolutely everything immutable that can possibly be so. One of the consequences of these two exhortations to good practice is that variables should be initialised (rather than declared and then assigned) and should be made immutable (by using const), as in:

  size_t const number_to_process = container.size() - offset_length;

rather than, say, 

  size_t number_to_process;

  number_to_process = container.size();
  number_to_process -= offset_length;

In the former case the compiler will stop you from mistakenly changing or reusing the variable; in the latter all bets are off.

Anyway, one of our implementation consultants, Bernard Strobl, has a keen interest in programming and pays a lot of attention during code reviews and tutorial sessions. As is his wont, Bernie jumped immediately and with great relish upon my transgression of good practice in my reuse of the variable line. Notwithstanding my love of my own opinion and my ability to lever bombast at high speed with almost no warm-up, when you're wrong, you're wrong.

And so I learned something, or at least remembered something that now informs a modified idiom:


Recls::FileSearch.new(root_dir, patterns, Recls::RECURSIVE | Recls::FILE).each do |fe|

  IO::readlines(fe.path).each_with_index do |line0index0|

    index = 1 + index0
    line = line0.chomp

    if line =~ / . . . some regex that finds something interesting .../

      . . . do something interesting to log or change the line, ...
    end
  end
end

As of version 0.4.12, our code transmogrification tool suite now contains corrected forms for every tool, and the commit bears the message "The Strobl Interjection" lest I forget my error.

Thanks, Bernie! :-)