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:
wkh
2026-10-14 21:48:46 +02:00
parent a38311021d
commit df8bcdfaf1
49 changed files with 21167 additions and 16 deletions
+25 -6
View File
@@ -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]
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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) })