command_line_reporter 2.1 → 3.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  ## Command Line Reporter
2
2
 
3
- This gem provides a DSL that makes it easy to write reports of various types in ruby. It eliminate
3
+ This gem provides a DSL that makes it easy to write reports of various types in ruby. It eliminates
4
4
  the need to litter your source with *puts* statements instead providing a more readable, expressive
5
5
  interface to your application. Some of the best features include:
6
6
 
@@ -9,12 +9,15 @@ interface to your application. Some of the best features include:
9
9
  * Easily created headers and footers for your report
10
10
  * Output suppression that makes it easy for your script to support a _quiet_ flag
11
11
 
12
+ The latest release also supports colors allowing you to distinguish data in new ways including bold
13
+ if your terminal supports it.
14
+
12
15
  ### Installation
13
16
 
14
- It is up on rubygems.org so add it to your bundle
17
+ It is up on rubygems.org so add it to your bundle in the Gemfile
15
18
 
16
19
  ```bash
17
- gem 'command_line_reporter', '>=2.1'
20
+ gem 'command_line_reporter', '>=3.0'
18
21
  ```
19
22
 
20
23
  or do it the old fashioned way:
@@ -55,6 +58,8 @@ There are several methods the mixin provides that do not depend on the formatter
55
58
  Either true|false. _Default: false_
56
59
  * _:rule_ - true|false indicates whether to include a horizontal rule below|above the
57
60
  header|footer. _Default: false_
61
+ * _:color_ - The color to use for the terminal output i.e. 'red' or 'blue' or 'green'
62
+ * _:bold_ - true|false to boldface the font
58
63
  * _report(hash) {block}_
59
64
  * The first argument is a hash that defines the options for the method. See the details in the
60
65
  formatter section for allowed values.
@@ -69,34 +74,51 @@ There are several methods the mixin provides that do not depend on the formatter
69
74
  * _horizontal_rule(hash)_
70
75
  * _:char_ - The character used to build the rule. _Default: '-'_
71
76
  * _:width_ - The width in characters of the rule. _Default: 100_
77
+ * _:color_ - The color to use for the terminal output i.e. 'red' or 'blue' or 'green'
78
+ * _:bold_ - true|false to boldface the font
72
79
  * _vertical_spacing(int)_
73
80
  * Number of blank lines to output. _Default: 1_
74
81
  * _datetime(hash)_
75
82
  * _:align_ - 'left'|'center'|'right' alignment of the timestamp. _Default: 'left'_
76
83
  * _:width_ - The width of the string in characters. _Default: 100_
77
84
  * _:format_ - Any allowed format from #strftime#. _Default: %Y-%m-%d %H:%I:%S%p_
85
+ * _:color_ - The color to use for the terminal output i.e. 'red' or 'blue' or 'green'
86
+ * _:bold_ - true|false to boldface the font
78
87
  * _aligned(string, hash)_
79
88
  * _text_ - String to display
80
89
  * _:align_ - 'left'|'right'|'center' align the string text. _Default: 'left'_
81
90
  * _:width_ - The width in characters of the string text. _Default: 100_
91
+ * _:color_ - The color to use for the terminal output i.e. 'red' or 'blue' or 'green'
92
+ * _:bold_ - true|false to boldface the font
82
93
  * _table(hash) {block}_
83
94
  * The first argument is a hash that defines properties of the table.
84
95
  * _:border_ - true|false indicates whether to include borders around the table cells
85
96
  * The second argument is a block which includes calls the to the _row_ method
86
97
  * _row {block}_
87
- * Only argument is a block with calls to _column_ allowed
98
+ * _:header_ - Set to true to indicate if this is a header row in the table.
99
+ * _:color_ - The color to use for the terminal output i.e. 'red' or 'blue' or 'green'
100
+ * _:bold_ - true|false to boldface the font
88
101
  * _column(string, hash)_
89
102
  * _text_ - String to display in the table cell
90
103
  * _options_ - The options to define the column
91
104
  * :width - defines the width of the column
92
105
  * :padding - The number of spaces to put on both the left and right of the text.
93
106
  * :align - Allowed values are left|right|center
107
+ * :color - The color to use for the terminal output i.e. 'red' or 'blue' or 'green'
108
+ * :bold - true|false to boldface the font
94
109
 
95
110
  ### To Do
96
111
 
97
- * Add the ability for a column to span across others
98
- * Add the progress method to the top level mixin so that there is no need to invoke through the
99
- formatter.
112
+ * Refactor the table structure to use a formatter that produces the current ascii output
113
+ * After the formatter is added to a table then create one for html output
114
+ * Add the ability for a column to span across others in a table
115
+
116
+ ### Contributors
117
+
118
+ * Thanks to [Mike Gunderloy](https://github.com/ffmike) for suggesting the need for suppressing
119
+ output and putting together a fantastic pull request and discussion
120
+ * Thanks to [Jason Rogers](https://github.com/jacaetevha) and [Peter
121
+ Suschlik](https://github.com/splattael) for their contributions as well on items I missed
100
122
 
101
123
  ### License
102
124
 
data/examples/nested.rb CHANGED
@@ -30,8 +30,8 @@ class Example
30
30
  end
31
31
  end
32
32
 
33
- puts '-' * 20
34
- %w(x y z).each {|v| puts "#{v}: #{eval v}"}
33
+ horizontal_rule(:width => 20)
34
+ %w(x y z).each {|v| aligned "#{v}: #{eval v}"}
35
35
  end
36
36
  end
37
37
 
data/examples/progress.rb CHANGED
@@ -16,12 +16,14 @@ class Example
16
16
  10.times do
17
17
  x += 1
18
18
  sleep 0.1
19
- formatter.progress
19
+ # formatter.progress
20
+ progress
20
21
 
21
22
  10.times do
22
23
  x += 1
23
24
  sleep 0.1
24
- formatter.progress
25
+ # formatter.progress
26
+ progress
25
27
  end
26
28
  end
27
29
  end
@@ -32,24 +34,24 @@ class Example
32
34
  10.times do
33
35
  y += 1
34
36
  sleep 0.1
35
- formatter.progress("#{y*10}%")
37
+ progress("#{y*10}%")
36
38
  end
37
39
  end
38
40
 
39
41
  report do
40
42
  3.times do
41
- formatter.progress("\\")
43
+ progress("\\")
42
44
  sleep 0.1
43
- formatter.progress("/")
45
+ progress("/")
44
46
  sleep 0.1
45
- formatter.progress("-")
47
+ progress("-")
46
48
  sleep 0.1
47
49
  end
48
50
  end
49
51
 
50
- report do
52
+ report(:color => 'red') do
51
53
  100.times do
52
- self.formatter.progress(erase_chars + NYAN_CHARS)
54
+ progress(erase_chars + NYAN_CHARS)
53
55
  sleep 0.1
54
56
  end
55
57
  end
data/examples/quiet.rb CHANGED
@@ -18,7 +18,7 @@ class Example
18
18
  10.times do
19
19
  x += 1
20
20
  sleep 0.1
21
- formatter.progress
21
+ progress
22
22
  end
23
23
  end
24
24
 
data/examples/simple.rb CHANGED
@@ -12,8 +12,9 @@ class Example
12
12
  sum = 0
13
13
  10.times do
14
14
  sum += 10
15
- self.formatter.progress
15
+ progress
16
16
  end
17
+ vertical_spacing
17
18
  aligned("Sum: #{sum}")
18
19
  end
19
20
  end
data/examples/table.rb CHANGED
@@ -1,3 +1,4 @@
1
+ # recoil <co>mmand_<li>ne_<re>porter
1
2
  require 'command_line_reporter'
2
3
 
3
4
  class Example
@@ -7,40 +8,61 @@ class Example
7
8
  header(:title => 'TABLE EXAMPLES - Borders, Wrapping, Alignment and Padding', :align => 'center', :width => 70)
8
9
 
9
10
  2.times do |j|
10
- header(:title => "Table #{j}", :align => 'center', :width => 65)
11
+ header :title => "Table #{j}", :align => 'center', :width => 65
11
12
 
12
- table(:border => j % 2 == 0) do
13
+ table :border => j % 2 == 0 do
13
14
  3.times do
14
15
  row do
15
16
  i = 0
16
17
  3.times do
17
18
  i += 10
18
- column('x' * (0 + rand(50)), :align => %w[left right center][rand(3)], :width => i, :padding => rand(5))
19
+ column 'x' * (0 + rand(50)), :align => %w[left right center][rand(3)], :width => i, :padding => rand(5)
19
20
  end
20
21
  end
21
22
  end
22
23
  end
23
24
 
24
- vertical_spacing(2)
25
+ vertical_spacing 2
25
26
  end
26
27
 
27
- header(:title => 'A simple example of how column properties are inherited from the first row')
28
+ header :title => 'An example of a table with a header row. The color and border properties are not inherited'
28
29
 
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)
30
+ table :border => true do
31
+ row :header => true, :color => 'red' do
32
+ column 'MY NAME IS REALLY LONG AND WILL WRAP AND HOPE', :width => 20, :align => 'center', :color => 'blue'
33
+ column 'ADDRESS', :width => 30, :padding => 5
34
+ column 'CITY', :width => 15
35
+ end
36
+ row :color => 'green', :bold => true do
37
+ column 'Ceaser'
38
+ column '1 Appian Way'
39
+ column 'Rome'
34
40
  end
35
41
  row do
36
- column('Ceaser')
37
- column('1 Appian Way')
38
- column('Rome')
42
+ column 'Richard Feynman'
43
+ column '1 Golden Gate'
44
+ column 'Quantum Field'
45
+ end
46
+ end
47
+
48
+ vertical_spacing 2
49
+ header :title => 'The same table with the properties inherited from the first row'
50
+
51
+ table :border => true do
52
+ row :color => 'red' do
53
+ column 'MY NAME IS REALLY LONG AND WILL WRAP AND HOPE', :width => 20, :align => 'center', :color => 'blue'
54
+ column 'ADDRESS', :width => 30, :padding => 5
55
+ column 'CITY', :width => 15
56
+ end
57
+ row :color => 'green', :bold => true do
58
+ column 'Ceaser'
59
+ column '1 Appian Way'
60
+ column 'Rome'
39
61
  end
40
62
  row do
41
- column('Richard Feynman')
42
- column('1 Golden Gate')
43
- column('Quantum Field')
63
+ column 'Richard Feynman'
64
+ column '1 Golden Gate'
65
+ column 'Quantum Field'
44
66
  end
45
67
  end
46
68
  end
data/lib/column.rb CHANGED
@@ -1,50 +1,67 @@
1
1
  require 'options_validator'
2
+ require 'colored'
2
3
 
3
- class Column
4
- include OptionsValidator
4
+ module CommandLineReporter
5
+ class Column
6
+ include OptionsValidator
5
7
 
6
- VALID_OPTIONS = [:width, :padding, :align]
7
- attr_accessor :text, :size, *VALID_OPTIONS
8
+ VALID_OPTIONS = [:width, :padding, :align, :color, :bold, :underline, :reversed]
9
+ attr_accessor :text, :size, *VALID_OPTIONS
8
10
 
9
- def initialize(text = nil, options = {})
10
- self.validate_options(options, *VALID_OPTIONS)
11
+ def initialize(text = nil, options = {})
12
+ self.validate_options(options, *VALID_OPTIONS)
11
13
 
12
- self.text = text
14
+ self.text = text
13
15
 
14
- self.width = options[:width] || 10
15
- self.align = options[:align] || 'left'
16
- self.padding = options[:padding] || 0
16
+ self.width = options[:width] || 10
17
+ self.align = options[:align] || 'left'
18
+ self.padding = options[:padding] || 0
19
+ self.color = options[:color] || nil
20
+ self.bold = options[:bold] || false
21
+ self.underline = options[:underline] || false
22
+ self.reversed = options[:reversed] || false
17
23
 
18
- raise ArgumentError unless self.width > 0
19
- raise ArgumentError unless self.padding.to_s.match(/^\d+$/)
24
+ raise ArgumentError unless self.width > 0
25
+ raise ArgumentError unless self.padding.to_s.match(/^\d+$/)
20
26
 
21
- self.size = self.width - 2 * self.padding
22
- end
27
+ self.size = self.width - 2 * self.padding
28
+ end
23
29
 
24
- def screen_rows
25
- if self.text.nil? || self.text.empty?
26
- [' ' * self.width]
27
- else
28
- self.text.scan(/.{1,#{self.size}}/m).map {|s| to_cell(s)}
30
+ def screen_rows
31
+ if self.text.nil? || self.text.empty?
32
+ [' ' * self.width]
33
+ else
34
+ self.text.scan(/.{1,#{self.size}}/m).map {|s| to_cell(s)}
35
+ end
29
36
  end
30
- end
31
37
 
32
- private
33
-
34
- def to_cell(str)
35
- cell = if str.empty?
36
- ' ' * self.size
37
- else
38
- case self.align
39
- when 'left'
40
- str.ljust(self.size)
41
- when 'right'
42
- str.rjust(self.size)
43
- when 'center'
44
- str.ljust((self.size - str.size)/2.0 + str.size).rjust(self.size)
38
+ private
39
+
40
+ def to_cell(str)
41
+ # NOTE: For making underline and reversed work Change so that based on the
42
+ # unformatted text it determines how much spacing to add left and right
43
+ # then colorize the cell text
44
+ cell = if str.empty?
45
+ ' ' * self.size
46
+ else
47
+ case self.align
48
+ when 'left'
49
+ str.ljust(self.size)
50
+ when 'right'
51
+ str.rjust(self.size)
52
+ when 'center'
53
+ str.ljust((self.size - str.size)/2.0 + str.size).rjust(self.size)
54
+ end
45
55
  end
46
- end
47
56
 
48
- ' ' * self.padding + cell + ' ' * self.padding
57
+ padding_str = ' ' * self.padding
58
+ padding_str + colorize(cell) + padding_str
59
+ end
60
+
61
+ def colorize(str)
62
+ str = str.send(color) if self.color
63
+ str = str.send('bold') if self.bold
64
+ str
65
+ end
49
66
  end
50
67
  end
@@ -11,6 +11,7 @@ module CommandLineReporter
11
11
  DEFAULTS = {
12
12
  :width => 100,
13
13
  :align => 'left',
14
+ :formatter => 'nested',
14
15
  }
15
16
 
16
17
  def suppress_output
@@ -36,21 +37,25 @@ module CommandLineReporter
36
37
  end
37
38
 
38
39
  def report(options = {}, &block)
39
- self.formatter ||= 'nested'
40
+ self.formatter ||= DEFAULTS[:formatter]
40
41
  self.formatter.format(options, block)
41
42
  end
42
43
 
44
+ def progress(override = nil)
45
+ self.formatter.progress(override)
46
+ end
47
+
43
48
  def footer(options = {})
44
49
  section(:footer, options)
45
50
  end
46
51
 
47
52
  def horizontal_rule(options = {})
48
- validate_options(options, :char, :width)
53
+ validate_options(options, :char, :width, :color, :bold)
49
54
 
50
55
  char = options[:char].is_a?(String) ? options[:char] : '-'
51
56
  width = options[:width] || DEFAULTS[:width]
52
57
 
53
- puts char * width
58
+ aligned(char * width, :width => width, :color => options[:color], :bold => options[:bold])
54
59
  end
55
60
 
56
61
  def vertical_spacing(lines = 1)
@@ -60,7 +65,7 @@ module CommandLineReporter
60
65
  end
61
66
 
62
67
  def datetime(options = {})
63
- validate_options(options, :align, :width, :format)
68
+ validate_options(options, :align, :width, :format, :color, :bold)
64
69
 
65
70
  format = options[:format] || '%Y-%m-%d - %l:%M:%S%p'
66
71
  align = options[:align] || DEFAULTS[:align]
@@ -70,67 +75,76 @@ module CommandLineReporter
70
75
 
71
76
  raise Exception if text.size > width
72
77
 
73
- aligned(text, {:align => align, :width => width})
78
+ aligned(text, :align => align, :width => width, :color => options[:color], :bold => options[:bold])
74
79
  end
75
80
 
76
81
  def aligned(text, options = {})
77
- validate_options(options, :align, :width)
82
+ validate_options(options, :align, :width, :color, :bold)
78
83
 
79
84
  align = options[:align] || DEFAULTS[:align]
80
85
  width = options[:width] || DEFAULTS[:width]
81
-
82
- case align
83
- when 'left'
84
- puts text
85
- when 'right'
86
- puts text.rjust(width)
87
- when 'center'
88
- puts text.rjust((width - text.size)/2 + text.size)
89
- else
90
- raise ArgumentError
91
- end
86
+ color = options[:color]
87
+ bold = options[:bold] || false
88
+
89
+ line = case align
90
+ when 'left'
91
+ text
92
+ when 'right'
93
+ text.rjust(width)
94
+ when 'center'
95
+ text.rjust((width - text.size)/2 + text.size)
96
+ else
97
+ raise ArgumentError
98
+ end
99
+
100
+ line = line.send(color) if color
101
+ line = line.send('bold') if bold
102
+
103
+ puts line
92
104
  end
93
105
 
94
106
  def table(options = {})
95
- @table = Table.new(options)
107
+ @table = CommandLineReporter::Table.new(options)
96
108
  yield
97
109
  @table.output
98
110
  end
99
111
 
100
112
  def row(options = {})
101
- @row = Row.new
113
+ @row = CommandLineReporter::Row.new(options)
102
114
  yield
103
115
  @table.add(@row)
104
116
  end
105
117
 
106
118
  def column(text, options = {})
107
- col = Column.new(text, options)
119
+ col = CommandLineReporter::Column.new(text, options)
108
120
  @row.add(col)
109
121
  end
110
122
 
111
123
  private
112
124
 
113
125
  def section(type, options)
114
- validate_options(options, :title, :width, :align, :spacing, :timestamp, :rule)
126
+ validate_options(options, :title, :width, :align, :spacing, :timestamp, :rule, :color, :bold)
115
127
 
116
128
  title = options[:title] || 'Report'
117
129
  width = options[:width] || DEFAULTS[:width]
118
130
  align = options[:align] || DEFAULTS[:align]
119
131
  lines = options[:spacing] || 1
132
+ color = options[:color]
133
+ bold = options[:bold] || false
120
134
 
121
135
  # This also ensures that width is a Fixnum
122
136
  raise ArgumentError if title.size > width
123
137
 
124
138
  if type == :footer
125
139
  vertical_spacing(lines)
126
- horizontal_rule(:char => options[:rule], :width => width) if options[:rule]
140
+ horizontal_rule(:char => options[:rule], :width => width, :color => color, :bold => bold) if options[:rule]
127
141
  end
128
142
 
129
- aligned(title, {:align => align, :width => width})
130
- datetime(:align => align, :width => width) if options[:timestamp]
143
+ aligned(title, :align => align, :width => width, :color => color, :bold => bold)
144
+ datetime(:align => align, :width => width, :color => color, :bold => bold) if options[:timestamp]
131
145
 
132
146
  if type == :header
133
- horizontal_rule(:char => options[:rule], :width => width) if options[:rule]
147
+ horizontal_rule(:char => options[:rule], :width => width, :color => color, :bold => bold) if options[:rule]
134
148
  vertical_spacing(lines)
135
149
  end
136
150
  end
@@ -1,13 +1,17 @@
1
1
  require 'singleton'
2
+ require 'options_validator'
3
+ require 'colored'
2
4
 
3
5
  module CommandLineReporter
4
6
  class NestedFormatter
5
7
  include Singleton
8
+ include OptionsValidator
6
9
 
7
- attr_accessor :indent_size, :complete_string, :message_string
10
+ VALID_OPTIONS = [:message, :type, :complete, :indent_size, :color, :bold]
11
+ attr_accessor :indent_size, :complete_string, :message_string, :color, :bold
8
12
 
9
13
  def format(options, block)
10
- raise ArgumentError unless (options.keys - [:message, :type, :complete, :indent_size]).empty?
14
+ self.validate_options(options, *VALID_OPTIONS)
11
15
 
12
16
  indent_level :incr
13
17
 
@@ -17,15 +21,15 @@ module CommandLineReporter
17
21
  complete_str = options[:complete] || self.complete_string
18
22
 
19
23
  if options[:type] == 'inline'
20
- print "#{message_str}..."
24
+ colorize("#{message_str}...", true, options)
21
25
  else
22
- puts message_str
26
+ colorize(message_str, false, options)
23
27
  complete_str = padding + complete_str
24
28
  end
25
29
 
26
30
  block.call
27
31
 
28
- puts complete_str
32
+ colorize(complete_str, false, options)
29
33
 
30
34
  indent_level :decr
31
35
  end
@@ -44,6 +48,17 @@ module CommandLineReporter
44
48
 
45
49
  private
46
50
 
51
+ def colorize(str, inline, options)
52
+ str = str.send(options[:color]) if options[:color]
53
+ str = str.bold if options[:bold]
54
+
55
+ if inline
56
+ print str
57
+ else
58
+ puts str
59
+ end
60
+ end
61
+
47
62
  def indent_level(value)
48
63
  case value
49
64
  when :incr
@@ -1,19 +1,34 @@
1
1
  require 'singleton'
2
+ require 'options_validator'
3
+ require 'colored'
2
4
 
3
5
  module CommandLineReporter
4
6
  class ProgressFormatter
5
7
  include Singleton
8
+ include OptionsValidator
6
9
 
7
- attr_accessor :indicator
10
+ VALID_OPTIONS = [:indicator, :color, :bold]
11
+ attr_accessor *VALID_OPTIONS
8
12
 
9
13
  def format(options, block)
14
+ self.validate_options(options, *VALID_OPTIONS)
15
+
10
16
  self.indicator = options[:indicator] if options[:indicator]
17
+ self.color = options[:color]
18
+ self.bold = options[:bold] || false
19
+
11
20
  block.call
21
+
12
22
  puts
13
23
  end
14
24
 
15
25
  def progress(override = nil)
16
- print override || self.indicator
26
+ str = override || self.indicator
27
+
28
+ str = str.send(self.color) if self.color
29
+ str = str.send('bold') if self.bold
30
+
31
+ print str
17
32
  end
18
33
 
19
34
  def indicator