command_line_reporter 1.1.0 → 2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +119 -3
- data/examples/table.rb +49 -0
- data/lib/column.rb +52 -0
- data/lib/command_line_reporter.rb +21 -6
- data/lib/options_validator.rb +5 -0
- data/lib/row.rb +60 -0
- data/lib/table.rb +44 -0
- data/lib/version.rb +1 -1
- data/spec/column_spec.rb +148 -0
- data/spec/command_line_reporter_spec.rb +80 -0
- data/spec/options_validator_spec.rb +25 -0
- data/spec/row_spec.rb +88 -0
- data/spec/spec_helper.rb +1 -0
- data/spec/support/matchers/argument.rb +17 -0
- data/spec/table_spec.rb +45 -0
- metadata +20 -5
data/README.md
CHANGED
@@ -4,6 +4,9 @@ This gem provides an simple way to add RSpec like formatting of the output of yo
|
|
4
4
|
eliminates the need to litter your code with *puts* statements instead providing a cleaner, more
|
5
5
|
ruby like way of reporting progress to the user throught the command line interface.
|
6
6
|
|
7
|
+
With the release of Version 2.0, it is now possible to produce tables with and without borders. See
|
8
|
+
the section on *Tables* for more examples.
|
9
|
+
|
7
10
|
### Installation
|
8
11
|
|
9
12
|
It is up on rubygems.org so add it to your bundle or do it the old fashioned way:
|
@@ -20,7 +23,7 @@ The gem provides a mixin that can be included in your scripts.
|
|
20
23
|
include CommandLineReporter
|
21
24
|
```
|
22
25
|
|
23
|
-
|
26
|
+
##### Standard Methods
|
24
27
|
|
25
28
|
There are several methods the mixin provides that do not depend on the formatter used:
|
26
29
|
|
@@ -58,6 +61,18 @@ There are several methods the mixin provides that do not depend on the formatter
|
|
58
61
|
* _text_ - String to display
|
59
62
|
* _:align_ - 'left'|'right'|'center' align the string text. _Default: 'left'_
|
60
63
|
* _:width_ - The width in characters of the string text. _Default: 100_
|
64
|
+
* _table(hash) {block}_
|
65
|
+
* The first argument is a hash that defines properties of the table.
|
66
|
+
* _:border_ - true|false indicates whether to include borders around the table cells
|
67
|
+
* The second argument is a block which includes calls the to the _row_ method
|
68
|
+
* _row {block}_
|
69
|
+
* Only argument is a block with calls to _column_ allowed
|
70
|
+
* _column(string, hash)_
|
71
|
+
* _text_ - String to display in the table cell
|
72
|
+
* _options_ - The options to define the column
|
73
|
+
* :width - defines the width of the column
|
74
|
+
* :padding - The number of spaces to put on both the left and right of the text.
|
75
|
+
* :align - Allowed values are left|right|center
|
61
76
|
|
62
77
|
### Progress Formatter
|
63
78
|
|
@@ -228,7 +243,108 @@ report(:message => 'running', :complete => 'finished', :type => 'inline', :inden
|
|
228
243
|
end
|
229
244
|
```
|
230
245
|
|
246
|
+
### Tables
|
247
|
+
|
248
|
+
Examples are always helpful so let's look at the following:
|
249
|
+
|
250
|
+
```ruby
|
251
|
+
require 'command_line_reporter'
|
252
|
+
|
253
|
+
class Example
|
254
|
+
include CommandLineReporter
|
255
|
+
|
256
|
+
def run
|
257
|
+
table(:border => true) do
|
258
|
+
row do
|
259
|
+
column('NAME', :width => 20)
|
260
|
+
column('ADDRESS', :width => 30, :align => 'right', :padding => 5)
|
261
|
+
column('CITY', :width => 15)
|
262
|
+
end
|
263
|
+
row do
|
264
|
+
column('Ceaser')
|
265
|
+
column('1 Appian Way')
|
266
|
+
column('Rome')
|
267
|
+
end
|
268
|
+
row do
|
269
|
+
column('Richard Feynman')
|
270
|
+
column('1 Golden Gate')
|
271
|
+
column('Quantum Field')
|
272
|
+
end
|
273
|
+
end
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
Example.new.run
|
278
|
+
```
|
279
|
+
|
280
|
+
This produces the very simple output with 2 rows and 3 columns of data:
|
281
|
+
|
282
|
+
```bash
|
283
|
+
+----------------------+--------------------------------+-----------------+
|
284
|
+
| NAME | ADDRESS | CITY |
|
285
|
+
+----------------------+--------------------------------+-----------------+
|
286
|
+
| Ceaser | 1 Appian Way | Rome |
|
287
|
+
+----------------------+--------------------------------+-----------------+
|
288
|
+
| Richard Feynman | 1 Golden Gate | Quantum Field |
|
289
|
+
+----------------------+--------------------------------+-----------------+
|
290
|
+
```
|
291
|
+
|
292
|
+
Notice how the properties of the columns for the second and third rows have been inherited from the
|
293
|
+
first like in HTML. This makes it a lot easier to write in freeform. What if you have data to
|
294
|
+
iterate over and have text that is wider than the column width you have selected? Not a problem as
|
295
|
+
the following example demonstrates all of the combinations of the various options:
|
296
|
+
|
297
|
+
```ruby
|
298
|
+
require 'command_line_reporter'
|
299
|
+
|
300
|
+
class Example
|
301
|
+
include CommandLineReporter
|
302
|
+
|
303
|
+
def run
|
304
|
+
table(:border => true) do
|
305
|
+
3.times do
|
306
|
+
row do
|
307
|
+
i = 0
|
308
|
+
3.times do
|
309
|
+
i += 10
|
310
|
+
column('x' * (0 + rand(50)), :align => %w[left right center][rand(3)], :width => i, :padding => rand(5))
|
311
|
+
end
|
312
|
+
end
|
313
|
+
end
|
314
|
+
end
|
315
|
+
end
|
316
|
+
end
|
317
|
+
```
|
318
|
+
|
319
|
+
This randomly produces a table with a border that has 3 rows and 3 columns. Each column gets wider
|
320
|
+
by 10 characters. The alignment of the column is demonstrated and you can see where some data
|
321
|
+
elements have padding around them.
|
322
|
+
|
323
|
+
```bash
|
324
|
+
+------------+----------------------+--------------------------------+
|
325
|
+
| xxxxxxxxxx | xxxxxxxxxxxxxx | xxxxxxxxxxxxxxxxxxxxxxxxxx |
|
326
|
+
| xxxxxx | xxxxxxxxx | xxxxxx |
|
327
|
+
+------------+----------------------+--------------------------------+
|
328
|
+
| xxxxxxxxxx | xxxxxxxxxxxxxx | xxxxxxxxxxxxxxxxxxxxxxxxxx |
|
329
|
+
| xxxxxxxxxx | xxxxxxxxxxxxxx | xxxxxxxxxxxxxxxxx |
|
330
|
+
| xxxxxxxxxx | xxxxxxxxxxxxxx | |
|
331
|
+
| xxxxxxx | xxxx | |
|
332
|
+
+------------+----------------------+--------------------------------+
|
333
|
+
| xxxxxxxxxx | xxxx | xxxxxxxxxxxxxxxxxxx |
|
334
|
+
| xxxxxx | | |
|
335
|
+
+------------+----------------------+--------------------------------+
|
336
|
+
```
|
337
|
+
|
338
|
+
This is all generated randomly to illustrate the features but you get the idea of how to use
|
339
|
+
alignment, width and padding.
|
340
|
+
|
341
|
+
The best feature is *wrapping*. If the text you are display in a cell is larger than the width it
|
342
|
+
was given, it will automatically wrap it for you. Padding and alignment are preserved. It palso
|
343
|
+
properly handles the case where the data in one cell causes the wrapping but other cells my not have
|
344
|
+
the same number of lines to wrap.
|
345
|
+
|
231
346
|
### To Do
|
232
347
|
|
233
|
-
|
234
|
-
|
348
|
+
* Add the ability for a column to span across others
|
349
|
+
* Add the progress method to the top level mixin so that there is no need to invoke through the
|
350
|
+
formatter.
|
data/examples/table.rb
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'command_line_reporter'
|
2
|
+
|
3
|
+
class Example
|
4
|
+
include CommandLineReporter
|
5
|
+
|
6
|
+
def run
|
7
|
+
header(:title => 'TABLE EXAMPLES - Borders, Wrapping, Alignment and Padding', :align => 'center', :width => 70)
|
8
|
+
|
9
|
+
2.times do |j|
|
10
|
+
header(:title => "Table #{j}", :align => 'center', :width => 65)
|
11
|
+
|
12
|
+
table(:border => j % 2 == 0) do
|
13
|
+
3.times do
|
14
|
+
row do
|
15
|
+
i = 0
|
16
|
+
3.times do
|
17
|
+
i += 10
|
18
|
+
column('x' * (0 + rand(50)), :align => %w[left right center][rand(3)], :width => i, :padding => rand(5))
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
vertical_spacing(2)
|
25
|
+
end
|
26
|
+
|
27
|
+
header(:title => 'A simple example of how column properties are inhereted from the first row')
|
28
|
+
|
29
|
+
table(:border => true) do
|
30
|
+
row do
|
31
|
+
column('NAME', :width => 20)
|
32
|
+
column('ADDRESS', :width => 30, :align => 'right', :padding => 5)
|
33
|
+
column('CITY', :width => 15)
|
34
|
+
end
|
35
|
+
row do
|
36
|
+
column('Ceaser')
|
37
|
+
column('1 Appian Way')
|
38
|
+
column('Rome')
|
39
|
+
end
|
40
|
+
row do
|
41
|
+
column('Richard Feynman')
|
42
|
+
column('1 Golden Gate')
|
43
|
+
column('Quantum Field')
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
Example.new.run
|
data/lib/column.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'options_validator'
|
2
|
+
|
3
|
+
class Column
|
4
|
+
include OptionsValidator
|
5
|
+
|
6
|
+
VALID_OPTIONS = [:width, :padding, :align]
|
7
|
+
attr_accessor :text, :size, *VALID_OPTIONS
|
8
|
+
|
9
|
+
def initialize(text = nil, options = {})
|
10
|
+
self.validate_options(options, *VALID_OPTIONS)
|
11
|
+
|
12
|
+
self.text = text
|
13
|
+
|
14
|
+
self.width = options[:width] || 10
|
15
|
+
self.align = options[:align] || 'left'
|
16
|
+
self.padding = options[:padding] || 0
|
17
|
+
|
18
|
+
raise ArgumentError unless self.width > 0
|
19
|
+
raise ArgumentError unless self.padding.to_s.match(/^\d+$/)
|
20
|
+
|
21
|
+
self.size = self.width - 2 * self.padding
|
22
|
+
|
23
|
+
# self.freeze
|
24
|
+
end
|
25
|
+
|
26
|
+
def screen_rows
|
27
|
+
if self.text.nil? || self.text.empty?
|
28
|
+
[' ' * self.width]
|
29
|
+
else
|
30
|
+
self.text.scan(/.{1,#{self.size}}/m).map {|s| to_cell(s)}
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def to_cell(str)
|
37
|
+
cell = if str.empty?
|
38
|
+
' ' * self.size
|
39
|
+
else
|
40
|
+
case self.align
|
41
|
+
when 'left'
|
42
|
+
str.ljust(self.size)
|
43
|
+
when 'right'
|
44
|
+
str.rjust(self.size)
|
45
|
+
when 'center'
|
46
|
+
str.ljust((self.size - str.size)/2.0 + str.size).rjust(self.size)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
' ' * self.padding + cell + ' ' * self.padding
|
51
|
+
end
|
52
|
+
end
|
@@ -1,6 +1,10 @@
|
|
1
|
+
require 'table'
|
2
|
+
|
1
3
|
Dir[File.join(File.dirname(__FILE__), '*_formatter.rb')].each {|r| require r}
|
2
4
|
|
3
5
|
module CommandLineReporter
|
6
|
+
include OptionsValidator
|
7
|
+
|
4
8
|
attr_reader :formatter
|
5
9
|
|
6
10
|
DEFAULTS = {
|
@@ -23,10 +27,8 @@ module CommandLineReporter
|
|
23
27
|
end
|
24
28
|
|
25
29
|
def report(options = {}, &block)
|
30
|
+
self.formatter ||= 'nested'
|
26
31
|
self.formatter.format(options, block)
|
27
|
-
rescue NoMethodError
|
28
|
-
self.formatter = 'nested'
|
29
|
-
retry
|
30
32
|
end
|
31
33
|
|
32
34
|
def footer(options = {})
|
@@ -80,12 +82,25 @@ module CommandLineReporter
|
|
80
82
|
end
|
81
83
|
end
|
82
84
|
|
83
|
-
|
85
|
+
def table(options = {})
|
86
|
+
@table = Table.new(options)
|
87
|
+
yield
|
88
|
+
@table.to_s
|
89
|
+
end
|
84
90
|
|
85
|
-
def
|
86
|
-
|
91
|
+
def row(options = {})
|
92
|
+
@row = Row.new
|
93
|
+
yield
|
94
|
+
@table.add(@row)
|
87
95
|
end
|
88
96
|
|
97
|
+
def column(text, options = {})
|
98
|
+
col = Column.new(text, options)
|
99
|
+
@row.add(col)
|
100
|
+
end
|
101
|
+
|
102
|
+
private
|
103
|
+
|
89
104
|
def section(type, options)
|
90
105
|
validate_options(options, :title, :width, :align, :spacing, :timestamp, :rule)
|
91
106
|
|
data/lib/row.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'column'
|
2
|
+
require 'forwardable'
|
3
|
+
|
4
|
+
class Row
|
5
|
+
extend Forwardable
|
6
|
+
|
7
|
+
attr_accessor :columns, :border
|
8
|
+
|
9
|
+
def initialize(options = {})
|
10
|
+
self.columns = []
|
11
|
+
self.border = false
|
12
|
+
end
|
13
|
+
|
14
|
+
def_delegator :@columns, :push, :add
|
15
|
+
|
16
|
+
def separator
|
17
|
+
@sep ||= '+' + self.columns.map {|c| '-' * (c.width + 2)}.join('+') + '+'
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_s
|
21
|
+
screen_count.times do |sr|
|
22
|
+
line = (self.border) ? '| ' : ''
|
23
|
+
self.columns.size.times do |mc|
|
24
|
+
col = self.columns[mc]
|
25
|
+
# Account for the fact that some columns will have more screen rows than their
|
26
|
+
# counterparts in the row. An example being:
|
27
|
+
# c1 = Column.new('x' * 50, :width => 10)
|
28
|
+
# c2 = Column.new('x' * 20, :width => 10)
|
29
|
+
#
|
30
|
+
# c1.screen_rows.size == 5
|
31
|
+
# c2.screen_rows.size == 2
|
32
|
+
#
|
33
|
+
# So when we don't have a screen row for c2 we need to fill the screen with the
|
34
|
+
# proper number of blanks so the layout looks like (parenthesis on the right just
|
35
|
+
# indicate screen row index)
|
36
|
+
#
|
37
|
+
# +-------------+------------+
|
38
|
+
# | xxxxxxxxxxx | xxxxxxxxxx | (0)
|
39
|
+
# | xxxxxxxxxxx | xxxxxxxxxx | (1)
|
40
|
+
# | xxxxxxxxxxx | | (2)
|
41
|
+
# | xxxxxxxxxxx | | (3)
|
42
|
+
# | xxxxxxxxxxx | | (4)
|
43
|
+
# +-------------+------------+
|
44
|
+
if col.screen_rows[sr].nil?
|
45
|
+
line << ' ' * col.width
|
46
|
+
else
|
47
|
+
line << self.columns[mc].screen_rows[sr]
|
48
|
+
end
|
49
|
+
line << ' ' + ((self.border) ? '| ' : '')
|
50
|
+
end
|
51
|
+
puts line
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def screen_count
|
58
|
+
@sc ||= self.columns.inject(0) {|max,column| column.screen_rows.size > max ? column.screen_rows.size : max}
|
59
|
+
end
|
60
|
+
end
|
data/lib/table.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'row'
|
2
|
+
require 'options_validator'
|
3
|
+
|
4
|
+
class Table
|
5
|
+
include OptionsValidator
|
6
|
+
|
7
|
+
VALID_OPTIONS = [:border]
|
8
|
+
attr_accessor :rows, *VALID_OPTIONS
|
9
|
+
|
10
|
+
def initialize(options = {})
|
11
|
+
self.validate_options(options, *VALID_OPTIONS)
|
12
|
+
|
13
|
+
self.border = options[:border] || false
|
14
|
+
|
15
|
+
@rows = []
|
16
|
+
end
|
17
|
+
|
18
|
+
def add(row)
|
19
|
+
# Inheritance from the table
|
20
|
+
row.border = self.border
|
21
|
+
|
22
|
+
# Inherit properties from the first row
|
23
|
+
if self.rows[0]
|
24
|
+
row.columns.each_with_index do |c,i|
|
25
|
+
c.align = self.rows[0].columns[i].align
|
26
|
+
c.padding = self.rows[0].columns[i].padding
|
27
|
+
c.width = self.rows[0].columns[i].width
|
28
|
+
c.size = c.width - 2 * c.padding
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
self.rows << row
|
33
|
+
end
|
34
|
+
|
35
|
+
def to_s
|
36
|
+
return if self.rows.size == 0 # we got here with nothing to print to the screen
|
37
|
+
|
38
|
+
puts self.rows[0].separator if self.border
|
39
|
+
self.rows.each do |row|
|
40
|
+
row.to_s
|
41
|
+
puts self.rows[0].separator if self.border
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
data/lib/version.rb
CHANGED
data/spec/column_spec.rb
ADDED
@@ -0,0 +1,148 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'column'
|
3
|
+
|
4
|
+
describe Column do
|
5
|
+
context 'creation' do
|
6
|
+
it 'rejects invalid options' do
|
7
|
+
expect {
|
8
|
+
Column.new('test', :asdf => '1234')
|
9
|
+
}.to raise_error ArgumentError
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'defaults options hash' do
|
13
|
+
expect {
|
14
|
+
Column.new('test')
|
15
|
+
}.to_not raise_error
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'defaults the width' do
|
19
|
+
Column.new('test').width.should == 10
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'accepts the width' do
|
23
|
+
Column.new('test', :width => 50).width.should == 50
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'requires valid width' do
|
27
|
+
expect {
|
28
|
+
Column.new('test', :width => 'asdf')
|
29
|
+
}.to raise_error ArgumentError
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'accepts text' do
|
33
|
+
Column.new('asdf').text.should == 'asdf'
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'defaults the padding' do
|
37
|
+
Column.new('test').padding.should == 0
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'accepts the padding' do
|
41
|
+
Column.new('test', :padding => 5).padding.should == 5
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'requires valid width' do
|
45
|
+
expect {
|
46
|
+
Column.new('test', :padding => 'asdf')
|
47
|
+
}.to raise_error ArgumentError
|
48
|
+
end
|
49
|
+
|
50
|
+
# it 'is immutable' do
|
51
|
+
# c = Column.new('test')
|
52
|
+
|
53
|
+
# expect {
|
54
|
+
# c.text = 'asdf'
|
55
|
+
# }.to raise_error RuntimeError, /frozen object/
|
56
|
+
|
57
|
+
# expect {
|
58
|
+
# c.width = 123
|
59
|
+
# }.to raise_error RuntimeError, /frozen object/
|
60
|
+
|
61
|
+
# expect {
|
62
|
+
# c.padding = 123
|
63
|
+
# }.to raise_error RuntimeError, /frozen object/
|
64
|
+
# end
|
65
|
+
end
|
66
|
+
|
67
|
+
describe '#screen_rows' do
|
68
|
+
context 'no wrapping' do
|
69
|
+
context 'no padding' do
|
70
|
+
it 'gives a single row' do
|
71
|
+
c = Column.new('x' * 5)
|
72
|
+
c.screen_rows.size == 1
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'handles empty text' do
|
76
|
+
c = Column.new
|
77
|
+
c.screen_rows[0].should == ' ' * 10
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'left justifies' do
|
81
|
+
c = Column.new('x' * 10, :width => 20)
|
82
|
+
c.screen_rows[0].should == 'x' * 10 + ' ' * 10
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'right justifies' do
|
86
|
+
c = Column.new('x' * 10, :align => 'right', :width => 20)
|
87
|
+
c.screen_rows[0].should == ' ' * 10 + 'x' * 10
|
88
|
+
end
|
89
|
+
|
90
|
+
it 'center justifies' do
|
91
|
+
c = Column.new('x' * 10, :align => 'center', :width => 20)
|
92
|
+
c.screen_rows[0].should == ' ' * 5 + 'x' * 10 + ' ' * 5
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
context 'accounts for padding' do
|
97
|
+
it 'left justifies' do
|
98
|
+
c = Column.new('x' * 10, :padding => 5, :width => 30)
|
99
|
+
c.screen_rows[0].should == ' ' * 5 + 'x' * 10 + ' ' * 15
|
100
|
+
end
|
101
|
+
it 'right justifies' do
|
102
|
+
c = Column.new('x' * 10, :align => 'right', :padding => 5, :width => 30)
|
103
|
+
c.screen_rows[0].should == ' ' * 15 + 'x' * 10 + ' ' * 5
|
104
|
+
end
|
105
|
+
it 'right justifies' do
|
106
|
+
c = Column.new('x' * 10, :align => 'center', :padding => 5, :width => 30)
|
107
|
+
c.screen_rows[0].should == ' ' * 10 + 'x' * 10 + ' ' * 10
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
context 'with wrapping' do
|
113
|
+
context 'no padding' do
|
114
|
+
it 'left justifies' do
|
115
|
+
c = Column.new('x' * 25, :width => 10)
|
116
|
+
c.screen_rows.should == ['x' * 10, 'x' * 10, 'x' * 5 + ' ' * 5]
|
117
|
+
end
|
118
|
+
|
119
|
+
it 'left justifies' do
|
120
|
+
c = Column.new('x' * 25, :align => 'right', :width => 10)
|
121
|
+
c.screen_rows.should == ['x' * 10, 'x' * 10, ' ' * 5 + 'x' * 5]
|
122
|
+
end
|
123
|
+
|
124
|
+
it 'left justifies' do
|
125
|
+
c = Column.new('x' * 25, :align => 'center', :width => 10)
|
126
|
+
c.screen_rows.should == ['x' * 10, 'x' * 10, ' ' * 3 + 'x' * 5 + ' ' * 2]
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
context 'account for padding' do
|
131
|
+
it 'left justifies' do
|
132
|
+
c = Column.new('x' * 25, :padding => 2, :width => 20)
|
133
|
+
c.screen_rows.should == [' ' * 2 + 'x' * 16 + ' ' * 2, ' ' * 2 + 'x' * 9 + ' ' * 9]
|
134
|
+
end
|
135
|
+
|
136
|
+
it 'right justifies' do
|
137
|
+
c = Column.new('x' * 25, :padding => 2, :align => 'right', :width => 20)
|
138
|
+
c.screen_rows.should == [' ' * 2 + 'x' * 16 + ' ' * 2, ' ' * 9 + 'x' * 9 + ' ' * 2]
|
139
|
+
end
|
140
|
+
|
141
|
+
it 'center justifies' do
|
142
|
+
c = Column.new('x' * 25, :padding => 2, :align => 'center', :width => 20)
|
143
|
+
c.screen_rows.should == [' ' * 2 + 'x' * 16 + ' ' * 2, ' ' * 6 + 'x' * 9 + ' ' * 5]
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
@@ -49,6 +49,14 @@ describe CommandLineReporter do
|
|
49
49
|
|
50
50
|
subject.formatter.class.should == CommandLineReporter::ProgressFormatter
|
51
51
|
end
|
52
|
+
|
53
|
+
it 'does not mask other application errors when a formatter is not set' do
|
54
|
+
capture_stdout {
|
55
|
+
subject.report {
|
56
|
+
lambda {self.some_method_that_does_not_exist}.should raise_error(NoMethodError)
|
57
|
+
}
|
58
|
+
}
|
59
|
+
end
|
52
60
|
end
|
53
61
|
|
54
62
|
describe '#header' do
|
@@ -509,4 +517,76 @@ describe CommandLineReporter do
|
|
509
517
|
end
|
510
518
|
end
|
511
519
|
end
|
520
|
+
|
521
|
+
describe '#table' do
|
522
|
+
it 'instantiates the table class' do
|
523
|
+
subject.should_receive(:puts).any_number_of_times
|
524
|
+
subject.should_receive(:table).once
|
525
|
+
subject.table { }
|
526
|
+
# subject.instance_variable_get(:@table).should_not be_nil
|
527
|
+
end
|
528
|
+
|
529
|
+
it 'requires a row to be defined' do
|
530
|
+
expect {
|
531
|
+
subject.table
|
532
|
+
}.to raise_error LocalJumpError
|
533
|
+
end
|
534
|
+
|
535
|
+
it 'accepts valid options' do
|
536
|
+
expect {
|
537
|
+
subject.table(:border => true) { }
|
538
|
+
}.to_not raise_error
|
539
|
+
end
|
540
|
+
|
541
|
+
it 'rejects invalid options' do
|
542
|
+
expect {
|
543
|
+
subject.table(:asdf => '100') { }
|
544
|
+
}.to raise_error ArgumentError
|
545
|
+
end
|
546
|
+
end
|
547
|
+
|
548
|
+
describe '#row' do
|
549
|
+
it 'instantiates a row class' do
|
550
|
+
subject.should_receive(:row).once
|
551
|
+
subject.should_receive(:puts).any_number_of_times
|
552
|
+
|
553
|
+
subject.table do
|
554
|
+
subject.row do
|
555
|
+
end
|
556
|
+
end
|
557
|
+
end
|
558
|
+
end
|
559
|
+
|
560
|
+
describe '#column' do
|
561
|
+
it 'instantiates multiple columns' do
|
562
|
+
subject.should_receive(:column).exactly(3).times
|
563
|
+
subject.should_receive(:puts).any_number_of_times
|
564
|
+
|
565
|
+
subject.table do
|
566
|
+
subject.row do
|
567
|
+
subject.column('asdf')
|
568
|
+
subject.column('qwer')
|
569
|
+
subject.column('zxcv')
|
570
|
+
end
|
571
|
+
end
|
572
|
+
end
|
573
|
+
|
574
|
+
it 'accepts valid options' do
|
575
|
+
subject.table do
|
576
|
+
subject.row do
|
577
|
+
subject.column('asdf', :width => 30)
|
578
|
+
end
|
579
|
+
end
|
580
|
+
end
|
581
|
+
|
582
|
+
it 'rejects invalid options' do
|
583
|
+
expect {
|
584
|
+
subject.table do
|
585
|
+
subject.row do
|
586
|
+
subject.column('asdf', :asdf => 30)
|
587
|
+
end
|
588
|
+
end
|
589
|
+
}.to raise_error ArgumentError
|
590
|
+
end
|
591
|
+
end
|
512
592
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'options_validator'
|
3
|
+
|
4
|
+
describe OptionsValidator do
|
5
|
+
subject { Class.new.extend(OptionsValidator) }
|
6
|
+
|
7
|
+
it 'accepts single key options' do
|
8
|
+
expect {
|
9
|
+
subject.validate_options({:valid => true}, :valid)
|
10
|
+
}.to_not raise_error
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'rejects invalid option hashes' do
|
14
|
+
expect {
|
15
|
+
subject.validate_options({:wrong => true}, :valid)
|
16
|
+
}.to raise_error ArgumentError
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'accepts multi-key options' do
|
20
|
+
expect {
|
21
|
+
valid = [:valid, :another]
|
22
|
+
subject.validate_options({:valid => true, :another => true}, *valid)
|
23
|
+
}.to_not raise_error
|
24
|
+
end
|
25
|
+
end
|
data/spec/row_spec.rb
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'row'
|
3
|
+
|
4
|
+
describe Row do
|
5
|
+
before :each do
|
6
|
+
@cols = 10.times.map {|v| Column.new("test#{v}")}
|
7
|
+
end
|
8
|
+
|
9
|
+
describe '#add' do
|
10
|
+
subject { Row.new }
|
11
|
+
|
12
|
+
it 'adds columns' do
|
13
|
+
subject.add(@cols[0])
|
14
|
+
subject.columns.size.should == 1
|
15
|
+
subject.columns[0].should == @cols[0]
|
16
|
+
subject.add(@cols[1])
|
17
|
+
subject.columns.should == @cols[0,2]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe '#to_s' do
|
22
|
+
before :each do
|
23
|
+
@cols = [
|
24
|
+
Column.new('asdf'),
|
25
|
+
Column.new('qwer', :align => 'center'),
|
26
|
+
Column.new('zxcv', :align => 'right'),
|
27
|
+
Column.new('x' * 25, :align => 'left', :width => 10),
|
28
|
+
Column.new('x' * 25, :align => 'center', :width => 10),
|
29
|
+
Column.new('x' * 35, :align => 'left', :width => 10),
|
30
|
+
]
|
31
|
+
end
|
32
|
+
|
33
|
+
before :all do
|
34
|
+
@one_space = ' '
|
35
|
+
@three_spaces = ' {3,3}'
|
36
|
+
@six_spaces = ' {6,6}'
|
37
|
+
@nine_spaces = ' {9,9}'
|
38
|
+
@five_xs = 'x{5,5}'
|
39
|
+
@ten_xs = 'x{10,10}'
|
40
|
+
end
|
41
|
+
|
42
|
+
context 'no border' do
|
43
|
+
context 'no wrap' do
|
44
|
+
it 'prints a single column' do
|
45
|
+
subject.add(@cols[0])
|
46
|
+
subject.should_receive(:puts).with(/^asdf#{@six_pieces}/)
|
47
|
+
subject.to_s
|
48
|
+
end
|
49
|
+
it 'prints three columns' do
|
50
|
+
subject.add(@cols[0])
|
51
|
+
subject.add(@cols[1])
|
52
|
+
subject.add(@cols[2])
|
53
|
+
subject.should_receive(:puts).with(/^asdf#{@six_spaces}#{@one_space}#{@three_spaces}qwer#{@three_spaces}#{@one_space}#{@six_spaces}zxcv $/)
|
54
|
+
subject.to_s
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
context 'with wrapping' do
|
59
|
+
it 'prints a single column' do
|
60
|
+
subject.add(@cols[3])
|
61
|
+
subject.should_receive(:puts).with(/^#{@ten_xs}#{@one_space}$/)
|
62
|
+
subject.should_receive(:puts).with(/^#{@ten_xs}#{@one_space}$/)
|
63
|
+
subject.should_receive(:puts).with(/^#{@five_xs}#{@six_spaces}$/)
|
64
|
+
subject.to_s
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'prints multiple columns of the same size' do
|
68
|
+
subject.add(@cols[3])
|
69
|
+
subject.add(@cols[4])
|
70
|
+
subject.should_receive(:puts).with(/^#{@ten_xs}#{@one_space}#{@ten_xs}#{@one_space}$/)
|
71
|
+
subject.should_receive(:puts).with(/^#{@ten_xs}#{@one_space}#{@ten_xs}#{@one_space}$/)
|
72
|
+
subject.should_receive(:puts).with(/^#{@five_xs}#{@nine_spaces}#{@five_xs}#{@three_spaces}$/)
|
73
|
+
subject.to_s
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'prints multiple columns with different size' do
|
77
|
+
subject.add(@cols[5])
|
78
|
+
subject.add(@cols[3])
|
79
|
+
subject.should_receive(:puts).with(/^#{@ten_xs}#{@one_space}#{@ten_xs}#{@one_space}$/)
|
80
|
+
subject.should_receive(:puts).with(/^#{@ten_xs}#{@one_space}#{@ten_xs}#{@one_space}$/)
|
81
|
+
subject.should_receive(:puts).with(/^#{@ten_xs}#{@one_space}#{@five_xs}#{@six_spaces}$/)
|
82
|
+
subject.should_receive(:puts).with(/^#{@five_xs} {5,17}$/)
|
83
|
+
subject.to_s
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -0,0 +1,17 @@
|
|
1
|
+
RSpec::Matchers.define :accepts_argument do |expected|
|
2
|
+
match do
|
3
|
+
expected.call.should raise_exception ArgumentError
|
4
|
+
end
|
5
|
+
|
6
|
+
# failure_message_for_should do |actual|
|
7
|
+
# 'should raise an ArgumentError'
|
8
|
+
# end
|
9
|
+
|
10
|
+
# failure_message_for_should_not do |actual|
|
11
|
+
# 'should not raise ArgumentError'
|
12
|
+
# end
|
13
|
+
|
14
|
+
# description do
|
15
|
+
# 'validates options argument'
|
16
|
+
# end
|
17
|
+
end
|
data/spec/table_spec.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'table'
|
3
|
+
|
4
|
+
describe Table do
|
5
|
+
context 'creation' do
|
6
|
+
it 'defaults options hash' do
|
7
|
+
expect {
|
8
|
+
Table.new
|
9
|
+
}.to_not raise_error
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'defaults the border' do
|
13
|
+
Table.new.border.should == false
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'accepts the border' do
|
17
|
+
Table.new(:border => true).border.should == true
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
context 'rows' do
|
22
|
+
it 'allows addition' do
|
23
|
+
cols = [Column.new('test1'), Column.new('test2')]
|
24
|
+
row = Row.new
|
25
|
+
cols.each {|c| row.add(c)}
|
26
|
+
expect {
|
27
|
+
Table.new.add(row)
|
28
|
+
}.to_not raise_error
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'normalizes all column width and sizes' do
|
32
|
+
cols = [Column.new('asdf', :width => 5), Column.new('qwer')]
|
33
|
+
row = Row.new
|
34
|
+
row.add(cols[0])
|
35
|
+
t = Table.new
|
36
|
+
t.add(row)
|
37
|
+
row = Row.new
|
38
|
+
row.add(cols[1])
|
39
|
+
t.add(row)
|
40
|
+
output = capture_stdout {
|
41
|
+
t.to_s
|
42
|
+
}
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: command_line_reporter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: '2.0'
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -10,11 +10,11 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date:
|
13
|
+
date: 2012-01-11 00:00:00.000000000Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: bundler
|
17
|
-
requirement: &
|
17
|
+
requirement: &2152892720 !ruby/object:Gem::Requirement
|
18
18
|
none: false
|
19
19
|
requirements:
|
20
20
|
- - ! '>='
|
@@ -22,7 +22,7 @@ dependencies:
|
|
22
22
|
version: 1.0.0
|
23
23
|
type: :development
|
24
24
|
prerelease: false
|
25
|
-
version_requirements: *
|
25
|
+
version_requirements: *2152892720
|
26
26
|
description: This gem makes it easy to provide a report while your ruby script is
|
27
27
|
executing
|
28
28
|
email: baywes@gmail.com
|
@@ -33,16 +33,26 @@ files:
|
|
33
33
|
- examples/nested.rb
|
34
34
|
- examples/progress.rb
|
35
35
|
- examples/simple.rb
|
36
|
+
- examples/table.rb
|
37
|
+
- lib/column.rb
|
36
38
|
- lib/command_line_reporter.rb
|
37
39
|
- lib/nested_formatter.rb
|
40
|
+
- lib/options_validator.rb
|
38
41
|
- lib/progress_formatter.rb
|
42
|
+
- lib/row.rb
|
43
|
+
- lib/table.rb
|
39
44
|
- lib/version.rb
|
40
45
|
- README.md
|
46
|
+
- spec/column_spec.rb
|
41
47
|
- spec/command_line_reporter_spec.rb
|
42
48
|
- spec/nested_formatter_spec.rb
|
49
|
+
- spec/options_validator_spec.rb
|
43
50
|
- spec/progress_formatter_spec.rb
|
51
|
+
- spec/row_spec.rb
|
44
52
|
- spec/spec_helper.rb
|
45
53
|
- spec/support/helpers/stdout.rb
|
54
|
+
- spec/support/matchers/argument.rb
|
55
|
+
- spec/table_spec.rb
|
46
56
|
homepage: http://github.com/wbailey/command_line_reporter
|
47
57
|
licenses: []
|
48
58
|
post_install_message:
|
@@ -57,7 +67,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
57
67
|
version: '0'
|
58
68
|
segments:
|
59
69
|
- 0
|
60
|
-
hash:
|
70
|
+
hash: 3958532185567160349
|
61
71
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
62
72
|
none: false
|
63
73
|
requirements:
|
@@ -71,8 +81,13 @@ signing_key:
|
|
71
81
|
specification_version: 3
|
72
82
|
summary: A tool for providing interactive command line applications
|
73
83
|
test_files:
|
84
|
+
- spec/column_spec.rb
|
74
85
|
- spec/command_line_reporter_spec.rb
|
75
86
|
- spec/nested_formatter_spec.rb
|
87
|
+
- spec/options_validator_spec.rb
|
76
88
|
- spec/progress_formatter_spec.rb
|
89
|
+
- spec/row_spec.rb
|
77
90
|
- spec/spec_helper.rb
|
78
91
|
- spec/support/helpers/stdout.rb
|
92
|
+
- spec/support/matchers/argument.rb
|
93
|
+
- spec/table_spec.rb
|