tablestakes 0.8.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/README.md +218 -0
- data/capitals.sorted +50 -0
- data/capitals.txt +51 -0
- data/cities.txt +290 -0
- data/doc/Table.html +1174 -0
- data/doc/created.rid +2 -0
- data/doc/images/add.png +0 -0
- data/doc/images/arrow_up.png +0 -0
- data/doc/images/brick.png +0 -0
- data/doc/images/brick_link.png +0 -0
- data/doc/images/bug.png +0 -0
- data/doc/images/bullet_black.png +0 -0
- data/doc/images/bullet_toggle_minus.png +0 -0
- data/doc/images/bullet_toggle_plus.png +0 -0
- data/doc/images/date.png +0 -0
- data/doc/images/delete.png +0 -0
- data/doc/images/find.png +0 -0
- data/doc/images/loadingAnimation.gif +0 -0
- data/doc/images/macFFBgHack.png +0 -0
- data/doc/images/package.png +0 -0
- data/doc/images/page_green.png +0 -0
- data/doc/images/page_white_text.png +0 -0
- data/doc/images/page_white_width.png +0 -0
- data/doc/images/plugin.png +0 -0
- data/doc/images/ruby.png +0 -0
- data/doc/images/tag_blue.png +0 -0
- data/doc/images/tag_green.png +0 -0
- data/doc/images/transparent.png +0 -0
- data/doc/images/wrench.png +0 -0
- data/doc/images/wrench_orange.png +0 -0
- data/doc/images/zoom.png +0 -0
- data/doc/index.html +71 -0
- data/doc/js/darkfish.js +155 -0
- data/doc/js/jquery.js +18 -0
- data/doc/js/navigation.js +142 -0
- data/doc/js/search.js +94 -0
- data/doc/js/search_index.js +1 -0
- data/doc/js/searcher.js +228 -0
- data/doc/rdoc.css +595 -0
- data/doc/table_of_contents.html +88 -0
- data/lib/tablestakes.rb +407 -0
- data/spec/factories.rb +16 -0
- data/spec/spec_helper.rb +11 -0
- data/spec/table_spec.rb +179 -0
- data/test.tab +4 -0
- metadata +110 -0
@@ -0,0 +1,88 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
|
3
|
+
<html>
|
4
|
+
<head>
|
5
|
+
<meta content="text/html; charset=UTF-8" http-equiv="Content-Type">
|
6
|
+
|
7
|
+
<title>Table of Contents - RDoc Documentation</title>
|
8
|
+
|
9
|
+
<link type="text/css" media="screen" href="./rdoc.css" rel="stylesheet">
|
10
|
+
|
11
|
+
<script type="text/javascript">
|
12
|
+
var rdoc_rel_prefix = "./";
|
13
|
+
</script>
|
14
|
+
|
15
|
+
<script type="text/javascript" charset="utf-8" src="./js/jquery.js"></script>
|
16
|
+
<script type="text/javascript" charset="utf-8" src="./js/navigation.js"></script>
|
17
|
+
<script type="text/javascript" charset="utf-8" src="./js/search_index.js"></script>
|
18
|
+
<script type="text/javascript" charset="utf-8" src="./js/search.js"></script>
|
19
|
+
<script type="text/javascript" charset="utf-8" src="./js/searcher.js"></script>
|
20
|
+
<script type="text/javascript" charset="utf-8" src="./js/darkfish.js"></script>
|
21
|
+
|
22
|
+
|
23
|
+
<body class="indexpage">
|
24
|
+
<h1>Table of Contents - RDoc Documentation</h1>
|
25
|
+
|
26
|
+
|
27
|
+
<h2 id="classes">Classes/Modules</h2>
|
28
|
+
<ul>
|
29
|
+
<li class="class">
|
30
|
+
<a href="Table.html">Table</a>
|
31
|
+
</li>
|
32
|
+
|
33
|
+
</ul>
|
34
|
+
|
35
|
+
<h2 id="methods">Methods</h2>
|
36
|
+
<ul>
|
37
|
+
|
38
|
+
<li class="method"><a href="Table.html#method-c-new">::new — Table</a>
|
39
|
+
|
40
|
+
<li class="method"><a href="Table.html#method-i-bottom">#bottom — Table</a>
|
41
|
+
|
42
|
+
<li class="method"><a href="Table.html#method-i-column">#column — Table</a>
|
43
|
+
|
44
|
+
<li class="method"><a href="Table.html#method-i-count">#count — Table</a>
|
45
|
+
|
46
|
+
<li class="method"><a href="Table.html#method-i-get_columns">#get_columns — Table</a>
|
47
|
+
|
48
|
+
<li class="method"><a href="Table.html#method-i-get_rows">#get_rows — Table</a>
|
49
|
+
|
50
|
+
<li class="method"><a href="Table.html#method-i-intersect">#intersect — Table</a>
|
51
|
+
|
52
|
+
<li class="method"><a href="Table.html#method-i-join">#join — Table</a>
|
53
|
+
|
54
|
+
<li class="method"><a href="Table.html#method-i-length">#length — Table</a>
|
55
|
+
|
56
|
+
<li class="method"><a href="Table.html#method-i-row">#row — Table</a>
|
57
|
+
|
58
|
+
<li class="method"><a href="Table.html#method-i-select">#select — Table</a>
|
59
|
+
|
60
|
+
<li class="method"><a href="Table.html#method-i-size">#size — Table</a>
|
61
|
+
|
62
|
+
<li class="method"><a href="Table.html#method-i-sub">#sub — Table</a>
|
63
|
+
|
64
|
+
<li class="method"><a href="Table.html#method-i-sub-21">#sub! — Table</a>
|
65
|
+
|
66
|
+
<li class="method"><a href="Table.html#method-i-tally">#tally — Table</a>
|
67
|
+
|
68
|
+
<li class="method"><a href="Table.html#method-i-to_a">#to_a — Table</a>
|
69
|
+
|
70
|
+
<li class="method"><a href="Table.html#method-i-to_s">#to_s — Table</a>
|
71
|
+
|
72
|
+
<li class="method"><a href="Table.html#method-i-top">#top — Table</a>
|
73
|
+
|
74
|
+
<li class="method"><a href="Table.html#method-i-union">#union — Table</a>
|
75
|
+
|
76
|
+
<li class="method"><a href="Table.html#method-i-where">#where — Table</a>
|
77
|
+
|
78
|
+
<li class="method"><a href="Table.html#method-i-write_file">#write_file — Table</a>
|
79
|
+
|
80
|
+
</ul>
|
81
|
+
|
82
|
+
|
83
|
+
<footer id="validator-badges">
|
84
|
+
<p><a href="http://validator.w3.org/check/referer">[Validate]</a>
|
85
|
+
<p>Generated by <a href="https://github.com/rdoc/rdoc">RDoc</a> 4.0.0.
|
86
|
+
<p>Generated with the <a href="http://deveiate.org/projects/Darkfish-Rdoc/">Darkfish Rdoc Generator</a> 3.
|
87
|
+
</footer>
|
88
|
+
|
data/lib/tablestakes.rb
ADDED
@@ -0,0 +1,407 @@
|
|
1
|
+
#!/usr/bin/ruby -w
|
2
|
+
#
|
3
|
+
# Tablestakes is an implementation of a generic table class
|
4
|
+
# which takes input from a tab-delimited file and creates a
|
5
|
+
# generic table data structure that can be manipulated with
|
6
|
+
# methods similar to the way a database table may be manipulated.
|
7
|
+
#
|
8
|
+
# Author:: J.B. Folkerts (mailto:jbf@pentambic.com)
|
9
|
+
# Copyright:: Copyright (c) 2014 J.B. Folkerts
|
10
|
+
# License:: Distributes under the same terms as Ruby
|
11
|
+
|
12
|
+
# This class is a Ruby representation of a table. All data is captured as
|
13
|
+
# type +String+ by default. Columns are referred to by their +String+ headers
|
14
|
+
# which are assumed to be identified in the first row of the input file.
|
15
|
+
# Output is written by default to tab-delimited files with the first row
|
16
|
+
# serving as the header names.
|
17
|
+
|
18
|
+
class Table
|
19
|
+
# The headers attribute contains the table headers used to reference
|
20
|
+
# columns in the +Table+. All headers are represented as +String+ types.
|
21
|
+
attr_reader :headers
|
22
|
+
@headers =[]
|
23
|
+
@table = {}
|
24
|
+
@indices = {}
|
25
|
+
# Structure of @table hash
|
26
|
+
# { :col1 => [1, 2, 3], :col2 => [1, 2, 3] }
|
27
|
+
|
28
|
+
|
29
|
+
# Instantiate a +Table+ object using a tab-delimited file
|
30
|
+
#
|
31
|
+
# +input+:: OPTIONAL +Array+ of rows or +String+ to identify the name of the tab-delimited file to read
|
32
|
+
def initialize(input=nil)
|
33
|
+
@headers = []
|
34
|
+
@table = {}
|
35
|
+
@indices = {}
|
36
|
+
|
37
|
+
if input.respond_to?(:fetch)
|
38
|
+
if input[0].respond_to?(:fetch)
|
39
|
+
#create +Table+ from rows
|
40
|
+
add_rows(input)
|
41
|
+
end
|
42
|
+
elsif input.respond_to?(:upcase)
|
43
|
+
# a string, then read_file
|
44
|
+
read_file(input)
|
45
|
+
elsif input.respond_to?(:headers)
|
46
|
+
init(input)
|
47
|
+
end
|
48
|
+
# else create empty +Table+
|
49
|
+
end
|
50
|
+
|
51
|
+
# Return a copy of a column from the table, identified by column name.
|
52
|
+
# Returns +nil+ if column name not found.
|
53
|
+
#
|
54
|
+
# +colname+:: +String+ to identify the name of the column
|
55
|
+
def column(colname)
|
56
|
+
# check arguments
|
57
|
+
return nil unless @table.has_key?(colname)
|
58
|
+
|
59
|
+
Array(@table[colname])
|
60
|
+
end
|
61
|
+
|
62
|
+
# Return a copy of a row from the table as an +Array+, given an index
|
63
|
+
# (i.e. row number). Returns empty Array if the index is out of bounds.
|
64
|
+
#
|
65
|
+
# +index+:: +FixNum+ indicating index of the row.
|
66
|
+
def row(index)
|
67
|
+
Array(get_row(index))
|
68
|
+
end
|
69
|
+
|
70
|
+
# Converts a +Table+ object to a tab-delimited string.
|
71
|
+
#
|
72
|
+
# none
|
73
|
+
def to_s
|
74
|
+
result = @headers.join("\t") << "\n"
|
75
|
+
|
76
|
+
@table[@headers.first].length.times do |row|
|
77
|
+
@headers.each do |col|
|
78
|
+
result << @table[col][row].to_s
|
79
|
+
unless col == @headers.last
|
80
|
+
result << "\t"
|
81
|
+
else
|
82
|
+
result << "\n"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
result
|
87
|
+
end
|
88
|
+
|
89
|
+
# Converts a +Table+ object to an array of arrays (each row)
|
90
|
+
#
|
91
|
+
# none
|
92
|
+
def to_a
|
93
|
+
result = [ Array(@headers) ]
|
94
|
+
|
95
|
+
@table[@headers.first].length.times do |row|
|
96
|
+
items = []
|
97
|
+
@headers.each do |col|
|
98
|
+
items << @table[col][row]
|
99
|
+
end
|
100
|
+
result << items
|
101
|
+
end
|
102
|
+
result
|
103
|
+
end
|
104
|
+
|
105
|
+
# Counts the number of instances of a particular string, given a column name,
|
106
|
+
# and returns an integer >= 0. Returns +nil+ if the column is not found. If
|
107
|
+
# no parameters are given, returns the number of rows in the table.
|
108
|
+
#
|
109
|
+
# +colname+:: OPTIONAL +String+ to identify the column to count
|
110
|
+
# +value+:: OPTIONAL +String+ value to count
|
111
|
+
def count(colname=nil, value=nil)
|
112
|
+
if colname.nil? || value.nil?
|
113
|
+
if @table.size > 0
|
114
|
+
@table.each_key {|e| return @table.fetch(e).length }
|
115
|
+
else
|
116
|
+
return nil
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
if @table[colname]
|
121
|
+
result = 0
|
122
|
+
@table[colname].each do |val|
|
123
|
+
val == value.to_s ? result += 1 : nil
|
124
|
+
end
|
125
|
+
result
|
126
|
+
else
|
127
|
+
nil
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
alias :size :count
|
132
|
+
alias :length :count
|
133
|
+
|
134
|
+
# Counts the number of instances of a particular string, given a column name,
|
135
|
+
# and returns an integer >= 0. Returns +nil+ if the column is not found. If
|
136
|
+
# no parameters are given, returns the number of rows in the table.
|
137
|
+
#
|
138
|
+
# +colname+:: +String+ to identify the column to count
|
139
|
+
# +num+:: OPTIONAL +String+ number of values to return
|
140
|
+
def top(colname, num=1)
|
141
|
+
freq = tally(colname).to_a[1..-1].sort_by {|k,v| v }.reverse
|
142
|
+
return Table.new(freq[0..num-1].unshift(["State","Count"]))
|
143
|
+
end
|
144
|
+
|
145
|
+
|
146
|
+
# Counts the number of instances of a particular string, given a column name,
|
147
|
+
# and returns an integer >= 0. Returns +nil+ if the column is not found. If
|
148
|
+
# no parameters are given, returns the number of rows in the table.
|
149
|
+
#
|
150
|
+
# +colname+:: +String+ to identify the column to count
|
151
|
+
# +num+:: OPTIONAL +String+ number of values to return
|
152
|
+
def bottom(colname, num=1)
|
153
|
+
freq = tally(colname).to_a[1..-1].sort_by {|k,v| v }
|
154
|
+
return Table.new(freq[0..num-1].unshift(["State","Count"]))
|
155
|
+
end
|
156
|
+
|
157
|
+
|
158
|
+
|
159
|
+
# Count instances in a particular field/column and return a +Table+ of the results.
|
160
|
+
# Returns +nil+ if the column is not found.
|
161
|
+
#
|
162
|
+
# +colname+:: +String+ to identify the column to tally
|
163
|
+
def tally(colname)
|
164
|
+
# check arguments
|
165
|
+
return nil unless @table.has_key?(colname)
|
166
|
+
|
167
|
+
result = {}
|
168
|
+
@table[colname].each do |val|
|
169
|
+
result.has_key?(val) ? result[val] += 1 : result[val] = 1
|
170
|
+
end
|
171
|
+
return Table.new([[colname,"Count"]] + result.to_a)
|
172
|
+
end
|
173
|
+
|
174
|
+
# Select columns from the table, given one or more column names. Returns an instance
|
175
|
+
# of +Table+ with the results. Returns nil if any column is not valid.
|
176
|
+
#
|
177
|
+
# +columns+:: Variable +String+ arguments to identify the columns to select
|
178
|
+
def select(*columns)
|
179
|
+
# check arguments
|
180
|
+
columns.each do |c|
|
181
|
+
return nil unless @table.has_key?(c)
|
182
|
+
end
|
183
|
+
|
184
|
+
result = []
|
185
|
+
result_headers = []
|
186
|
+
columns.each { |col| @headers.include?(col) ? result_headers << col : nil }
|
187
|
+
result << result_headers
|
188
|
+
@table[@headers.first].length.times do |row|
|
189
|
+
this_row = []
|
190
|
+
result_headers.each do |col|
|
191
|
+
this_row << @table[col][row]
|
192
|
+
end
|
193
|
+
result << this_row
|
194
|
+
end
|
195
|
+
unless result_headers.empty?
|
196
|
+
return Table.new(result)
|
197
|
+
else
|
198
|
+
return nil
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
alias :get_columns :select
|
203
|
+
|
204
|
+
# Given a particular condition for a given column field/column, return a subtable
|
205
|
+
# that matches the condition. If no condition is given, a new +Table+ is returned with
|
206
|
+
# all records.
|
207
|
+
# Returns +nil+ if the condition is not met or the column is not found.
|
208
|
+
#
|
209
|
+
# +colname+:: +String+ to identify the column to tally
|
210
|
+
# +condition+:: OPTIONAL +String+ containing a ruby condition to evaluate
|
211
|
+
def where(colname, condition=nil)
|
212
|
+
# check arguments
|
213
|
+
return nil unless @table.has_key?(colname)
|
214
|
+
|
215
|
+
result = []
|
216
|
+
result << @headers
|
217
|
+
@table[colname].each_index do |index|
|
218
|
+
if condition
|
219
|
+
eval("'#{@table[colname][index]}' #{condition}") ? result << get_row(index) : nil
|
220
|
+
else
|
221
|
+
result << get_row(index)
|
222
|
+
end
|
223
|
+
end
|
224
|
+
result.length > 1 ? Table.new(result) : nil
|
225
|
+
end
|
226
|
+
|
227
|
+
alias :get_rows :where
|
228
|
+
|
229
|
+
# Given a second table to join against, and a field/column, return a +Table+ which
|
230
|
+
# contains a join of the two tables. Join only lists the common column once, under
|
231
|
+
# the column name of the first table (if different from the name of thee second).
|
232
|
+
# All columns from both tables are returned. Returns +nil+ if the column is not found.
|
233
|
+
#
|
234
|
+
# +table2+:: +Table+ to identify the secondary table in the join
|
235
|
+
# +colname+:: +String+ to identify the column to join on
|
236
|
+
# +col2name+:: OPTIONAL +String+ to identify the column in the second table to join on
|
237
|
+
def join(table2, colname, col2name=nil)
|
238
|
+
# check arguments
|
239
|
+
raise ArgumentError, "Invalid table!" unless table2.is_a?(Table)
|
240
|
+
return nil unless @table.has_key?(colname)
|
241
|
+
if col2name.nil? # Assume colname applies for both tables
|
242
|
+
col2name = colname
|
243
|
+
end
|
244
|
+
t2_col_index = table2.headers.index(col2name)
|
245
|
+
return nil unless t2_col_index # is not nil
|
246
|
+
|
247
|
+
|
248
|
+
# ensure no duplication of header values
|
249
|
+
table2.headers.each do |h|
|
250
|
+
if @headers.include?(h)
|
251
|
+
update_header(h, '_' << h )
|
252
|
+
if h == colname
|
253
|
+
colname = '_' << colname
|
254
|
+
end
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
result = [ Array(@headers) + Array(table2.headers) ]
|
259
|
+
@table[colname].each_index do |index|
|
260
|
+
t2_index = table2.column(col2name).find_index(@table[colname][index])
|
261
|
+
unless t2_index.nil?
|
262
|
+
result << self.row(index) + table2.row(t2_index)
|
263
|
+
end
|
264
|
+
end
|
265
|
+
if result.length == 1 #no rows selected
|
266
|
+
return nil
|
267
|
+
else
|
268
|
+
return Table.new(result)
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
272
|
+
|
273
|
+
# Given a field/column, and a regular expression to match against, and a replacement string,
|
274
|
+
# update the table such that it substitutes the column data with the replacement string.
|
275
|
+
# Returns +nil+ if the column is not found.
|
276
|
+
#
|
277
|
+
# +colname+:: +String+ to identify the column to join on
|
278
|
+
# +re+:: +Regexp+ to match the value in the selected column
|
279
|
+
# +replace+:: +String+ to specify the replacement text for the given +Regexp+
|
280
|
+
def sub(colname, re, replace)
|
281
|
+
# check arguments
|
282
|
+
raise ArgumentError, "No regular expression to match against" unless re
|
283
|
+
raise ArgumentError, "No replacement string specified" unless replace
|
284
|
+
return nil unless @table.has_key?(colname)
|
285
|
+
|
286
|
+
@table[colname].each do |item|
|
287
|
+
item.sub!(re, replace)
|
288
|
+
end
|
289
|
+
return self
|
290
|
+
end
|
291
|
+
|
292
|
+
# Return the union of columns from different tables, eliminating duplicates.
|
293
|
+
# Return nil if a column is not found.
|
294
|
+
#
|
295
|
+
# +table2+:: +Table+ to identify the secondary table in the union
|
296
|
+
# +colname+:: +String+ to identify the column to union
|
297
|
+
# +col2name+:: OPTIONAL +String+ to identify the column in the second table to union
|
298
|
+
def union(table2, colname, col2name=nil)
|
299
|
+
# check arguments
|
300
|
+
raise ArgumentError, "Invalid table!" unless table2.is_a?(Table)
|
301
|
+
return nil unless @table.has_key?(colname)
|
302
|
+
if col2name.nil? # Assume colname applies for both tables
|
303
|
+
col2name = colname
|
304
|
+
end
|
305
|
+
return nil unless table2.headers.include?(col2name)
|
306
|
+
|
307
|
+
return self.column(colname) | table2.column(col2name)
|
308
|
+
end
|
309
|
+
|
310
|
+
# Return the intersection of columns from different tables, eliminating duplicates.
|
311
|
+
# Return nil if a column is not found.
|
312
|
+
#
|
313
|
+
# +table2+:: +Table+ to identify the secondary table in the intersection
|
314
|
+
# +colname+:: +String+ to identify the column to intersection
|
315
|
+
# +col2name+:: OPTIONAL +String+ to identify the column in the second table to intersection
|
316
|
+
def intersect(table2, colname, col2name=nil)
|
317
|
+
# check arguments
|
318
|
+
raise ArgumentError, "Invalid table!" unless table2.is_a?(Table)
|
319
|
+
return nil unless @table.has_key?(colname)
|
320
|
+
if col2name.nil? # Assume colname applies for both tables
|
321
|
+
col2name = colname
|
322
|
+
end
|
323
|
+
return nil unless table2.headers.include?(col2name)
|
324
|
+
|
325
|
+
return self.column(colname) & table2.column(col2name)
|
326
|
+
end
|
327
|
+
|
328
|
+
alias :sub! :sub
|
329
|
+
|
330
|
+
# Write a representation of the +Table+ object to a file (tab delimited).
|
331
|
+
#
|
332
|
+
# +filename+:: +String+ to identify the name of the file to write
|
333
|
+
def write_file(filename)
|
334
|
+
file = File.open(filename, "w")
|
335
|
+
file.print self.to_s
|
336
|
+
end
|
337
|
+
|
338
|
+
private
|
339
|
+
|
340
|
+
def read_file(filename)
|
341
|
+
file = File.open(filename, "r")
|
342
|
+
@headers = file.gets.chomp.split("\t")
|
343
|
+
@headers.each {|col| @table.store(col, []) }
|
344
|
+
file.each_line do |line|
|
345
|
+
fields = line.chomp.split("\t")
|
346
|
+
if fields.length != @headers.length
|
347
|
+
$stderr.write "INVALID NUMBER OF FIELDS: #{fields.join(';')}\n"
|
348
|
+
else
|
349
|
+
@headers.each { |col| @table[col] << fields.shift }
|
350
|
+
end
|
351
|
+
nil
|
352
|
+
end
|
353
|
+
end
|
354
|
+
|
355
|
+
def add_rows(array_of_rows)
|
356
|
+
array_of_rows.each do |r|
|
357
|
+
row = r.clone
|
358
|
+
if @headers.empty?
|
359
|
+
@headers = row
|
360
|
+
else
|
361
|
+
unless row.length == @headers.length
|
362
|
+
raise ArgumentError, "Wrong number of fields in Table input"
|
363
|
+
end
|
364
|
+
@headers.each do |col|
|
365
|
+
@table[col] = [] unless @table[col]
|
366
|
+
@table[col] << row.shift
|
367
|
+
end
|
368
|
+
end
|
369
|
+
end
|
370
|
+
end
|
371
|
+
|
372
|
+
def get_row(index)
|
373
|
+
result = []
|
374
|
+
@headers.each do |col|
|
375
|
+
result << @table[col][index].to_s
|
376
|
+
end
|
377
|
+
return result
|
378
|
+
end
|
379
|
+
|
380
|
+
def get_col(colname)
|
381
|
+
result = []
|
382
|
+
@table[colname].each {|e| result << e }
|
383
|
+
end
|
384
|
+
|
385
|
+
def copy
|
386
|
+
result = []
|
387
|
+
result << @headers
|
388
|
+
@table[@headers.first].each_index do |index|
|
389
|
+
result << get_row(index)
|
390
|
+
end
|
391
|
+
result.length > 1 ? Table.new(result) : Table.new()
|
392
|
+
end
|
393
|
+
|
394
|
+
def update_header(item, new_item)
|
395
|
+
i = @headers.index(item)
|
396
|
+
@headers[i] = new_item unless i.nil?
|
397
|
+
@table.fetch(item,nil).nil? ? nil : @table[new_item] = @table[item]
|
398
|
+
end
|
399
|
+
|
400
|
+
def init(table)
|
401
|
+
@headers = table.headers.map {|x| x }
|
402
|
+
@headers.each do |key|
|
403
|
+
@table[key] = table.table[key].map {|x| x }
|
404
|
+
end
|
405
|
+
@indices = {}
|
406
|
+
end
|
407
|
+
end
|