diff --git a/lib/Docopt.php b/lib/Docopt.php index d6a1939..349904d 100644 --- a/lib/Docopt.php +++ b/lib/Docopt.php @@ -38,32 +38,33 @@ class Docopt { * --options, , commands, which could be * [optional], (required), (mutually | exclusive) or repeated... * - * Example - * ------- + * Example: * - * > use MensBeam\Docopt\Docopt; - * > $doc = << [--timeout=] - * <<< my_program serial [--baud=] [--timeout=] - * <<< my_program (-h | --help | --version) - * <<< - * <<< Options: - * <<< -h, --help Show this screen and exit. - * <<< --baud= Baudrate [default: 9600] - * <<< DOCSTRING; - * > $argv = ['tcp', '127.0.0.1', '80', '--timeout', '30']; - * > echo json_encode(Docopt::docopt($doc, $argv), \JSON_PRETTY_PRINT); - * { - * "--baud": "9600", - * "--help": false, - * "--timeout": "30", - * "--version": false, - * "": "127.0.0.1", - * "": "80", - * "serial": false, - * "tcp": true - * } + * ``` + * use MensBeam\Docopt\Docopt; + * $doc = << [--timeout=] + * my_program serial [--baud=] [--timeout=] + * my_program (-h | --help | --version) + * + * Options: + * -h, --help Show this screen and exit. + * --baud= Baudrate [default: 9600] + * DOCSTRING; + * $argv = ['tcp', '127.0.0.1', '80', '--timeout', '30']; + * echo json_encode(Docopt::docopt($doc, $argv), \JSON_PRETTY_PRINT); + * //{ + * // "--baud": "9600", + * // "--help": false, + * // "--timeout": "30", + * // "--version": false, + * // "": "127.0.0.1", + * // "": "80", + * // "serial": false, + * // "tcp": true + * //} + * ``` * * @param string $docstring Description of your command-line interface * @param string[]|string|null $argv Argument list to be parsed. $_SERVER['argv'] is used if null is provided @@ -81,6 +82,7 @@ class Docopt { bool $more_magic = false ): ParsedOptions { # argv = sys.argv[1:] if argv is None else argv + $argv = $argv ?? array_slice($_SERVER['argv'] ?? [], 1); # maybe_frame = inspect.currentframe() # if maybe_frame: # parent_frame = doc_parent_frame = magic_parent_frame = maybe_frame.f_back @@ -91,6 +93,8 @@ class Docopt { # more_magic = True # else: # magic_parent_frame = magic_parent_frame.f_back + // DEVIATION: All these lines are to do with automatic invocation of the "magic" variant of docopt() + // We cannot do this in PHP # if not docstring: # go look for one, if none exists, raise Exception # while not docstring and doc_parent_frame: # docstring = doc_parent_frame.f_locals.get("__doc__") @@ -98,6 +102,7 @@ class Docopt { # doc_parent_frame = doc_parent_frame.f_back # if not docstring: # raise DocoptLanguageError("Either __doc__ must be defined in the scope of a parent or passed as the first argument.") + // DEVIATION: All these lines look for a docstring in the parent context. We simply require one as input # output_value_assigned = False # if more_magic and parent_frame: # import dis @@ -110,14 +115,27 @@ class Docopt { # MAYBE_STORE = next(instrs) # if MAYBE_STORE and (MAYBE_STORE.opname.startswith("STORE") or MAYBE_STORE.opname.startswith("RETURN")): # output_value_assigned = True + // DEVIATION: This is all for magic which is not possible in PHP + # usage_sections = parse_section("usage:", docstring) # if len(usage_sections) == 0: # raise DocoptLanguageError('"usage:" section (case-insensitive) not found. Perhaps missing indentation?') # if len(usage_sections) > 1: # raise DocoptLanguageError('More than one "usage:" (case-insensitive).') + $usage_sections = Util::parse_section("usage:", $docstring); + if (sizeof($usage_sections) === 0) { + throw new DocoptLanguageError('"usage:" section (case-insensitive) not found. Perhaps missing indentation?'); + } + if (sizeof($usage_sections) > 1) { + throw new DocoptLanguageError('More than one "usage:" (case-insensitive).'); + } # options_pattern = re.compile(r"\n\s*?options:", re.IGNORECASE) # if options_pattern.search(usage_sections[0]): # raise DocoptExit("Warning: options (case-insensitive) was found in usage." "Use a blank line between each section..") + $options_pattern = '/\n\s*?options:/si'; + if (preg_match($options_pattern, $usage_sections[0])) { + throw new DocoptExit("Warning: options (case-insensitive) was found in usage."."Use a blank line between each section.."); + } # DocoptExit.usage = usage_sections[0] # options = parse_defaults(docstring) # pattern = parse_pattern(formal_usage(DocoptExit.usage), options)