Codebase list erlang-getopt / fde61fe
Merge pull request #39 from suprematic/master Add support for UTF-8 encoded binaries Juan Jose Comellas authored 6 years ago GitHub committed 6 years ago
3 changed file(s) with 42 addition(s) and 11 deletion(s). Raw diff Collapse all Expand all
5656 specifications. The type specification for the tuple is:
5757
5858 ```erlang
59 -type arg_type() :: 'atom' | 'binary' | 'boolean' | 'float' | 'integer' | 'string'.
59 -type arg_type() :: 'atom' | 'binary' | 'utf8_binary' | 'boolean' | 'float' | 'integer' | 'string'.
6060
6161 -type arg_value() :: atom() | binary() | boolean() | float() | integer() | string().
6262
243243 Argument Types
244244 --------------
245245
246 The arguments allowed for options are: *atom*; *binary*; *boolean*; *float*; *integer*; *string*.
246 The arguments allowed for options are: *atom*; *binary*; *utf8_binary*; *boolean*;
247 *float*; *integer*; *string*.
247248 The `getopt` module checks every argument to see if it can be converted to its
248249 correct type.
249250
254255 Numeric arguments can only be negative when passed as part of an assignment expression.
255256
256257 e.g. `--increment=-100` is a valid expression; whereas `--increment -100` is invalid
258
259 Arguments of `utf8_binary` type allow proper binary encoding of arguments containing
260 code points greater than 255. The resulting value is a normalized UTF-8 binary.
261
262 As of Erlang/20, `standard_error` device has `unicode` option set to `false`.
263 It prevents correct printing of usage for arguments containing unicode
264 binaries/strings as default values. To fix this, one needs to enable unicode:
265
266 ```erlang
267 io:setopts(standard_error, [{unicode, true}]).
268 ```
257269
258270
259271 Implicit Arguments
1212
1313 -export([parse/2, check/2, parse_and_check/2, format_error/2,
1414 usage/2, usage/3, usage/4, usage/6, tokenize/1]).
15 -export([usage_cmd_line/2]).
15 -export([usage_cmd_line/2, usage_options/1]).
1616
1717 -define(LINE_LENGTH, 75).
1818 -define(MIN_USAGE_COMMAND_LINE_OPTION_LENGTH, 25).
2929 (Char) =:= $\n orelse (Char) =:= $\r)).
3030
3131 %% Atom indicating the data type that an argument can be converted to.
32 -type arg_type() :: 'atom' | 'binary' | 'boolean' | 'float' | 'integer' | 'string'.
32 -type arg_type() :: 'atom' | 'binary' | 'utf8_binary' | 'boolean' | 'float' | 'integer' | 'string'.
3333 %% Data type that an argument can be converted to.
3434 -type arg_value() :: atom() | binary() | boolean() | float() | integer() | string().
3535 %% Argument specification.
434434 to_type(Type, Arg);
435435 to_type(binary, Arg) ->
436436 list_to_binary(Arg);
437 to_type(utf8_binary, Arg) ->
438 unicode:characters_to_nfc_binary(Arg);
437439 to_type(atom, Arg) ->
438440 list_to_atom(Arg);
439441 to_type(integer, Arg) ->
729731
730732
731733 -spec usage_help_text(option_spec()) -> string().
732 usage_help_text({_Name, _Short, _Long, {_ArgType, ArgValue}, [_ | _] = Help}) ->
733 Help ++ " [default: " ++ default_arg_value_to_string(ArgValue) ++ "]";
734 usage_help_text({_Name, _Short, _Long, {ArgType, ArgValue}, [_ | _] = Help}) ->
735 Help ++ " [default: " ++ default_arg_value_to_string(ArgType, ArgValue) ++ "]";
734736 usage_help_text({_Name, _Short, _Long, _ArgSpec, Help}) ->
735737 Help.
736738
803805 lists:reverse(Acc).
804806
805807
806 default_arg_value_to_string(Value) when is_atom(Value) ->
808 default_arg_value_to_string(_, Value) when is_atom(Value) ->
807809 atom_to_list(Value);
808 default_arg_value_to_string(Value) when is_binary(Value) ->
810 default_arg_value_to_string(binary, Value) when is_binary(Value) ->
809811 binary_to_list(Value);
810 default_arg_value_to_string(Value) when is_integer(Value) ->
812 default_arg_value_to_string(utf8_binary, Value) when is_binary(Value) ->
813 unicode:characters_to_list(Value);
814 default_arg_value_to_string(_, Value) when is_integer(Value) ->
811815 integer_to_list(Value);
812 default_arg_value_to_string(Value) when is_float(Value) ->
816 default_arg_value_to_string(_, Value) when is_float(Value) ->
813817 lists:flatten(io_lib:format("~w", [Value]));
814 default_arg_value_to_string(Value) ->
818 default_arg_value_to_string(_, Value) ->
815819 Value.
816820
817821
322322 ?_assertEqual("option 'verbose' has invalid argument: 100",
323323 format_error(OptSpecList, {error, {invalid_option_arg, {verbose, "100"}}}))}
324324 ].
325
326 utf8_binary_test_() ->
327 OptSpecList = [{utf8, undefined, "utf8", utf8_binary, "UTF-8 arg"}],
328 Unicode = [228, 220, 223, 1455],
329 Utf8 = unicode:characters_to_binary(Unicode),
330 io:setopts(standard_error, [{encoding, utf8}]),
331 OptSpecsWithDefault = [{utf8, undefined, "utf8", {utf8_binary, Utf8}, "UTF-8 arg"}],
332 [{"Empty utf8_binary argument",
333 ?_assertEqual({ok, {[{utf8, <<>>}], []}}, parse(OptSpecList, ["--utf8", ""]))},
334 {"Non empty utf8_binary argument",
335 ?_assertEqual({ok, {[{utf8, Utf8}], []}}, parse(OptSpecList, ["--utf8", Unicode]))},
336 {"Default utf8_binary argument",
337 ?_assertEqual({ok, {[{utf8, Utf8}], []}}, parse(OptSpecsWithDefault, []))},
338 {"Default utf8_binary argument usage",
339 ?_assert(is_list(string:find(getopt:usage_options(OptSpecsWithDefault), Unicode)))}].