commander-rb / commander

The complete solution for Ruby command-line executables
MIT License
822 stars 74 forks source link

Global option values ignored when args provided #86

Closed orien closed 4 years ago

orien commented 4 years ago

Global options are ignored when additional command line arguments are also provided.

Using the test harness below, I get the following results.

1. Without extra arguments provided ✅

In this scenario without extra arguments provided, the command correctly uses the provided global option value.

./command.rb experiment --config config-value
args:   []
config: "config-value"

2. With extra arguments provided after the global config :x:

However with arguments provided after the configuration value, the command incorrectly falls back to the default value.

./command.rb experiment --config config-value arg1 arg2
args:   ["arg1", "arg2"]
config: "default"

3. With extra arguments provided before the global config :x:

Similarly with arguments provided before the configuration value, the command incorrectly falls back to the default value.

./command.rb experiment arg1 arg2 --config config-value
args:   ["arg1", "arg2"]
config: "default"

command.rb test harness

#!/usr/bin/env ruby

require 'rubygems'
require 'commander'

class MyApplication
  include Commander::Methods

  def run
    program :name, 'Example with global option'
    program :description, 'Example with global option'
    program :version, '1.0.0'
    global_option '-c', '--config CONFIG', String, 'A global option'

    command :experiment do |c|
      c.action do |args, options|
        options.default {config: 'default'}
        say "args:   #{args.inspect}"
        say "config: #{options.config.inspect}"
      end
    end

    run!
  end
end

MyApplication.new.run if $0 == __FILE__
orien commented 4 years ago

This was working in version 4.4.5, but not in version 4.4.6 and later. I assume something in the https://github.com/commander-rb/commander/compare/v4.4.5...v4.4.6 change set is the culprit.

orien commented 4 years ago

The problem is in the clearing of the Command#proxy_options during the parsing of command options. https://github.com/commander-rb/commander/blob/adaa197613bfc7833f7d3b23bc702a0507b9ee24/lib/commander/command.rb#L166

The expectation seems to be the proxy_options will be repopulated during parsing. However, this process only repopulates the command specific options, and not the global options. The global options are populated only once via the Runner.

https://github.com/commander-rb/commander/blob/adaa197613bfc7833f7d3b23bc702a0507b9ee24/lib/commander/runner.rb#L398

orien commented 4 years ago

One way to solve this is to separate the proxy_options into global and command specific options. Then, clear only the command specific options during command option parsing.

I'll put this in a pull request and see how it looks.