Class: Cellar
Constant Summary
collapse
- VERSION =
"0.2.1"
Instance Attribute Summary collapse
Instance Method Summary
collapse
Constructor Details
#initialize(obj = nil, header: true, strict: true, index: nil) ⇒ Cellar
Returns a new instance of Cellar.
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
|
# File 'lib/cellar.rb', line 37
def initialize(obj=nil, header: true, strict: true, index: nil)
@fields = []
@values = []
@finder = {}
@seeker = {}
@index = index
@widest = 0
if obj.is_a?(Array)
if obj.first.is_a?(Array)
self.fields = obj.shift if
@rows = obj unless obj.empty?
elsif !obj.empty?
? (self.fields = obj) : (@rows = obj)
end
end
@strict = strict.nil? ? !@fields.empty? : !!strict
end
|
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(field, *args) ⇒ Object
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
|
# File 'lib/cellar.rb', line 168
def method_missing(field, *args)
field = field.to_s
equal = field.chomp!("=")
index = index(field)
if equal
index ||= add_field(field)
value = @values[index] = args.first
elsif index
raise "variable lookup ignores arguments" unless args.empty?
value = @values[index]
else
value = ""
end
value
end
|
Instance Attribute Details
Returns the value of attribute fields.
33
34
35
|
# File 'lib/cellar.rb', line 33
def fields
@fields
end
|
Returns the value of attribute strict.
35
36
37
|
# File 'lib/cellar.rb', line 35
def strict
@strict
end
|
Returns the value of attribute values.
34
35
36
|
# File 'lib/cellar.rb', line 34
def values
@values
end
|
Instance Method Details
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
|
# File 'lib/cellar.rb', line 211
def <<(data)
@rows ||= []
@row = row = @rows.size
if self.class === data.class
@rows << @values = []
self[*data.fields] = data.values
elsif data.is_a?(Array) && !data.first.is_a?(Array)
@rows << (@values = data)
else
raise "unable to << your object"
end
if @index
block = @index if @index.is_a?(Proc)
field = @index unless block
index = index(field) or raise "unknown index #{field.inspect}" if field
if key = block ? block.call(self) : @values[index]
@seeker[key] and raise "duplicate index: #{key.inspect}"
@seeker[key] = row
end
end
self
end
|
#[](*fields) ⇒ Object
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
|
# File 'lib/cellar.rb', line 113
def [](*fields)
case fields.size
when 0
[]
when 1
first = fields.first
first.is_a?(Cellar) and return self[*first.fields]
index = index(fields.first)
value = @values[index] if index
else
fields.inject([]) do |values, field|
index = index(field)
value = case index
when nil then nil
when Array then @values.values_at(*index)
else @values[index]
end
Array === value ? values.concat(value) : values.push(value)
end
end
end
|
#[]=(*fields) ⇒ Object
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
|
# File 'lib/cellar.rb', line 135
def []=(*fields)
values = Array(fields.pop).dup
fields = fields.map {|field| Array(index(field) || add_field(field))}.flatten
if fields.empty?
@values.replace(values)
elsif values.size > fields.size
raise "unable to assign #{values.size} values to #{fields.size} fields for values=#{values.inspect}"
else
fields.each_with_index do |field, pos|
@values[field] = values[pos]
end
end
@values
end
|
#add_field(field) ⇒ Object
57
58
59
60
61
62
63
64
65
66
67
|
# File 'lib/cellar.rb', line 57
def add_field(field)
field = field.to_s
index = @fields.size
@fields << field
finders = @finder.size
@finder[field.downcase.gsub(/\W/,'_')] ||= index
@finder.size == finders + 1 or warn "field clash for #{field.inspect}"
@finder[field] ||= index
@widest = field.length if field.length > @widest
index
end
|
197
198
199
|
# File 'lib/cellar.rb', line 197
def cells
[@fields.dup] + (@rows || [@values])
end
|
108
109
110
111
|
# File 'lib/cellar.rb', line 108
def clear
@values = []
self
end
|
275
276
277
278
|
# File 'lib/cellar.rb', line 275
def each
@rows or raise "no rows defined"
@rows.each_with_index {|values, row| yield(row(row)) }
end
|
#field(pos) ⇒ Object
164
165
166
|
# File 'lib/cellar.rb', line 164
def field(pos)
@fields[pos]
end
|
#fill!(data, &block) ⇒ Object
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
|
# File 'lib/cellar.rb', line 234
def fill!(data, &block)
self.class == data.class or raise "unable to fill with your #{data.class}"
data.values.each_with_index do |val, idx|
next if val.blank?
field = data.fields[idx]
index = index(field) || add_field(field)
value = @values[index]
if block && !value.blank?
val = block.call(value, val)
next if val.blank?
end
@values[index] = val
end
self
end
|
#from_array(list) ⇒ Object
285
286
287
288
289
|
# File 'lib/cellar.rb', line 285
def from_array(list)
clear
@values = list.map {|v| v.to_s.strip if v }
self
end
|
#from_hash(hash) ⇒ Object
291
292
293
294
295
|
# File 'lib/cellar.rb', line 291
def from_hash(hash)
clear
hash.each {|k,v| self[k] = v.to_s if v }
self
end
|
#index(field) ⇒ Object
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
|
# File 'lib/cellar.rb', line 82
def index(field)
case field
when String, Symbol
field = field.to_s
index = @finder[field] || @finder[field.downcase.gsub(/\W/,'_')]
raise "no field #{field.inspect}" if !index && @strict
index
when Integer
raise "no field at index #{field}" if field >= @fields.size && @strict
field < 0 ? field % @fields.size : field
when Range
from = field.begin
till = field.end
from = from.blank? ? 0 : index(from)
till = till.blank? ? -1 : index(till)
case from <=> till
when 1 then field.exclude_end? ? [*(till+1)..from].reverse : [*till..from].reverse
when 0 then from
when -1 then field.exclude_end? ? from...till : from..till
else "no fields match #{field.inspect}"
end
else
raise "unable to index fields by #{field.class.inspect} [#{field.inspect}]"
end
end
|
#index!(field = nil, &block) ⇒ Object
250
251
252
253
254
255
256
257
258
259
260
261
262
|
# File 'lib/cellar.rb', line 250
def index!(field=nil, &block)
@rows ||= []
@index = field || block or raise "index needs a field or a block"
index = index(field) or raise "unknown index #{field.inspect}" if field && @rows.size > 0
@seeker.clear
@rows.each_with_index do |values, row|
if key = block ? yield(row(row)) : values[index]
@seeker[key] and raise "duplicate index: #{key.inspect}"
@seeker[key] = row
end
end
self
end
|
280
281
282
283
|
# File 'lib/cellar.rb', line 280
def map
@rows or raise "no rows defined"
@rows.map.with_index {|values, row| yield(row(row)) }
end
|
#rename_field(field, other) ⇒ Object
69
70
71
72
73
74
75
76
77
78
79
80
|
# File 'lib/cellar.rb', line 69
def rename_field(field, other)
field = field.to_s
index = index(field) or raise "unable to rename the #{field.inspect} field"
@finder.delete(field.downcase.gsub(/\W/,'_'))
@finder.delete(field)
other = other.to_s
fields[index] = other
@finder[other.downcase.gsub(/\W/,'_')] ||= index
@finder[other] ||= index
@widest = fields.map(&:size).max
index
end
|
#row(row = nil) ⇒ Object
205
206
207
208
209
|
# File 'lib/cellar.rb', line 205
def row(row=nil)
@rows or raise "no rows defined"
@values = row ? @rows[@row = row] : []
self
end
|
#row=(row) ⇒ Object
192
193
194
195
|
# File 'lib/cellar.rb', line 192
def row=(row)
@rows or raise "no rows defined"
row(row) end
|
201
202
203
|
# File 'lib/cellar.rb', line 201
def rows
@rows
end
|
#rows=(rows) ⇒ Object
186
187
188
189
190
|
# File 'lib/cellar.rb', line 186
def rows=(rows)
rows or raise "no rows defined"
@rows = rows
row(0) end
|
#seek!(seek) ⇒ Object
264
265
266
267
268
269
270
271
272
273
|
# File 'lib/cellar.rb', line 264
def seek!(seek)
return nil if @rows.blank? || @seeker.blank?
if row = @seeker[seek]
row(row)
else
@values = []
@row = nil
end
end
|
#show!(list = nil, output: :stdout) ⇒ Object
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
|
# File 'lib/cellar.rb', line 311
def show!(list=nil, output: :stdout)
tabs = output == :tabs
meth = list.is_a?(Array) ? list.method(:push) : method(:puts)
join = tabs ? "\t" : " │ "
size = @fields.size
full = cells
full.each_with_index do |vals, i| 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] unless tabs
full.each do |vals|
meth[pict % vals]
meth[line] if !tabs && ((seen += 1) == 0)
end
meth[line, "#{seen} row#{'s' if seen != 1} displayed", ""] unless tabs
self
end
|
#show? ⇒ Boolean
307
308
309
|
# File 'lib/cellar.rb', line 307
def show?
self
end
|
297
298
299
300
301
302
303
|
# File 'lib/cellar.rb', line 297
def to_hash!
@fields.size.times.inject({}) do |h, i|
v = @values[i]
h[@fields[i].downcase.gsub(/\W/,'_')] = v if !v.blank?
h
end
end
|