hirber 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
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