Argument_parser_number_9

One thing I return to again and again, is parsing arguments. I have studied most of the available options for ruby: optimist, optimist_xl, rationalist, slop etc.

I have also built several parsers of my own.. using different approaches.

Today I started thinking: What is the main problem when parsing arguments.

Well, the main problem is to know whether an item is a key or a value.

Example:
--name Olle --age 32 --verbose my_file.txt

We can’t just read key/value key/value .. because then --verbose gets the value my_file.txt

The solution is obvious: refuse valueless arguments!

--name Olle --age 32 --verbose false -- my_file.txt

  • Everything after -- is positionals.
  • Everything before -- is key/value pairs.

We don’t accept and adapt to a stupid standard. Instead we create our own and educate the end user.

Given this our main loop becomes:

loop {
  k, v = enum.next, (enum.next rescue nil)
}

My version is using a plugin system where a plugin can run before, during or after parsing.

Plugins run in the order loaded. A plugin can CONFLICT with another plugin. And a plugin has its hook(s): :pre :coerce :post (before, during, after).

My parser now has five (optional) plugins:

  • equals (accepts : and = when setting a value. Ex: --name=Olle)
  • list (accepts -v 3 -v 4 -v 5 as a list. Also accepts -v list/3,4,5)
  • positional (splits arguments on single ‘–’. Left is named, right is positional)
  • short_split (converts -abc 1 to -a 1 -b 1 -c 1)
  • single_short (treats -abc as -a bc and -s3 as -s 3)

arg_parser.rb is 31 lines; plugin_manager.rb is 32 lines.