Added mutually exclusive groups

This commit is contained in:
mpeterv
2014-03-09 14:28:55 +04:00
parent fae3fb4500
commit 7bf5777413
4 changed files with 141 additions and 2 deletions

View File

@@ -11,7 +11,7 @@ description = {
}
dependencies = {
"lua >= 5.1, < 5.3",
"30log >= 0.8"
"30log >= 0.9.1"
}
build = {
type = "builtin",

67
spec/mutex_spec.lua Normal file
View File

@@ -0,0 +1,67 @@
local Parser = require "argparse"
describe("tests related to mutexes", function()
it("handles mutex correctly", function()
local parser = Parser()
parser:mutex(
parser:flag "-q" "--quiet"
:description "Supress logging. ",
parser:flag "-v" "--verbose"
:description "Print additional debug information. "
)
local args = parser:parse{"-q"}
assert.same({quiet = true}, args)
args = parser:parse{"-v"}
assert.same({verbose = true}, args)
args = parser:parse{}
assert.same({}, args)
end)
it("raises an error if mutex is broken", function()
local parser = Parser()
parser:mutex(
parser:flag "-q" "--quiet"
:description "Supress logging. ",
parser:flag "-v" "--verbose"
:description "Print additional debug information. "
)
assert.has_error(function() parser:parse{"-qv"} end, "option '-v' can not be used together with option '-q'")
assert.has_error(function() parser:parse{"-v", "--quiet"} end, "option '--quiet' can not be used together with option '-v'")
end)
it("handles multiple mutexes", function()
local parser = Parser()
parser:mutex(
parser:flag "-q" "--quiet",
parser:flag "-v" "--verbose"
)
parser:mutex(
parser:flag "-l" "--local",
parser:option "-f" "--from"
)
local args = parser:parse{"-qq", "-fTHERE"}
assert.same({quiet = true, from = "THERE"}, args)
args = parser:parse{"-vl"}
assert.same({verbose = true, ["local"] = true}, args)
end)
it("handles mutexes in commands", function()
local parser = Parser()
parser:mutex(
parser:flag "-q" "--quiet",
parser:flag "-v" "--verbose"
)
local install = parser:command "install"
install:mutex(
install:flag "-l" "--local",
install:option "-f" "--from"
)
local args = parser:parse{"install", "-l"}
assert.same({install = true, ["local"] = true}, args)
assert.has_error(function() parser:parse{"install", "-qlv"} end, "option '-v' can not be used together with option '-q'")
end)
end)

View File

@@ -158,4 +158,25 @@ describe("tests related to usage message generation", function()
)
end)
end)
it("creates correct usage message for mutexes", function()
local parser = Parser "foo"
:add_help(false)
parser:mutex(
parser:flag "-q" "--quiet",
parser:flag "-v" "--verbose",
parser:flag "-i" "--interactive"
)
parser:mutex(
parser:flag "-l" "--local",
parser:option "-f" "--from"
)
parser:option "--yet-another-option"
assert.equal(table.concat({
"Usage: foo ([-q] | [-v] | [-i]) ([-l] | [-f <from>])",
" [--yet-another-option <yet-another-option>]"
}, "\r\n"), parser:get_usage()
)
end)
end)

View File

@@ -157,6 +157,7 @@ do -- Create classes with setters
_arguments = {},
_options = {},
_commands = {},
_mutexes = {},
_require_command = true
}, {
name = typecheck.string "name",
@@ -424,6 +425,17 @@ function Parser:command(...)
return command
end
function Parser:mutex(...)
local options = {...}
for i, option in ipairs(options) do
assert(getmetatable(option) == Option, ("bad argument #%d to 'mutex' (Option expected)"):format(i))
end
table.insert(self._mutexes, options)
return self
end
local max_usage_width = 70
local usage_welcome = "Usage: "
@@ -442,11 +454,27 @@ function Parser:get_usage()
end
end
-- set of mentioned elements
local used = {}
for _, mutex in ipairs(self._mutexes) do
local buf = {}
for _, option in ipairs(mutex) do
table.insert(buf, option:_get_usage())
used[option] = true
end
add("(" .. table.concat(buf, " | ") .. ")")
end
for _, elements in ipairs{self._options, self._arguments} do
for _, element in ipairs(elements) do
if not used[element] then
add(element:_get_usage())
end
end
end
if #self._commands > 0 then
if self._require_command then
@@ -583,6 +611,8 @@ function Parser:_parse(args, errhandler)
local options = {}
local arguments = {}
local commands
local option_mutexes = {}
local used_mutexes = {}
local opt_context = {}
local com_context
local result = {}
@@ -726,6 +756,16 @@ function Parser:_parse(args, errhandler)
invocations[option] = 0
end
for _, mutex in ipairs(parser._mutexes) do
for _, option in ipairs(mutex) do
if not option_mutexes[option] then
option_mutexes[option] = {mutex}
else
table.insert(option_mutexes[option], mutex)
end
end
end
for _, argument in ipairs(parser._arguments) do
table.insert(arguments, argument)
invocations[argument] = 0
@@ -784,6 +824,17 @@ function Parser:_parse(args, errhandler)
end
cur_option = opt_context[data]
if option_mutexes[cur_option] then
for _, mutex in ipairs(option_mutexes[cur_option]) do
if used_mutexes[mutex] and used_mutexes[mutex] ~= cur_option then
error_("option '%s' can not be used together with option '%s'", data, used_mutexes[mutex]._name)
else
used_mutexes[mutex] = cur_option
end
end
end
do_action(cur_option)
invoke(cur_option)
end