hirber 0.8.0

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.
Files changed (56) hide show
  1. checksums.yaml +7 -0
  2. data/.gemspec +21 -0
  3. data/.travis.yml +11 -0
  4. data/CHANGELOG.rdoc +165 -0
  5. data/CONTRIBUTING.md +1 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.rdoc +205 -0
  8. data/Rakefile +35 -0
  9. data/lib/bond/completions/hirb.rb +15 -0
  10. data/lib/hirb.rb +84 -0
  11. data/lib/hirb/console.rb +43 -0
  12. data/lib/hirb/dynamic_view.rb +113 -0
  13. data/lib/hirb/formatter.rb +126 -0
  14. data/lib/hirb/helpers.rb +18 -0
  15. data/lib/hirb/helpers/auto_table.rb +24 -0
  16. data/lib/hirb/helpers/markdown_table.rb +14 -0
  17. data/lib/hirb/helpers/object_table.rb +14 -0
  18. data/lib/hirb/helpers/parent_child_tree.rb +24 -0
  19. data/lib/hirb/helpers/tab_table.rb +24 -0
  20. data/lib/hirb/helpers/table.rb +376 -0
  21. data/lib/hirb/helpers/table/filters.rb +10 -0
  22. data/lib/hirb/helpers/table/resizer.rb +82 -0
  23. data/lib/hirb/helpers/tree.rb +181 -0
  24. data/lib/hirb/helpers/unicode_table.rb +15 -0
  25. data/lib/hirb/helpers/vertical_table.rb +37 -0
  26. data/lib/hirb/import_object.rb +10 -0
  27. data/lib/hirb/menu.rb +226 -0
  28. data/lib/hirb/pager.rb +106 -0
  29. data/lib/hirb/string.rb +44 -0
  30. data/lib/hirb/util.rb +96 -0
  31. data/lib/hirb/version.rb +3 -0
  32. data/lib/hirb/view.rb +272 -0
  33. data/lib/hirb/views.rb +8 -0
  34. data/lib/hirb/views/couch_db.rb +11 -0
  35. data/lib/hirb/views/misc_db.rb +15 -0
  36. data/lib/hirb/views/mongo_db.rb +17 -0
  37. data/lib/hirb/views/orm.rb +11 -0
  38. data/lib/hirb/views/rails.rb +19 -0
  39. data/lib/ripl/hirb.rb +15 -0
  40. data/test/auto_table_test.rb +33 -0
  41. data/test/console_test.rb +27 -0
  42. data/test/dynamic_view_test.rb +94 -0
  43. data/test/formatter_test.rb +176 -0
  44. data/test/hirb_test.rb +39 -0
  45. data/test/import_test.rb +9 -0
  46. data/test/menu_test.rb +272 -0
  47. data/test/object_table_test.rb +79 -0
  48. data/test/pager_test.rb +162 -0
  49. data/test/resizer_test.rb +62 -0
  50. data/test/table_test.rb +667 -0
  51. data/test/test_helper.rb +60 -0
  52. data/test/tree_test.rb +184 -0
  53. data/test/util_test.rb +59 -0
  54. data/test/view_test.rb +178 -0
  55. data/test/views_test.rb +22 -0
  56. metadata +164 -0
@@ -0,0 +1,62 @@
1
+ require File.join(File.dirname(__FILE__), 'test_helper')
2
+
3
+ describe "Resizer" do
4
+ def table(options)
5
+ @table = Helpers::Table.new [options[:field_lengths].keys.inject({}) {|t,e| t[e] = '1'; t}]
6
+ @table.field_lengths = options[:field_lengths]
7
+ @table.width = options[:width]
8
+ @table.max_fields = options[:max_fields] if options[:max_fields]
9
+ @width, @field_lengths = @table.width, @table.field_lengths
10
+ @table
11
+ end
12
+
13
+ it "resize ensures columns total doesn't exceed max width" do
14
+ table :field_lengths=>{:f1=>135, :f2=>45, :f3=>4, :f4=>55}, :width=>195
15
+ Helpers::Table::Resizer.resize!(@table)
16
+ @field_lengths.values.inject {|a,e| a+=e}.should <= @width
17
+ end
18
+
19
+ it "resize sets columns by relative lengths" do
20
+ table :field_lengths=>{:a=>30, :b=>30, :c=>40}, :width=>60
21
+ Helpers::Table::Resizer.resize!(@table)
22
+ @field_lengths.values.inject {|a,e| a+=e}.should <= @width
23
+ @field_lengths.values.uniq.size.should.not == 1
24
+ end
25
+
26
+ it "resize sets all columns roughly equal when adusting long fields don't work" do
27
+ table :field_lengths=>{:field1=>10, :field2=>15, :field3=>100}, :width=>20
28
+ Helpers::Table::Resizer.resize!(@table)
29
+ @field_lengths.values.inject {|a,e| a+=e}.should <= @width
30
+ @field_lengths.values.each {|e| e.should <= 4 }
31
+ end
32
+
33
+ describe "add_extra_width and max_fields" do
34
+ def table_and_resize(options={})
35
+ defaults = {:field_lengths=>{:f1=>135, :f2=>30, :f3=>4, :f4=>100}, :width=>195, :max_fields=>{:f1=>80, :f4=>30} }
36
+ @table = table defaults.merge(options)
37
+ # repeated from table since instance variables aren't copied b/n contexts
38
+ @width, @field_lengths = @table.width, @table.field_lengths
39
+ Helpers::Table::Resizer.resize! @table
40
+ end
41
+
42
+ it "doesn't add to already maxed out field" do
43
+ table_and_resize
44
+ @field_lengths[:f3].should == 4
45
+ end
46
+
47
+ it "restricted before adding width" do
48
+ table_and_resize
49
+ @field_lengths[:f4].should <= 30
50
+ end
51
+
52
+ it "adds to restricted field" do
53
+ table_and_resize
54
+ @field_lengths[:f1].should <= 80
55
+ end
56
+
57
+ it "adds to unrestricted field" do
58
+ table_and_resize :field_lengths=>{:f1=>135, :f2=>70, :f3=>4, :f4=>100}
59
+ @field_lengths[:f2].should == 70
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,667 @@
1
+ # encoding: UTF-8
2
+ require File.join(File.dirname(__FILE__), 'test_helper')
3
+
4
+ describe "Table" do
5
+ def table(*args)
6
+ Helpers::Table.render(*args)
7
+ end
8
+ before_all { reset_config }
9
+
10
+ describe "basic table" do
11
+ it "renders" do
12
+ expected_table = <<-TABLE.unindent
13
+ +---+---+
14
+ | a | b |
15
+ +---+---+
16
+ | 1 | 2 |
17
+ | 3 | 4 |
18
+ +---+---+
19
+ 2 rows in set
20
+ TABLE
21
+ table([{:a=>1, :b=>2}, {:a=>3, :b=>4}]).should == expected_table
22
+ end
23
+
24
+ it "also renders to the same table with :simple style given" do
25
+ expected_table = <<-TABLE.unindent
26
+ +---+---+
27
+ | a | b |
28
+ +---+---+
29
+ | 1 | 2 |
30
+ | 3 | 4 |
31
+ +---+---+
32
+ 2 rows in set
33
+ TABLE
34
+ table([{:a=>1, :b=>2}, {:a=>3, :b=>4}], :style => :simple).should == expected_table
35
+ end
36
+
37
+ it "with no headers renders" do
38
+ expected_table = <<-TABLE.unindent
39
+ +---+---+
40
+ | 1 | 2 |
41
+ +---+---+
42
+ 1 row in set
43
+ TABLE
44
+ table([{:a=>1, :b=>2}], :headers=>false).should == expected_table
45
+ end
46
+
47
+ it "with no headers and nil fields renders" do
48
+ expected_table = <<-TABLE.unindent
49
+ +---+---+
50
+ | 1 | |
51
+ +---+---+
52
+ 1 row in set
53
+ TABLE
54
+ table([{:a=>1, :b=>nil}], :headers=>false).should == expected_table
55
+ end
56
+
57
+ it "with string keys renders" do
58
+ expected_table = <<-TABLE.unindent
59
+ +---+---+
60
+ | a | b |
61
+ +---+---+
62
+ | 1 | 2 |
63
+ | 3 | 4 |
64
+ +---+---+
65
+ 2 rows in set
66
+ TABLE
67
+ table([{'a'=>1, 'b'=>2}, {'a'=>3, 'b'=>4}]).should == expected_table
68
+ end
69
+
70
+ it "with no keys renders" do
71
+ expected_table = <<-TABLE.unindent
72
+ +--+
73
+ | |
74
+ +--+
75
+ | |
76
+ +--+
77
+ 1 row in set
78
+ TABLE
79
+ table([{}]).should == expected_table
80
+ end
81
+
82
+ it "with array only rows renders" do
83
+ expected_table = <<-TABLE.unindent
84
+ +---+---+
85
+ | 0 | 1 |
86
+ +---+---+
87
+ | 1 | 2 |
88
+ | 3 | 4 |
89
+ +---+---+
90
+ 2 rows in set
91
+ TABLE
92
+ table([[1,2], [3,4]]).should == expected_table
93
+ end
94
+
95
+ it "with too many fields defaults to vertical table" do
96
+ rows = [Array.new(25, "A"* 10)]
97
+ Helpers::VerticalTable.expects(:render).with(rows, anything)
98
+ capture_stderr { table(rows)}.should =~ /Warning:/
99
+ end
100
+
101
+ it "with no rows renders" do
102
+ table([]).should == "0 rows in set"
103
+ end
104
+
105
+ it "with invalid rows raises an argumenterror" do
106
+ lambda { table(:a=>1) }.should.raise(ArgumentError).message.should =~ /Table must/
107
+ end
108
+
109
+ it "renders utf8" do
110
+ expected_table = <<-TABLE.unindent
111
+ +--------------------+
112
+ | name |
113
+ +--------------------+
114
+ | アイウエオカキ |
115
+ | クケコサシスセソタチツテ |
116
+ | Tata l'asticote |
117
+ | toto létoile PAOLI |
118
+ +--------------------+
119
+ 4 rows in set
120
+ TABLE
121
+ table([{:name=>"アイウエオカキ"}, {:name=>"クケコサシスセソタチツテ"}, {:name=>"Tata l'asticote"}, {:name=>"toto létoile PAOLI"}]).should == expected_table
122
+ end
123
+
124
+ it "stringifies newlines and tabs and renders" do
125
+ expected_table = <<-TABLE.unindent
126
+ +-----+---+
127
+ | a | b |
128
+ +-----+---+
129
+ | 1#{'\n'} | 2 |
130
+ | 3#{'\t'} | 4 |
131
+ +-----+---+
132
+ 2 rows in set
133
+ TABLE
134
+ value = [{'a'=>"1\n", 'b'=>2}, {'a'=>"3\t", 'b'=>4}]
135
+ table(value).should == expected_table
136
+ value.should == [{'a'=>"1\n", 'b'=>2}, {'a'=>"3\t", 'b'=>4}]
137
+ end
138
+
139
+ it "with a field of only array values renders values comma joined" do
140
+ expected_table = <<-TABLE.unindent
141
+ +----+------+
142
+ | a | b |
143
+ +----+------+
144
+ | 1 | 1, 2 |
145
+ | ok | 3, 4 |
146
+ +----+------+
147
+ 2 rows in set
148
+ TABLE
149
+ table([{:a=>1, :b=>[1,2]}, {:a=>'ok', :b=>[3,4]}]).should == expected_table
150
+ end
151
+
152
+ it "with filter class default doesn't override explicit filters" do
153
+ expected_table = <<-TABLE.unindent
154
+ +------+-------+
155
+ | name | value |
156
+ +------+-------+
157
+ | a | 1 |
158
+ +------+-------+
159
+ 1 row in set
160
+ TABLE
161
+ table([{:name=>'a', :value=>{:b=>1}}], :filters=>{:value=>:size}).should == expected_table
162
+ end
163
+ end
164
+
165
+ describe "table with" do
166
+ it "fields option renders" do
167
+ expected_table = <<-TABLE.unindent
168
+ +---+---+
169
+ | b | a |
170
+ +---+---+
171
+ | 2 | 1 |
172
+ | 4 | 3 |
173
+ +---+---+
174
+ 2 rows in set
175
+ TABLE
176
+ table([{:a=>1, :b=>2}, {:a=>3, :b=>4}], :fields=>[:b, :a]).should == expected_table
177
+ end
178
+
179
+ it "fields option and array only rows" do
180
+ expected_table = <<-TABLE.unindent
181
+ +---+---+
182
+ | 0 | 2 |
183
+ +---+---+
184
+ | 1 | 3 |
185
+ +---+---+
186
+ 1 row in set
187
+ TABLE
188
+ table([[1,2,3]], :fields=>[0,2]).should == expected_table
189
+ end
190
+
191
+ it "fields and number options copies fields option and does not modify it" do
192
+ options = {:fields=>[:f1], :number=>true}
193
+ table([{:f1=>1, :f2=>2}], options)
194
+ options[:fields].should == [:f1]
195
+ end
196
+
197
+ it "invalid fields option renders empty columns" do
198
+ expected_table = <<-TABLE.unindent
199
+ +---+---+
200
+ | b | c |
201
+ +---+---+
202
+ | 2 | |
203
+ | 4 | |
204
+ +---+---+
205
+ 2 rows in set
206
+ TABLE
207
+ table([{:a=>1, :b=>2}, {:a=>3, :b=>4}], :fields=>[:b, :c]).should == expected_table
208
+ end
209
+
210
+ it "grep_fields option and symbol fields" do
211
+ expected_table = <<-TABLE.unindent
212
+ +----+----+
213
+ | f1 | f2 |
214
+ +----+----+
215
+ | 1 | 2 |
216
+ +----+----+
217
+ 1 row in set
218
+ TABLE
219
+ table([{:f1 => 1, :f2 => 2, :gf1 => 3}], :grep_fields => /^f/).should == expected_table
220
+ end
221
+
222
+ it "grep_fields option and non-symbol fields" do
223
+ expected_table = <<-TABLE.unindent
224
+ +---+
225
+ | 1 |
226
+ +---+
227
+ | 2 |
228
+ +---+
229
+ 1 row in set
230
+ TABLE
231
+ table([[1,2,3]], :grep_fields => /1/).should == expected_table
232
+ end
233
+
234
+ it "invalid field in max_fields option renders" do
235
+ expected_table = <<-TABLE.unindent
236
+ +------------+---+
237
+ | a | b |
238
+ +------------+---+
239
+ | AAAAAAA... | 2 |
240
+ +------------+---+
241
+ 1 row in set
242
+ TABLE
243
+ table([{:a=> "A" * 50, :b=>2}], :max_fields=>{:a=>10,:c=>10}).should == expected_table
244
+ end
245
+
246
+ it "max_fields option with fields less than 3 characters renders" do
247
+ expected_table = <<-TABLE.unindent
248
+ +----+---+
249
+ | a | b |
250
+ +----+---+
251
+ | AA | 2 |
252
+ +----+---+
253
+ 1 row in set
254
+ TABLE
255
+ table([{:a=> "A" * 50, :b=>2}], :max_fields=>{:a=>2}, :resize=>false).should == expected_table
256
+ end
257
+
258
+ it "max_fields option without resize renders" do
259
+ expected_table = <<-TABLE.unindent
260
+ +------------+---+
261
+ | a | b |
262
+ +------------+---+
263
+ | AAAAAAA... | 2 |
264
+ +------------+---+
265
+ 1 row in set
266
+ TABLE
267
+ table([{:a=> "A" * 50, :b=>2}], :max_fields=>{:a=>10}, :resize=>false).should == expected_table
268
+ end
269
+
270
+ it "max_fields option with percentage renders" do
271
+ expected_table = <<-TABLE.unindent
272
+ +------------------+---+
273
+ | a | b |
274
+ +------------------+---+
275
+ | AAAAAAAAAAAAA... | 2 |
276
+ +------------------+---+
277
+ 1 row in set
278
+ TABLE
279
+ table([{:a=> "A" * 50, :b=>2}], :max_fields=>{:a=>'0.15'}).should == expected_table
280
+ end
281
+
282
+ it "max_width option renders" do
283
+ expected_table = <<-TABLE.unindent
284
+ +-----------+---+------------+
285
+ | a | b | c |
286
+ +-----------+---+------------+
287
+ | AAAAAA... | 2 | CCCCCCCCCC |
288
+ +-----------+---+------------+
289
+ 1 row in set
290
+ TABLE
291
+ table([{:a=> "A" * 50, :b=>2, :c=>"C"*10}], :max_width=>30).should == expected_table
292
+ end
293
+
294
+ it "resize option false renders full table" do
295
+ expected_table = <<-TABLE.unindent
296
+ +----------------------------------------------------+---+------------+
297
+ | a | b | c |
298
+ +----------------------------------------------------+---+------------+
299
+ | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA | 2 | CCCCCCCCCC |
300
+ +----------------------------------------------------+---+------------+
301
+ 1 row in set
302
+ TABLE
303
+ table([{:a=> "A" * 50, :b=>2, :c=>"C"*10}], :resize=>false).should == expected_table
304
+ end
305
+
306
+ it "global width renders" do
307
+ expected_table = <<-TABLE.unindent
308
+ +-----------+---+------------+
309
+ | a | b | c |
310
+ +-----------+---+------------+
311
+ | AAAAAA... | 2 | CCCCCCCCCC |
312
+ +-----------+---+------------+
313
+ 1 row in set
314
+ TABLE
315
+ View.load_config
316
+ View.resize(30)
317
+ table([{:a=> "A" * 50, :b=>2, :c=>"C"*10}]).should == expected_table
318
+ reset_config
319
+ end
320
+
321
+ it "headers option and headers longer than fields renders" do
322
+ expected_table = <<-TABLE.unindent
323
+ +---+---------+---------+
324
+ | a | field B | field C |
325
+ +---+---------+---------+
326
+ | A | 2 | C |
327
+ +---+---------+---------+
328
+ 1 row in set
329
+ TABLE
330
+ table([{:a=> "A", :b=>2, :c=>"C"}], :headers=>{:b=>"field B", :c=>"field C"}).should == expected_table
331
+ end
332
+
333
+ it "headers option and headers shortened by max_fields renders" do
334
+ expected_table = <<-TABLE.unindent
335
+ +-------+---+
336
+ | fi... | b |
337
+ +-------+---+
338
+ | A | 2 |
339
+ +-------+---+
340
+ 1 row in set
341
+ TABLE
342
+ table([{:a=> "A", :b=>2}], :headers=>{:a=>"field A"}, :max_fields=>{:a=>5}, :resize=>false).should == expected_table
343
+ end
344
+
345
+ it "headers option as an array renders" do
346
+ expected_table = <<-TABLE.unindent
347
+ +---+---+
348
+ | A | B |
349
+ +---+---+
350
+ | 1 | 2 |
351
+ | 3 | 4 |
352
+ +---+---+
353
+ 2 rows in set
354
+ TABLE
355
+ table([[1,2], [3,4]], :headers=>['A', 'B']).should == expected_table
356
+ end
357
+
358
+ it "header_filter option renders" do
359
+ expected_table = <<-TABLE.unindent
360
+ +---+---+
361
+ | A | B |
362
+ +---+---+
363
+ | 2 | 3 |
364
+ +---+---+
365
+ 1 row in set
366
+ TABLE
367
+ table([{:a=> 2, :b=>3}], :header_filter=>:capitalize).should == expected_table
368
+ end
369
+
370
+ it "filters option renders" do
371
+ expected_table = <<-TABLE.unindent
372
+ +-----------+---+
373
+ | 0 | 1 |
374
+ +-----------+---+
375
+ | s,o,m,e | 2 |
376
+ | t,h,i,n,g | 1 |
377
+ +-----------+---+
378
+ 2 rows in set
379
+ TABLE
380
+ table([['some', {:num=>2}], ['thing', {:num=>1}]], :filters=>{0=>lambda {|e| e.split("").join(",")},
381
+ 1=>[:[], :num]}).should == expected_table
382
+ end
383
+
384
+ it "filters option calls Filters method and renders" do
385
+ module ::Hirb::Helpers::Table::Filters
386
+ def semicolon_join(arr); arr.join('; '); end
387
+ end
388
+
389
+ expected_table = <<-TABLE.unindent
390
+ +------+------------------------------+
391
+ | 0 | 1 |
392
+ +------+------------------------------+
393
+ | some | unsightly; unreadable; array |
394
+ +------+------------------------------+
395
+ 1 row in set
396
+ TABLE
397
+ table([[['some'], %w{unsightly unreadable array}]], :filters=>{1=>:semicolon_join}).should == expected_table
398
+ end
399
+
400
+ it "number option renders" do
401
+ expected_table = <<-TABLE.unindent
402
+ +--------+---+---+
403
+ | number | 0 | 1 |
404
+ +--------+---+---+
405
+ | 1 | a | b |
406
+ | 2 | c | d |
407
+ +--------+---+---+
408
+ 2 rows in set
409
+ TABLE
410
+ table([['a','b'], ['c', 'd']], :number=>true).should == expected_table
411
+ end
412
+
413
+ it "number option renders with header that can be overridden" do
414
+ expected_table = <<-TABLE.unindent
415
+ +----+---+---+
416
+ | SR | 0 | 1 |
417
+ +----+---+---+
418
+ | 1 | a | b |
419
+ | 2 | c | d |
420
+ +----+---+---+
421
+ 2 rows in set
422
+ TABLE
423
+ table([['a','b'], ['c', 'd']], :number=>true, :headers => {:hirb_number => "SR"}).should == expected_table
424
+ end
425
+
426
+ it "description option false renders" do
427
+ expected_table = <<-TABLE.unindent
428
+ +---+---+
429
+ | 0 | 1 |
430
+ +---+---+
431
+ | a | b |
432
+ | c | d |
433
+ +---+---+
434
+ TABLE
435
+ table([['a','b'], ['c', 'd']], :description=>false).should == expected_table
436
+ end
437
+
438
+ it "vertical option renders vertical table" do
439
+ expected_table = <<-TABLE.unindent
440
+ *** 1. row ***
441
+ a: 1
442
+ b: 2
443
+ *** 2. row ***
444
+ a: 3
445
+ b: 4
446
+ 2 rows in set
447
+ TABLE
448
+ table([{:a=>1, :b=>2}, {:a=>3, :b=>4}], :vertical=>true).should == expected_table
449
+ end
450
+
451
+ it "vertical option renders vertical table with newlines" do
452
+ expected_table = <<-TABLE.unindent
453
+ *** 1. row ***
454
+ a: 1
455
+ b: 2
456
+ *** 2. row ***
457
+ a: 3
458
+ b: 4
459
+ and one
460
+ 2 rows in set
461
+ TABLE
462
+ table([{:a=>1, :b=>2}, {:a=>3, :b=>"4\nand one"}], :vertical=>true).should == expected_table
463
+ end
464
+
465
+ it "vertical option renders vertical table successively" do
466
+ expected_table = <<-TABLE.unindent
467
+ *** 1. row ***
468
+ a: 1
469
+ b: 2
470
+ *** 2. row ***
471
+ a: 3
472
+ b: 4
473
+ 2 rows in set
474
+ TABLE
475
+ options = {:vertical=>true}
476
+ table([{:a=>1, :b=>2}, {:a=>3, :b=>4}], options).should == expected_table
477
+ table([{:a=>1, :b=>2}, {:a=>3, :b=>4}], options).should == expected_table
478
+ end
479
+
480
+ it "hide_empty and vertical options renders" do
481
+ expected_table = <<-TABLE.unindent
482
+ *** 1. row ***
483
+ b: 2
484
+ *** 2. row ***
485
+ a: 3
486
+ 2 rows in set
487
+ TABLE
488
+ table([{:a=>'', :b=>2}, {:a=>3, :b=>nil}], :hide_empty=>true, :vertical=>true).should == expected_table
489
+ end
490
+
491
+ it "unicode option renders" do
492
+ expected_table = <<-TABLE.unindent
493
+ ┌───┬───┐
494
+ │ a │ b │
495
+ ├───┼───┤
496
+ │ 1 ╎ 2 │
497
+ │ 3 ╎ 4 │
498
+ └───┴───┘
499
+ 2 rows in set
500
+ TABLE
501
+ table([{:a=>1, :b=>2}, {:a=>3, :b=>4}], :unicode => true).should == expected_table
502
+ end
503
+
504
+ it "tab option renders" do
505
+ expected_table = <<-TABLE.unindent
506
+ a b
507
+ 1 2
508
+ 3 4
509
+ TABLE
510
+ table([{:a=>1, :b=>2}, {:a=>3, :b=>4}], :tab => true).should == expected_table
511
+ end
512
+
513
+ it "tab option with no headers renders" do
514
+ expected_table = <<-TABLE.unindent
515
+ 1 2
516
+ 3 4
517
+ TABLE
518
+ table([{:a=>1, :b=>2}, {:a=>3, :b=>4}], :tab => true, :headers => false).
519
+ should == expected_table
520
+ end
521
+
522
+ it "markdown option renders" do
523
+ expected_table = <<-TABLE.chomp
524
+ | a | b |
525
+ |--- | ---|
526
+ | 1 | 2 |
527
+ | 3 | 4 |
528
+
529
+ 2 rows in set
530
+ TABLE
531
+ table([{:a=>1, :b=>2}, {:a=>3, :b=>4}], :markdown => true).
532
+ should == "\n#{expected_table}"
533
+ end
534
+
535
+ it "markdown option with no headers renders" do
536
+ expected_table = <<-TABLE.chomp
537
+ | 1 | 2 |
538
+ | 3 | 4 |
539
+
540
+ 2 rows in set
541
+ TABLE
542
+ table([{:a=>1, :b=>2}, {:a=>3, :b=>4}], :markdown => true, :headers => false).
543
+ should == "\n#{expected_table}"
544
+ end
545
+
546
+ it "all_fields option renders all fields" do
547
+ expected_table = <<-TABLE.unindent
548
+ +---+---+---+
549
+ | a | b | c |
550
+ +---+---+---+
551
+ | 1 | 2 | |
552
+ | 3 | | 4 |
553
+ +---+---+---+
554
+ 2 rows in set
555
+ TABLE
556
+ table([{:a=>1, :b=>2}, {:a=>3, :c=>4}], :all_fields=>true).should == expected_table
557
+ end
558
+
559
+ it "change_fields option renders" do
560
+ expected_table = <<-TABLE.unindent
561
+ +------+-------+
562
+ | name | value |
563
+ +------+-------+
564
+ | 1 | 2 |
565
+ | 2 | 3 |
566
+ +------+-------+
567
+ 2 rows in set
568
+ TABLE
569
+ table([[1,2],[2,3]], :change_fields=>{0=>'name', 1=>'value'}).should == expected_table
570
+ table([[1,2],[2,3]], :change_fields=>['name', 'value']).should == expected_table
571
+ end
572
+
573
+ it "change_fields and fields option renders" do
574
+ expected_table = <<-TABLE.unindent
575
+ +------+
576
+ | name |
577
+ +------+
578
+ | 1 |
579
+ | 2 |
580
+ +------+
581
+ 2 rows in set
582
+ TABLE
583
+ table([[1,2],[2,3]], :change_fields=>['name', 'value'], :fields=>['name']).should == expected_table
584
+ end
585
+
586
+ it "invalid fields in change_fields options are ignored" do
587
+ expected_table = <<-TABLE.unindent
588
+ +------+-------+
589
+ | name | value |
590
+ +------+-------+
591
+ | 1 | 2 |
592
+ | 2 | 3 |
593
+ +------+-------+
594
+ 2 rows in set
595
+ TABLE
596
+ table([{:a=>1,:b=>2}, {:a=>2,:b=>3}], :change_fields=>{:a=>'name', :b=>'value', :c=>'time'}).should == expected_table
597
+ table([[1,2],[2,3]], :change_fields=>['name', 'value','time']).should == expected_table
598
+ end
599
+
600
+ it "filter_any option filters any value" do
601
+ expected_table = <<-TABLE.unindent
602
+ +---------+
603
+ | a |
604
+ +---------+
605
+ | {:b=>1} |
606
+ | 2 |
607
+ +---------+
608
+ 2 rows in set
609
+ TABLE
610
+ table([{:a=>{:b=>1}}, {:a=>2}], :filter_any=>true).should == expected_table
611
+ end
612
+
613
+ it "filter_classes option overrides class-wide filter_classes" do
614
+ expected_table = <<-TABLE.unindent
615
+ +---+
616
+ | a |
617
+ +---+
618
+ | 1 |
619
+ +---+
620
+ 1 row in set
621
+ TABLE
622
+ table([{:a=>{:b=>1}}], :filter_classes=>{Hash=>:size}).should == expected_table
623
+ end
624
+ end
625
+
626
+ describe "table with callbacks" do
627
+ before_all {
628
+ Helpers::Table.send(:define_method, :and_one_callback) do |obj, opt|
629
+ obj.each {|row| row.each {|k,v| row[k] += opt[:add] } }
630
+ obj
631
+ end
632
+ }
633
+ it "detects and runs them" do
634
+ expected_table = <<-TABLE.unindent
635
+ +---+---+
636
+ | a | b |
637
+ +---+---+
638
+ | 2 | 3 |
639
+ | 4 | 5 |
640
+ +---+---+
641
+ 2 rows in set
642
+ TABLE
643
+ table([{'a'=>1, 'b'=>2}, {'a'=>3, 'b'=>4}], :add=>1).should == expected_table
644
+ end
645
+
646
+ it "doesn't run callbacks in delete_callbacks option" do
647
+ Helpers::Table.send(:define_method, :and_two_callback) do |obj, opt|
648
+ obj.each {|row| row.each {|k,v| row[k] = row[k] * 2 } }
649
+ obj
650
+ end
651
+
652
+ expected_table = <<-TABLE.unindent
653
+ +---+---+
654
+ | a | b |
655
+ +---+---+
656
+ | 2 | 3 |
657
+ | 4 | 5 |
658
+ +---+---+
659
+ 2 rows in set
660
+ TABLE
661
+ table([{'a'=>1, 'b'=>2}, {'a'=>3, 'b'=>4}], :add=>1, :delete_callbacks=>[:and_two]).should == expected_table
662
+
663
+ Helpers::Table.send(:remove_method, :and_two_callback)
664
+ end
665
+ after_all { Helpers::Table.send(:remove_method, :and_one_callback) }
666
+ end
667
+ end