Added help message generation; Improved optional arguments handling.

This commit is contained in:
mpeterv
2014-01-26 15:20:42 +04:00
parent d279429896
commit 404ec5213a
5 changed files with 116 additions and 3 deletions

View File

@@ -15,6 +15,14 @@ describe("tests related to positional arguments", function()
assert.same({foo = "bar"}, args) assert.same({foo = "bar"}, args)
end) end)
it("handles optional argument correctly", function()
local parser = argparse.parser()
parser:argument "foo"
:args "?"
local args = parser:parse({"bar"})
assert.same({foo = "bar"}, args)
end)
it("handles several arguments correctly", function() it("handles several arguments correctly", function()
local parser = argparse.parser() local parser = argparse.parser()
parser:argument "foo1" parser:argument "foo1"
@@ -86,6 +94,7 @@ describe("tests related to positional arguments", function()
it("handles sudden option correctly", function() it("handles sudden option correctly", function()
local parser = argparse.parser() local parser = argparse.parser()
:add_help(false)
parser:argument "foo" parser:argument "foo"
assert.has_error(function() parser:parse{"-q"} end, "unknown option '-q'") assert.has_error(function() parser:parse{"-q"} end, "unknown option '-q'")

View File

@@ -13,6 +13,7 @@ describe("tests related to commands", function()
it("switches context properly", function() it("switches context properly", function()
local parser = argparse.parser "name" local parser = argparse.parser "name"
:add_help(false)
local install = parser:command "install" local install = parser:command "install"
install:flag "-q" "--quiet" install:flag "-q" "--quiet"

View File

@@ -185,6 +185,7 @@ describe("tests related to options", function()
it("handles unknown options correctly", function() it("handles unknown options correctly", function()
local parser = argparse.parser() local parser = argparse.parser()
:add_help(false)
assert.has_error(function() parser:parse{"--server"} end, "unknown option '--server'") assert.has_error(function() parser:parse{"--server"} end, "unknown option '--server'")
assert.has_error(function() parser:parse{"--server=localhost"} end, "unknown option '--server'") assert.has_error(function() parser:parse{"--server=localhost"} end, "unknown option '--server'")
assert.has_error(function() parser:parse{"-s"} end, "unknown option '-s'") assert.has_error(function() parser:parse{"-s"} end, "unknown option '-s'")

View File

@@ -3,11 +3,13 @@ local argparse = require "argparse"
describe("tests related to usage message generation", function() describe("tests related to usage message generation", function()
it("creates correct usage message for empty parser", function() it("creates correct usage message for empty parser", function()
local parser = argparse.parser "foo" local parser = argparse.parser "foo"
:add_help(false)
assert.equal(parser:prepare():get_usage(), "Usage: foo") assert.equal(parser:prepare():get_usage(), "Usage: foo")
end) end)
it("creates correct usage message for arguments", function() it("creates correct usage message for arguments", function()
local parser = argparse.parser "foo" local parser = argparse.parser "foo"
:add_help(false)
parser:argument "first" parser:argument "first"
parser:argument "second-and-third" parser:argument "second-and-third"
:args "2" :args "2"
@@ -24,6 +26,7 @@ describe("tests related to usage message generation", function()
it("creates correct usage message for options", function() it("creates correct usage message for options", function()
local parser = argparse.parser "foo" local parser = argparse.parser "foo"
:add_help(false)
parser:flag "-q" "--quiet" parser:flag "-q" "--quiet"
parser:option "--from" parser:option "--from"
:count "1" :count "1"
@@ -38,6 +41,7 @@ describe("tests related to usage message generation", function()
it("creates correct usage message for commands", function() it("creates correct usage message for commands", function()
local parser = argparse.parser "foo" local parser = argparse.parser "foo"
:add_help(false)
parser:flag "-q" "--quiet" parser:flag "-q" "--quiet"
local run = parser:command "run" local run = parser:command "run"
run:option "--where" run:option "--where"
@@ -50,8 +54,10 @@ describe("tests related to usage message generation", function()
it("creates correct usage message for subcommands", function() it("creates correct usage message for subcommands", function()
local parser = argparse.parser "foo" local parser = argparse.parser "foo"
:add_help(false)
parser:flag "-q" "--quiet" parser:flag "-q" "--quiet"
local run = parser:command "run" local run = parser:command "run"
:add_help(false)
run:option "--where" run:option "--where"
parser:prepare() parser:prepare()
@@ -66,6 +72,7 @@ describe("tests related to usage message generation", function()
it("uses message provided by user", function() it("uses message provided by user", function()
local parser = argparse.parser "foo" local parser = argparse.parser "foo"
:usage "Usage: obvious" :usage "Usage: obvious"
:add_help(false)
parser:flag "-q" "--quiet" parser:flag "-q" "--quiet"
assert.equal( assert.equal(
@@ -76,6 +83,7 @@ describe("tests related to usage message generation", function()
it("uses per-option message provided by user", function() it("uses per-option message provided by user", function()
local parser = argparse.parser "foo" local parser = argparse.parser "foo"
:add_help(false)
parser:flag "-q" "--quiet" parser:flag "-q" "--quiet"
:usage "[-q | --quiet]" :usage "[-q | --quiet]"
@@ -87,6 +95,7 @@ describe("tests related to usage message generation", function()
it("uses argnames provided by user", function() it("uses argnames provided by user", function()
local parser = argparse.parser "foo" local parser = argparse.parser "foo"
:add_help(false)
parser:argument "inputs" parser:argument "inputs"
:args "1-2" :args "1-2"
:argname "<input>" :argname "<input>"

View File

@@ -51,9 +51,10 @@ local Parser = class {
_options = {}, _options = {},
_commands = {}, _commands = {},
_require_command = false, _require_command = false,
_add_help = true,
_fields = { _fields = {
"name", "description", "target", "require_command", "name", "description", "target", "require_command",
"action", "usage" "action", "usage", "help", "add_help"
} }
}:include(Declarative) }:include(Declarative)
@@ -169,7 +170,7 @@ function Parser:error(fmt, ...)
if _TEST then if _TEST then
error(msg) error(msg)
else else
io.stderr:write(("%s\r\nError: %s\r\n"):format(self:get_usage(), msg)) io.stderr:write(("%s\r\n\r\nError: %s\r\n"):format(self:get_usage(), msg))
os.exit(1) os.exit(1)
end end
end end
@@ -275,7 +276,7 @@ function Parser:make_types()
if element._maxcount == 1 then if element._maxcount == 1 then
if element._maxargs == 0 then if element._maxargs == 0 then
element._type = "flag" element._type = "flag"
elseif element._maxargs == 1 and element._minargs == 1 then elseif element._maxargs == 1 and (element._minargs == 1 or element._mincount == 1) then
element._type = "arg" element._type = "arg"
else else
element._type = "multi-arg" element._type = "multi-arg"
@@ -294,11 +295,21 @@ function Parser:make_types()
end end
function Parser:prepare() function Parser:prepare()
if self._add_help then
self:flag "-h" "--help"
:description "Show this help message and exit. "
:action(function()
print(self:get_help())
os.exit(0)
end)
end
self:make_charset() self:make_charset()
self:make_targets() self:make_targets()
self:make_boundaries() self:make_boundaries()
self:make_command_names() self:make_command_names()
self:make_types() self:make_types()
return self return self
end end
@@ -329,6 +340,88 @@ function Parser:get_usage()
return self._usage return self._usage
end end
local function make_two_columns(s1, s2)
if #s1 < 22 then
return " " .. s1 .. (" "):rep(22 - #s1) .. s2
else
if s2 == "" then
return " " .. s1
else
return " " .. s1 .. "\r\n" .. (" "):rep(25) .. s2
end
end
end
local function make_description(element)
if element._default then
if element._description then
return ("%s (default: %s)"):format(element._description, element._default)
else
return ("default: %s"):format(element._default)
end
else
return element._description or ""
end
end
local function make_name(option)
local variants = {}
local variant
for _, alias in ipairs(option._aliases) do
variant = option:get_arg_usage("<" .. option._target .. ">")
table.insert(variant, 1, alias)
variant = table.concat(variant, " ")
table.insert(variants, variant)
end
return table.concat(variants, ", ")
end
function Parser:get_help()
if not self._help then
local blocks = {self:get_usage()}
if self._description then
table.insert(blocks, self._description)
end
if #self._arguments > 0 then
local buf = {"Arguments: "}
for _, argument in ipairs(self._arguments) do
table.insert(buf, make_two_columns(argument._name, make_description(argument)))
end
table.insert(blocks, table.concat(buf, "\r\n"))
end
if #self._options > 0 then
local buf = {"Options: "}
for _, option in ipairs(self._options) do
table.insert(buf, make_two_columns(make_name(option), make_description(option)))
end
table.insert(blocks, table.concat(buf, "\r\n"))
end
if #self._commands > 0 then
local buf = {"Commands: "}
for _, command in ipairs(self._commands) do
table.insert(buf, make_two_columns(table.concat(command._aliases, ", "), command._description or ""))
end
table.insert(blocks, table.concat(buf, "\r\n"))
end
self._help = table.concat(blocks, "\r\n\r\n")
end
return self._help
end
local function get_tip(context, wrong_name) local function get_tip(context, wrong_name)
local context_pool = {} local context_pool = {}
local possible_name local possible_name