Euphoria
Ticket #496:
Add validation and conversion to cmd_parse
-
Reported by
jeremy
Dec 05, 2010
cmd_parse() currently always returns strings. It would be nice (and easy) to add conversion and some built in validation attributes to given options. Options should be:
- INTEGER
- ATOM
- BOOLEAN
- DATETIME, format
- EXISTING_FILE
- EXISTING_DIR
- CONVERSION_RID
Example use:
sequence opts = {
{ "w", 0, "Width of each LCD character", { HAS_PARAMETER, INTEGER } },
{ 0, "after", "Limit results for items created after date", { HAS_PARAMETER, DATETIME, "%m/%d/%Y" } },
{ 0, "template", "Template file for output", { HAS_PARAMETER, EXISTING_FILE } }
}
I'm sure once discussion starts up on 4.1, other attributes will come up.
Details
1. Comment by Jerome
Mar 02, 2013
This ticket is already assigned but here is a first go. I didn't add DATETIME or CONVERSION_RID because I wasn't clear on the intent!
# HG changeset patch
# User Ira Hill
# Date 1362239222 18000
# Node ID 653c040bbc956721d00609e3ec8951a2e505c5d6
# Parent e4a83317c7ce3e42603bb4aff92c945b33e6deb1
Ticket 496: Cmd_parse updates with validation and conversion
diff -r e4a83317c7ce -r 653c040bbc95 include/std/cmdline.e
--- a/include/std/cmdline.e Fri Mar 01 16:55:16 2013 -0500
+++ b/include/std/cmdline.e Sat Mar 02 10:47:02 2013 -0500
@@ -14,8 +14,9 @@
include std/sequence.e
include std/text.e
include std/types.e
-
-
+include std/convert.e
+include std/search.e
+include std/filesys.e
--****
-- === Constants
@@ -26,6 +27,21 @@
--** This option switch does have a parameter. See [[:cmd_parse]]
HAS_PARAMETER = 'p',
+ --** HAS_PARAMETER option for Integer type. See [[:cmd_parse]]
+ PARAM_INTEGER = 'I',
+
+ --** HAS_PARAMETER option for Atom type. See [[:cmd_parse]]
+ PARAM_ATOM = 'A',
+
+ --** HAS_PARAMETER option for Boolean type. See [[:cmd_parse]]
+ PARAM_BOOLEAN = 'B',
+
+ --** HAS_PARAMETER option for Existing File. See [[:cmd_parse]]
+ PARAM_EXISTING_FILE = 'F',
+
+ --** HAS_PARAMETER option for Existing Dir. See [[:cmd_parse]]
+ PARAM_EXISTING_DIR = 'D',
+
--** This option switch is not case sensitive. See [[:cmd_parse]]
NO_CASE = 'i',
@@ -1099,6 +1115,33 @@
return { cmds, call_count }
end function
+function convert_opt( object param, object opt )
+ integer loc
+ object orig_param = param
+ loc = find_any({PARAM_ATOM,PARAM_INTEGER,PARAM_BOOLEAN,PARAM_EXISTING_FILE,PARAM_EXISTING_DIR},opt)
+ if (loc) then
+ switch opt[loc] do
+ case PARAM_ATOM then
+ param = to_number(param)
+ case PARAM_INTEGER then
+ param = to_integer(param)
+ case PARAM_BOOLEAN then
+ param = to_integer(param)
+ if param > 0 then param = TRUE else param = FALSE end if
+ case PARAM_EXISTING_FILE then
+ param = {file_exists(param), orig_param}
+ case PARAM_EXISTING_DIR then
+ if sequence( dir(param) ) then
+ param = {1, orig_param}
+ else
+ param = {0, orig_param}
+ end if
+ case else
+ end switch
+ end if
+return param
+end function
+
function handle_opt( sequence find_result, integer arg_idx, sequence opts, map parsed_opts,
sequence cmds, object add_help_rid, object parse_options, sequence call_count,
integer validation, integer help_on_error, integer auto_help )
@@ -1158,10 +1201,10 @@
{find_result[2]}, opts, add_help_rid, cmds, parse_options, help_on_error, auto_help )
end if
else
- map:put(parsed_opts, opt[MAPNAME], param)
+ map:put(parsed_opts, opt[MAPNAME], convert_opt(param, opt[OPTIONS]))
end if
else
- map:put(parsed_opts, opt[MAPNAME], param, map_add_operation)
+ map:put(parsed_opts, opt[MAPNAME], convert_opt(param, opt[OPTIONS]), map_add_operation)
end if
end if
Tested with the following:
-- test.ex
include std/cmdline.e
include std/map.e as map
include std/pretty.e
include std/filesys.e
sequence option_definition = {
{ "a", "atom", "Give an atom", { MULTIPLE, HAS_PARAMETER, PARAM_ATOM} },
{ "i", "int", "Give an int", { MULTIPLE, HAS_PARAMETER, PARAM_INTEGER} },
{ "b", "bool", "Give a bool", { HAS_PARAMETER, PARAM_BOOLEAN} },
{ "d", "dir", "Give a dir", { HAS_PARAMETER, PARAM_EXISTING_DIR} },
{ "f", "file", "Give a file", { HAS_PARAMETER, PARAM_EXISTING_FILE} },
$
}
map:map opts = cmd_parse(option_definition, NO_HELP)
pretty_print(1, map:get(opts, "atom"), {3} )
puts(1,"\n")
pretty_print(1, map:get(opts, "int"), {3} )
puts(1,"\n")
pretty_print(1, map:get(opts, "bool"), {3} )
puts(1,"\n")
pretty_print(1, map:get(opts, "dir"), {3} )
puts(1,"\n")
pretty_print(1, map:get(opts, "file"), {3} )
puts(1,"\n")
-- End test.ex
[../source/build/test]$ ../eui test.ex -a 10.4 -a=-15.9234 -i=-11 -i 15 -b=2 -d /usr/share/euphoria -f /tmp/no_file_here.txt
{10.4,-15.9234}
{-11,15}
1
{
1,
"/usr/share/euphoria"
}
{
0,
"/tmp/no_file_here.txt"
}
2. Comment by SDPringle
Mar 02, 2013
This gives me a larger idea; value() returns {error_code,value}. CONVERSION_ID is probably meant to be a routine id of a routine that behaves like value(). It seems more robust to offer only conversion id, and a special EUPHORIA_VALUE_RID which means use 'value()'. Then write value() like routines for parsing datetime, boolean, existig file. The value returned by these routines should be a pair with an error value because the string could be badly formed.