leejarvis / slop

Simple Lightweight Option Parsing - ✨ new contributors welcome ✨

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

suppress_errors config item not suppressing errors

MadBomber opened this issue · comments

It looks like I may be rambling. Consider this a "thinking out loud" exercise and ignore (close the issue) if you want.

I ran into a little bit of a quandary regarding the use of the config element :supporess_errors It is defined for both the Option class and the Parser class. At the option level you can suppress exceptions for specific options.

I =ASSUMED= that using the :supress_errors config element on the parse.new constructor would be the equivalent of applying the config item to ALL options. In effect I was expecting no exceptions from:

parser = Slop::Parser.new(opts, suppress_errors: true)
result = parser.parse(ARGV)

But that is not how it works. Using suppress_errors on the parser only seems to block the exception dealing with user entered switches on the command line that have not been defined. A defined option that requires a value and has no default will still generate an exception out of the Option class when no value has been provided by the user. To suppress all errors it looks like I must add the suppress_errors: true element to every option AND to the Parser constructor.

I am not convinced that my expectation is the general case.

Hi, could you show me the code and the arguments you're using (with expected vs actual output) so I can reproduce the problem?

Thanks.

The results that I got from my test program tell me that I'm all wet. Slop.parse works like I wanted it to work. Here is the test program.

#!/usr/bin/env ruby

require 'slop'

def slop_one(command_line)
  Slop.parse(command_line) do |o|
    o.string '-p', '--pig', 'a piggy name'
  end
end

def slop_two(command_line)
  Slop.parse(command_line, suppress_errors: true) do |o|
    o.string '-p', '--pig', 'a piggy name'
  end
end

def slop_three(command_line)
  Slop.parse(command_line) do |o|
    o.string '-p', '--pig', 'a piggy name', suppress_errors: true
  end
end

def slop_four(command_line)
  Slop.parse(command_line, suppress_errors: true) do |o|
    o.string '-p', '--pig', 'a piggy name', suppress_errors: true
  end
end

def test_it(slop_to_piggy)
  puts "\n\n====== Test Configuration: #{slop_to_piggy}"


  [
    %w[ -p piggy ],   # No errors
    %w[ -p ],         # missing argument
    %w[ --xyzzy ],    # unknown flag
    %w[ --xyzzy -p ]  # unknown flag AND missing argument
  ].each do |command_line|
    puts "\nARGV: #{command_line.inspect}"
    begin
      send(slop_to_piggy, command_line)
    rescue Exception => e
      puts "EXCEPTION: #{e}"
    end
  end
end

%w[ slop_one slop_two slop_three slop_four ].each {|config| test_it(config)}

This is the output I get:

ruby-2.3.0 Git:master tests $ ./slop_test.rb


====== Test Configuration: slop_one

ARGV: ["-p", "piggy"]

ARGV: ["-p"]
EXCEPTION: missing argument for -p, --pig

ARGV: ["--xyzzy"]
EXCEPTION: unknown option `--xyzzy'

ARGV: ["--xyzzy", "-p"]
EXCEPTION: unknown option `--xyzzy'


====== Test Configuration: slop_two

ARGV: ["-p", "piggy"]

ARGV: ["-p"]

ARGV: ["--xyzzy"]

ARGV: ["--xyzzy", "-p"]


====== Test Configuration: slop_three

ARGV: ["-p", "piggy"]

ARGV: ["-p"]

ARGV: ["--xyzzy"]
EXCEPTION: unknown option `--xyzzy'

ARGV: ["--xyzzy", "-p"]
EXCEPTION: unknown option `--xyzzy'


====== Test Configuration: slop_four

ARGV: ["-p", "piggy"]

ARGV: ["-p"]

ARGV: ["--xyzzy"]

ARGV: ["--xyzzy", "-p"]
ruby-2.3.0 Git:master tests $

The thing that puzzles me is that these results are not what I was getting in my main program yesterday. I'm going to look at my main program one more time to see how I messed it up.

I rewrote the slop_two method to mirror the actual sequence I have in my main program:

def slop_two(command_line)
  opts = Slop::Options.new
  opts.string '-p', '--pig', 'a piggy name'
  parser = Slop::Parser.new(opts, suppress_errors: true)
  parser.parse(command_line)
end

I am expecting the parser constructor to behavior the same way that Slop.parse did in the test program I wrote in the previous message; but, it does not. Here is the output I get with the rewritten method:

====== Test Configuration: slop_two

ARGV: ["-p", "piggy"]

ARGV: ["-p"]
EXCEPTION: missing argument for -p, --pig

ARGV: ["--xyzzy"]

ARGV: ["--xyzzy", "-p"]
EXCEPTION: missing argument for -p, --pig

To recap,

Slop.parse(command_line, suppress_errors: true) ... 

suppresses all exceptions which is what I expected ; BUT

  parser = Slop::Parser.new(opts, suppress_errors: true)
  parser.parse(command_line)

allows the missing argument exception to be generated which is not what I expected; however, it may really be the desired way to do it. To achieve what I want without having to add suppress_errors: true to each option is to add it to the Options.new line like this:

opts = Slop::Options.new(suppress_errors: true)

So adding the suppress element to both the Options.new and the Parser.new does what I want without having to repeat the element for every single option definition.... and this is what Slop.parse actually does.

I don't see any reason why Slop needs to change. It is nicely adaptable.

Thank you for letting me talk this through. I'm going to review the Slop README.md to see if there is a way that I can add my new found insight. I will generate a pull request if I get happy with any new verbage.

I just generated a pull request which adds some text to the README.md file.

Thanks for talking through this.

The Slop::Options constructor builds its own Slop::Parser instance and passes the configuration hash into this. The example in the README about Advanced Usage is probably confusing in this way because it's doesn't contain any configuration options.

I'll take a look at your PR now, and I'll close this.