Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 18 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,13 @@ window.__glpythonMount = (args, send) => {
const visualizerMode = options.find((option) => option === "box" || option === "substitution") ?? null
const libraryUrls = options.filter((option) => /^https?:\/\//.test(option))
// "features=run,repl,…" shows only these parts (the course builds its
// profiles from it); without it, everything shows. "large" enlarges the
// code and the visualizer, e.g. for a demo on the projector.
const featureNames = ["run", "tests", "visualize", "reset", "repl", "export", "ide"]
// profiles from it); without it, everything shows - except "coverage"
// (after Tests, the lines no example executed), which a course switches on
// explicitly. "large" enlarges the code and the visualizer, e.g. for a demo
// on the projector.
const featureNames = ["run", "tests", "visualize", "reset", "repl", "export", "ide", "coverage"]
const featuresOption = options.find((option) => option.startsWith("features="))
const requestedFeatures = featuresOption ? featuresOption.slice("features=".length).split(",").map((name) => name.trim()).filter(Boolean) : featureNames
const requestedFeatures = featuresOption ? featuresOption.slice("features=".length).split(",").map((name) => name.trim()).filter(Boolean) : featureNames.filter((name) => name !== "coverage")
const unknownFeatures = requestedFeatures.filter((name) => !featureNames.includes(name))
const hasFeature = (name) => requestedFeatures.includes(name)
const large = options.includes("large")
Expand Down Expand Up @@ -977,6 +979,17 @@ button stays disabled.
`visualize`, `reset`, `repl` (the input line below the output), `export` (the
visualizer's «→-Kette kopieren») and `ide` (Copy IDE link ▾). Without it, everything shows. Hidden parts are
not rendered at all. An unknown name shows a short warning below the buttons.

`coverage` is the one name that isn't part of «everything»: only a block that
lists it gets it. After **Tests**, when all examples pass, the report then
lists the lines of the block's functions that no example executed, each with
its code («Von keinem Beispiel ausgeführt: Zeile 11: `return "ungenügend"`»),
or, when every line ran, a neutral note that this doesn't show whether the
examples check the edge cases. Coverage finds untested code, not wrong code:
`return note > 4` is fully covered by `5.5` and `3.5`. Only the file that runs
counts, not libraries or other files, and only lines in function bodies (not
`def` lines, docstrings or code outside functions). Nothing is marked in the
block's code editor; the report gives the line and its code.
`large` makes the code 20px (line height 1.6) and the visualizer at least 60% of
the window, e.g. for the projector in presentation mode.

Expand All @@ -986,6 +999,7 @@ passing `@0` on so a block can add more options (a mode or library URLs):
```text
@Code.erkunden: @GLPython.eval(features=run,repl,visualize,ide @0)
@Code.rezept: @GLPython.eval(features=run,repl,visualize,tests,ide @0)
@Code.rezept3: @GLPython.eval(features=run,repl,visualize,tests,ide,coverage @0)
@Code.pruefung: @GLPython.eval(features=run @0)
@Code.demo: @GLPython.visual(large @0)
```
Expand Down
111 changes: 111 additions & 0 deletions examples/profiles.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import: https://raw.githubusercontent.com/glpython-edu/glpython-liascript/main

@Code.rezept: @GLPython.eval(features=run,repl,visualize,tests,ide @0)

@Code.rezept3: @GLPython.eval(features=run,repl,visualize,tests,ide,coverage @0)

@Code.pruefung: @GLPython.eval(features=run @0)

@Code.voll: @GLPython.eval(@0)
Expand All @@ -28,6 +30,7 @@ Jede Folie zeigt ein Profil des Kurses. Die Profile sind Makros des Kurses, die
|----------|------------------------------------------------|
| erkunden | `features=run,repl,visualize,ide` |
| rezept | `features=run,repl,visualize,tests,ide` |
| rezept3 | `features=run,repl,visualize,tests,ide,coverage` |
| pruefung | `features=run` |
| voll | (alles) |
| demo | `@GLPython.visual(large)` |
Expand Down Expand Up @@ -60,6 +63,114 @@ def quadrat(x):
```
@Code.rezept

## rezept3

Wie rezept, dazu nach «Tests» (wenn alle Beispiele bestehen): die Zeilen, die
kein Beispiel ausgeführt hat. Erwartet: keine Zeile, aber der Hinweis auf die
Grenzfälle (4 fehlt als Beispiel).

```python
def ist_genuegend(note):
"""
>>> ist_genuegend(5.5)
True
>>> ist_genuegend(3.5)
False
"""
return note >= 4
```
@Code.rezept3

Erwartet: Zeile 11, `return "ungenügend"`.

```python
def bewertung(note):
"""
>>> bewertung(5)
'genügend'
>>> bewertung(6)
'genügend'
"""
if note >= 4:
return "genügend"
else:
return "ungenügend"
```
@Code.rezept3

Erwartet: Zeile 12, `return 0` (der Fall 0).

```python
def vorzeichen(x):
"""
>>> vorzeichen(3)
1
>>> vorzeichen(-2)
-1
"""
if x > 0:
return 1
elif x < 0:
return -1
return 0
```
@Code.rezept3

Mit einer Bibliothek als zweiter Datei: nichts aus `noten.py`, obwohl kein
Beispiel `runde(0.5)` erreicht. Erwartet: der Hinweis auf die Grenzfälle.

```python -noten.py
def runde(note):
if note < 1:
return 1
return round(note * 2) / 2
```
```python +main.py
from noten import runde

def schnitt(a, b):
"""
>>> schnitt(4, 5)
4.5
"""
return runde((a + b) / 2)
```
@Code.rezept3

Ein Beispiel schlägt fehl: nur der Fehler, nichts zur Abdeckung.

```python
def bewertung(note):
"""
>>> bewertung(5)
'genügend'
>>> bewertung(3)
'genügend'
"""
if note >= 4:
return "genügend"
else:
return "ungenügend"
```
@Code.rezept3

Dasselbe wie oben mit dem Profil rezept: keine Abdeckung.

```python
def bewertung(note):
"""
>>> bewertung(5)
'genügend'
>>> bewertung(6)
'genügend'
"""
if note >= 4:
return "genügend"
else:
return "ungenügend"
```
@Code.rezept

## pruefung

Nur Ausführen - wie in einer Prüfung.
Expand Down
Loading