OptionParser: Issues with Subcommand State Preservation

Recently, I read a post about a useful command-line tool library called docopt, and it reminded me of my experience with Crystal’s OptionParser.

As you know, Crystal’s standard library OptionParser can create command-line tools with subcommands. I am using OptionParser to build a command-line tool with subcommands.

However, I am confused about the with_preserved_state feature in the parser method. This feature saves the parser’s state and resets it after parsing. This can be inconvenient when you want to perform an action after parsing all arguments. For example, if you want to show help for a subcommand:

dog paw --help

If you want to display the subcommand’s help message after parsing all arguments, you need to save the help message in a separate variable because the parser forgets it after execution.

on("-h", "--help", "Show this help") do
  @action = Action::Help
end

@help_message = self.to_s

Similarly, the parser doesn’t remember which subcommand it parsed, so you also need to save that yourself. This might be fine.

Resetting the parser’s state is useful for testing. However, command-line tools usually parse arguments only once at runtime. So, situations where you need to parse options multiple times are rare. In such cases, it would be better to have an explicit clear method.

Crystal is an object-oriented language, and it’s natural for classes to have state. parse is a method of the OptionParser class, not a module function. So, it’s not intuitive that the method’s behavior is transparent unless you read the source code.

Maintaining backward compatibility is important. It would be helpful if the parse method had an optional argument to choose whether to use with_preserved_state.

These are my personal thoughts based on my use case with OptionParser. It might not apply to all users, but I wanted to share my concerns.

(Translation by ChatGPT)

This was discussed on GitHub.