Class: TextTable

Inherits:
Object
  • Object
show all
Defined in:
lib/texttable.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(*args) ⇒ TextTable

Returns a new instance of TextTable.



42
43
44
45
46
47
48
49
50
51
52
# File 'lib/texttable.rb', line 42

def initialize(*args)
  cols = args
  cols        =  cols[0] if           cols[0].is_a?(Array) && cols[0][0].is_a?(Array)
  cols, *rows =  cols    if           cols[0].is_a?(Array)
  rows        = *rows[0] if  rows &&  rows[0].is_a?(Array) && rows[0][0].is_a?(Array)
  rows        = []       if !rows || !rows[0].is_a?(Array) || rows[0].empty?
  @cols = Hash.new {|h,k| h[k] = h.size}
  @rows = rows
  row(0)
  cols.each_with_index {|col, i| index!(col || i) }
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(field, *args) ⇒ Object



137
138
139
140
141
142
143
144
145
146
147
148
# File 'lib/texttable.rb', line 137

def method_missing(field, *args)
  field = field.to_s
  equal = field.chomp!('=')
  index = index(field, equal)
  if equal
    value = vals[index] = args.first
  elsif index
    raise "variable lookup ignores arguments" unless args.empty?
    value = vals[index]
  end
  value
end

Instance Attribute Details

#rowsObject

Returns the value of attribute rows.



2
3
4
# File 'lib/texttable.rb', line 2

def rows
  @rows
end

#valuesObject

Returns the value of attribute values.



2
3
4
# File 'lib/texttable.rb', line 2

def values
  @values
end

Class Method Details

.add(*args) ⇒ Object



16
17
18
# File 'lib/texttable.rb', line 16

def add(*args)
  new.add(*args)
end

.csv(src, sep = ',', encoding: nil, **kw) ⇒ Object



5
6
7
8
9
10
11
12
# File 'lib/texttable.rb', line 5

def csv(src, sep=',', encoding: nil, **kw)
  require 'csv'
  new CSV.read(src || ARGF, {
    col_sep:  sep,
    encoding: encoding ? encoding + ":UTF-8" : nil,
    **kw
  }.compact)
end

.load(data, delim = "\t", headers = true) ⇒ Object



20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/texttable.rb', line 20

def load(data, delim="\t", headers=true)
  case data
  when String
    if data.include?(delim) # string
      text = data
    elsif File.exist?(data) # filename
      text = File.read(data)
    end
  when File, ARGF
    text = data.read
  end

  text or raise "unable to load #{data.inspect}"
  rows = text.split(/\r?\n/).map {|line| line.split(delim).map {|part| part.strip}}
  info = new
  rows.shift.each_with_index {|col, i| info.index!(col || i) } if headers
  info.rows = rows
  info.row(0)
  info
end

.psv(*args, **kw) ⇒ Object



14
# File 'lib/texttable.rb', line 14

def psv(*args, **kw); csv(args.shift, "|" , *args, **kw); end

.tsv(*args, **kw) ⇒ Object



13
# File 'lib/texttable.rb', line 13

def tsv(*args, **kw); csv(args.shift, "\t", *args, **kw); end

Instance Method Details

#[](field, val = nil) ⇒ Object



126
127
128
129
130
# File 'lib/texttable.rb', line 126

def [](field, val=nil)
  index = index(field)
  value = vals[index] if index
  value.nil? ? val : value
end

#[]=(field, value) ⇒ Object



132
133
134
135
# File 'lib/texttable.rb', line 132

def []=(field, value)
  index = index!(field)
  vals[index] = value
end

#add(obj, *args) ⇒ Object Also known as: <<



160
161
162
163
# File 'lib/texttable.rb', line 160

def add(obj, *args)
  @values = @rows[@row = @rows.size] = []
  update(obj, *args)
end

#as_json(obj = defined?(ConfigHash) ? +{} : {}) ⇒ Object



195
196
197
# File 'lib/texttable.rb', line 195

def as_json(obj = defined?(ConfigHash) ? +{} : {})
  (@rows || []).map {|r| r.each_with_index.inject(obj) {|h, (v, c)| h[fields[c]] = v; h }}
end

#convert_key(key) ⇒ Object



78
79
80
81
82
83
84
# File 'lib/texttable.rb', line 78

def convert_key(key)
  key.
    gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2').
    gsub(/([a-z\d])([A-Z])/, '\1_\2').
    gsub(/\W/, '_').
    downcase
end

#csv(sep = ',', encoding: nil, **kw) ⇒ Object



199
200
201
202
203
204
205
206
207
208
209
210
211
# File 'lib/texttable.rb', line 199

def csv(sep=',', encoding: nil, **kw)
  require 'csv'
  out = kw.key?(:out) ? (kw.delete(:out) || "").dup : nil
  csv = CSV.new(out || $stdout, {
    col_sep:     sep,
    encoding:    encoding ? encoding + ":UTF-8" : nil,
    quote_empty: false, #!# TODO: make this an option
    **kw
  })
  csv << @cols.keys
  @rows.each {|vals| csv << vals}
  out
end

#eachObject



117
118
119
120
# File 'lib/texttable.rb', line 117

def each
  @rows or raise "no rows defined"
  @rows.each_with_index {|_, row| yield(row(row)) }
end

#each_pairObject



122
123
124
# File 'lib/texttable.rb', line 122

def each_pair
  @cols.each {|col, pos| yield col, @values[pos] }
end

#fieldsObject



90
91
92
# File 'lib/texttable.rb', line 90

def fields
  @cols.keys
end

#index(field, auto = false) ⇒ Object



54
55
56
57
58
59
60
61
62
63
64
# File 'lib/texttable.rb', line 54

def index(field, auto=false)
  case field
  when String, Symbol
    field = convert_key(field)
    index = @cols.key?(field) ? @cols[field] : auto ? @cols[field] : nil
  when Numeric
    field
  else
    raise "invalid field index #{field.inspect}"
  end
end

#index!(field) ⇒ Object



66
67
68
# File 'lib/texttable.rb', line 66

def index!(field)
  index(field, true)
end

#lookup!(field) ⇒ Object



70
71
72
73
74
75
76
# File 'lib/texttable.rb', line 70

def lookup!(field)
  @rows or raise "no rows defined"
  index = index(field)
  lookup = {}
  @rows.each_with_index {|cols, i| lookup[cols[index]] = i}
  lookup
end

#next!(step = 1) ⇒ Object



105
106
107
# File 'lib/texttable.rb', line 105

def next!(step=1)
  row(@row += step) if @row < (size - step)
end

#prev!(step = 1) ⇒ Object



109
110
111
# File 'lib/texttable.rb', line 109

def prev!(step=1)
  row(@row -= step) if @row > 0
end

#psv(**kw) ⇒ Object



213
# File 'lib/texttable.rb', line 213

def psv(**kw); csv("|" , **kw); end

#row(row = nil) ⇒ Object



94
95
96
97
98
# File 'lib/texttable.rb', line 94

def row(row=nil)
  row or return @row
  @values = @rows[@row = row]
  self
end

#row=(row) ⇒ Object



100
101
102
103
# File 'lib/texttable.rb', line 100

def row=(row)
  @values = @rows[@row = row]
  @row
end

#showObject



167
168
169
# File 'lib/texttable.rb', line 167

def show(*)
  self
end

#show!(list = nil) ⇒ Object



171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
# File 'lib/texttable.rb', line 171

def show!(list=nil)
  meth = list.is_a?(Array) ? list.method(:push) : method(:puts)
  join = ""
  size = @cols.size
  full = [@cols.keys] + rows
  full.each_with_index do |vals, i| # only when asymmetric
    miss = size - vals.size
    full[i] += [nil] * miss  if miss > 0
    full[i] = vals[0...size] if miss < 0
  end
  lens = full.map {|r| r.map {|c| c.to_s.size}}.transpose.map(&:max)
  pict = lens.map {|len| "%-#{len}.#{len}s" }.join(join)
  pict = [join, pict, join].join.strip
  line = (pict % ([""] * size)).tr("", "•─")
  seen = -1
  meth["", line]
  full.each do |vals|
    meth[pict % vals]
    meth[line] if (seen += 1) == 0
  end
  meth[line, "#{seen} rows displayed", ""]
  self
end

#sizeObject



86
87
88
# File 'lib/texttable.rb', line 86

def size
  @rows.size
end

#sql(table = 'table', quote: false, timestamps: false, verb: 'insert', out: nil) ⇒ Object



215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
# File 'lib/texttable.rb', line 215

def sql(table='table', quote: false, timestamps: false, verb: 'insert', out: nil)
  q = quote ? '`' : ''
  flip = @cols.invert
  @rows.each do |vals|
    list = vals.each_with_index.inject([]) do |list, (item, i)|
      item = item.to_s #!# FIXME: force all to a string for now...
      list << "#{q}#{flip[i]}#{q}='#{item.gsub("'","''")}'" if item =~ /\S/
      list
    end
    list.push('created_at=now(), updated_at=now()') if timestamps
    if !list.empty?
      line = "#{verb} into #{q}#{table}#{q} set #{list * ', '};"
      out ? (out << line) : puts(line)
    end
  end
  out
end

#tsv(**kw) ⇒ Object



212
# File 'lib/texttable.rb', line 212

def tsv(**kw); csv("\t", **kw); end

#update(obj, *args) ⇒ Object



150
151
152
153
154
155
156
157
158
# File 'lib/texttable.rb', line 150

def update(obj, *args)
  obj = [obj, *args] if args.size > 0
  case obj
    when Hash  then obj.each {|k, v| @values[index(k.to_s, true)] = v }
    when Array then @values.replace(obj)
    else raise "unable to add #{obj.class} objects"
  end
  self
end

#valsObject



113
114
115
# File 'lib/texttable.rb', line 113

def vals
  @values ||= @rows[@row] ||= []
end