tablr 0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,3 @@
1
+ 0.1 - July 18th, 2011
2
+
3
+ * Initial release
data/COPYING ADDED
@@ -0,0 +1,10 @@
1
+ Copyright (c) 2011, Daniel Durante
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
5
+
6
+ * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
7
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
8
+ * Neither the name of Sinatra Fedora nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
9
+
10
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,60 @@
1
+ # Tablr #
2
+
3
+ Easy console tables in Ruby
4
+
5
+ ## Examples ##
6
+
7
+ # New table
8
+ table = Tablr.new
9
+
10
+ # We can name our columns initially...
11
+ table.columns ['Column X', 'Column 2', 'Column 3']
12
+
13
+ # Or we can just add a column on the fly
14
+ (1..20).each do |number|
15
+ table.add_row 'Column 1', "Entry #{number}"
16
+ end
17
+
18
+ # Just for more filler...
19
+ (1..10).each do
20
+ table.add_row 'Column 2', "Random: #{rand(20)}"
21
+ end
22
+
23
+ # And let's print!
24
+ table.print
25
+
26
+ ### RESULTS ###
27
+
28
+ +----------+------------+----------+----------+
29
+ | Column X | Column 2 | Column 3 | Column 1 |
30
+ +----------+------------+----------+----------+
31
+ | | Random: 8 | | Entry 1 |
32
+ | | Random: 3 | | Entry 2 |
33
+ | | Random: 10 | | Entry 3 |
34
+ | | Random: 17 | | Entry 4 |
35
+ | | Random: 4 | | Entry 5 |
36
+ | | Random: 1 | | Entry 6 |
37
+ | | Random: 19 | | Entry 7 |
38
+ | | Random: 15 | | Entry 8 |
39
+ | | Random: 5 | | Entry 9 |
40
+ | | Random: 11 | | Entry 10 |
41
+ | | | | Entry 11 |
42
+ | | | | Entry 12 |
43
+ | | | | Entry 13 |
44
+ | | | | Entry 14 |
45
+ | | | | Entry 15 |
46
+ | | | | Entry 16 |
47
+ | | | | Entry 17 |
48
+ | | | | Entry 18 |
49
+ | | | | Entry 19 |
50
+ | | | | Entry 20 |
51
+ | | | | |
52
+ +----------+------------+----------+----------+
53
+
54
+ ## TODO ##
55
+
56
+ * Clean up the code (always)
57
+ * A way to delete a row all across columns or a specific column
58
+ * Join cells together (Dkubb's Veritas?)
59
+ * Quicker way to add rows
60
+ * Basic expressions (SUM, AVG, etc).
@@ -0,0 +1,434 @@
1
+ module TablrSpace
2
+ # TITLE:
3
+ #
4
+ # OrderedHash (originally Dictionary)
5
+ #
6
+ # AUTHORS:
7
+ #
8
+ # - Jan Molic
9
+ # - Thomas Sawyer
10
+ #
11
+ # CREDIT:
12
+ #
13
+ # - Andrew Johnson (merge, to_a, inspect, shift and Hash[])
14
+ # - Jeff Sharpe (reverse and reverse!)
15
+ # - Thomas Leitner (has_key? and key?)
16
+ #
17
+ # LICENSE:
18
+ #
19
+ # Copyright (c) 2005 Jan Molic, Thomas Sawyer
20
+ #
21
+ # Ruby License
22
+ #
23
+ # This module is free software. You may use, modify, and/or redistribute this
24
+ # software under the same terms as Ruby.
25
+ #
26
+ # This program is distributed in the hope that it will be useful, but WITHOUT
27
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
28
+ # FOR A PARTICULAR PURPOSE.
29
+ #
30
+ # Originally ported from OrderHash 2.0, Copyright (c) 2005 jan molic
31
+ #
32
+ # LOG:
33
+ #
34
+ # - 2007.10.31 trans
35
+ # Fixed initialize so the constructor blocks correctly effected dictionary
36
+ # rather then just the internal hash.
37
+
38
+ # = Dictionary
39
+ #
40
+ # The Dictionary class is a Hash that preserves order.
41
+ # So it has some array-like extensions also. By defualt
42
+ # a Dictionary object preserves insertion order, but any
43
+ # order can be specified including alphabetical key order.
44
+ #
45
+ # == Usage
46
+ #
47
+ # Just require this file and use Dictionary instead of Hash.
48
+ #
49
+ # # You can do simply
50
+ # hsh = Dictionary.new
51
+ # hsh['z'] = 1
52
+ # hsh['a'] = 2
53
+ # hsh['c'] = 3
54
+ # p hsh.keys #=> ['z','a','c']
55
+ #
56
+ # # or using Dictionary[] method
57
+ # hsh = Dictionary['z', 1, 'a', 2, 'c', 3]
58
+ # p hsh.keys #=> ['z','a','c']
59
+ #
60
+ # # but this doesn't preserve order
61
+ # hsh = Dictionary['z'=>1, 'a'=>2, 'c'=>3]
62
+ # p hsh.keys #=> ['a','c','z']
63
+ #
64
+ # # Dictionary has useful extensions: push, pop and unshift
65
+ # p hsh.push('to_end', 15) #=> true, key added
66
+ # p hsh.push('to_end', 30) #=> false, already - nothing happen
67
+ # p hsh.unshift('to_begin', 50) #=> true, key added
68
+ # p hsh.unshift('to_begin', 60) #=> false, already - nothing happen
69
+ # p hsh.keys #=> ["to_begin", "a", "c", "z", "to_end"]
70
+ # p hsh.pop #=> ["to_end", 15], if nothing remains, return nil
71
+ # p hsh.keys #=> ["to_begin", "a", "c", "z"]
72
+ # p hsh.shift #=> ["to_begin", 30], if nothing remains, return nil
73
+ #
74
+ # == Usage Notes
75
+ #
76
+ # * You can use #order_by to set internal sort order.
77
+ # * #<< takes a two element [k,v] array and inserts.
78
+ # * Use ::auto which creates Dictionay sub-entries as needed.
79
+ # * And ::alpha which creates a new Dictionary sorted by key.
80
+ class OrderedHash
81
+
82
+ include Enumerable
83
+
84
+ class << self
85
+ #--
86
+ # TODO is this needed? Doesn't the super class do this?
87
+ #++
88
+ def [](*args)
89
+ hsh = new
90
+ if Hash === args[0]
91
+ hsh.replace(args[0])
92
+ elsif (args.size % 2) != 0
93
+ raise ArgumentError, "odd number of elements for Hash"
94
+ else
95
+ while !args.empty?
96
+ hsh[args.shift] = args.shift
97
+ end
98
+ end
99
+ hsh
100
+ end
101
+
102
+ # Like #new but the block sets the order.
103
+ #
104
+ def new_by(*args, &blk)
105
+ new(*args).order_by(&blk)
106
+ end
107
+
108
+ # Alternate to #new which creates a dictionary sorted by key.
109
+ #
110
+ # d = Dictionary.alpha
111
+ # d["z"] = 1
112
+ # d["y"] = 2
113
+ # d["x"] = 3
114
+ # d #=> {"x"=>3,"y"=>2,"z"=>2}
115
+ #
116
+ # This is equivalent to:
117
+ #
118
+ # Dictionary.new.order_by { |key,value| key }
119
+ def alpha(*args, &block)
120
+ new(*args, &block).order_by_key
121
+ end
122
+
123
+ # Alternate to #new which auto-creates sub-dictionaries as needed.
124
+ #
125
+ # d = Dictionary.auto
126
+ # d["a"]["b"]["c"] = "abc" #=> { "a"=>{"b"=>{"c"=>"abc"}}}
127
+ #
128
+ def auto(*args)
129
+ #AutoDictionary.new(*args)
130
+ leet = lambda { |hsh, key| hsh[key] = new(&leet) }
131
+ new(*args, &leet)
132
+ end
133
+ end
134
+
135
+ # New Dictionary.
136
+ def initialize(*args, &blk)
137
+ @order = []
138
+ @order_by = nil
139
+ if blk
140
+ dict = self # This ensure autmatic key entry effect the
141
+ oblk = lambda{ |hsh, key| blk[dict,key] } # dictionary rather then just the interal hash.
142
+ @hash = Hash.new(*args, &oblk)
143
+ else
144
+ @hash = Hash.new(*args)
145
+ end
146
+ end
147
+
148
+ def order
149
+ reorder if @order_by
150
+ @order
151
+ end
152
+
153
+ # Keep dictionary sorted by a specific sort order.
154
+ def order_by( &block )
155
+ @order_by = block
156
+ order
157
+ self
158
+ end
159
+
160
+ # Keep dictionary sorted by key.
161
+ #
162
+ # d = Dictionary.new.order_by_key
163
+ # d["z"] = 1
164
+ # d["y"] = 2
165
+ # d["x"] = 3
166
+ # d #=> {"x"=>3,"y"=>2,"z"=>2}
167
+ #
168
+ # This is equivalent to:
169
+ #
170
+ # Dictionary.new.order_by { |key,value| key }
171
+ #
172
+ # The initializer Dictionary#alpha also provides this.
173
+ def order_by_key
174
+ @order_by = lambda { |k,v| k }
175
+ order
176
+ self
177
+ end
178
+
179
+ # Keep dictionary sorted by value.
180
+ #
181
+ # d = Dictionary.new.order_by_value
182
+ # d["z"] = 1
183
+ # d["y"] = 2
184
+ # d["x"] = 3
185
+ # d #=> {"x"=>3,"y"=>2,"z"=>2}
186
+ #
187
+ # This is equivalent to:
188
+ #
189
+ # Dictionary.new.order_by { |key,value| value }
190
+ def order_by_value
191
+ @order_by = lambda { |k,v| v }
192
+ order
193
+ self
194
+ end
195
+
196
+ #
197
+ def reorder
198
+ if @order_by
199
+ assoc = @order.collect{ |k| [k,@hash[k]] }.sort_by(&@order_by)
200
+ @order = assoc.collect{ |k,v| k }
201
+ end
202
+ @order
203
+ end
204
+
205
+ def ==(hsh2)
206
+ if hsh2.is_a?( Dictionary )
207
+ @order == hsh2.order &&
208
+ @hash == hsh2.instance_variable_get("@hash")
209
+ else
210
+ false
211
+ end
212
+ end
213
+
214
+ def [] k
215
+ @hash[ k ]
216
+ end
217
+
218
+ def fetch(k, *a, &b)
219
+ @hash.fetch(k, *a, &b)
220
+ end
221
+
222
+ # Store operator.
223
+ #
224
+ # h[key] = value
225
+ #
226
+ # Or with additional index.
227
+ #
228
+ # h[key,index] = value
229
+ def []=(k, i=nil, v=nil)
230
+ if v
231
+ insert(i,k,v)
232
+ else
233
+ store(k,i)
234
+ end
235
+ end
236
+
237
+ def insert( i,k,v )
238
+ @order.insert( i,k )
239
+ @hash.store( k,v )
240
+ end
241
+
242
+ def store( a,b )
243
+ @order.push( a ) unless @hash.has_key?( a )
244
+ @hash.store( a,b )
245
+ end
246
+
247
+ def clear
248
+ @order = []
249
+ @hash.clear
250
+ end
251
+
252
+ def delete( key )
253
+ @order.delete( key )
254
+ @hash.delete( key )
255
+ end
256
+
257
+ def each_key
258
+ order.each { |k| yield( k ) }
259
+ self
260
+ end
261
+
262
+ def each_value
263
+ order.each { |k| yield( @hash[k] ) }
264
+ self
265
+ end
266
+
267
+ def each
268
+ order.each { |k| yield( k,@hash[k] ) }
269
+ self
270
+ end
271
+ alias each_pair each
272
+
273
+ def delete_if
274
+ order.clone.each { |k| delete k if yield(k,@hash[k]) }
275
+ self
276
+ end
277
+
278
+ def values
279
+ ary = []
280
+ order.each { |k| ary.push @hash[k] }
281
+ ary
282
+ end
283
+
284
+ def keys
285
+ order
286
+ end
287
+
288
+ def invert
289
+ hsh2 = self.class.new
290
+ order.each { |k| hsh2[@hash[k]] = k }
291
+ hsh2
292
+ end
293
+
294
+ def reject( &block )
295
+ self.dup.delete_if(&block)
296
+ end
297
+
298
+ def reject!( &block )
299
+ hsh2 = reject(&block)
300
+ self == hsh2 ? nil : hsh2
301
+ end
302
+
303
+ def replace( hsh2 )
304
+ @order = hsh2.order
305
+ @hash = hsh2.hash
306
+ end
307
+
308
+ def shift
309
+ key = order.first
310
+ key ? [key,delete(key)] : super
311
+ end
312
+
313
+ def unshift( k,v )
314
+ unless @hash.include?( k )
315
+ @order.unshift( k )
316
+ @hash.store( k,v )
317
+ true
318
+ else
319
+ false
320
+ end
321
+ end
322
+
323
+ def <<(kv)
324
+ push( *kv )
325
+ end
326
+
327
+ def push( k,v )
328
+ unless @hash.include?( k )
329
+ @order.push( k )
330
+ @hash.store( k,v )
331
+ true
332
+ else
333
+ false
334
+ end
335
+ end
336
+
337
+ def pop
338
+ key = order.last
339
+ key ? [key,delete(key)] : nil
340
+ end
341
+
342
+ def inspect
343
+ ary = []
344
+ each {|k,v| ary << k.inspect + "=>" + v.inspect}
345
+ '{' + ary.join(", ") + '}'
346
+ end
347
+
348
+ def dup
349
+ a = []
350
+ each{ |k,v| a << k; a << v }
351
+ self.class[*a]
352
+ end
353
+
354
+ def update( hsh2 )
355
+ hsh2.each { |k,v| self[k] = v }
356
+ reorder
357
+ self
358
+ end
359
+ alias :merge! update
360
+
361
+ def merge( hsh2 )
362
+ self.dup.update(hsh2)
363
+ end
364
+
365
+ def select
366
+ ary = []
367
+ each { |k,v| ary << [k,v] if yield k,v }
368
+ ary
369
+ end
370
+
371
+ def reverse!
372
+ @order.reverse!
373
+ self
374
+ end
375
+
376
+ def reverse
377
+ dup.reverse!
378
+ end
379
+
380
+ def first
381
+ @hash[order.first]
382
+ end
383
+
384
+ def last
385
+ @hash[order.last]
386
+ end
387
+
388
+ def length
389
+ @order.length
390
+ end
391
+ alias :size :length
392
+
393
+ def empty?
394
+ @hash.empty?
395
+ end
396
+
397
+ def has_key?(key)
398
+ @hash.has_key?(key)
399
+ end
400
+
401
+ def key?(key)
402
+ @hash.key?(key)
403
+ end
404
+
405
+ def to_a
406
+ ary = []
407
+ each { |k,v| ary << [k,v] }
408
+ ary
409
+ end
410
+
411
+ def to_json
412
+ buf = "["
413
+ map do |k,v|
414
+ buf << k.to_json
415
+ buf << ", "
416
+ buf << v.to_json
417
+ end.join(", ")
418
+ buf << "]"
419
+ buf
420
+ end
421
+
422
+ def to_s
423
+ self.to_a.to_s
424
+ end
425
+
426
+ def to_hash
427
+ @hash.dup
428
+ end
429
+
430
+ def to_h
431
+ @hash.dup
432
+ end
433
+ end
434
+ end
@@ -0,0 +1,35 @@
1
+ =begin
2
+ tablr.rb - Easy console tables with ruby
3
+ *
4
+ * Copyright (c) 2011, Daniel Durante <officedebo at gmail dot com>
5
+ * All rights reserved.
6
+ *
7
+ * Redistribution and use in source and binary forms, with or without
8
+ * modification, are permitted provided that the following conditions are met:
9
+ *
10
+ * * Redistributions of source code must retain the above copyright notice,
11
+ * this list of conditions and the following disclaimer.
12
+ * * Redistributions in binary form must reproduce the above copyright
13
+ * notice, this list of conditions and the following disclaimer in the
14
+ * documentation and/or other materials provided with the distribution.
15
+ * * Neither the name of Redis nor the names of its contributors may be used
16
+ * to endorse or promote products derived from this software without
17
+ * specific prior written permission.
18
+ *
19
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29
+ * POSSIBILITY OF SUCH DAMAGE.
30
+ =end
31
+
32
+ $:.unshift File.dirname(__FILE__)
33
+
34
+ require 'support/orderedhash.rb'
35
+ require 'tablr/tablr.rb'
@@ -0,0 +1,112 @@
1
+ class Tablr
2
+ attr_accessor :columns
3
+
4
+ def initialize(options = {})
5
+ @columns ||= TablrSpace::OrderedHash.auto
6
+ @row_data ||= TablrSpace::OrderedHash.new
7
+ options[:separate] ||= "false"
8
+ options[:headers] ||= "true"
9
+
10
+ @options = options
11
+ end
12
+
13
+ # Add columns
14
+ def columns(columns)
15
+ Array(columns).each { |v| @columns[v] = { :length => v.length, :rows => [] } }
16
+ end
17
+ alias_method :column, :columns
18
+ alias_method :add_column, :columns
19
+
20
+ # Add rows
21
+ def add_row(column, value)
22
+ add_column(column) unless column_exists?(column) or !column.is_a? String
23
+
24
+ Array(value).each do |v|
25
+ @columns[column][:rows].push v
26
+ adjust(column, v.length)
27
+ end
28
+ end
29
+
30
+ # Adjust max width for padding
31
+ def adjust(column, length)
32
+ return nil unless column_exists?(column)
33
+ @columns[column][:length] = length if length > @columns[column][:length]
34
+ end
35
+
36
+ def print
37
+ str = <<EOL
38
+ #{headers}
39
+ #{lines}
40
+ #{print_rows}#{lines}
41
+ EOL
42
+ puts str
43
+ end
44
+ alias_method :exec, :print
45
+ alias_method :display, :print
46
+
47
+ protected
48
+
49
+ def column_exists?(column)
50
+ @columns.has_key? column
51
+ end
52
+
53
+ def lines
54
+ str = '+'
55
+ # Get number of dashes within columns
56
+ @columns.each { |k,v| str << '-' * v[:length] << '--+' }
57
+ str
58
+ end
59
+
60
+ def headers
61
+ return '' if @options[:headers] == "false"
62
+ str = lines << "\n"
63
+ @columns.each { |k,v| str << "| #{k}" << " " * str_length(k, v[:length], -1) }
64
+ str << "|"
65
+ end
66
+
67
+ def print_rows
68
+ str, array = '', Array.new
69
+ # Store the max lengths of each header quickly
70
+ @columns.each do |k,v|
71
+ array.push v[:length]
72
+ end
73
+
74
+ get_rows.each_with_index do |value, i|
75
+ str << "|"
76
+ value.each_with_index do |v, index|
77
+ str << " #{v}" << " " * str_length(v, array[index].to_i, 0) << " |"
78
+ end
79
+ str << "\n"
80
+ str << lines if @options[:separate] == "true"
81
+ end
82
+ str
83
+ end
84
+
85
+ def fill_rows
86
+ max_count = 0
87
+ @columns.each_with_index do |v, k|
88
+ max_count = v[1][:rows].length if v[1][:rows].length > max_count
89
+ end
90
+ @columns.each_with_index do |v, k|
91
+ (0..(max_count-v[1][:rows].length)).each do |i|
92
+ add_row v[0], ""
93
+ end
94
+ end
95
+ end
96
+
97
+ def get_rows
98
+ count, array = @columns.length-1, Array.new
99
+ fill_rows
100
+ @columns.each_with_index do |value, key|
101
+ value[1][:rows].each_with_index do |v, k|
102
+ array[k] = [] if array[k].nil?
103
+ array[k].insert -1, v
104
+ end
105
+ end
106
+ array
107
+ end
108
+
109
+ def str_length(key, length, padding=1)
110
+ (length-(key.length)-padding).abs
111
+ end
112
+ end
metadata ADDED
@@ -0,0 +1,61 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: tablr
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: "0.1"
6
+ platform: ruby
7
+ authors:
8
+ - Daniel Durante
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2011-07-18 00:00:00 -04:00
14
+ default_executable:
15
+ dependencies: []
16
+
17
+ description: Create tables easily with Tablr in your console.
18
+ email: officedebo@gmail.com
19
+ executables: []
20
+
21
+ extensions: []
22
+
23
+ extra_rdoc_files: []
24
+
25
+ files:
26
+ - lib/support/orderedhash.rb
27
+ - lib/tablr/tablr.rb
28
+ - lib/tablr.rb
29
+ - CHANGELOG
30
+ - COPYING
31
+ - README.markdown
32
+ has_rdoc: true
33
+ homepage: https://github.com/durango/Tablr
34
+ licenses:
35
+ - MIT
36
+ post_install_message:
37
+ rdoc_options: []
38
+
39
+ require_paths:
40
+ - lib
41
+ required_ruby_version: !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: "0"
47
+ required_rubygems_version: !ruby/object:Gem::Requirement
48
+ none: false
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: 1.3.6
53
+ requirements: []
54
+
55
+ rubyforge_project:
56
+ rubygems_version: 1.6.2
57
+ signing_key:
58
+ specification_version: 3
59
+ summary: Tables in your console in Ruby
60
+ test_files: []
61
+