-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Conditional execution of an example based on the capture of a tag
Exported the clipboard's state through the 'options' stack. From that, a new concern named 'Conditional' can mark an example to be skipped if a particular tag has a non-empty string value in the clipboard. This introduces three new and mutually exclusive options: +on, +if, +unless. All of them take the name of a tag: +on and +if will execute the example if the given tag has a non-empty string; +unless will execute it if it has an empty string.
- Loading branch information
Showing
4 changed files
with
147 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
from __future__ import unicode_literals | ||
from byexample.concern import Concern | ||
import re | ||
from functools import partial | ||
|
||
stability = 'experimental' | ||
|
||
class UnknownConditionTag(Exception): | ||
def __init__(self, example, missing): | ||
msg = "You enabled the conditional execution of this example " \ | ||
"based on the tag that *is not* in the clipboard.\n" \ | ||
"May be the example from where you capture it was skipped," \ | ||
"may be the tag '%s' is misspelled or may be the Clipboard " \ | ||
"was disabled." % (missing) | ||
|
||
Exception.__init__(self, msg) | ||
|
||
class Conditional(Concern): | ||
target = 'conditional' | ||
|
||
def extend_option_parser(self, parser): | ||
mutexg = parser.add_mutually_exclusive_group() | ||
mutexg.add_argument( | ||
"+if", | ||
"+on", | ||
nargs=1, | ||
default=False, | ||
help="run the example only if the condition matches; skip the example otherwise." | ||
) | ||
mutexg.add_argument( | ||
"+unless", | ||
nargs=1, | ||
default=True, | ||
help="run the example unless the condition matches; skip the example otherwise." | ||
) | ||
return parser | ||
|
||
def finish_parse(self, example, options, exception): | ||
if exception is not None: | ||
return | ||
|
||
options.up(example.options) | ||
ifcond = options['if'] | ||
uncond = options['unless'] | ||
options.down() | ||
|
||
if ifcond is not False: | ||
cond = ifcond[0] | ||
neg = True | ||
elif uncond is not True: | ||
cond = uncond[0] | ||
neg = False | ||
else: | ||
return | ||
|
||
clipboard = options.get('clipboard', {}) | ||
if cond not in clipboard: | ||
raise UnknownConditionTag(example, cond) | ||
|
||
skip = bool(clipboard[cond]) # TODO emptiness is enough?: what about strings like '0' and 'false'? | ||
if neg: | ||
skip = not skip | ||
|
||
if skip: | ||
example.options['skip'] = True | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
<!-- | ||
Check that we have byexample installed first | ||
$ hash byexample # byexample: +fail-fast | ||
$ alias byexample=byexample\ --pretty\ none | ||
-- | ||
--> | ||
|
||
# Conditional Execution | ||
|
||
``byexample`` allows the *conditional execution* of an example. | ||
|
||
Consider the following real situation: | ||
|
||
``byexample`` supports the execution of shell commands using different | ||
shells: ``dash``, ``ksh`` and ``bash``. | ||
|
||
To prove this I should write three examples using each one a different | ||
shell. | ||
|
||
But what happen if the environment where ``byexample`` is running does not | ||
have one of the shells? | ||
|
||
Failing is not fun, forcing to the user to have installed all the shells | ||
just to run the documentation/test is not fun either. | ||
|
||
For this ``byexample`` allows to execute an example only if | ||
a condition matches. | ||
|
||
First, we test if a given shell exists and we | ||
[capture](/{{ site.uprefix }}/basic/capture-and-paste.md) the output: | ||
|
||
```shell | ||
$ hash ksh 2>/dev/null && echo "installed" | ||
<ksh-installed> | ||
``` | ||
|
||
The ``<ksh-installed>`` tag will contain the *non-empty string* ``installed`` | ||
if the ``ksh`` shell is installed in the system or it will be *empty* if not. | ||
|
||
Then we can write the conditional example: | ||
|
||
```shell | ||
$ byexample -l shell -o '+shell=ksh' test/ds/shell-example # byexample: +if=ksh-installed | ||
<...> | ||
[PASS] Pass: 14 Fail: 0 Skip: 0 | ||
``` | ||
|
||
The ``+if`` option receives the name of a tag: if this capture tag is empty, the | ||
example is [skipped](/{{ site.uprefix }}/basic/skip-and-pass.md), | ||
it is executed as usual otherwise. | ||
|
||
The ``+on`` is an alias of ``+if``; ``+unless`` works the same but | ||
it negates the condition. | ||
|
||
```shell | ||
$ echo non-empty-string | ||
<good> | ||
|
||
$ echo executed # byexample: +if=good | ||
executed | ||
|
||
$ echo executed # byexample: +on=good | ||
executed | ||
|
||
$ echo not-executed # byexample: +unless=good | ||
this-will-never-run | ||
``` | ||
|
||
> *New* in ``byexample 8.1.0``. This feature is marked as ``experimental``. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters