Version 0.2.0: RDB_ICASE, Changelog, --version, angepasste Man-Pages
This commit is contained in:
+16
@@ -7,6 +7,7 @@ require 'open3'
|
||||
require 'date'
|
||||
require 'tmpdir'
|
||||
require 'fileutils'
|
||||
require_relative 'rdb/version'
|
||||
|
||||
module Rdb
|
||||
ROOT = File.expand_path('..', __dir__)
|
||||
@@ -16,6 +17,21 @@ module Rdb
|
||||
COMMANDS = {}
|
||||
|
||||
class << self
|
||||
# RDB_ICASE=1 makes column names match without regard to case. An exact
|
||||
# match always wins; several case-insensitive matches are an error.
|
||||
def icase?
|
||||
!%w[0 no false].include?(ENV['RDB_ICASE'].to_s.downcase) && !ENV['RDB_ICASE'].to_s.empty?
|
||||
end
|
||||
|
||||
def column_index(head, name)
|
||||
exact = head.index(name)
|
||||
return exact if exact || !icase?
|
||||
|
||||
hits = head.each_index.select { |i| head[i].casecmp?(name) }
|
||||
die "column name '#{name}' is ambiguous: #{hits.map { |i| head[i] }.join(', ')}" if hits.size > 1
|
||||
hits.first
|
||||
end
|
||||
|
||||
def die(msg)
|
||||
abort "#{File.basename($PROGRAM_NAME)}: #{msg}"
|
||||
end
|
||||
|
||||
@@ -15,8 +15,9 @@ Rdb.register('column', 'Display columns of a table in any order', 'column [ Colu
|
||||
t = table_in
|
||||
next t.write if args.empty?
|
||||
|
||||
idx = args.map { |a| t.head.index(a) }
|
||||
t.with(head: args, rows: t.rows.map { |r| idx.map { |i| i ? r[i] : '' } }).write
|
||||
idx = args.map { |a| Rdb.column_index(t.head, a) }
|
||||
head = args.each_with_index.map { |a, n| idx[n] ? t.head[idx[n]] : a }
|
||||
t.with(head: head, rows: t.rows.map { |r| idx.map { |i| i ? r[i] : '' } }).write
|
||||
end
|
||||
Rdb.alias_for('project', 'column')
|
||||
|
||||
|
||||
@@ -40,6 +40,24 @@ module Rdb
|
||||
|
||||
# Replace column names in an awk expression with $N, leaving strings,
|
||||
# regexes and other identifiers alone.
|
||||
AWK_WORDS = %w[BEGIN END NR NF FS OFS ORS RS FNR FILENAME SUBSEP RSTART RLENGTH ENVIRON ARGC ARGV
|
||||
if else while for do in break continue next exit return function delete getline
|
||||
print printf length substr index split sub gsub match sprintf sin cos atan2 exp log
|
||||
sqrt int rand srand tolower toupper system].freeze
|
||||
|
||||
# With RDB_ICASE, a word that is not an awk keyword or function call may
|
||||
# name a column in any case, provided that exactly one column fits.
|
||||
def icase_column(names, expr, i)
|
||||
return unless Rdb.icase?
|
||||
|
||||
word = expr[i..][/\A\w+/].to_s
|
||||
return if word.empty? || AWK_WORDS.include?(word) || expr[i + word.size..].to_s.match?(/\A\s*\(/)
|
||||
|
||||
hits = names.select { |n, _| n.casecmp?(word) }
|
||||
Rdb.die "column name '#{word}' is ambiguous: #{hits.map(&:first).join(', ')}" if hits.size > 1
|
||||
hits.first
|
||||
end
|
||||
|
||||
def to_awk(expr, head)
|
||||
names = head.each_with_index.sort_by { |n, _| -n.size }
|
||||
out = +''
|
||||
@@ -59,6 +77,7 @@ module Rdb
|
||||
i = j + 1
|
||||
elsif c.match?(/[A-Za-z_#]/) && (i.zero? || !expr[i - 1].match?(/[\w$]/))
|
||||
hit = names.find { |n, _| !n.empty? && expr[i, n.size] == n && !expr[i + n.size].to_s.match?(/\w/) }
|
||||
hit ||= icase_column(names, expr, i)
|
||||
if hit
|
||||
out << "$#{hit[1] + 1}"
|
||||
i += hit[0].size
|
||||
|
||||
+1
-1
@@ -53,7 +53,7 @@ module Rdb
|
||||
end
|
||||
|
||||
def column(name)
|
||||
@head.index(name) || Rdb.die("#{path}: no column named '#{name}'")
|
||||
Rdb.column_index(@head, name) || Rdb.die("#{path}: no column named '#{name}'")
|
||||
end
|
||||
|
||||
def row_at(offset)
|
||||
|
||||
+1
-1
@@ -60,7 +60,7 @@ module Rdb
|
||||
end
|
||||
|
||||
def index_of(name)
|
||||
@head.index(name) || Rdb.die("no column named '#{name}'")
|
||||
Rdb.column_index(@head, name) || Rdb.die("no column named '#{name}'")
|
||||
end
|
||||
|
||||
def to_s
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Rdb
|
||||
VERSION = '0.2.0'
|
||||
end
|
||||
Reference in New Issue
Block a user