Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle quoted multi-word argument & option values #21

Open
tuaris opened this issue Sep 7, 2019 · 2 comments
Open

Handle quoted multi-word argument & option values #21

tuaris opened this issue Sep 7, 2019 · 2 comments

Comments

@tuaris
Copy link

tuaris commented Sep 7, 2019

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.

@shabbyrobe
Copy link
Member

Hi tuaris, thanks for reporting.

The PHP port of docopt is a pretty straight transliteration of the Python code. It was done this way to make integrating upstream patches easier and to ensure consistency between the implementations.

Unfortunately, that means that until the issue is fixed in the Python version, the PHP version will be stuck with this behaviour. I think it makes sense to update the README here to indicate this is a known issue though. I'll keep this issue open so that it's known that this is a problem, but I'll label it as "NeedsUpstreamFix" or somesuch.

@JKingweb
Copy link
Contributor

JKingweb commented Dec 26, 2023

This report is a little misleading. Docopt will only act incorrectly if the input command is provided as a string (docopt then does naïve splitting). If the input is an alread-split array, the bug does not manifest.

If you're just using $argv anyway, providing that array is the best option. If your input is a string for whatever reason, you can use a dedicated argument tokenizer to produce an argument array for docopt to use.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants