Rdb: Ruby-Nachbau der MWC /rdb-Werkzeuge

This commit is contained in:
wkh
2026-10-11 20:33:17 +02:00
commit a9990169e9
308 changed files with 16738 additions and 0 deletions
+99
View File
@@ -0,0 +1,99 @@
# frozen_string_literal: true
# Reports, forms and mailing lists.
# Fill in a form for one row: <Column> is replaced by the value, <!command!>
# by the output of the shell command, and <!cmd <Column>!> passes data to it.
def fill_form(form, head, row)
values = head.zip(row).to_h { |h, v| [h.strip, v.to_s] }
form.gsub(/<!(.*?)!>|<([^<>!\n]*)>/m) do
if Regexp.last_match(1)
cmd = Regexp.last_match(1).gsub(/<([^<>!\n]*)>/) { values.fetch(Regexp.last_match(1).strip, Regexp.last_match(0)) }
`#{cmd}`
else
name = Regexp.last_match(2).strip
values.key?(name) ? values[name] : Regexp.last_match(0)
end
end
end
Rdb.register('report', 'Write reports using a form and a table', 'report form < tableorlist') do |args|
die 'usage: report form < tableorlist' unless args.size == 1
ENV['PATH'] = "#{File.join(Rdb::ROOT, 'bin')}:#{ENV['PATH']}"
form = File.read(args[0])
t = table_in
t.rows.each { |r| $stdout.write fill_form(form, t.head, r) }
end
Rdb.register('reportwriter', 'Sample program to write standard reports', 'reportwriter [-lines] [title] < table') do |args|
lines = args.first&.match?(/\A-\d+\z/) ? args.shift[1..].to_i : 20
title = args.join(' ')
t = table_in
date = Date.today.strftime('%-d %b %Y')
w = t.head.each_index.map { |i| (t.rows.map { |r| r[i].strip.size } + [t.head[i].size]).max }
line = ->(cells) { cells.each_with_index.map { |c, i| c.strip.ljust(w[i]) }.join(' ').rstrip }
pages = t.rows.each_slice(lines).to_a
pages = [[]] if pages.empty?
pages.each_with_index do |chunk, n|
puts title.center(w.sum + 3 * (w.size - 1)).rstrip unless title.empty?
puts "Report Date: #{date}".center(w.sum + 3 * (w.size - 1)).rstrip, ''
puts line.(t.head), line.(t.head.map { |h| '-' * h.size })
chunk.each { |r| puts line.(r) }
puts '', " Page #{n + 1}"
puts "\f" if n < pages.size - 1
end
end
Rdb.register('screen', 'Convert a form into a screen-input shell program', 'screen < form > shellprogram') do |_args|
names = []
reads = []
painted = $stdin.read.lines.each_with_index.map do |line, n|
line = line.chomp("\n")
out = line.dup
line.scan(/<!(.*?)!>|<([^<>!]*)>/) do
m = Regexp.last_match
col = m.begin(0) + 1
if m[1]
reads << format('cursor %2d %2d ; %s;', n + 1, col, m[1].strip)
else
names << m[2].strip
reads << format('cursor %2d %2d ; read %s;', n + 1, col, m[2].strip)
end
out[m.begin(0), m[0].size] = ' ' * m[0].size
end
out
end
puts ': paint crt screen', 'exec 1>/dev/tty', 'cat <<SCREEN', "${CLEAR}#{painted.join("\n")}", 'SCREEN'
puts ': read user input', *reads
puts ': output table head', 'exec 1>&2'
puts %(echo "#{names.join("\t")}"), %(echo "#{names.map { |x| '-' * x.size }.join("\t")}")
puts ': append row', %(echo "#{names.map { |x| "$#{x}" }.join("\t")}")
end
def label_lines(head, row)
h = head.zip(row).to_h
[h['Name'], h['Company'], h['Street'], "#{h['City']}, #{h['State']} #{h['ZIP']}".strip].compact
end
Rdb.register('label', 'Print mailing labels from a mailing list', 'label < list') do |_args|
t = table_in
t.rows.each { |r| puts label_lines(t.head, r) }
end
Rdb.register('letter', 'Print form letters from a mailing list', 'letter letter.1 ... < maillist') do |args|
die 'usage: letter letter.1 letter.2 < maillist' if args.empty?
parts = args.map { |f| File.readlines(f, chomp: true) }
t = table_in
wrap = lambda do |text|
text.split.each_with_object(['']) { |w, ls| (ls.last + ' ' + w).strip.size > 65 ? ls << w : ls[-1] = (ls.last + ' ' + w).strip }
end
t.rows.each do |r|
h = t.head.zip(r).to_h
puts label_lines(t.head, r), '', "Dear #{h['Name']}:", ''
first = parts.first.join(' ')
rest = parts.drop(1).flatten
close = rest.index { |l| l.end_with?(',') } || rest.size
para = [first, "#{h['Company']}.", rest.first(close).join(' ')].reject(&:empty?).join(' ')
puts wrap.(para), *rest.drop(close), "\n"
end
end