command_line_reporter 2.1 → 3.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/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