Skip to content

Handle quoted multi-word argument & option values #21

Open
@tuaris

Description

Not sure if I'm "doing it wrong", but I am having the same issue as reported in other languages, where Docopt does not treat quote delimited strings as one parameter.

As demonstrated here

Also reported in:

docopt/docopt#207
docopt/try.docopt.org#3
docopt/docopt.R#4

Until this is fixed I suggest putting a warning or removing examples like git commit where it's typical for a command like git commit -m "To have multiple words inside a quote".

In the mean time I have created a workaround that isn't perfect but has so far worked okay for me. I pre-process and post-process the input/output.

The pre-process function replaces any quoted strings with a variable so that git commit -m "To have multiple words inside a quote" becomes git commit -m $_v12345abcdef.

function pre_processor(string $string) {
	$variables = [];

	$new_string = preg_replace_callback('/["\'](.*?(?<!\\\\))["\']/m', function($match) use (&$variables) {
		// Results in a var name like 'v12345abcdef'
		$varName = 'v' . hash('fnv164', $match[0]);
		$variables[$varName] = $match[1];
		// Results in a placeholder like $_v12345abcdef
		return '$_' . $varName;
	},$string);

	return ['string' => $new_string, 'variables' => $variables];
}

The $new_string is the passed to Docopt handler in place of the normal CLI input args. The result of which is then sent to a post processing function to fill the variables back in

function post_processor(array $args, array $variables) {
	foreach ($args as &$arg){
		// find any thing that matches like $_v12345abcdef and replace it with the actual value
		$arg = preg_replace_callback('/\$_(v[a-f0-9]{16})\b/', function($match) use ($variables) {
			return str_replace($match[0], isset($variables[$match[1]]) ? $variables[$match[1]] : $match[0], $match[0]);
		}, $arg);
	}
	
	return $args;
}

For example, you might have something that looks like this:

function handle($string) {
	list('string' => $processed_string, 'variables' => $variables) = pre_processor($string);
	$result = $DOCOPT->handle($doc, $processed_string);	
	$real_args = post_processor($result->args, $variables);
	return $real_args;
}

I haven't looked through the Docopt.php code, but this might be something that could be done as part of the existing handle() function.

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions