anchor.diff:    , ?_assertEqual(#option{long="--help"}, option_parse("--help"))
     , ?_assertEqual(#option{short="-h", long="--help"}, option_parse("-h --help"))
     , ?_assertEqual(#option{short="-h", long="--help"}, option_parse("--help -h"))
  -  , ?_assertEqual(#option{short="-h", long="--help"},
  -                  option_parse("-h, --help"))
  +  , ?_assertEqual(#option{short="-h", long="--help"}, option_parse("-h,--help"))
   
     , ?_assertEqual(#option{short="-h", argcount=1}, option_parse("-h TOPIC"))
     , ?_assertEqual(#option{long="--help", argcount=1},
  
positive.code:                   parse_args("-h arg -- -v", O))
    ].
  
  printable_usage(Doc) ->
    case re:split(Doc, "([Uu][Ss][Aa][Gg][Ee]:)", [{return, list}]) of
      UsageSplit when length(UsageSplit) < 3 ->
        throw("\"usage:\" (case-insensitive) not found.");
      UsageSplit when length(UsageSplit) > 3 ->
        throw("More than one \"usage:\" (case-insensitive)");
      [_|UsageSplit] ->
        L = re:split(lists:flatten(UsageSplit), "\\n\\s*\\n", [{return, list}]),
        string:strip(hd(L))
    end.
  
  formal_usage(PrintableUsage) ->
    %% Split and drop "usage:"
    [_Usage, ProgName|Args] = string:tokens(PrintableUsage, " \n"),
    F = fun (S) when (S) == ProgName -> ") | (";
            (S)                      -> S
        end,
    "( " ++ string:join(lists:map(F, Args), " ") ++ " )".
  
  printable_and_formal_usage_test_() ->
    Doc =
      "Usage: prog [-hv] ARG
              prog N M
  
       prog is a program.",
    [ ?_assertEqual("Usage: prog [-hv] ARG\n            prog N M",
                    printable_usage(Doc))
    , ?_assertEqual("( [-hv] ARG ) | ( N M )",
                    formal_usage(printable_usage(Doc)))
    , ?_assertEqual("uSaGe: prog ARG",
                    printable_usage("uSaGe: prog ARG\n\t \t\n bla"))
    ].
  
  
  parse_pattern(Source, Options) ->
    ok.
  
  %% docopt_any_options_test_() ->
  %%   Doc = "Usage: prog [options] A
  
  %%     -q  Be quiet
  %%     -v  Be verbose.",
  %%   [ ?_assertEqual([{"A", "arg"}, {"-v", false}, {"-q", false}],
  %%                   docopt(Doc, "arg"))
  %%   , ?_assertEqual([{"A", "arg"}, {"-v", true}, {"-q", false}],
  %%                   docopt(Doc, "-v arg"))
  %%   , ?_assertEqual([{"A", "arg"}, {"-v", false}, {"-q", true}],
  %%                   docopt(Doc, "-q arg"))
  %%   ].
  
  option_parse(Str) ->
    {Options, Desc} = partition(string:strip(Str), "  "),
    ParsedOpt = lists:foldl(fun([$-,$-|_] = S, Opt) -> Opt#option{long     = S};
                               ([$-|_]    = S, Opt) -> Opt#option{short    = S};
                               (_            , Opt) -> Opt#option{argcount = 1}
                            end, #option{}, string:tokens(Options, ",= ")),
    case ParsedOpt of
      #option{argcount = 1} -> ParsedOpt#option{value = default_value(Desc)};
      ParsedOpt             -> ParsedOpt
    end.
  
  default_value(Desc) ->
    {ok, Re} = re:compile("\\[default: (.*)\\]", [caseless]),
    case re:run(Desc, Re, [{capture, [1], list}]) of
      {match, [DefaultValue]} -> DefaultValue;
      nomatch                 -> false
    end.
  
  option_name(#option{long=undefined, short=Short}) -> Short;
  option_name(#option{long=Long})                   -> Long.
  
  partition(Str, Delim) ->
    case string:str(Str, Delim) of
      0 -> {Str, ""};
      I ->
        Left  = string:substr(Str, 1, I - 1),
        Right = string:substr(Str, I + length(Delim)),
        {Left, Right}
    end.
  
  partition_test_() ->
    [ ?_assertEqual({"foobar", ""}     , partition("foobar"      , "abc"))
  
negative.code:   ].
  
  option_name_test_() ->
    [ ?_assertEqual("-h"    , option_name(#option{short="-h"}))
    , ?_assertEqual("--help", option_name(#option{short="-h", long="--help"}))
    , ?_assertEqual("--help", option_name(#option{long="--help"}))
    ].
  