simple-sql 0.5.15 → 0.5.16

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 47d594c256de7bf4157b70be496694616ade42814fb0a1559a67fc893b61cbd2
4
- data.tar.gz: e8c200c5a73ea3b64787ab597ea7eb6b8c4a4e9be06416c968eb86654aaf27d9
3
+ metadata.gz: 10f81f5db33aaa6a5f76d3b22fa5f73cd5327fd6fca0f276b112024db322f852
4
+ data.tar.gz: 7c4b1301bd7fb1de48957cd1cb1d7b402cabd99ee1d3defb7d9971290168159f
5
5
  SHA512:
6
- metadata.gz: b4ea4c955d1957d9e774e7aa27f8bc5508014a6ef75090acbe6ba46319e4f443899ae46bad712a11b45aa19a5240d2f68dba8639fa8f8f811e6fd6e3cc796be1
7
- data.tar.gz: 7f220c8ec126a72dec5369bd9600f361ee1ecd3e552f437b9d136d36067f6564978402184f488a5289c68a8997ce834490b31019480c9fe1fbe816a5a55c2909
6
+ metadata.gz: b4a7f2c661bf5751a2d6c06ddf9e261f0327832f236d80ef19da676826899cff721e0bb21e16d8d8bf64019a3006bc11d1720730d3d512fc991c023c464c61ed
7
+ data.tar.gz: ed8e1227f194bdd687e5329c22dc8406ed076d25d973dc3b7624dca033c0db86ac1c84804cba204b169a20c73d5028d0c3ccd0d2047f321a2b4b966fe9301fb9
@@ -68,7 +68,7 @@ class Simple::SQL::Connection
68
68
  records = all sql, *args, into: Hash
69
69
  end
70
70
 
71
- Simple::SQL::Helpers::Printer.print(records, width: width, io: io)
71
+ ::Simple::SQL::Helpers::Printer.print(records, width: width, io: io)
72
72
  records
73
73
  end
74
74
 
@@ -1,4 +1,4 @@
1
- # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
1
+ # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity
2
2
 
3
3
  # private
4
4
  module Simple::SQL::Helpers::Printer
@@ -6,30 +6,42 @@ module Simple::SQL::Helpers::Printer
6
6
 
7
7
  ROW_SEPARATOR = " | "
8
8
 
9
- def self.print(records, io: STDOUT, width: :auto)
9
+ def print(records, io: STDOUT, width: :auto)
10
10
  # check args
11
11
 
12
12
  return if records.empty?
13
- return if records.first.keys.empty?
14
13
 
15
- if width == :auto && io.isatty
16
- width = `tput cols`.to_i
17
- end
14
+ column_count = records.first.length
15
+ return if column_count == 0
16
+
17
+ # -- determine/adjust total width for output. -----------------------------
18
+
19
+ width = terminal_width(io) if width == :auto
18
20
  width = nil if width && width <= 0
19
21
 
20
- # prepare printing
22
+ # -- prepare printing -----------------------------------------------------
21
23
 
22
24
  rows = materialize_rows(records)
23
- column_widths = calculate_column_widths(rows)
24
- column_widths = optimize_column_widths(column_widths, width, rows.first.length) if width
25
+ column_widths = column_max_lengths(rows)
26
+ if width
27
+ column_widths = distribute_column_widths(column_widths, width, column_count, rows.first)
28
+ end
25
29
 
26
- # print
30
+ # -- print ----------------------------------------------------------------
27
31
 
28
32
  print_records(rows, io, column_widths)
29
33
  end
30
34
 
31
35
  private
32
36
 
37
+ def terminal_width(io)
38
+ return unless io.isatty
39
+
40
+ `tput cols`.to_i
41
+ rescue Errno::ENOENT
42
+ nil
43
+ end
44
+
33
45
  def materialize_rows(records)
34
46
  keys = records.first.keys
35
47
 
@@ -41,31 +53,75 @@ module Simple::SQL::Helpers::Printer
41
53
  rows
42
54
  end
43
55
 
44
- def calculate_column_widths(rows)
56
+ def column_max_lengths(rows)
45
57
  rows.inject([0] * rows.first.length) do |ary, row|
46
58
  ary.zip(row.map(&:length)).map(&:max)
47
59
  end
48
60
  end
49
61
 
50
- def optimize_column_widths(column_widths, width, column_count)
51
- required_width = column_widths.sum + column_count * ROW_SEPARATOR.length
52
- overflow = required_width - width
53
- return column_widths if overflow <= 0
62
+ MIN_COLUMN_WIDTH = 7
63
+
64
+ def distribute_column_widths(column_widths, total_chars, column_count, title_row)
65
+ # caluclate available width: this is the number of characters available in
66
+ # total, reduced by the characters "wasted" for row separators.
67
+ available_chars = total_chars - (column_count - 1) * ROW_SEPARATOR.length
68
+
69
+ return column_widths if available_chars <= 0
70
+
71
+ # [TODO] The algorithm below produces ok-ish results - but usually misses a few characters
72
+ # that could still be assigned a column. To do this we shuld emply D'Hondt or something
73
+ # similar.
74
+
75
+ # -- initial setup --------------------------------------------------------
76
+ #
77
+ # We guarantee each column a minimum number of characters of MIN_COLUMN_WIDTH.
78
+ # If the column does not need that many characters, it will only be allocated
79
+ # the number of characters that are really necessary.
80
+ #
81
+ # If necessary we then extend a column to fit its title.
54
82
 
55
- # TODO: Use d'hondt with a minimum percentage for a fairer distribution
56
- # The following is just a quick hack...
57
- overflow += 40
83
+ result = [MIN_COLUMN_WIDTH] * column_count
84
+ result = result.zip(column_widths).map(&:min)
85
+ result = result.zip(title_row).map { |r, title| [r, title.length].max }
86
+
87
+ # -- return if there are no more characters available ---------------------
88
+
89
+ # This happens if the terminal is **way** to narrow.
90
+ return column_widths if result.sum > available_chars
91
+
92
+ # -- distribute unassigned characters -------------------------------------
93
+
94
+ unassigned_widths = column_widths.zip(result).sum { |cw, r| cw - r }
95
+ if unassigned_widths > 0
96
+ available_space = available_chars - result.sum
97
+ if available_space > 0
98
+
99
+ result = result.zip(column_widths).map do |r, cw|
100
+ r + (cw - r) * available_space / unassigned_widths
101
+ end
102
+ end
103
+ end
104
+
105
+ # [TODO] We can still have available characters at this point.
106
+ # unassigned_chars = available_chars - result.sum
107
+
108
+ result
109
+ end
58
110
 
59
- column_widths.map do |col_width|
60
- (col_width - overflow * col_width * 1.0 / required_width).to_i
111
+ def format_value(value, width)
112
+ if value.length < width
113
+ "%-#{width}s" % value
114
+ elsif value.length == width
115
+ value
116
+ else
117
+ value[0, width - 1] + "…"
61
118
  end
62
119
  end
63
120
 
64
121
  def print_records(rows, io, column_widths)
65
122
  rows.each_with_index do |row, idx|
66
123
  parts = row.zip(column_widths).map do |value, col_width|
67
- s = "%-#{col_width}s " % value
68
- s[0..col_width]
124
+ format_value value, col_width
69
125
  end
70
126
 
71
127
  io.puts parts.join(ROW_SEPARATOR)
@@ -1,5 +1,5 @@
1
1
  module Simple
2
2
  module SQL
3
- VERSION = "0.5.15"
3
+ VERSION = "0.5.16"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: simple-sql
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.15
4
+ version: 0.5.16
5
5
  platform: ruby
6
6
  authors:
7
7
  - radiospiel
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2019-06-28 00:00:00.000000000 Z
12
+ date: 2019-07-05 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: pg_array_parser