Skip to content

Commit

Permalink
Conditional execution of an example based on the capture of a tag
Browse files Browse the repository at this point in the history
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
eldipa committed Mar 2, 2019
1 parent b6b371c commit 797052f
Show file tree
Hide file tree
Showing 4 changed files with 147 additions and 2 deletions.
1 change: 1 addition & 0 deletions byexample/modules/clipboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ def extend_option_parser(self, parser):

def start(self, examples, runners, filepath, options):
self.clipboard = {}
options['clipboard'] = self.clipboard

@staticmethod
def repl_from_clipboard(m, clipboard, missing):
Expand Down
66 changes: 66 additions & 0 deletions byexample/modules/cond.py
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

71 changes: 71 additions & 0 deletions docs/advanced/conditional-execution.md
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``.
11 changes: 9 additions & 2 deletions docs/languages/shell.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
<!--
$ hash ksh 2>/dev/null && echo "installed"
<ksh-installed>
$ hash dash 2>/dev/null && echo "installed"
<dash-installed>
$ hash byexample # byexample: +fail-fast
$ alias byexample=byexample\ --pretty\ none
Expand Down Expand Up @@ -263,11 +270,11 @@ $ byexample -l shell -o '+shell=bash' test/ds/shell-example
<...>
[PASS] Pass: 14 Fail: 0 Skip: 0
$ byexample -l shell -o '+shell=dash' test/ds/shell-example
$ byexample -l shell -o '+shell=dash' test/ds/shell-example # byexample: +if=dash-installed
<...>
[PASS] Pass: 14 Fail: 0 Skip: 0
$ byexample -l shell -o '+shell=ksh' test/ds/shell-example # byexample: +pass
$ byexample -l shell -o '+shell=ksh' test/ds/shell-example # byexample: +if=ksh-installed
<...>
[PASS] Pass: 14 Fail: 0 Skip: 0
```
Expand Down

0 comments on commit 797052f

Please sign in to comment.