Skip to content

Commit

Permalink
adding MinMaxConstraint and validate for ManageIQ#131
Browse files Browse the repository at this point in the history
  • Loading branch information
nanobowers committed May 12, 2024
1 parent b5e5d7d commit e9d30c7
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 0 deletions.
24 changes: 24 additions & 0 deletions lib/optimist.rb
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,24 @@ def error_message(longargs)
end
end

class MinMaxConstraint < Constraint
attr_reader :min, :max
def initialize(syms, min, max)
super(syms)
@min = min
@max = max
end
def error_condition(overlap_size)
return (min && overlap_size < min) || (max && overlap_size > max)
end
def error_message(longargs)
minmaxmsg = []
minmaxmsg << "fewer than #{min}" if min
minmaxmsg << "greater than #{max}" if max
"cannot have {minmaxmsg.join(' or ')} of these args #{longargs.join(', ')}"
end
end

## The commandline parser. In typical usage, the methods in this class
## will be handled internally by Optimist::options. In this case, only the
## #opt, #banner and #version, #depends, and #conflicts methods will
Expand Down Expand Up @@ -267,6 +285,12 @@ def either(*syms)
@constraints << EitherConstraint.new(syms)
end

# Validate arguments with min-max, similar to depends/conflicts
def validate(min: nil, max: nil, args:)
args.each { |sym| raise ArgumentError, "unknown option '#{sym}'" unless @specs[sym] }
@constraints << MinMaxConstraint.new(args, min, max)
end

## Defines a set of words which cause parsing to terminate when
## encountered, such that any options to the left of the word are
## parsed as usual, and options to the right of the word are left
Expand Down
33 changes: 33 additions & 0 deletions test/optimist/parser_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -897,6 +897,39 @@ def test_depends
assert_raises(CommandlineError) { @p.parse %w(--mellow --two --jello --one) }
end

def test_validate_minmax
[:one, :two, :three, :four, :five].each {|o| @p.opt(o)}
@p.validate(min: 2, max: 3, args: [:one, :two, :three, :four])
assert_raises(CommandlineError) { @p.parse %w(--one --two --three --four) } # 4 bad
assert_raises(CommandlineError) { @p.parse %w(--five --one --two --three --four) } # 4 bad
assert_raises(CommandlineError) { @p.parse %w(--three) } # bad
@p.parse %w(--one --two --three) # 3 ok
@p.parse %w(--two --three --four) # different 3 ok
@p.parse %w(--two --four) # 2 ok
@p.parse %w(--one --five --four --two) # 3 ok, with extra non-validated arg
end

def test_validate_max
[:one, :two, :three, :four, :five].each {|o| @p.opt(o)}
@p.validate(max: 2, args: [:one, :two, :three, :four])
assert_raises(CommandlineError) { @p.parse %w(--one --two --four) } # 3 bad
assert_raises(CommandlineError) { @p.parse %w(--five --one --two --three) } # 3 bad
@p.parse %w(--two --four) # 2 ok
@p.parse %w(--two) # 1 ok
@p.parse %w() # 0 ok
end

def test_validate_min
[:one, :two, :three, :four, :five].each {|o| @p.opt(o)}
@p.validate(min: 3, args: [:one, :two, :three, :four])
@p.parse %w(--four --one --two --three) # 4 ok
@p.parse %w(--five --one --two --three) # 3 ok
assert_raises(CommandlineError) { @p.parse %w(--two --four) } # 2 bad
assert_raises(CommandlineError) { @p.parse %w(--two) } # 1 bad
assert_raises(CommandlineError) { @p.parse %w(--five) } # 0 bad
assert_raises(CommandlineError) { @p.parse %w() } # 0 bad
end

def test_depend_error_messages
@p.opt :one
@p.opt "two"
Expand Down

0 comments on commit e9d30c7

Please sign in to comment.