Handbuch-Beispiele als Test, search/seek mit Schlüsseltabelle
- doc/handbuch.txt: OCR-Text des COHERENT-/rdb-Handbuchs - demo/handbuch/ und test/handbuch_test.rb: Beispiele aus dem Lehrbuchteil, mise run test führt sie mit aus - search/seek: Schlüsselspalten aus dem Kopf der Schlüsseltabelle - gregorian -u ohne führende Null im Monat, mean ganzzahlig ohne .00 - Mit justify aufgefüllte Spaltennamen werden wieder gefunden - coherent.pdf in .gitignore
This commit is contained in:
@@ -1,2 +1,3 @@
|
||||
/bin/*
|
||||
!/bin/rdb
|
||||
/coherent.pdf
|
||||
|
||||
@@ -7,6 +7,18 @@ folgen [Semantic Versioning](https://semver.org/lang/de/). Die Version steht in
|
||||
|
||||
## [Unveröffentlicht]
|
||||
|
||||
### Hinzugefügt
|
||||
- `doc/handbuch.txt`: der Text des gedruckten Handbuchs „COHERENT /rdb Relational Database Manager“ (346 Seiten), per OCR aus dem Scan, mit PDF- und Buchseiten.
|
||||
- `demo/handbuch/`: die Beispiele aus dem Lehrbuchteil (Kapitel 2, 3, 6, 7, 10, 11, 15) mit ihren Tabellen. `beispiele.txt` hält Befehl und gedruckte Ausgabe, `test/handbuch_test.rb` vergleicht sie; `mise run test` führt ihn mit aus. Druckfehler des Buchs und Stellen, an denen wir abweichen, sind dort vermerkt.
|
||||
|
||||
### Geändert
|
||||
- `search` und `seek` ohne Schlüsselspalte nehmen die Spaltennamen aus dem Kopf einer Schlüsseltabelle auf der Standardeingabe (`search -mh mailtable < name`, Handbuch S. 105). Vorher galt immer die erste Spalte der Datentabelle.
|
||||
- `gregorian -u` schreibt den Monat ohne führende Null (`6/01/89`), wie im Handbuch.
|
||||
- `mean` schreibt einen ganzzahligen Mittelwert ohne `.00` (`4786`, Handbuch S. 26).
|
||||
|
||||
### Behoben
|
||||
- Spaltennamen, die `justify` mit Leerzeichen aufgefüllt hat, wurden nicht mehr gefunden: `column Name` lieferte eine leere Spalte, `index` brach ab. Leerraum um die Namen im Kopf zählt jetzt nicht mehr.
|
||||
|
||||
## [0.7.0] - 2026-10-12
|
||||
|
||||
### Hinzugefügt
|
||||
|
||||
@@ -13,7 +13,7 @@ sind nach dem Handbuch neu geschrieben.
|
||||
mise trust # einmal nach dem Clone: mise.toml freigeben
|
||||
mise install # Ruby 3.4
|
||||
mise run install # legt die Symlinks row, column, total ... in bin/ an
|
||||
mise run test # 114 Tests
|
||||
mise run test # 114 Tests und die Beispiele aus dem Handbuch
|
||||
```
|
||||
|
||||
Ohne `mise trust` brechen in einem frisch geklonten Ordner alle `mise`-Befehle ab.
|
||||
@@ -89,6 +89,28 @@ Eine Zeile mit `##` erscheint als Überschrift in der Ausgabe, eine mit `#` ist
|
||||
ein stiller Kommentar. Neue Befehle brauchen hier ein Beispiel, sonst schlägt der Test
|
||||
`test_testall_mentions_every_command` fehl.
|
||||
|
||||
## Beispiele aus dem gedruckten Handbuch
|
||||
|
||||
`doc/handbuch.txt` ist der Text des gedruckten Handbuchs „COHERENT /rdb Relational
|
||||
Database Manager“ (Mark Williams, 346 Seiten), per OCR aus dem Scan `coherent.pdf`.
|
||||
Er ist nicht korrigiert: Tabulatoren fehlen, Tabellen können verrutscht sein. Jede
|
||||
Seite ist mit PDF- und Buchseite markiert (Buchseite = PDF-Seite − 10). Kapitel 1–16
|
||||
sind ein Lehrbuch, Kapitel 17 enthält dieselben Man-Pages wie `man/`.
|
||||
|
||||
`demo/handbuch/` enthält die Beispiele aus dem Lehrbuch mit ihren Tabellen, ein
|
||||
Unterordner je Kapitel. `beispiele.txt` hält zu jedem Beispiel den Befehl und die
|
||||
Ausgabe, wie sie im Buch steht; `test/handbuch_test.rb` führt alles aus und vergleicht
|
||||
(ohne Leerraum, das Buch richtet mit Leerzeichen aus). In der Datei bedeutet:
|
||||
|
||||
```
|
||||
@ kap03 die folgenden Befehle laufen in diesem Unterordner
|
||||
## S. 26 ... Überschrift mit Buchseite
|
||||
$ befehl darunter die Ausgabe laut Buch
|
||||
# ... Kommentar, z. B. ein Druckfehler des Buchs (die Ausgabe ist korrigiert)
|
||||
! ... hier weichen wir bewusst ab; nicht verglichen, der Test meldet aber,
|
||||
wenn die Ausgabe doch wieder zum Buch passt
|
||||
```
|
||||
|
||||
## Vorlagen: `form` und `entry`
|
||||
|
||||
- `demo/form` ist eine Vorlage für `report` und `letter`: sie setzt Spaltenwerte in einen Text ein.
|
||||
@@ -217,10 +239,16 @@ er nicht mehr passt (außer mit `-a`). Beide halten die Indizes aktuell.
|
||||
## Unterschiede zum Original
|
||||
|
||||
- Es gibt kein COHERENT-Programmmaterial, daher sind die **Ausgaben nur anhand der
|
||||
Man-Pages geprüft**, nicht gegen das echte /rdb. Die Beispiele aus dem
|
||||
Handbuch sind als Tests enthalten (`test/rdb_test.rb`).
|
||||
- Die Indexdateien haben ein eigenes, einfaches Format (das Original ist nicht
|
||||
dokumentiert). Sie sind nicht mit alten /rdb-Dateien austauschbar.
|
||||
Man-Pages und dem gedruckten Handbuch geprüft**, nicht gegen das echte /rdb. Die
|
||||
Beispiele aus den Man-Pages sind als Tests enthalten (`test/rdb_test.rb`), die aus
|
||||
dem Lehrbuch in `demo/handbuch/` (`test/handbuch_test.rb`).
|
||||
- Die Indexdateien sind dem Original nachgebaut, aber nicht gleich (Handbuch S. 103–108):
|
||||
die Hashtabelle `.h` hat 2n statt 2n+1 Plätze, und in `.i` steht der Schlüssel vor
|
||||
dem Offset statt dahinter. Alte /rdb-Indizes muss man neu bauen.
|
||||
- `sorttable` lässt Zeilen mit gleichem Schlüssel in ihrer Reihenfolge; das Original
|
||||
ordnet sie nach der ganzen Zeile, wie `sort` (Handbuch S. 94).
|
||||
- `subtotal` schreibt bei einer Summe von null ein leeres Feld; das Handbuch zeigt
|
||||
`0` und die Kontonummern als `101.0` (S. 30).
|
||||
- Spaltennamen unterscheiden wie im Original Groß- und Kleinschreibung. Mit
|
||||
`RDB_ICASE=1` (z. B. in `mise.toml` unter `[env]`) wird sie ignoriert:
|
||||
ein exakter Treffer gewinnt, mehrere ähnliche sind ein Fehler. In
|
||||
@@ -252,6 +280,8 @@ lib/rdb/fast.rb Schnellzugriff über Byte-Offsets
|
||||
lib/rdb/cmd/*.rb die Befehle, nach Gruppen
|
||||
man/ Man-Pages (troff-Quellen aus den MWC-Archiven)
|
||||
demo/ Beispieltabellen; testall.cmds = je ein Beispiel pro Befehl, testall.old = letzter Lauf
|
||||
demo/handbuch/ die Beispiele aus dem gedruckten Handbuch, je Kapitel ein Ordner
|
||||
doc/handbuch.txt Text des gedruckten Handbuchs (OCR)
|
||||
test/ Tests
|
||||
```
|
||||
|
||||
|
||||
@@ -0,0 +1,641 @@
|
||||
# Beispiele aus dem Lehrbuchteil des gedruckten Handbuchs
|
||||
# "COHERENT /rdb Relational Database Manager" (coherent.pdf, Kapitel 1-16).
|
||||
#
|
||||
# Aufbau:
|
||||
# @ ordner die folgenden Befehle laufen in diesem Unterordner
|
||||
# ## text Überschrift mit Seitenangabe (Buchseite)
|
||||
# $ befehl wird mit sh ausgeführt; die Zeilen darunter sind die Ausgabe laut Buch
|
||||
# ! text das Programm weicht hier vom Buch ab (Grund im Text); nicht verglichen
|
||||
# # text Kommentar, z. B. ein Druckfehler im Buch, der in der Ausgabe korrigiert ist
|
||||
#
|
||||
# Verglichen wird ohne Leerraum: Spalten dürfen mit Tabulator oder Leerzeichen
|
||||
# getrennt sein, Strichzeilen dürfen verschieden lang sein, Leerzeilen zählen nicht.
|
||||
# Der Test test/handbuch_test.rb führt alles in einer Kopie dieses Ordners aus.
|
||||
|
||||
@ kap02
|
||||
|
||||
## S. 12: column Amount Description < expenses
|
||||
# Druckfehler im Buch: dort steht nur "column Amount".
|
||||
$ column Amount Description < expenses
|
||||
Amount Description
|
||||
------ ----------------------------
|
||||
67.00 plane ticket
|
||||
12.00 meal with client
|
||||
150.00 hotel bill
|
||||
|
||||
## S. 12-13: row 'Amount > 50' < expenses
|
||||
$ row 'Amount > 50' < expenses
|
||||
Date Amount Account Description
|
||||
------ ------ ------- -----------
|
||||
850125 67.00 4120 plane ticket
|
||||
850127 150.00 4120 hotel bill
|
||||
|
||||
## S. 13: column und row in einer Pipe
|
||||
$ column Amount Description < expenses | row 'Amount > 50'
|
||||
Amount Description
|
||||
------ -----------
|
||||
67.00 plane ticket
|
||||
150.00 hotel bill
|
||||
|
||||
## S. 18: justify < mlist
|
||||
$ justify < mlist
|
||||
name address city st
|
||||
---- ------- ---- --
|
||||
Evan Main St. Santa Cruz CA
|
||||
Rod Broadway Ithaca NY
|
||||
|
||||
## S. 18: column st name < mlist | sorttable | jointable - states
|
||||
$ column st name < mlist | sorttable | jointable - states
|
||||
st name state
|
||||
-- ---- -----
|
||||
CA Evan California
|
||||
NY Rod New York
|
||||
|
||||
@ kap03
|
||||
|
||||
## S. 25-26: column Item Cost Amount < inventory
|
||||
$ column Item Cost Amount < inventory
|
||||
Item Cost Amount
|
||||
---- ---- ------
|
||||
1 50 3
|
||||
2 5 100
|
||||
3 80 5
|
||||
4 19 23
|
||||
5 24 99
|
||||
6 147 89
|
||||
7 175 5
|
||||
|
||||
## S. 26: row 'Cost > 50' < inventory
|
||||
$ row 'Cost > 50' < inventory
|
||||
Item Amount Cost Value Description
|
||||
---- ------ ---- ----- -----------
|
||||
3 5 80 400 clamps
|
||||
6 89 147 13083 bunsen burners
|
||||
7 5 175 875 scales
|
||||
|
||||
## S. 26: column Item Cost Value < inventory | row 'Cost > 50'
|
||||
# Druckfehler im Buch: die dritte Spalte heißt dort Amount (mit den Werten von Amount).
|
||||
$ column Item Cost Value < inventory | row 'Cost > 50'
|
||||
Item Cost Value
|
||||
---- ---- -----
|
||||
3 80 400
|
||||
6 147 13083
|
||||
7 175 875
|
||||
|
||||
## S. 26: ... | mean -l Value
|
||||
# Druckfehler im Buch: Kopf und Werte der dritten Spalte wie oben; der Mittelwert 4786 stimmt.
|
||||
$ column Item Cost Value < inventory | row 'Cost > 50' | mean -l Value
|
||||
Item Cost Value
|
||||
---- ---- -----
|
||||
3 80 400
|
||||
6 147 13083
|
||||
7 175 875
|
||||
---- ---- -----
|
||||
4786
|
||||
|
||||
## S. 27: compute 'Value = Onhand * Cost' < stock
|
||||
# Im Buch heißt die Tabelle inventory; hier stock, weil S. 25 eine andere inventory zeigt.
|
||||
$ compute 'Value = Onhand * Cost' < stock
|
||||
Item Onhand Cost Value Description
|
||||
---- ------ ---- ----- -----------
|
||||
1 3 5 15 rubber gloves
|
||||
2 100 1 100 test tubes
|
||||
3 5 8 40 clamps
|
||||
4 23 2 46 plates
|
||||
5 99 3 297 cleaning cloth
|
||||
6 89 18 1602 bunsen burners
|
||||
7 5 175 875 scales
|
||||
|
||||
## S. 27: compute mit if, über zwei Zeilen
|
||||
$ compute 'if (Item == 4) \
|
||||
Cost += 5; Value = Onhand * Cost' < stock
|
||||
Item Onhand Cost Value Description
|
||||
---- ------ ---- ----- -----------
|
||||
1 3 5 15 rubber gloves
|
||||
2 100 1 100 test tubes
|
||||
3 5 8 40 clamps
|
||||
4 23 7 161 plates
|
||||
5 99 3 297 cleaning cloth
|
||||
6 89 18 1602 bunsen burners
|
||||
7 5 175 875 scales
|
||||
|
||||
## S. 28: justify Onhand Value Cost < stock
|
||||
$ justify Onhand Value Cost < stock
|
||||
Item Onhand Cost Value Description
|
||||
---- ------ ---- ----- -----------
|
||||
1 3 5 15 rubber gloves
|
||||
2 100 1 100 test tubes
|
||||
3 5 8 40 clamps
|
||||
4 23 2 46 plates
|
||||
5 99 3 297 cleaning cloth
|
||||
6 89 18 1602 bunsen burners
|
||||
7 5 175 875 scales
|
||||
|
||||
## S. 28: column Description Item Onhand Cost Value < stock
|
||||
# Druckfehler im Buch: bei plates steht dort Value 51 statt 46.
|
||||
$ column Description Item Onhand Cost Value < stock
|
||||
Description Item Onhand Cost Value
|
||||
----------- ---- ------ ---- -----
|
||||
rubber gloves 1 3 5 15
|
||||
test tubes 2 100 1 100
|
||||
clamps 3 5 8 40
|
||||
plates 4 23 2 46
|
||||
cleaning cloth 5 99 3 297
|
||||
bunsen burners 6 89 18 1602
|
||||
scales 7 5 175 875
|
||||
|
||||
## S. 29: total < stock
|
||||
# Druckfehler im Buch: 2980 (mit Value 51 für plates, siehe oben); richtig ist 2975.
|
||||
$ total < stock
|
||||
Item Onhand Cost Value Description
|
||||
---- ------ ---- ----- -----------
|
||||
28 324 212 2975
|
||||
|
||||
## S. 29: total -l Value < stock
|
||||
# Druckfehler im Buch wie oben: Value 51 und Summe 2980.
|
||||
$ total -l Value < stock
|
||||
Item Onhand Cost Value Description
|
||||
---- ------ ---- ----- -----------
|
||||
1 3 5 15 rubber gloves
|
||||
2 100 1 100 test tubes
|
||||
3 5 8 40 clamps
|
||||
4 23 2 46 plates
|
||||
5 99 3 297 cleaning cloth
|
||||
6 89 18 1602 bunsen burners
|
||||
7 5 175 875 scales
|
||||
---- ------ ---- ----- -----------
|
||||
2975
|
||||
|
||||
## S. 30: subtotal -l Account Debit Credit < ledger
|
||||
! Das Buch zeigt die Kontonummern als 101.0 und 130.0 und schreibt 0, wo eine Summe null ist; wir lassen das Feld leer und behalten 101.
|
||||
$ subtotal -l Account Debit Credit < ledger
|
||||
Account Date Debit Credit
|
||||
------- ------ ----- ------
|
||||
101.0 820102 25000
|
||||
101.0 820103 5000
|
||||
101.0 820104 15000
|
||||
------- ------ ----- -----
|
||||
101.0 25000 20000
|
||||
|
||||
130.0 820104 30000
|
||||
------- ------ ----- -----
|
||||
130.0 30000 0
|
||||
|
||||
150.1 820103 10000
|
||||
------- ------ ----- -----
|
||||
150.1 10000 0
|
||||
|
||||
211.1 820104 15000
|
||||
211.1 820102 25000
|
||||
211.1 820103 5000
|
||||
------- ------ ----- -----
|
||||
211.1 0 45000
|
||||
|
||||
## S. 30-31: subtotal Account Debit Credit < ledger
|
||||
! Wie oben: 101.0 statt 101 und 0 statt leer.
|
||||
$ subtotal Account Debit Credit < ledger
|
||||
Account Date Debit Credit
|
||||
------- ---- ----- ------
|
||||
101.0 25000 20000
|
||||
130.0 30000 0
|
||||
150.1 10000 0
|
||||
211.1 0 45000
|
||||
|
||||
## S. 31-32: row 'Value > 100' < stock | column Description Value | sorttable
|
||||
$ row 'Value > 100' < stock | column Description Value | sorttable
|
||||
Description Value
|
||||
----------- -----
|
||||
bunsen burners 1602
|
||||
cleaning cloth 297
|
||||
scales 875
|
||||
|
||||
## S. 34: das Skript fix
|
||||
$ compute 'Value = Onhand * Cost' < stock | justify
|
||||
Item Onhand Cost Value Description
|
||||
---- ------ ---- ----- -----------
|
||||
1 3 5 15 rubber gloves
|
||||
2 100 1 100 test tubes
|
||||
3 5 8 40 clamps
|
||||
4 23 2 46 plates
|
||||
5 99 3 297 cleaning cloth
|
||||
6 89 18 1602 bunsen burners
|
||||
7 5 175 875 scales
|
||||
|
||||
@ kap06
|
||||
|
||||
## S. 73-74: jointable employee child
|
||||
$ jointable employee child
|
||||
Id First Last Birth Sex Name
|
||||
-- ----- ---- ----- --- ----
|
||||
1 Howard Ho 450503 Male Sally
|
||||
1 Howard Ho 450503 Male Lynn
|
||||
|
||||
## S. 74-75: jointable course course.student
|
||||
$ jointable course course.student
|
||||
Course Credit Room Day Time Student
|
||||
------ ------ ---- --- ---- -------
|
||||
art-1a 3 RB-8 MWF 10am 1
|
||||
chem-1 4 HA-18 TTh 2pm 1
|
||||
chem-1 4 HA-18 TTh 2pm 2
|
||||
|
||||
## S. 75: jointable -j Student student course.student
|
||||
$ jointable -j Student student course.student
|
||||
Student First Last Year Course
|
||||
------- ----- ---- ---- ------
|
||||
1 Jim Clark 2 art-1a
|
||||
1 Jim Clark 2 chem-1
|
||||
2 Mary Witte 1 chem-1
|
||||
|
||||
## S. 75: zwei Verbunde hintereinander
|
||||
$ jointable -j Student student course.student | \
|
||||
jointable -j Course - course
|
||||
Student First Last Year Course Credit Room Day Time
|
||||
------- ----- ---- ---- ------ ------ ---- --- ----
|
||||
1 Jim Clark 2 art-1a 3 RB-8 MWF 10am
|
||||
1 Jim Clark 2 chem-1 4 HA-18 TTh 2pm
|
||||
2 Mary Witte 1 chem-1 4 HA-18 TTh 2pm
|
||||
|
||||
## S. 76: Raumgröße je Kurs (room.size)
|
||||
# Im Buch heißt die Kurstabelle course; hier courses, weil S. 74 eine andere course zeigt.
|
||||
$ sorttable Room < courses | jointable -j Room - room | column Course Room Size > room.size
|
||||
$ cat room.size
|
||||
Course Room Size
|
||||
------ ---- ----
|
||||
cs-101 DB-1 250
|
||||
chem-1 HA-18 17
|
||||
his-10 HA-18 17
|
||||
art-1a RB-8 23
|
||||
econ-1 RB-8 23
|
||||
|
||||
## S. 80: column Course Student Grade Teacher Title < universe
|
||||
$ column Course Student Grade Teacher Title < universe
|
||||
Course Student Grade Teacher Title
|
||||
------ ------- ----- ------- -----
|
||||
chem-1 1 3 1 Assist.
|
||||
chem-1 2 2 1 Assist.
|
||||
chem-1 3 2 1 Assist.
|
||||
cs-101 2 1 2 Prof.
|
||||
cs-101 4 4 2 Prof.
|
||||
econ-1 1 3 2 Prof.
|
||||
econ-1 2 3 2 Prof.
|
||||
econ-1 3 2 2 Prof.
|
||||
his-10 1 3 3 Assoc.
|
||||
|
||||
## S. 81: column Course Teacher Title < universe > course.teacher
|
||||
$ column Course Teacher Title < universe > course.teacher
|
||||
$ cat course.teacher
|
||||
Course Teacher Title
|
||||
------ ------- -----
|
||||
chem-1 1 Assist.
|
||||
chem-1 1 Assist.
|
||||
chem-1 1 Assist.
|
||||
cs-101 2 Prof.
|
||||
cs-101 2 Prof.
|
||||
econ-1 2 Prof.
|
||||
econ-1 2 Prof.
|
||||
econ-1 2 Prof.
|
||||
his-10 3 Assoc.
|
||||
|
||||
## S. 81: column Course Student Grade < universe > grade
|
||||
$ column Course Student Grade < universe > grade
|
||||
$ cat grade
|
||||
Course Student Grade
|
||||
------ ------- -----
|
||||
chem-1 1 3
|
||||
chem-1 2 2
|
||||
chem-1 3 2
|
||||
cs-101 2 1
|
||||
cs-101 4 4
|
||||
econ-1 1 3
|
||||
econ-1 2 3
|
||||
econ-1 3 2
|
||||
his-10 1 3
|
||||
|
||||
## S. 81: uniq < course.teacher
|
||||
$ uniq < course.teacher
|
||||
Course Teacher Title
|
||||
------ ------- -----
|
||||
chem-1 1 Assist.
|
||||
cs-101 2 Prof.
|
||||
econ-1 2 Prof.
|
||||
his-10 3 Assoc.
|
||||
|
||||
## S. 82: column Teacher Title < course.teacher | uniq > teacher
|
||||
$ column Teacher Title < course.teacher | uniq > teacher
|
||||
$ cat teacher
|
||||
Teacher Title
|
||||
------- -----
|
||||
1 Assist.
|
||||
2 Prof.
|
||||
3 Assoc.
|
||||
|
||||
## S. 82: column Course Teacher < course.teacher
|
||||
# Laut Buch ist course.teacher hier schon mit uniq bereinigt.
|
||||
$ uniq < course.teacher | column Course Teacher
|
||||
Course Teacher
|
||||
------ -------
|
||||
chem-1 1
|
||||
cs-101 2
|
||||
econ-1 2
|
||||
his-10 3
|
||||
|
||||
@ kap06-telefonbuch
|
||||
|
||||
# S. 82-85: Das Buch zeigt die Tabellen teacher, teacher.course, course.student
|
||||
# und student nicht, nur das Ergebnis. Sie sind daraus und aus der Tabelle grade
|
||||
# (S. 79) zurückgerechnet; Namen und Nummern der anderen Lehrer sind erfunden.
|
||||
|
||||
## S. 83-84: tmp1, die Lehrernummer von Joy Xi
|
||||
$ row 'First == "Joy" && Last == "Xi" ' < teacher | column Teacher
|
||||
Teacher
|
||||
-------
|
||||
2
|
||||
|
||||
## S. 84: tmp2, ihre Kurse
|
||||
$ row 'First == "Joy" && Last == "Xi" ' < teacher | column Teacher | jointable - teacher.course | column Course | sorttable
|
||||
Course
|
||||
------
|
||||
cs-101
|
||||
econ-1
|
||||
|
||||
## S. 84: tmp3, die Studenten in diesen Kursen
|
||||
$ row 'First == "Joy" && Last == "Xi" ' < teacher | column Teacher | jointable - teacher.course | column Course | sorttable | jointable - course.student | column Student Course | sorttable -n
|
||||
Student Course
|
||||
------- ------
|
||||
1 econ-1
|
||||
2 cs-101
|
||||
2 econ-1
|
||||
3 econ-1
|
||||
4 cs-101
|
||||
|
||||
## S. 83-85: das ganze Telefonbuch
|
||||
# Druckfehler im Buch: die Ausgabe zeigt zusätzlich die Spalte Year, obwohl nur
|
||||
# Course Last First Phone projiziert werden.
|
||||
$ row 'First == "Joy" && Last == "Xi" ' < teacher |
|
||||
column Teacher |
|
||||
tee tmp1 |
|
||||
jointable - teacher.course |
|
||||
column Course |
|
||||
sorttable |
|
||||
tee tmp2 |
|
||||
jointable - course.student |
|
||||
column Student Course |
|
||||
sorttable -n |
|
||||
tee tmp3 |
|
||||
jointable - student |
|
||||
column Course Last First Phone |
|
||||
sorttable > phonebook
|
||||
$ cat phonebook
|
||||
Course Last First Phone
|
||||
------ ---- ----- -----
|
||||
cs-101 Dunce Boris 765-4321
|
||||
cs-101 Early Mary 123-4567
|
||||
econ-1 Early Mary 123-4567
|
||||
econ-1 Farkel Freddy 123-1234
|
||||
econ-1 Knott Why 123-7654
|
||||
|
||||
@ kap07
|
||||
|
||||
## S. 90: eine Tabelle Zeile für Zeile in der Shell lesen
|
||||
$ exec 0< inventory; read HEAD; set $HEAD; echo "The first field is $1 and the fifth field is $5."
|
||||
The first field is Item and the fifth field is Description.
|
||||
|
||||
## S. 91-92: das Skript onhand
|
||||
$ sh onhand 2 < inventory
|
||||
We have 100 test tubes on hand.
|
||||
|
||||
## S. 93: listtosh < mail.list
|
||||
! Das Buch schützt den Apostroph als 'McDonald\'s'; in der Shell wirkt der Backslash in '...' aber nicht. Wir schreiben 'McDonald'\''s', das eval richtig liest.
|
||||
$ listtosh < mail.list
|
||||
Number='1'
|
||||
Name='Ronald McDonald'
|
||||
Company='McDonald\'s'
|
||||
Street='123 Mac Attack'
|
||||
City='Menphis'
|
||||
State='TENN'
|
||||
ZIP='30000'
|
||||
Phone='(111) 222-3333'
|
||||
|
||||
## S. 93: column Name Phone < mail.list | listtosh
|
||||
! Hier zeigt das Buch beide Zuweisungen in einer Zeile, eine Seite vorher und in der Man-Page steht jede auf einer eigenen. Wir schreiben eine je Zeile; für eval ist das gleich.
|
||||
$ column Name Phone < mail.list | listtosh
|
||||
Name='Ronald McDonald' Phone='(111) 222-3333'
|
||||
|
||||
## S. 94: eval mit listtosh
|
||||
$ eval `column Name Phone < mail.list | listtosh`; echo "$Name's phone number is $Phone."
|
||||
Ronald McDonald's phone number is (111) 222-3333.
|
||||
|
||||
## S. 94: ein Satz als Shell-Variablen
|
||||
$ echo `row 'Item == 3' < inventory | tabletolist | listtosh`; eval `row 'Item == 3' < inventory | tabletolist | listtosh`; echo "We have $Amount $Description."
|
||||
Item='3' Amount='5' Cost='80' Value='400' Description='clamps'
|
||||
We have 5 clamps.
|
||||
|
||||
## S. 94-95: der Lohnbericht (UNIX World)
|
||||
# column legt die noch fehlende Spalte total leer an, compute füllt sie.
|
||||
$ jointable hours employee |
|
||||
sorttable code |
|
||||
jointable -j1 code -j2 number - task |
|
||||
sorttable number |
|
||||
column number fname lname code hours rate total |
|
||||
compute 'total = hours * rate' |
|
||||
justify > tmp
|
||||
! Bei Anne Rowan (3) steht im Buch code 2 vor code 1. sorttable im Original sortiert gleiche Schlüssel nach der ganzen Zeile (wie sort), unser sorttable lässt ihre Reihenfolge.
|
||||
$ subtotal -l number hours total < tmp
|
||||
number fname lname code hours rate total
|
||||
------ ----- ----- ---- ----- ---- -----
|
||||
1 John Wilson 2 3 75 225
|
||||
1 John Wilson 2 4 75 300
|
||||
------ ----- ----- ---- ----- ---- -----
|
||||
1 7 525
|
||||
|
||||
2 Fred Jackson 1 4 85 340
|
||||
2 Fred Jackson 2 5 85 425
|
||||
------ ----- ----- ---- ----- ---- -----
|
||||
2 9 765
|
||||
|
||||
3 Anne Rowan 2 5 75 375
|
||||
3 Anne Rowan 1 6 75 450
|
||||
------ ----- ----- ---- ----- ---- -----
|
||||
3 11 825
|
||||
|
||||
## S. 95: die Gesamtsumme
|
||||
$ total total < tmp | justify | tail -1
|
||||
2115
|
||||
|
||||
@ kap10
|
||||
|
||||
## S. 103/107: index -mh mailtable Name
|
||||
! Das Buch hat 2n+1 = 5 Plätze und rechnet die Summe der Zeichen (ohne Leerzeichen) modulo 5; wir nehmen 2n = 4 Plätze.
|
||||
$ index -mh mailtable Name
|
||||
$ cat mailtable.h
|
||||
Offset
|
||||
--------
|
||||
0
|
||||
156
|
||||
0
|
||||
104
|
||||
0
|
||||
|
||||
## S. 104: echo "Ronald McDonald" | search -mh mailtable Name
|
||||
$ echo "Ronald McDonald" | search -mh mailtable Name
|
||||
Number Name Company Phone
|
||||
------ --------------- ------------- --------------
|
||||
1 Ronald McDonald McDonald's (111) 222-3333
|
||||
|
||||
## S. 105: search -mh mailtable < name
|
||||
$ search -mh mailtable < name
|
||||
Number Name Company Phone
|
||||
------ --------------- ------------- --------------
|
||||
1 Ronald McDonald McDonald's (111) 222-3333
|
||||
2 Chiquita Banana United Brands 1234
|
||||
|
||||
## S. 105: cat name | search -mh mailtable
|
||||
$ cat name | search -mh mailtable
|
||||
Number Name Company Phone
|
||||
------ --------------- ------------- --------------
|
||||
1 Ronald McDonald McDonald's (111) 222-3333
|
||||
2 Chiquita Banana United Brands 1234
|
||||
|
||||
## S. 106: index -mr mailtable
|
||||
$ index -mr mailtable
|
||||
$ cat mailtable.r
|
||||
Offset
|
||||
---------
|
||||
104
|
||||
156
|
||||
|
||||
## S. 108: index -mi mailtable Name
|
||||
! Das Buch schreibt die Spalten in der Reihenfolge Offset Name; bei uns steht der Schlüssel vorn (Name Offset).
|
||||
$ index -mi mailtable Name
|
||||
$ cat mailtable.i
|
||||
Offset Name
|
||||
------ -------
|
||||
156 Chiquita Banana
|
||||
104 Ronald McDonald
|
||||
|
||||
## S. 109: search -mi -x mailtable Name (Teiltreffer)
|
||||
$ echo Ron | search -mi -x mailtable Name
|
||||
Number Name Company Phone
|
||||
------ --------------- ---------- --------------
|
||||
1 Ronald McDonald McDonald's (111) 222-3333
|
||||
|
||||
## S. 107: index -mb mailtable Name sortiert die Tabelle
|
||||
$ index -mb mailtable Name
|
||||
$ cat mailtable
|
||||
Number Name Company Phone
|
||||
------ --------------- ------------- --------------
|
||||
2 Chiquita Banana United Brands 1234
|
||||
1 Ronald McDonald McDonald's (111) 222-3333
|
||||
|
||||
@ kap11
|
||||
|
||||
## S. 111-112: seek, blank und replace löschen Satz 5
|
||||
! Das Buch nennt als Ort "207 245 0 9"; das hängt davon ab, wie die Tabelle mit Leerzeichen aufgefüllt war.
|
||||
$ echo 5 | seek -mb -o tmp inventory Item
|
||||
|
||||
## S. 112: blank < tmp | replace -mb inventory $LOCATION
|
||||
$ LOCATION=`echo 5 | seek -mb -o tmp inventory Item`; blank < tmp | replace -mb inventory $LOCATION
|
||||
$ cat inventory
|
||||
Item Amount Cost Value Description
|
||||
---- ------ ---- ----- -----------
|
||||
1 3 50 150 rubber gloves
|
||||
2 100 5 500 test tubes
|
||||
3 5 80 400 clamps
|
||||
4 23 19 437 plates
|
||||
|
||||
6 89 147 13083 bunsen burners
|
||||
7 5 175 875 scales
|
||||
|
||||
## S. 113: julian Date < project > tmp
|
||||
! Das Buch rechnet 890601 als 1752623; die Man-Page von gregorian rechnet 861222 als 1752827, also einen früheren Tag mit einer größeren Zahl. Wir folgen der Man-Page. Die Abstände (30, 31, 31, 30 Tage) stimmen.
|
||||
$ julian Date < project > tmp; cat tmp
|
||||
Date Description
|
||||
------- -----------
|
||||
1752623 Start project
|
||||
1752653 Project crises
|
||||
1752684 Abandon project
|
||||
1752715 Coverup blame
|
||||
1752745 Write off losses
|
||||
|
||||
## S. 113-114: 45 Tage später
|
||||
$ compute 'Date += 45' < tmp > tmp1; gregorian Date < tmp1 > project; cat project
|
||||
Date Description
|
||||
------ -----------
|
||||
890716 Start project
|
||||
890815 Project crises
|
||||
890915 Abandon project
|
||||
891016 Coverup blame
|
||||
891115 Write off losses
|
||||
|
||||
## S. 114: Tage zwischen zwei Daten
|
||||
$ julian Start Stop < house | compute 'Days = Stop - Start' | gregorian Start Stop > tmp; mv tmp house; cat house
|
||||
Start Stop Days Step
|
||||
------ ------ ---- ----
|
||||
890101 890118 17 Lay concrete
|
||||
890121 890212 22 Setup frame
|
||||
890215 890302 15 Build walls
|
||||
890305 890401 27 Install fixtures
|
||||
890408 890425 17 Sell at a loss
|
||||
|
||||
## S. 115: Datum im US-Format
|
||||
# Das Buch rechnet hier mit dem ursprünglichen project (vor den 45 Tagen).
|
||||
$ printf 'Date\tDescription\n----\t-----------\n890601\tStart project\n890701\tProject crises\n890801\tAbandon project\n890901\tCoverup blame\n891001\tWrite off losses\n' > project; julian Date < project | gregorian -u Date | justify Date
|
||||
Date Description
|
||||
-------- ----------------
|
||||
6/01/89 Start project
|
||||
7/01/89 Project crises
|
||||
8/01/89 Abandon project
|
||||
9/01/89 Coverup blame
|
||||
10/01/89 Write off losses
|
||||
|
||||
## S. 116: union journalcash journalloan journaladjust > journal
|
||||
$ union journalcash journalloan journaladjust > journal; cat journal
|
||||
Date Account Debit Credit Description
|
||||
------ ------- ----- ------ -----------
|
||||
891222 101 25000 cash from loan
|
||||
891223 101 5000 cash payment
|
||||
891224 101 15000 cash payment to CCPSC for parts
|
||||
891222 211.1 25000 loan number #378-14 Bank Amerigold
|
||||
891223 211.2 5000 note payable to Zarkoff Equipment
|
||||
891224 130 30000 inventory - parts from CCPSC
|
||||
|
||||
## S. 117: difference journal journalloan
|
||||
$ difference journal journalloan
|
||||
Date Account Debit Credit Description
|
||||
------ ------- ----- ------ -----------
|
||||
891222 101 25000 cash from loan
|
||||
891223 101 5000 cash payment
|
||||
891224 101 15000 cash payment to CCPSC for parts
|
||||
891224 130 30000 inventory - parts from CCPSC
|
||||
|
||||
## S. 117: intersect journal journaladjust
|
||||
$ intersect journal journaladjust
|
||||
Date Account Debit Credit Description
|
||||
------ ------- ----- ------ -----------
|
||||
891224 130 30000 inventory - parts from CCPSC
|
||||
|
||||
@ kap15
|
||||
|
||||
## S. 131-132: tabletofact female male parent isa > fact
|
||||
$ tabletofact female male parent isa > fact; cat fact
|
||||
female(michele).
|
||||
female(beth).
|
||||
female(sandy).
|
||||
female(jan).
|
||||
male(kirk).
|
||||
male(rod).
|
||||
male(shawn).
|
||||
male(durk).
|
||||
parent(michele,rod).
|
||||
parent(kirk,rod).
|
||||
isa(rod,human).
|
||||
isa(human,mammal).
|
||||
isa(mammal,animal).
|
||||
isa(animal,lifeform).
|
||||
|
||||
## S. 132: tabletorule ruletable > rule
|
||||
$ tabletorule ruletable > rule; cat rule
|
||||
mother(X,Y) :- female(X) , parent(X,Y).
|
||||
father(X,Y) :- male(X) , parent(X,Y).
|
||||
son(X,Y) :- male(X) , parent(Y,X).
|
||||
isa(X,Y) :- isa(X,Z) , isa(Z,Y).
|
||||
@@ -0,0 +1,5 @@
|
||||
Date Amount Account Description
|
||||
---- ------ ------- -----------
|
||||
850125 67.00 4120 plane ticket
|
||||
850126 12.00 4120 meal with client
|
||||
850127 150.00 4120 hotel bill
|
||||
@@ -0,0 +1,4 @@
|
||||
name address city st
|
||||
---- ------- ---- --
|
||||
Evan Main St. Santa Cruz CA
|
||||
Rod Broadway Ithaca NY
|
||||
@@ -0,0 +1,5 @@
|
||||
st state
|
||||
-- -----
|
||||
CA California
|
||||
NV Nevada
|
||||
NY New York
|
||||
@@ -0,0 +1,9 @@
|
||||
Item Amount Cost Value Description
|
||||
---- ------ ---- ----- -----------
|
||||
1 3 50 150 rubber gloves
|
||||
2 100 5 500 test tubes
|
||||
3 5 80 400 clamps
|
||||
4 23 19 437 plates
|
||||
5 99 24 2376 cleaning cloth
|
||||
6 89 147 13083 bunsen burners
|
||||
7 5 175 875 scales
|
||||
@@ -0,0 +1,10 @@
|
||||
Account Date Debit Credit
|
||||
------- ---- ----- ------
|
||||
101 820102 25000
|
||||
101 820103 5000
|
||||
101 820104 15000
|
||||
130 820104 30000
|
||||
150.1 820103 10000
|
||||
211.1 820104 15000
|
||||
211.1 820102 25000
|
||||
211.1 820103 5000
|
||||
@@ -0,0 +1,9 @@
|
||||
Item Onhand Cost Value Description
|
||||
---- ------ ---- ----- -----------
|
||||
1 3 5 15 rubber gloves
|
||||
2 100 1 100 test tubes
|
||||
3 5 8 40 clamps
|
||||
4 23 2 46 plates
|
||||
5 99 3 297 cleaning cloth
|
||||
6 89 18 1602 bunsen burners
|
||||
7 5 175 875 scales
|
||||
@@ -0,0 +1,13 @@
|
||||
Course Student
|
||||
------ -------
|
||||
art-1a 1
|
||||
art-1a 4
|
||||
chem-1 1
|
||||
chem-1 2
|
||||
chem-1 3
|
||||
cs-101 2
|
||||
cs-101 4
|
||||
econ-1 1
|
||||
econ-1 2
|
||||
econ-1 3
|
||||
his-10 1
|
||||
@@ -0,0 +1,6 @@
|
||||
Student First Last Year Phone
|
||||
------- ----- ---- ---- -----
|
||||
1 Why Knott 1 123-7654
|
||||
2 Mary Early 4 123-4567
|
||||
3 Freddy Farkel 3 123-1234
|
||||
4 Boris Dunce 2 765-4321
|
||||
@@ -0,0 +1,5 @@
|
||||
Teacher First Last Phone Title
|
||||
------- ----- ---- ----- -----
|
||||
1 Ann Ode 555-0101 Assist.
|
||||
2 Joy Xi 555-0102 Prof.
|
||||
3 Max Ray 555-0103 Assoc.
|
||||
@@ -0,0 +1,7 @@
|
||||
Teacher Course
|
||||
------- ------
|
||||
1 chem-1
|
||||
2 cs-101
|
||||
2 econ-1
|
||||
3 art-1a
|
||||
3 his-10
|
||||
@@ -0,0 +1,4 @@
|
||||
Parent Name
|
||||
------ ----
|
||||
1 Sally
|
||||
1 Lynn
|
||||
@@ -0,0 +1,4 @@
|
||||
Course Credit Room Day Time
|
||||
------ ------ ---- --- ----
|
||||
art-1a 3 RB-8 MWF 10am
|
||||
chem-1 4 HA-18 TTh 2pm
|
||||
@@ -0,0 +1,5 @@
|
||||
Course Student
|
||||
------ -------
|
||||
art-1a 1
|
||||
chem-1 1
|
||||
chem-1 2
|
||||
@@ -0,0 +1,7 @@
|
||||
Course Credit Room Day Time Teacher
|
||||
------ ------ ---- --- ---- -------
|
||||
art-1a 3 RB-8 MWF 10am 3
|
||||
chem-1 4 HA-18 TTh 2pm 1
|
||||
cs-101 4 DB-1 MWF 2am 2
|
||||
econ-1 3 RB-8 TTH 1pm 2
|
||||
his-10 3 HA-18 MWF 11am 3
|
||||
@@ -0,0 +1,4 @@
|
||||
Id First Last Birth Sex
|
||||
-- ----- ---- ----- ---
|
||||
1 Howard Ho 450503 Male
|
||||
2 Jane Dobbs 540129 Female
|
||||
@@ -0,0 +1,5 @@
|
||||
Room Type Size Hall
|
||||
---- ---- ---- ----
|
||||
DB-1 Lecture 250 Daddy Bucks
|
||||
HA-18 Lab 17 Hillary Addler
|
||||
RB-8 Tacky 23 Roberta Bucks
|
||||
@@ -0,0 +1,4 @@
|
||||
Student First Last Year
|
||||
------- ----- ---- ----
|
||||
1 Jim Clark 2
|
||||
2 Mary Witte 1
|
||||
@@ -0,0 +1,11 @@
|
||||
Course Student Grade Teacher Title Child
|
||||
------ ------- ----- ------- ----- -----
|
||||
chem-1 1 3 1 Assist. Sally, Mike, Joy
|
||||
chem-1 2 2 1 Assist. Fred
|
||||
chem-1 3 2 1 Assist.
|
||||
cs-101 2 1 2 Prof. Fred
|
||||
cs-101 4 4 2 Prof.
|
||||
econ-1 1 3 2 Prof. Sally, Mike, Joy
|
||||
econ-1 2 3 2 Prof. Fred
|
||||
econ-1 3 2 2 Prof.
|
||||
his-10 1 3 3 Assoc. Sally, Mike, Joy
|
||||
@@ -0,0 +1,5 @@
|
||||
number fname lname rate
|
||||
------ ----- ----- ----
|
||||
1 John Wilson 75
|
||||
2 Fred Jackson 85
|
||||
3 Anne Rowan 75
|
||||
@@ -0,0 +1,8 @@
|
||||
number hours code
|
||||
------ ----- ----
|
||||
1 3 2
|
||||
1 4 2
|
||||
2 4 1
|
||||
2 5 2
|
||||
3 5 2
|
||||
3 6 1
|
||||
@@ -0,0 +1,9 @@
|
||||
Item Amount Cost Value Description
|
||||
---- ------ ---- ----- -----------
|
||||
1 3 50 150 rubber gloves
|
||||
2 100 5 500 test tubes
|
||||
3 5 80 400 clamps
|
||||
4 23 19 437 plates
|
||||
5 99 24 2376 cleaning cloth
|
||||
6 89 147 13083 bunsen burners
|
||||
7 5 175 875 scales
|
||||
@@ -0,0 +1,9 @@
|
||||
|
||||
Number 1
|
||||
Name Ronald McDonald
|
||||
Company McDonald's
|
||||
Street 123 Mac Attack
|
||||
City Menphis
|
||||
State TENN
|
||||
ZIP 30000
|
||||
Phone (111) 222-3333
|
||||
@@ -0,0 +1,14 @@
|
||||
USAGE='usage: onhand Item < inventory'
|
||||
FOUND=0
|
||||
NOFOUND=1
|
||||
read HEAD
|
||||
read DASH
|
||||
while read $HEAD
|
||||
do
|
||||
if test "$Item" -eq "$1"
|
||||
then
|
||||
echo We have $Amount $Description on hand.
|
||||
exit $FOUND
|
||||
fi
|
||||
done
|
||||
exit $NOFOUND
|
||||
@@ -0,0 +1,4 @@
|
||||
number name
|
||||
------ ----
|
||||
1 unix/world
|
||||
2 \rdb
|
||||
@@ -0,0 +1,4 @@
|
||||
Number Name Company Phone
|
||||
------ --------------- ------------- --------------
|
||||
1 Ronald McDonald McDonald's (111) 222-3333
|
||||
2 Chiquita Banana United Brands 1234
|
||||
@@ -0,0 +1,4 @@
|
||||
Name
|
||||
----
|
||||
Ronald McDonald
|
||||
Chiquita Banana
|
||||
@@ -0,0 +1,7 @@
|
||||
Start Stop Days Step
|
||||
----- ---- ---- ----
|
||||
890101 890118 Lay concrete
|
||||
890121 890212 Setup frame
|
||||
890215 890302 Build walls
|
||||
890305 890401 Install fixtures
|
||||
890408 890425 Sell at a loss
|
||||
@@ -0,0 +1,9 @@
|
||||
Item Amount Cost Value Description
|
||||
---- ------ ---- ----- -----------
|
||||
1 3 50 150 rubber gloves
|
||||
2 100 5 500 test tubes
|
||||
3 5 80 400 clamps
|
||||
4 23 19 437 plates
|
||||
5 99 24 2376 cleaning cloth
|
||||
6 89 147 13083 bunsen burners
|
||||
7 5 175 875 scales
|
||||
@@ -0,0 +1,3 @@
|
||||
Date Account Debit Credit Description
|
||||
---- ------- ----- ------ -----------
|
||||
891224 130 30000 inventory - parts from CCPSC
|
||||
@@ -0,0 +1,5 @@
|
||||
Date Account Debit Credit Description
|
||||
---- ------- ----- ------ -----------
|
||||
891222 101 25000 cash from loan
|
||||
891223 101 5000 cash payment
|
||||
891224 101 15000 cash payment to CCPSC for parts
|
||||
@@ -0,0 +1,4 @@
|
||||
Date Account Debit Credit Description
|
||||
---- ------- ----- ------ -----------
|
||||
891222 211.1 25000 loan number #378-14 Bank Amerigold
|
||||
891223 211.2 5000 note payable to Zarkoff Equipment
|
||||
@@ -0,0 +1,7 @@
|
||||
Date Description
|
||||
---- -----------
|
||||
890601 Start project
|
||||
890701 Project crises
|
||||
890801 Abandon project
|
||||
890901 Coverup blame
|
||||
891001 Write off losses
|
||||
@@ -0,0 +1,6 @@
|
||||
Female
|
||||
------
|
||||
michele
|
||||
beth
|
||||
sandy
|
||||
jan
|
||||
@@ -0,0 +1,6 @@
|
||||
Name Isa
|
||||
---- ---
|
||||
rod human
|
||||
human mammal
|
||||
mammal animal
|
||||
animal lifeform
|
||||
@@ -0,0 +1,6 @@
|
||||
Male
|
||||
----
|
||||
kirk
|
||||
rod
|
||||
shawn
|
||||
durk
|
||||
@@ -0,0 +1,4 @@
|
||||
Parent Child
|
||||
------ -----
|
||||
michele rod
|
||||
kirk rod
|
||||
@@ -0,0 +1,6 @@
|
||||
True If
|
||||
---- --
|
||||
mother(X,Y) female(X) , parent(X,Y)
|
||||
father(X,Y) male(X) , parent(X,Y)
|
||||
son(X,Y) male(X) , parent(Y,X)
|
||||
isa(X,Y) isa(X,Z) , isa(Z,Y)
|
||||
+20131
File diff suppressed because it is too large
Load Diff
+25
-6
@@ -3,6 +3,7 @@
|
||||
# Finding, adding, changing and locking records. Many of these take the name
|
||||
# of the table instead of reading it on stdin, because they change the file.
|
||||
|
||||
require 'stringio'
|
||||
require_relative '../fast'
|
||||
|
||||
# Parse the common fast-access options. Stops at the first non-option, which
|
||||
@@ -30,8 +31,26 @@ def need_index(table, method)
|
||||
Rdb.die("no index #{table}#{suffix}: run index -m#{method} #{table}")
|
||||
end
|
||||
|
||||
def each_key(ncols)
|
||||
if $stdin.tty?
|
||||
# The key columns and, unless keys come from the terminal, the keys. Without key
|
||||
# columns on the command line a key table names them in its head line
|
||||
# (handbook p. 105: "search -mh mailtable < name"); otherwise the first column.
|
||||
def key_columns(args, data)
|
||||
return [args.empty? ? [data.head[0]] : args, nil] if $stdin.tty?
|
||||
|
||||
text = $stdin.read.to_s
|
||||
lines = text.lines.map { |l| l.chomp("\n") }
|
||||
cols = args
|
||||
if cols.empty?
|
||||
keyed = lines.size >= 2 && Rdb::Table.dash_line?(lines[1].split("\t", -1))
|
||||
cols = keyed ? lines[0].split("\t", -1).map(&:strip) : [data.head[0]]
|
||||
end
|
||||
[cols, Rdb::Fast.read_keys(StringIO.new(text), cols.size)]
|
||||
end
|
||||
|
||||
def each_key(ncols, keys = nil, &block)
|
||||
if keys
|
||||
keys.each(&block)
|
||||
elsif $stdin.tty?
|
||||
$stdin.each_line { |l| yield l.chomp.split("\t", -1).first(ncols) }
|
||||
else
|
||||
Rdb::Fast.read_keys($stdin, ncols).each { |k| yield k }
|
||||
@@ -56,9 +75,9 @@ Rdb.register('search', 'Search a table',
|
||||
table = args.shift or die 'usage: search [-m[bhirs]] table [keycolumn ...] < keys'
|
||||
data = Rdb::Fast::Data.new(table)
|
||||
need_index(table, o[:m])
|
||||
keycols = args.empty? ? [data.head[0]] : args
|
||||
keycols, keys = key_columns(args, data)
|
||||
puts data.head.join("\t"), Rdb::Table.dash_row(data.head) unless o[:h]
|
||||
each_key(keycols.size) do |key|
|
||||
each_key(keycols.size, keys) do |key|
|
||||
hits = Rdb::Fast.search(data, o[:m], keycols, key, first: o[:s] || o[:l], partial: o[:x], exact: o[:exact])
|
||||
hits.each do |h|
|
||||
puts h.row.line
|
||||
@@ -73,8 +92,8 @@ Rdb.register('seek', 'Return the beginning and ending offset of a row', 'seek [-
|
||||
table = args.shift or die 'usage: seek [-m] [-o outfile] table [keycolumn ...]'
|
||||
data = Rdb::Fast::Data.new(table)
|
||||
need_index(table, o[:m])
|
||||
keycols = args.empty? ? [data.head[0]] : args
|
||||
each_key(keycols.size) do |key|
|
||||
keycols, keys = key_columns(args, data)
|
||||
each_key(keycols.size, keys) do |key|
|
||||
Rdb::Fast.search(data, o[:m], keycols, key, first: true).each do |h|
|
||||
puts "#{h.row.from} #{h.row.to} #{h.xfrom} #{h.xto}"
|
||||
if o[:o]
|
||||
|
||||
@@ -217,7 +217,7 @@ STATS.each do |cmd, desc|
|
||||
when 'precision' then nums ? dec.to_s : ''
|
||||
when 'datatype' then filled.empty? || !nums ? '-1' : dec.to_s
|
||||
when 'total' then nums ? fmt(nums.sum, dec) : ''
|
||||
when 'mean' then nums && !nums.empty? ? fmt(nums.sum / nums.size, [dec, 2].max) : ''
|
||||
when 'mean' then nums && !nums.empty? ? fmt(nums.sum / nums.size, (nums.sum % nums.size).zero? ? dec : [dec, 2].max) : ''
|
||||
when 'maximum' then nums && !nums.empty? ? fmt(nums.max, dec) : ''
|
||||
when 'minimum' then nums && !nums.empty? ? fmt(nums.min, dec) : ''
|
||||
end
|
||||
|
||||
+1
-1
@@ -144,7 +144,7 @@ module Rdb
|
||||
dt = Date.jd(s.to_i + JULIAN_OFFSET)
|
||||
case fmt
|
||||
when 'e' then format('%02d/%02d/%02d', dt.day, dt.month, dt.year % 100)
|
||||
when 'u' then format('%02d/%02d/%02d', dt.month, dt.day, dt.year % 100)
|
||||
when 'u' then format('%d/%02d/%02d', dt.month, dt.day, dt.year % 100) # 1/31/89, as in the handbook
|
||||
else format('%02d%02d%02d', dt.year % 100, dt.month, dt.day)
|
||||
end
|
||||
end
|
||||
|
||||
+1
-1
@@ -42,7 +42,7 @@ module Rdb
|
||||
off += l.bytesize
|
||||
end
|
||||
Rdb.die("#{path}: is a list; fast access needs a table") if bytes.start_with?("\n")
|
||||
@head = lines.shift&.line.to_s.split("\t", -1)
|
||||
@head = lines.shift&.line.to_s.split("\t", -1).map(&:strip)
|
||||
lines.shift if lines.first && Table.dash_line?(lines.first.cells)
|
||||
@rows = lines
|
||||
@by_from = lines.to_h { |r| [r.from, r] }
|
||||
|
||||
+2
-1
@@ -22,7 +22,8 @@ module Rdb
|
||||
return parse_list(text) if text.start_with?("\n")
|
||||
|
||||
lines = text.lines.map { |l| l.chomp("\n") }
|
||||
head = (lines.shift || '').split("\t", -1)
|
||||
# justify pads the names too ("Name "); they still name the column
|
||||
head = (lines.shift || '').split("\t", -1).map(&:strip)
|
||||
lines.shift if lines.first && dash_line?(lines.first.split("\t", -1))
|
||||
rows = lines.map { |l| l.split("\t", -1) }
|
||||
new(head, rows.map { |r| r.fill('', r.size...head.size) })
|
||||
|
||||
@@ -13,7 +13,7 @@ run = "rdb install"
|
||||
|
||||
[tasks.test]
|
||||
description = "Run the rdb tests"
|
||||
run = "ruby test/rdb_test.rb"
|
||||
run = ["ruby test/rdb_test.rb", "ruby test/handbuch_test.rb"]
|
||||
|
||||
[tasks.testall]
|
||||
description = "Run the demo script and show what changed since the last known-good run"
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'minitest/autorun'
|
||||
require 'open3'
|
||||
require 'tmpdir'
|
||||
require 'fileutils'
|
||||
|
||||
# Runs the examples from the printed handbook (demo/handbuch/beispiele.txt) and
|
||||
# compares each output with the one printed in the book. Whitespace does not
|
||||
# count: the book aligns columns with spaces, we write tabs.
|
||||
class HandbuchTest < Minitest::Test
|
||||
ROOT = File.expand_path('..', __dir__)
|
||||
DIR = File.join(ROOT, 'demo', 'handbuch')
|
||||
|
||||
Example = Struct.new(:dir, :title, :cmd, :expected, :deviation)
|
||||
|
||||
def self.examples
|
||||
list = []
|
||||
dir = '.'
|
||||
title = nil
|
||||
deviation = nil
|
||||
cur = nil
|
||||
lines = File.readlines(File.join(DIR, 'beispiele.txt'), chomp: true)
|
||||
until lines.empty?
|
||||
line = lines.shift
|
||||
if line.start_with?('$ ')
|
||||
cmd = line[2..]
|
||||
cmd += "\n" + lines.shift while cmd.match?(/[|\\]\s*\z/) && lines.any?
|
||||
cur = Example.new(dir, title, cmd, [], deviation)
|
||||
list << cur
|
||||
elsif line.start_with?('@ ')
|
||||
dir = line[2..].strip
|
||||
cur = nil
|
||||
elsif line.start_with?('## ')
|
||||
title = line[3..]
|
||||
deviation = nil
|
||||
cur = nil
|
||||
elsif line.start_with?('! ')
|
||||
deviation = line[2..]
|
||||
elsif line.start_with?('#')
|
||||
next
|
||||
elsif cur
|
||||
cur.expected << line
|
||||
end
|
||||
end
|
||||
list
|
||||
end
|
||||
|
||||
# Cells without whitespace; dash runs count as one dash; blank lines drop out.
|
||||
def self.normalize(lines)
|
||||
lines.map { |l| l.split.map { |w| w.match?(/\A-+\z/) ? '-' : w }.join(' ') }.reject(&:empty?)
|
||||
end
|
||||
|
||||
def run_example(ex, scratch)
|
||||
env = { 'PATH' => "#{File.join(ROOT, 'bin')}:#{ENV['PATH']}" }
|
||||
out, _st = Open3.capture2e(env, 'sh', '-c', ex.cmd, chdir: File.join(scratch, ex.dir), stdin_data: '')
|
||||
out.lines(chomp: true)
|
||||
end
|
||||
|
||||
def test_examples_from_the_book
|
||||
failures = []
|
||||
fixed = []
|
||||
Dir.mktmpdir('rdb-handbuch') do |scratch|
|
||||
FileUtils.cp_r(Dir[File.join(DIR, '*')], scratch)
|
||||
self.class.examples.each do |ex|
|
||||
got = self.class.normalize(run_example(ex, scratch))
|
||||
next if ex.expected.empty?
|
||||
|
||||
want = self.class.normalize(ex.expected)
|
||||
if ex.deviation
|
||||
fixed << "#{ex.title}: stimmt jetzt mit dem Buch überein, '!' entfernen" if got == want
|
||||
elsif got != want
|
||||
failures << "#{ex.title}\n $ #{ex.cmd}\n Buch: #{want.inspect}\n erhalten: #{got.inspect}"
|
||||
end
|
||||
end
|
||||
end
|
||||
assert_empty failures + fixed, (failures + fixed).join("\n\n")
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user