columnist 1.0.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.
data/spec/columnist.rb ADDED
@@ -0,0 +1,693 @@
1
+ require 'spec_helper'
2
+
3
+ describe Columnist do
4
+ let :use_class do
5
+ Class.new do
6
+ include Columnist
7
+ end
8
+ end
9
+
10
+ let(:timestamp_regex) { /\d{4}-\d{2}-\d{2} - (\d| )\d:\d{2}:\d{2}[AP]M/ }
11
+
12
+ let :controls do
13
+ {
14
+ :clear => "\e[0m",
15
+ :bold => "\e[1m",
16
+ :red => "\e[31m",
17
+ }
18
+ end
19
+
20
+ let(:linechar) { "\u2501" == 'u2501' ? '-' : "\u2501" }
21
+
22
+ subject { use_class.new }
23
+
24
+ describe '#formatter=' do
25
+ it 'only allows allowed formatters' do
26
+ expect {
27
+ subject.formatter = 'asfd'
28
+ }.to raise_error ArgumentError
29
+ end
30
+
31
+ it 'specifies the progress formatter' do
32
+ subject.formatter = 'progress'
33
+ expect(subject.formatter.class).to eq(Columnist::ProgressFormatter)
34
+ end
35
+
36
+ it 'specifies the nested formatter' do
37
+ subject.formatter = 'nested'
38
+ expect(subject.formatter.class).to eq(Columnist::NestedFormatter)
39
+ end
40
+ end
41
+
42
+ describe '#report' do
43
+ it 'uses the nested formatter as default' do
44
+ capture_stdout {
45
+ subject.report { }
46
+ }
47
+
48
+ expect(subject.formatter.class).to eq(Columnist::NestedFormatter)
49
+ end
50
+
51
+ it 'uses the progress formatter' do
52
+ capture_stdout {
53
+ subject.formatter = 'progress'
54
+ subject.report { }
55
+ }
56
+
57
+ expect(subject.formatter.class).to eq(Columnist::ProgressFormatter)
58
+ end
59
+
60
+ it 'does not mask other application errors when a formatter is not set' do
61
+ capture_stdout {
62
+ subject.report {
63
+ expect {self.some_method_that_does_not_exist}.to raise_error(NoMethodError)
64
+ }
65
+ }
66
+ end
67
+ end
68
+
69
+ describe '#header' do
70
+ context 'argument validation' do
71
+
72
+ it 'does not accept an invalid option' do
73
+ expect {
74
+ subject.header(:asdf => 'tests')
75
+ }.to raise_error ArgumentError
76
+ end
77
+
78
+ it 'accepts a title' do
79
+ expect {
80
+ allow(subject).to receive(:puts)
81
+ subject.header(:title => 'test')
82
+ }.to_not raise_error
83
+ end
84
+
85
+ it 'does not allow a title > width' do
86
+ expect {
87
+ subject.header(:title => 'xxxxxxxxxxx', :width => 5)
88
+ }.to raise_error ArgumentError
89
+ end
90
+
91
+ it 'accepts width' do
92
+ expect {
93
+ allow(subject).to receive(:puts)
94
+ subject.header(:width => 100)
95
+ }.to_not raise_error
96
+ end
97
+
98
+ it 'ensure width is a number' do
99
+ expect {
100
+ subject.header(:width => '100')
101
+ }.to raise_error ArgumentError
102
+ end
103
+
104
+ it 'accepts align' do
105
+ expect {
106
+ allow(subject).to receive(:puts)
107
+ subject.header(:align => 'center')
108
+ }.to_not raise_error
109
+ end
110
+
111
+ it 'ensure align is a valid value' do
112
+ expect {
113
+ subject.header(:align => :asdf)
114
+ }.to raise_error ArgumentError
115
+ end
116
+
117
+ it 'accepts spacing' do
118
+ expect {
119
+ allow(subject).to receive(:puts)
120
+ subject.header(:spacing => 2)
121
+ }.to_not raise_error
122
+ end
123
+
124
+ it 'accepts timestamp' do
125
+ expect {
126
+ allow(subject).to receive(:puts)
127
+ subject.header(:timestamp => true)
128
+ }.to_not raise_error
129
+ end
130
+
131
+ it 'accepts color' do
132
+ expect {
133
+ allow(subject).to receive(:puts)
134
+ subject.header(:color => 'red')
135
+ }.to_not raise_error
136
+ end
137
+
138
+ it 'accepts bold' do
139
+ expect {
140
+ allow(subject).to receive(:puts)
141
+ subject.header(:bold => true)
142
+ }.to_not raise_error
143
+ end
144
+ end
145
+
146
+ context 'alignment' do
147
+ before :each do
148
+ @title = 'test11test'
149
+ end
150
+
151
+ it 'left aligns title by default' do
152
+ expect(subject).to receive(:puts).with(@title)
153
+ expect(subject).to receive(:puts).with("\n")
154
+ subject.header(:title => @title) { }
155
+ end
156
+
157
+ it 'left aligns title' do
158
+ expect(subject).to receive(:puts).with(@title)
159
+ expect(subject).to receive(:puts).with("\n")
160
+ subject.header(:title => @title, :align => 'left') { }
161
+ end
162
+
163
+ it 'right aligns title using default width' do
164
+ expect(subject).to receive(:puts).with(' ' * 90 + @title)
165
+ expect(subject).to receive(:puts).with("\n")
166
+ subject.header(:title => @title, :align => 'right')
167
+ end
168
+
169
+ it 'right aligns title using specified width' do
170
+ expect(subject).to receive(:puts).with(' ' * 40 + @title)
171
+ expect(subject).to receive(:puts).with("\n")
172
+ subject.header(:title => @title, :align => 'right', :width => 50)
173
+ end
174
+
175
+ it 'center aligns title using default width' do
176
+ expect(subject).to receive(:puts).with(' ' * 45 + @title)
177
+ expect(subject).to receive(:puts).with("\n")
178
+ subject.header(:title => @title, :align => 'center')
179
+ end
180
+
181
+ it 'center aligns title using specified width' do
182
+ expect(subject).to receive(:puts).with(' ' * 35 + @title)
183
+ expect(subject).to receive(:puts).with("\n")
184
+ subject.header(:title => @title, :align => 'center', :width => 80)
185
+ end
186
+ end
187
+
188
+ context 'spacing' do
189
+ it 'defaults to a single line of spacing between report' do
190
+ expect(subject).to receive(:puts).with('title')
191
+ expect(subject).to receive(:puts).with("\n")
192
+ subject.header(:title => 'title')
193
+ end
194
+
195
+ it 'uses the defined spacing between report' do
196
+ expect(subject).to receive(:puts).with('title')
197
+ expect(subject).to receive(:puts).with("\n" * 3)
198
+ subject.header(:title => 'title', :spacing => 3)
199
+ end
200
+ end
201
+
202
+ context 'timestamp subheading' do
203
+ it 'is added with default alignment' do
204
+ expect(subject).to receive(:puts).with('title')
205
+ expect(subject).to receive(:puts).with(/^#{timestamp_regex}/)
206
+ expect(subject).to receive(:puts).with("\n")
207
+ subject.header(:title => 'title', :timestamp => true)
208
+ end
209
+
210
+ it 'added with right alignment' do
211
+ expect(subject).to receive(:puts).with(/^ *title$/)
212
+ expect(subject).to receive(:puts).with(/^ *#{timestamp_regex}$/)
213
+ expect(subject).to receive(:puts).with("\n")
214
+ subject.header(:title => 'title', :align => 'right', :timestamp => true, :width => 80)
215
+ end
216
+
217
+ it 'added with center alignment' do
218
+ expect(subject).to receive(:puts).with(/^ *title *$/)
219
+ expect(subject).to receive(:puts).with(/^ *#{timestamp_regex} *$/)
220
+ expect(subject).to receive(:puts).with("\n")
221
+ subject.header(:title => 'title', :align => 'center', :timestamp => true, :width => 80)
222
+ end
223
+ end
224
+
225
+ context 'horizontal rule' do
226
+ it 'uses dashes by default' do
227
+ expect(subject).to receive(:puts)
228
+ expect(subject).to receive(:puts).with(linechar * 100)
229
+ expect(subject).to receive(:puts)
230
+ subject.header(:rule => true)
231
+ end
232
+
233
+ it 'uses = as the rule character' do
234
+ expect(subject).to receive(:puts)
235
+ expect(subject).to receive(:puts).with('=' * 100)
236
+ expect(subject).to receive(:puts)
237
+ subject.header(:rule => '=')
238
+ end
239
+ end
240
+
241
+ context 'color' do
242
+ it 'single red line' do
243
+ expect(subject).to receive(:puts).with(controls[:red] + 'Report' + controls[:clear])
244
+ expect(subject).to receive(:puts)
245
+ subject.header(:color => 'red')
246
+ end
247
+
248
+ it 'multimple red lines' do
249
+ expect(subject).to receive(:puts).with(controls[:red] + 'Report' + controls[:clear])
250
+ expect(subject).to receive(:puts).with(controls[:red] + linechar * 100 + controls[:clear])
251
+ expect(subject).to receive(:puts)
252
+ subject.header(:color => 'red', :rule => true)
253
+ end
254
+ end
255
+
256
+ context 'bold' do
257
+ it 'single line' do
258
+ expect(subject).to receive(:puts).with(controls[:bold] + 'Report' + controls[:clear])
259
+ expect(subject).to receive(:puts)
260
+ subject.header(:bold => true)
261
+ end
262
+
263
+ it 'multimple lines' do
264
+ expect(subject).to receive(:puts).with(controls[:bold] + 'Report' + controls[:clear])
265
+ expect(subject).to receive(:puts).with(controls[:bold] + linechar * 100 + controls[:clear])
266
+ expect(subject).to receive(:puts)
267
+ subject.header(:bold => true, :rule => true)
268
+ end
269
+ end
270
+ end
271
+
272
+ describe '#horizontal_rule' do
273
+ context 'argument validation' do
274
+ it 'does not allow invalid options' do
275
+ expect {
276
+ subject.horizontal_rule(:asdf => true)
277
+ }.to raise_error ArgumentError
278
+ end
279
+
280
+ it 'accepts char' do
281
+ expect {
282
+ expect(subject).to receive(:puts)
283
+ subject.horizontal_rule(:char => '*')
284
+ }.to_not raise_error
285
+ end
286
+
287
+ it 'accepts width' do
288
+ expect {
289
+ expect(subject).to receive(:puts)
290
+ subject.horizontal_rule(:width => 10)
291
+ }.to_not raise_error
292
+ end
293
+ end
294
+
295
+ context 'drawing' do
296
+ it 'writes a 100 yard dash by default' do
297
+ expect(subject).to receive(:puts).with(linechar * 100)
298
+ subject.horizontal_rule
299
+ end
300
+
301
+ it 'writes a 100 yard asterisk' do
302
+ expect(subject).to receive(:puts).with('*' * 100)
303
+ subject.horizontal_rule(:char => '*')
304
+ end
305
+
306
+ it 'writes a 50 yard equals' do
307
+ expect(subject).to receive(:puts).with('=' * 50)
308
+ subject.horizontal_rule(:char => '=', :width => 50)
309
+ end
310
+ end
311
+
312
+ it 'outputs color' do
313
+ expect(subject).to receive(:puts).with(controls[:red] + linechar * 100 + controls[:clear])
314
+ subject.horizontal_rule(:color => 'red')
315
+ end
316
+
317
+ it 'outputs bold' do
318
+ expect(subject).to receive(:puts).with(controls[:bold] + linechar * 100 + controls[:clear])
319
+ subject.horizontal_rule(:bold => true)
320
+ end
321
+ end
322
+
323
+ describe '#vertical_spacing' do
324
+ it 'accepts a fixnum as a valid argument' do
325
+ expect {
326
+ subject.vertical_spacing('asdf')
327
+ }.to raise_error ArgumentError
328
+ end
329
+
330
+ it 'prints carriage returns for the number of lines' do
331
+ expect(subject).to receive(:puts).with("\n" * 3)
332
+ subject.vertical_spacing(3)
333
+ end
334
+ end
335
+
336
+ describe '#datetime' do
337
+ context 'argument validation' do
338
+ it 'does not allow invalid options' do
339
+ expect {
340
+ subject.datetime(:asdf => true)
341
+ }.to raise_error ArgumentError
342
+ end
343
+
344
+ it 'accepts align' do
345
+ expect {
346
+ expect(subject).to receive(:puts)
347
+ subject.datetime(:align => 'left')
348
+ }.to_not raise_error
349
+ end
350
+
351
+ it 'accepts width' do
352
+ expect {
353
+ expect(subject).to receive(:puts)
354
+ subject.datetime(:width => 70)
355
+ }.to_not raise_error
356
+ end
357
+
358
+ it 'accepts format' do
359
+ expect {
360
+ expect(subject).to receive(:puts)
361
+ subject.datetime(:format => '%m/%d/%Y')
362
+ }.to_not raise_error
363
+ end
364
+
365
+ it 'does not allow invalid width' do
366
+ expect {
367
+ subject.datetime(:align => 'right', :width => 'asdf')
368
+ }.to raise_error
369
+ end
370
+
371
+ it 'does not allow invalid align' do
372
+ expect {
373
+ subject.datetime(:align => 1234)
374
+ }.to raise_error
375
+ end
376
+
377
+ it 'does not allow a timestamp format larger than the width' do
378
+ expect {
379
+ subject.datetime(:width => 8)
380
+ }.to raise_error
381
+ end
382
+ end
383
+
384
+ context 'display' do
385
+ it 'a default format - left aligned' do
386
+ expect(subject).to receive(:puts).with(/^#{timestamp_regex} *$/)
387
+ subject.datetime
388
+ end
389
+
390
+ it 'a default format - right aligned' do
391
+ expect(subject).to receive(:puts).with(/^ *#{timestamp_regex}$/)
392
+ subject.datetime(:align => 'right')
393
+ end
394
+
395
+ it 'a default format - center aligned' do
396
+ expect(subject).to receive(:puts).with(/^ *#{timestamp_regex} *$/)
397
+ subject.datetime(:align => 'center')
398
+ end
399
+
400
+ it 'a modified format' do
401
+ expect(subject).to receive(:puts).with(/^\d{2}\/\d{2}\/\d{2} *$/)
402
+ subject.datetime(:format => '%y/%m/%d')
403
+ end
404
+ end
405
+
406
+ it 'outputs color' do
407
+ expect(subject).to receive(:puts).with(/^\e\[31m#{timestamp_regex}\e\[0m/)
408
+ subject.datetime(:color => 'red')
409
+ end
410
+
411
+ it 'outputs bold' do
412
+ expect(subject).to receive(:puts).with(/^\e\[1m#{timestamp_regex}\e\[0m/)
413
+ subject.datetime(:bold => true)
414
+ end
415
+ end
416
+
417
+ describe '#aligned' do
418
+ context 'argument validation' do
419
+ it 'accepts align' do
420
+ expect {
421
+ allow(subject).to receive(:puts)
422
+ subject.aligned('test', :align => 'left')
423
+ }.to_not raise_error
424
+ end
425
+
426
+ it 'does not allow invalid align values' do
427
+ expect {
428
+ subject.aligned('test', :align => 1234)
429
+ }.to raise_error ArgumentError
430
+ end
431
+
432
+ it 'accepts width' do
433
+ expect {
434
+ allow(subject).to receive(:puts)
435
+ subject.aligned('test', :width => 40)
436
+ }.to_not raise_error
437
+ end
438
+
439
+ it 'does not allow invalid width values' do
440
+ expect {
441
+ subject.aligned('test', :align => 'right', :width => 'asdf')
442
+ }.to raise_error
443
+ end
444
+ end
445
+
446
+ it 'outputs color' do
447
+ expect(subject).to receive(:puts).with(controls[:red] + 'x' * 10 + controls[:clear])
448
+ subject.aligned('x' * 10, :color => 'red')
449
+ end
450
+
451
+ it 'outputs bold' do
452
+ expect(subject).to receive(:puts).with(controls[:bold] + 'x' * 10 + controls[:clear])
453
+ subject.aligned('x' * 10, :bold => true)
454
+ end
455
+
456
+ end
457
+
458
+ describe '#footer' do
459
+ context 'argument validation' do
460
+ it 'accepts title' do
461
+ expect {
462
+ allow(subject).to receive(:puts)
463
+ subject.footer(:title => 'test')
464
+ }.to_not raise_error
465
+ end
466
+
467
+ it 'accepts align' do
468
+ expect {
469
+ allow(subject).to receive(:puts)
470
+ subject.footer(:align => 'right')
471
+ }.to_not raise_error
472
+ end
473
+
474
+ it 'does not accept invalid align' do
475
+ expect {
476
+ subject.header(:align => 1234)
477
+ }.to raise_error ArgumentError
478
+ end
479
+
480
+ it 'accepts width' do
481
+ expect {
482
+ allow(subject).to receive(:puts)
483
+ subject.footer(:width => 50)
484
+ }.to_not raise_error
485
+ end
486
+
487
+ it 'does not accept invalid width' do
488
+ expect {
489
+ subject.footer(:width => 'asdf')
490
+ }.to raise_error ArgumentError
491
+ end
492
+
493
+ it 'does not allow title > width' do
494
+ expect {
495
+ subject.footer(:title => 'testtesttest', :width => 6)
496
+ }.to raise_error ArgumentError
497
+ end
498
+
499
+ it 'accepts spacing' do
500
+ expect {
501
+ allow(subject).to receive(:puts)
502
+ subject.footer(:spacing => 3)
503
+ }.to_not raise_error
504
+ end
505
+ end
506
+
507
+ context 'alignment' do
508
+ before :each do
509
+ @title = 'test12test'
510
+ end
511
+
512
+ it 'left aligns the title by default' do
513
+ expect(subject).to receive(:puts).with("\n")
514
+ expect(subject).to receive(:puts).with(@title)
515
+ subject.footer(:title => @title)
516
+ end
517
+
518
+ it 'left aligns the title' do
519
+ expect(subject).to receive(:puts).with("\n")
520
+ expect(subject).to receive(:puts).with(@title)
521
+ subject.footer(:title => @title, :align => 'left')
522
+ end
523
+
524
+ it 'right aligns the title' do
525
+ expect(subject).to receive(:puts).with("\n")
526
+ expect(subject).to receive(:puts).with(' ' * 90 + @title)
527
+ subject.footer(:title => @title, :align => 'right')
528
+ end
529
+
530
+ it 'right aligns the title using width' do
531
+ expect(subject).to receive(:puts).with("\n")
532
+ expect(subject).to receive(:puts).with(' ' * 40 + @title)
533
+ subject.footer(:title => @title, :align => 'right', :width => 50)
534
+ end
535
+
536
+ it 'center aligns the title' do
537
+ expect(subject).to receive(:puts).with("\n")
538
+ expect(subject).to receive(:puts).with(' ' * 45 + @title)
539
+ subject.footer(:title => @title, :align => 'center')
540
+ end
541
+
542
+ it 'center aligns the title using width' do
543
+ expect(subject).to receive(:puts).with("\n")
544
+ expect(subject).to receive(:puts).with(' ' * 35 + @title)
545
+ subject.footer(:title => @title, :align => 'center', :width => 80)
546
+ end
547
+ end
548
+
549
+ context 'spacing' do
550
+ it 'defaults to a single line of spacing between report' do
551
+ expect(subject).to receive(:puts).with("\n")
552
+ expect(subject).to receive(:puts).with('title')
553
+ subject.footer(:title => 'title')
554
+ end
555
+
556
+ it 'uses the defined spacing between report' do
557
+ expect(subject).to receive(:puts).with("\n" * 3)
558
+ expect(subject).to receive(:puts).with('title')
559
+ subject.footer(:title => 'title', :spacing => 3)
560
+ end
561
+ end
562
+
563
+ context 'timestamp subheading' do
564
+ it 'is added with default alignment' do
565
+ expect(subject).to receive(:puts).with("\n")
566
+ expect(subject).to receive(:puts).with('title')
567
+ expect(subject).to receive(:puts).with(/^#{timestamp_regex}/)
568
+ subject.footer(:title => 'title', :timestamp => true)
569
+ end
570
+
571
+ it 'added with right alignment' do
572
+ expect(subject).to receive(:puts).with("\n")
573
+ expect(subject).to receive(:puts).with(/^ *title$/)
574
+ expect(subject).to receive(:puts).with(/^ *#{timestamp_regex}$/)
575
+ subject.footer(:title => 'title', :align => 'right', :timestamp => true, :width => 80)
576
+ end
577
+
578
+ it 'added with center alignment' do
579
+ expect(subject).to receive(:puts).with("\n")
580
+ expect(subject).to receive(:puts).with(/^ *title *$/)
581
+ expect(subject).to receive(:puts).with(/^ *#{timestamp_regex} *$/)
582
+ subject.footer(:title => 'title', :align => 'center', :timestamp => true, :width => 80)
583
+ end
584
+ end
585
+
586
+ context 'horizontal rule' do
587
+ it 'uses dashes by default' do
588
+ expect(subject).to receive(:puts)
589
+ expect(subject).to receive(:puts).with(linechar * 100)
590
+ expect(subject).to receive(:puts)
591
+ subject.footer(:rule => true)
592
+ end
593
+
594
+ it 'uses = as the rule character' do
595
+ expect(subject).to receive(:puts)
596
+ expect(subject).to receive(:puts).with('=' * 100)
597
+ expect(subject).to receive(:puts)
598
+ subject.footer(:rule => '=')
599
+ end
600
+ end
601
+
602
+ it 'outputs red' do
603
+ expect(subject).to receive(:puts).with("\n")
604
+ expect(subject).to receive(:puts).with(controls[:red] + 'title' + controls[:clear])
605
+ expect(subject).to receive(:puts).with(/^\e\[31m#{timestamp_regex}\e\[0m/)
606
+ subject.footer(:title => 'title', :timestamp => true, :color => 'red')
607
+ end
608
+
609
+ it 'outputs bold' do
610
+ expect(subject).to receive(:puts).with("\n")
611
+ expect(subject).to receive(:puts).with(controls[:bold] + 'title' + controls[:clear])
612
+ expect(subject).to receive(:puts).with(/^\e\[1m#{timestamp_regex}\e\[0m/)
613
+ subject.footer(:title => 'title', :timestamp => true, :bold => true)
614
+ end
615
+ end
616
+
617
+ describe '#table' do
618
+ it 'instantiates the table class' do
619
+ allow(subject).to receive(:puts)
620
+ expect(subject).to receive(:table).once
621
+ subject.table { }
622
+ end
623
+
624
+ it 'requires a row to be defined' do
625
+ expect {
626
+ subject.table
627
+ }.to raise_error LocalJumpError
628
+ end
629
+
630
+ it 'accepts valid options' do
631
+ expect {
632
+ subject.table(:border => true) { }
633
+ }.to_not raise_error
634
+ end
635
+
636
+ it 'rejects invalid options' do
637
+ expect {
638
+ allow(subject).to receive(:puts)
639
+ subject.table(:asdf => '100') { }
640
+ }.to raise_error ArgumentError
641
+ end
642
+ end
643
+
644
+ describe '#row' do
645
+ it 'instantiates a row class' do
646
+ expect(subject).to receive(:row).once
647
+ allow(subject).to receive(:puts)
648
+
649
+ subject.table do
650
+ subject.row do
651
+ end
652
+ end
653
+ end
654
+ end
655
+
656
+ describe '#column' do
657
+ it 'instantiates multiple columns' do
658
+ expect(subject).to receive(:column).exactly(3).times
659
+ allow(subject).to receive(:puts)
660
+
661
+ subject.table do
662
+ subject.row do
663
+ subject.column('asdf')
664
+ subject.column('qwer')
665
+ subject.column('zxcv')
666
+ end
667
+ end
668
+ end
669
+
670
+ it 'accepts valid options' do
671
+ expect(subject).to receive(:column).once
672
+ allow(subject).to receive(:puts)
673
+
674
+ subject.table do
675
+ subject.row do
676
+ subject.column('asdf', :width => 30)
677
+ end
678
+ end
679
+ end
680
+
681
+ it 'rejects invalid options' do
682
+ allow(subject).to receive(:puts)
683
+ expect {
684
+ subject.table do
685
+ subject.row do
686
+ subject.column('asdf', :asdf => 30)
687
+ end
688
+ end
689
+ }.to raise_error ArgumentError
690
+ end
691
+ end
692
+
693
+ end