bovem 0.6.0 → 0.8.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.
@@ -0,0 +1 @@
1
+ --exclude lib/devdnsd/patches/.+ --exclude utils/ -m markdown
@@ -1,16 +1,15 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- bovem (0.6.0)
4
+ bovem (0.8.0)
5
5
  lazier (~> 1.0)
6
- rainbow (~> 1.1.0)
7
6
 
8
7
  GEM
9
8
  remote: http://rubygems.org/
10
9
  specs:
11
- actionpack (3.2.7)
12
- activemodel (= 3.2.7)
13
- activesupport (= 3.2.7)
10
+ actionpack (3.2.8)
11
+ activemodel (= 3.2.8)
12
+ activesupport (= 3.2.8)
14
13
  builder (~> 3.0.0)
15
14
  erubis (~> 2.7.0)
16
15
  journey (~> 1.0.4)
@@ -18,22 +17,22 @@ GEM
18
17
  rack-cache (~> 1.2)
19
18
  rack-test (~> 0.6.1)
20
19
  sprockets (~> 2.1.3)
21
- activemodel (3.2.7)
22
- activesupport (= 3.2.7)
20
+ activemodel (3.2.8)
21
+ activesupport (= 3.2.8)
23
22
  builder (~> 3.0.0)
24
- activesupport (3.2.7)
23
+ activesupport (3.2.8)
25
24
  i18n (~> 0.6)
26
25
  multi_json (~> 1.0)
27
26
  builder (3.0.0)
28
27
  coderay (1.0.7)
29
28
  diff-lcs (1.1.3)
30
29
  erubis (2.7.0)
31
- github-markup (0.7.2)
30
+ github-markup (0.7.4)
32
31
  hike (1.2.1)
33
32
  i18n (0.6.0)
34
33
  journey (1.0.4)
35
34
  json (1.7.4)
36
- lazier (1.0.1)
35
+ lazier (1.0.2)
37
36
  actionpack (~> 3.0)
38
37
  json (~> 1.7.0)
39
38
  tzinfo (~> 0.3.0)
@@ -48,17 +47,16 @@ GEM
48
47
  rack (>= 0.4)
49
48
  rack-test (0.6.1)
50
49
  rack (>= 1.0)
51
- rainbow (1.1.4)
52
50
  rake (0.9.2.2)
53
51
  redcarpet (2.1.1)
54
52
  rspec (2.11.0)
55
53
  rspec-core (~> 2.11.0)
56
54
  rspec-expectations (~> 2.11.0)
57
55
  rspec-mocks (~> 2.11.0)
58
- rspec-core (2.11.0)
59
- rspec-expectations (2.11.1)
56
+ rspec-core (2.11.1)
57
+ rspec-expectations (2.11.2)
60
58
  diff-lcs (~> 1.1.3)
61
- rspec-mocks (2.11.1)
59
+ rspec-mocks (2.11.2)
62
60
  simplecov (0.6.4)
63
61
  multi_json (~> 1.0)
64
62
  simplecov-html (~> 0.5.3)
@@ -22,7 +22,6 @@ Gem::Specification.new do |gem|
22
22
  gem.require_paths = ["lib"]
23
23
 
24
24
  gem.add_dependency("lazier", "~> 1.0")
25
- gem.add_dependency("rainbow", "~> 1.1.0")
26
25
 
27
26
  gem.add_development_dependency("rspec", "~> 2.11.0")
28
27
  gem.add_development_dependency("rake", "~> 0.9.0")
@@ -4,7 +4,6 @@
4
4
  # Licensed under the MIT license, which can be found at http://www.opensource.org/licenses/mit-license.php.
5
5
  #
6
6
 
7
- require "rainbow"
8
7
  require "logger"
9
8
  require "lazier"
10
9
 
@@ -13,4 +12,5 @@ Lazier.load!(:object)
13
12
  require "bovem/version" if !defined?(Bovem::Version)
14
13
  require "bovem/errors"
15
14
  require "bovem/configuration"
16
- require "bovem/logger"
15
+ require "bovem/logger"
16
+ require "bovem/console"
@@ -0,0 +1,527 @@
1
+ # encoding: utf-8
2
+ #
3
+ # This file is part of the bovem gem. Copyright (C) 2012 and above Shogun <shogun_panda@me.com>.
4
+ # Licensed under the MIT license, which can be found at http://www.opensource.org/licenses/mit-license.php.
5
+ #
6
+
7
+ module Bovem
8
+ # List of valid terminal colors.
9
+ TERM_COLORS = {
10
+ :black => 0,
11
+ :red => 1,
12
+ :green => 2,
13
+ :yellow => 3,
14
+ :blue => 4,
15
+ :magenta => 5,
16
+ :cyan => 6,
17
+ :white => 7,
18
+ :default => 9,
19
+ }
20
+
21
+ # List of valid terminal text effects.
22
+ TERM_EFFECTS = {
23
+ :reset => 0,
24
+ :bright => 1,
25
+ :italic => 3,
26
+ :underline => 4,
27
+ :blink => 5,
28
+ :inverse => 7,
29
+ :hide => 8,
30
+ }
31
+
32
+ # This is a text utility wrapper console I/O.
33
+ class Console
34
+ # The line width. Default to `80`.
35
+ attr_accessor :line_width
36
+
37
+ # The current screen width.
38
+ attr_accessor :screen_width
39
+
40
+ # Current indentation width.
41
+ attr_accessor :indentation
42
+
43
+ # The string used for indentation.
44
+ attr_accessor :indentation_string
45
+
46
+ # Whether to show executed commands.
47
+ # attr_accessor :show_commands
48
+
49
+ # Whether to show output of executed commands.
50
+ # attr_accessor :show_outputs
51
+
52
+ # Whether to simply print commands rather than executing them.
53
+ # attr_accessor :skip_commands
54
+
55
+ # Returns a unique instance for Console.
56
+ #
57
+ # @return [Console] A new instance.
58
+ def self.instance
59
+ @instance ||= ::Bovem::Console.new
60
+ end
61
+
62
+ # Parse a style and returns terminal codes.
63
+ #
64
+ # Supported styles and colors are those in {Bovem::TERM_COLORS} and {Bovem::TERM_EFFECTS}. You can also prefix colors with `bg_` (like `bg_red`) for background colors.
65
+ #
66
+ # @param style [String] The style to parse.
67
+ # @return [String] A string with ANSI color codes.
68
+ def self.parse_style(style)
69
+ style = style.ensure_string
70
+ sym = style.to_sym
71
+ rv = ""
72
+
73
+ if ::Bovem::TERM_EFFECTS.include?(sym) then
74
+ rv = "\e[#{Bovem::TERM_EFFECTS[sym]}m"
75
+ elsif style.index("bg_") == 0 then
76
+ sym = style[3, style.length].to_sym
77
+ rv = "\e[#{40 + ::Bovem::TERM_COLORS[sym]}m" if ::Bovem::TERM_COLORS.include?(sym)
78
+ elsif style != "reset" then
79
+ rv = "\e[#{30 + ::Bovem::TERM_COLORS[sym]}m" if ::Bovem::TERM_COLORS.include?(sym)
80
+ end
81
+
82
+ rv
83
+ end
84
+
85
+ # Replaces colors markers in a string.
86
+ #
87
+ # @param message [String] The message to analyze.
88
+ # @param plain [Boolean] If ignore (cleanify) color markers into the message.
89
+ # @return [String] The replaced message.
90
+ # @see #parse_style
91
+ def self.replace_markers(message, plain = false)
92
+ stack = []
93
+
94
+ regexp = /((\{mark=([a-z\-_]+)\})|(\{\/mark\}))/mi
95
+
96
+ message = message.gsub(regexp) do
97
+ tag = $1
98
+ styles = $3
99
+ replacement = ""
100
+
101
+ if tag == "{/mark}" then # If it is a tag, pop from the latest opened.
102
+ stack.pop
103
+ styles = stack.last
104
+ replacement = plain || stack.blank? ? "" : styles.split("-").collect { |s| self.parse_style(s) }.join("")
105
+ else
106
+ replacement = plain ? "" : styles.split("-").collect { |s| self.parse_style(s) }.join("")
107
+
108
+ if replacement.length > 0 then
109
+ stack << "reset" if stack.blank?
110
+ stack << styles
111
+ end
112
+ end
113
+
114
+ replacement
115
+ end
116
+
117
+ message
118
+ end
119
+
120
+ # Executes a command and returns its output.
121
+ #
122
+ # @param command [String] The command to execute.
123
+ # @return [String] The command's output.
124
+ def self.execute(command)
125
+ %x{#{command}}
126
+ end
127
+
128
+ # Initializes a new Console.
129
+ def initialize
130
+ @line_width = 80
131
+ @indentation = 0
132
+ @indentation_string = " "
133
+ end
134
+
135
+ # Gets the current screen width.
136
+ #
137
+ # @return [Fixnum] The screen width.
138
+ def get_screen_width
139
+ ::Bovem::Console.execute("tput cols").to_integer
140
+ end
141
+
142
+ # Sets the new indentation width.
143
+ #
144
+ # @param width [Fixnum] The new width.
145
+ # @param is_absolute [Boolean] If the new width should not be added to the current one but rather replace it.
146
+ # @return [Fixnum] The new indentation width.
147
+ def set_indentation(width, is_absolute = false)
148
+ self.indentation = [(!is_absolute ? self.indentation : 0) + width, 0].max.to_i
149
+ self.indentation
150
+ end
151
+
152
+ # Resets indentation width to `0`.
153
+ #
154
+ # @return [Fixnum] The new indentation width.
155
+ def reset_indentation
156
+ self.indentation = 0
157
+ self.indentation
158
+ end
159
+
160
+ # Starts a indented region of text.
161
+ #
162
+ # @param width [Fixnum] The new width.
163
+ # @param is_absolute [Boolean] If the new width should not be added to the current one but rather replace it.
164
+ # @return [Fixnum] The new indentation width.
165
+ def with_indentation(width, is_absolute = false)
166
+ old = self.indentation
167
+ self.set_indentation(width, is_absolute)
168
+ yield
169
+ self.set_indentation(old, true)
170
+
171
+ self.indentation
172
+ end
173
+
174
+ # Wraps a message in fixed line width.
175
+ #
176
+ # @param message [String] The message to wrap.
177
+ # @param width [Fixnum] The maximum width of a line. Default to the current line width.
178
+ # @return [String] The wrapped message.
179
+ def wrap(message, width = nil)
180
+ if width.to_integer <= 0 then
181
+ message
182
+ else
183
+ width = (width == true || width.to_integer < 0 ? @line_width : width.to_integer)
184
+
185
+ message.split("\n").collect { |line|
186
+ line.length > width ? line.gsub(/(.{1,#{width}})(\s+|$)/, "\\1\n").strip : line
187
+ }.join("\n")
188
+ end
189
+ end
190
+
191
+ # Indents a message.
192
+ #
193
+ # @param message [String] The message to indent.
194
+ # @param width [Fixnum] The indentation width. `true` means to use thecurrent indentation, a negative value of `-x` will indent of `x` absolute spaces. `nil` or `false` will skip indentation.
195
+ # @param newline_separator [String] The character used for newlines.
196
+ # @return [String] The indentend message.
197
+ def indent(message, width = true, newline_separator = "\n")
198
+ if width.to_integer != 0 then
199
+ width = (width == true ? 0 : width.to_integer)
200
+ width = width < 0 ? -width : @indentation + width
201
+
202
+ message = message.split(newline_separator).collect {|line|
203
+ (@indentation_string * width) + line
204
+ }.join(newline_separator)
205
+ end
206
+
207
+ message
208
+ end
209
+
210
+ # Replaces colors markers in a string.
211
+ #
212
+ # Supported styles and colors are those in {Bovem::TERM_COLORS} and {Bovem::TERM_EFFECTS}. You can also prefix colors with `bg_` (like `bg_red`) for background colors.
213
+ #
214
+ # @param message [String] The message to analyze.
215
+ # @param plain [Boolean] If ignore (cleanify )color markers into the message.
216
+ # @return [String] The replaced message.
217
+ def replace_markers(message, plain = false)
218
+ ::Bovem::Console.replace_markers(message, plain)
219
+ end
220
+
221
+ # Formats a message.
222
+ #
223
+ # You can style text by using `{color}` and `{reset}` syntax.
224
+ #
225
+ # @param message [String] The message to format.
226
+ # @param suffix [Object] If not `nil` or `false`, a suffix to add to the message. `true` means to add `\n`.
227
+ # @param indent [Object] If not `nil` or `false`, the width to use for indentation. `true` means to use thecurrent indentation, a negative value of `-x` will indent of `x` absolute spaces.
228
+ # @param wrap [Object] If not `nil` or `false`, the maximum length of a line. `true` means the current line width.
229
+ # @param plain [Boolean] If ignore color markers into the message.
230
+ # @return [String] The formatted message.
231
+ def format(message, suffix = "\n", indent = true, wrap = true, plain = false)
232
+ rv = message
233
+
234
+ rv = self.replace_markers(rv, plain) # Replace markers
235
+ rv = self.wrap(rv, wrap) # Wrap
236
+ rv = self.indent(rv, indent) # Indent
237
+
238
+ rv += suffix if suffix # Add the suffix
239
+ rv
240
+ end
241
+
242
+ # Formats a message to be written right-aligned.
243
+ #
244
+ # @param message [String] The message to format.
245
+ # @param width [Fixnum] The screen width. If `true`, it is automatically computed.
246
+ # @param go_up [Boolean] If go up one line before formatting.
247
+ # @param plain [Boolean] If ignore color markers into the message.
248
+ # @return [String] The formatted message.
249
+ def format_right(message, width = true, go_up = true, plain = false)
250
+ message = self.replace_markers(message, plain)
251
+
252
+ rv = go_up ? "\e[A" : ""
253
+
254
+ @screen_width ||= self.get_screen_width
255
+ width = (width == true || width.to_integer < 1 ? @screen_width : width.to_integer)
256
+
257
+ # Get padding
258
+ padding = width - message.to_s.gsub(/(\e\[[0-9]*[a-z]?)|(\\n)/i, "").length
259
+
260
+ # Return
261
+ rv + "\e[0G\e[#{padding}C" + message
262
+ end
263
+
264
+ # Writes a message.
265
+ #
266
+ # @param message [String] The message to format.
267
+ # @param suffix [Object] If not `nil` or `false`, a suffix to add to the message. `true` means to add `\n`.
268
+ # @param indent [Object] If not `nil` or `false`, the width to use for indentation. `true` means to use thecurrent indentation, a negative value of `-x` will indent of `x` absolute spaces.
269
+ # @param wrap [Object] If not `nil` or `false`, the maximum length of a line for wrapped text. `true` means the current line width.
270
+ # @param plain [Boolean] If ignore color markers into the message.
271
+ # @param print [Boolean] If `false`, the result will be returned instead of be printed.
272
+ # @return [String] The printed message.
273
+ #
274
+ # @see #format
275
+ def write(message, suffix = "\n", indent = true, wrap = false, plain = false, print = true)
276
+ rv = self.format(message, suffix, indent, wrap, plain)
277
+ Kernel.puts(rv) if print
278
+ rv
279
+ end
280
+
281
+ # Writes a status to the output. Valid values are `:ok`, `:pass`, `:fail`, `:warn`.
282
+ #
283
+ # @param status [Symbol] The status to write.
284
+ # @param plain [Boolean] If not use colors.
285
+ # @param go_up [Boolean] If go up one line before formatting.
286
+ # @param right [Boolean] If to print results on the right.
287
+ # @param print [Boolean] If `false`, the result will be returned instead of be printed.
288
+ # @return [Array] An dictionary with `:label` and `:color` keys for the status.
289
+ def status(status, plain = false, go_up = true, right = true, print = true)
290
+ statuses = {
291
+ :ok => {:label => " OK ", :color => "bright green"},
292
+ :pass => {:label => "PASS", :color => "bright cyan"},
293
+ :warn => {:label => "WARN", :color => "bright yellow"},
294
+ :fail => {:label => "FAIL", :color => "bright red"}
295
+ }
296
+ statuses.default = statuses[:pass]
297
+
298
+ rv = statuses[status]
299
+
300
+ if print then
301
+ banner = self.get_banner(rv[:label], rv[:color])
302
+
303
+ if right then
304
+ Kernel.puts self.format_right(banner + " ", true, go_up, plain)
305
+ else
306
+ Kernel.puts self.format(banner + " ", "\n", true, true, plain)
307
+ end
308
+ end
309
+
310
+ rv
311
+ end
312
+
313
+ # Gets a banner for the messages.
314
+ #
315
+ # @param label [String] The label for the banner.
316
+ # @param base_color [String] The color for the label.
317
+ # @param full_colored [String] If all the message should be of the label color.
318
+ # @param bracket_color [String] The color of the brackets.
319
+ # @param brackets [Array] An array of dimension 2 to use for brackets.
320
+ # @return [String] The banner.
321
+ # @see #format
322
+ def get_banner(label, base_color, full_colored = false, bracket_color = "blue", brackets = ["[", "]"])
323
+ brackets = brackets.ensure_array
324
+ bracket_color = base_color if full_colored
325
+ "{mark=%s}%s{mark=%s}%s{/mark}%s{/mark}" % [bracket_color.parameterize, brackets[0], base_color.parameterize, label, brackets[1]]
326
+ end
327
+
328
+ # Writes a message prepending a cyan type banner.
329
+ #
330
+ # @param message [String] The message to format.
331
+ # @param suffix [Object] If not `nil` or `false`, a suffix to add to the message. `true` means to add `\n`.
332
+ # @param indent [Object] If not `nil` or `false`, the width to use for indentation. `true` means to use thecurrent indentation, a negative value of `-x` will indent of `x` absolute spaces.
333
+ # @param wrap [Object] If not `nil` or `false`, the maximum length of a line for wrapped text. `true` means the current line width.
334
+ # @param plain [Boolean] If ignore color markers into the message.
335
+ # @param indented_banner [Boolean] If also the banner should be indented.
336
+ # @param full_colored [Boolean] If the banner should be fully colored.
337
+ # @param print [Boolean] If `false`, the result will be returned instead of be printed.
338
+ #
339
+ # @see #format
340
+ def info(message, suffix = "\n", indent = true, wrap = false, plain = false, indented_banner = false, full_colored = false, print = true)
341
+ banner = self.get_banner(" INFO", "bright cyan", full_colored)
342
+ message = self.indent(message, indented_banner ? 0 : indent)
343
+ self.write(banner + " " + message, suffix, indented_banner ? indent : 0, wrap, plain, print)
344
+ end
345
+
346
+ # Writes a message prepending a green type banner.
347
+ #
348
+ # @param message [String] The message to format.
349
+ # @param suffix [Object] If not `nil` or `false`, a suffix to add to the message. `true` means to add `\n`.
350
+ # @param indent [Object] If not `nil` or `false`, the width to use for indentation. `true` means to use thecurrent indentation, a negative value of `-x` will indent of `x` absolute spaces.
351
+ # @param wrap [Object] If not `nil` or `false`, the maximum length of a line for wrapped text. `true` means the current line width.
352
+ # @param plain [Boolean] If ignore color markers into the message.
353
+ # @param indented_banner [Boolean] If also the banner should be indented.
354
+ # @param full_colored [Boolean] If the banner should be fully colored.
355
+ # @param print [Boolean] If `false`, the result will be returned instead of be printed.
356
+ #
357
+ # @see #format
358
+ def begin(message, suffix = "\n", indent = true, wrap = false, plain = false, indented_banner = false, full_colored = false, print = true)
359
+ banner = " " + self.get_banner("*", "bright green")
360
+ message = self.indent(message, indented_banner ? 0 : indent)
361
+ self.write(banner + " " + message, suffix, indented_banner ? indent : 0, wrap, plain, print)
362
+ end
363
+
364
+ # Writes a message prepending a yellow type banner.
365
+ #
366
+ # @param message [String] The message to format.
367
+ # @param suffix [Object] If not `nil` or `false`, a suffix to add to the message. `true` means to add `\n`.
368
+ # @param indent [Object] If not `nil` or `false`, the width to use for indentation. `true` means to use thecurrent indentation, a negative value of `-x` will indent of `x` absolute spaces.
369
+ # @param wrap [Object] If not `nil` or `false`, the maximum length of a line for wrapped text. `true` means the current line width.
370
+ # @param plain [Boolean] If ignore color markers into the message.
371
+ # @param indented_banner [Boolean] If also the banner should be indented.
372
+ # @param full_colored [Boolean] If the banner should be fully colored.
373
+ # @param print [Boolean] If `false`, the result will be returned instead of be printed.
374
+ #
375
+ # @see #format
376
+ def warn(message, suffix = "\n", indent = true, wrap = false, plain = false, indented_banner = false, full_colored = false, print = true)
377
+ banner = self.get_banner(" WARN", "bright yellow", full_colored)
378
+ message = self.indent(message, indented_banner ? 0 : indent)
379
+ self.write(banner + " " + message, suffix, indented_banner ? indent : 0, wrap, plain, print)
380
+ end
381
+
382
+ # Writes a message prepending a red type banner.
383
+ #
384
+ # @param message [String] The message to format.
385
+ # @param suffix [Object] If not `nil` or `false`, a suffix to add to the message. `true` means to add `\n`.
386
+ # @param indent [Object] If not `nil` or `false`, the width to use for indentation. `true` means to use thecurrent indentation, a negative value of `-x` will indent of `x` absolute spaces.
387
+ # @param wrap [Object] If not `nil` or `false`, the maximum length of a line for wrapped text. `true` means the current line width.
388
+ # @param plain [Boolean] If ignore color markers into the message.
389
+ # @param indented_banner [Boolean] If also the banner should be indented.
390
+ # @param full_colored [Boolean] If the banner should be fully colored.
391
+ # @param print [Boolean] If `false`, the result will be returned instead of be printed.
392
+ #
393
+ # @see #format
394
+ def error(message, suffix = "\n", indent = true, wrap = false, plain = false, indented_banner = false, full_colored = false, print = true)
395
+ banner = self.get_banner("ERROR", "bright red", full_colored)
396
+ message = self.indent(message, indented_banner ? 0 : indent)
397
+ self.write(banner + " " + message, suffix, indented_banner ? indent : 0, wrap, plain, print)
398
+ end
399
+
400
+ # Writes a message prepending a red type banner and then quits the application.
401
+ #
402
+ # @param message [String] The message to format.
403
+ # @param suffix [Object] If not `nil` or `false`, a suffix to add to the message. `true` means to add `\n`.
404
+ # @param indent [Object] If not `nil` or `false`, the width to use for indentation. `true` means to use thecurrent indentation, a negative value of `-x` will indent of `x` absolute spaces.
405
+ # @param wrap [Object] If not `nil` or `false`, the maximum length of a line for wrapped text. `true` means the current line width.
406
+ # @param plain [Boolean] If ignore color markers into the message.
407
+ # @param indented_banner [Boolean] If also the banner should be indented.
408
+ # @param full_colored [Boolean] If the banner should be fully colored.
409
+ # @param return_code [Fixnum] The code to return to the shell.
410
+ # @param print [Boolean] If `false`, the result will be returned instead of be printed.
411
+ #
412
+ # @see #format
413
+ def fatal(message, suffix = "\n", indent = true, wrap = false, plain = false, indented_banner = false, full_colored = false, return_code = -1, print = true)
414
+ self.error(message, suffix, indent, wrap, plain, indented_banner, full_colored, print)
415
+ Kernel.abort(return_code)
416
+ end
417
+
418
+ # Writes a message prepending a magenta type banner.
419
+ #
420
+ # @param message [String] The message to format.
421
+ # @param suffix [Object] If not `nil` or `false`, a suffix to add to the message. `true` means to add `\n`.
422
+ # @param indent [Object] If not `nil` or `false`, the width to use for indentation. `true` means to use thecurrent indentation, a negative value of `-x` will indent of `x` absolute spaces.
423
+ # @param wrap [Object] If not `nil` or `false`, the maximum length of a line for wrapped text. `true` means the current line width.
424
+ # @param plain [Boolean] If ignore color markers into the message.
425
+ # @param indented_banner [Boolean] If also the banner should be indented.
426
+ # @param full_colored [Boolean] If the banner should be fully colored.
427
+ # @param print [Boolean] If `false`, the result will be returned instead of be printed.
428
+ #
429
+ # @see #format
430
+ def debug(message, suffix = "\n", indent = true, wrap = false, plain = false, indented_banner = false, full_colored = false, print = true)
431
+ banner = self.get_banner("DEBUG", "bright magenta", full_colored)
432
+ message = self.indent(message, indented_banner ? 0 : indent)
433
+ self.write(banner + " " + message, suffix, indented_banner ? indent : 0, wrap, plain, print)
434
+ end
435
+
436
+ # Reads a string from the console.
437
+ #
438
+ # @param prompt [String|Boolean] A prompt to show. If `true`, `Please insert a value:` will be used, if `nil` or `false` no prompt will be shown.
439
+ # @param default_value [String] Default value if user simply pressed the enter key.
440
+ # @param validator [Array|Regexp] An array of values or a Regexp to match the submitted value against.
441
+ # @param echo [Boolean] If to show submitted text to the user.
442
+ def read(prompt = true, default_value = nil, validator = nil, echo = true)
443
+ # TODO: Echo and print prompt without newline
444
+
445
+ # Write the prompt
446
+ prompt = "Please insert a value" if prompt == true
447
+ final_prompt = !prompt.nil? ? prompt.gsub(/:?\s*$/, "") + ": " : nil
448
+
449
+ # Adjust validator
450
+ validator = validator.ensure_array.collect {|v| v.ensure_string} if validator.present? && !validator.is_a?(::Regexp)
451
+
452
+ # Handle echo
453
+ stty = ::Bovem::Console.execute("which stty").strip
454
+ disable_echo = !echo && stty.present? && /-echo\b/mix.match(::Bovem::Console.execute(stty)).nil?
455
+
456
+ # Disable echo
457
+ ::Bovem::Console.execute("#{stty} -echo") if disable_echo
458
+
459
+ begin
460
+ catch(:reply) do
461
+ while true do
462
+ valid = true
463
+
464
+ if final_prompt then
465
+ Kernel.print self.format(final_prompt, false, false)
466
+ $stdout.flush
467
+ end
468
+
469
+ reply = Kernel.gets.chop
470
+ reply = default_value if reply.empty?
471
+
472
+ # Match against the validator
473
+ if validator.present? then
474
+ if validator.is_a?(Array) then
475
+ valid = false if validator.length > 0 && !validator.include?(reply)
476
+ elsif validator.is_a?(Regexp) then
477
+ valid = false if !validator.match(reply)
478
+ end
479
+ end
480
+
481
+ if !valid then
482
+ self.write("Sorry, your reply was not understood. Please try again.", false, false)
483
+ else
484
+ throw(:reply, reply)
485
+ end
486
+ end
487
+ end
488
+ rescue Interrupt
489
+ default_value
490
+ ensure
491
+ ::Bovem::Console.execute("#{stty} echo") if disable_echo
492
+ end
493
+ end
494
+
495
+ # Execute a block of code in a indentation region and then prints out and ending status message.
496
+ #
497
+ # @param message [String] The message to format.
498
+ # @param suffix [Object] If not `nil` or `false`, a suffix to add to the message. `true` means to add `\n`.
499
+ # @param indent [Object] If not `nil` or `false`, the width to use for indentation. `true` means to use thecurrent indentation, a negative value of `-x` will indent of `x` absolute spaces.
500
+ # @param wrap [Object] If not `nil` or `false`, the maximum length of a line for wrapped text. `true` means the current line width.
501
+ # @param plain [Boolean] If ignore color markers into the message.
502
+ # @param indented_banner [Boolean] If also the banner should be indented.
503
+ # @param full_colored [Boolean] If the banner should be fully colored.
504
+ # @param block_indentation [Fixnum] The new width for the indented region.
505
+ # @param block_indentation_absolute [Boolean] If the new width should not be added to the current one but rather replace it.
506
+ # @return [Symbol] The exit status for the block.
507
+ def task(message = nil, suffix = "\n", indent = true, wrap = false, plain = false, indented_banner = false, full_colored = false, block_indentation = 2, block_indentation_absolute = false)
508
+ status = nil
509
+
510
+ self.begin(message, suffix, indent, wrap, plain, indented_banner, full_colored) if message.present?
511
+
512
+ self.with_indentation(block_indentation, block_indentation_absolute) do
513
+ rv = block_given? ? yield.ensure_array : [:ok] # Execute block
514
+ status = rv[0] # Return value
515
+
516
+ if status == :fatal then
517
+ self.status(:fail, plain)
518
+ exit(rv.length > 1 ? rv[1].to_integer : -1)
519
+ else
520
+ self.status(status, plain)
521
+ end
522
+ end
523
+
524
+ status
525
+ end
526
+ end
527
+ end
@@ -75,8 +75,7 @@ module Bovem
75
75
  else :white
76
76
  end
77
77
 
78
- header = ("[%s T+%0.5f] %s:" %[datetime.strftime("%Y/%b/%d %H:%M:%S"), [datetime.to_f - self.start_time.to_f, 0].max, severity.rjust(5)]).bright
79
- header = header.color(color) if color.present?
78
+ header = ::Bovem::Console.replace_markers("{mark=bright-#{color}}[%s T+%0.5f] %s:{/mark}" %[datetime.strftime("%Y/%b/%d %H:%M:%S"), [datetime.to_f - self.start_time.to_f, 0].max, severity.rjust(5)])
80
79
  "%s %s\n" % [header, msg]
81
80
  }
82
81
  end
@@ -14,7 +14,7 @@ module Bovem
14
14
  MAJOR = 0
15
15
 
16
16
  # The minor version.
17
- MINOR = 6
17
+ MINOR = 8
18
18
 
19
19
  # The patch version.
20
20
  PATCH = 0
@@ -7,7 +7,7 @@
7
7
  require "spec_helper"
8
8
 
9
9
  describe Bovem::Configuration do
10
- class BaseConfiguration < Bovem::Configuration
10
+ class BaseConfiguration < ::Bovem::Configuration
11
11
  property :property
12
12
  end
13
13
 
@@ -27,8 +27,8 @@ describe Bovem::Configuration do
27
27
  file1 = ::File.open("#{test_prefix}-1", "w") {|f| f.write("config.property = ") }
28
28
  file2 = ::File.open("#{test_prefix}-2", "w") {|f| f.write("config.non_property = 1234") }
29
29
 
30
- expect { config = BaseConfiguration.new("#{test_prefix}-1")}.to raise_error(Bovem::Errors::InvalidConfiguration)
31
- expect { config = BaseConfiguration.new("#{test_prefix}-2")}.to raise_error(Bovem::Errors::InvalidConfiguration)
30
+ expect { config = BaseConfiguration.new("#{test_prefix}-1")}.to raise_error(::Bovem::Errors::InvalidConfiguration)
31
+ expect { config = BaseConfiguration.new("#{test_prefix}-2")}.to raise_error(::Bovem::Errors::InvalidConfiguration)
32
32
 
33
33
  File.unlink("#{test_prefix}-1")
34
34
  File.unlink("#{test_prefix}-2")
@@ -0,0 +1,419 @@
1
+ # encoding: utf-8
2
+ #
3
+ # This file is part of the bovem gem. Copyright (C) 2012 and above Shogun <shogun_panda@me.com>.
4
+ # Licensed under the MIT license, which can be found at http://www.opensource.org/licenses/mit-license.php.
5
+ #
6
+
7
+ require "spec_helper"
8
+
9
+ describe Bovem::Console do
10
+ let(:console) { ::Bovem::Console.new }
11
+
12
+ before(:each) do
13
+ Kernel.stub(:puts).and_return(nil)
14
+ end
15
+
16
+ describe ".instance" do
17
+ it "should always return the same instance" do
18
+ instance = ::Bovem::Console.instance
19
+ expect(::Bovem::Console.instance).to be(instance)
20
+ end
21
+ end
22
+
23
+ describe ".parse_style" do
24
+ it "should correctly parse styles" do
25
+ expect(::Bovem::Console.parse_style("red")).to eq("\e[31m")
26
+ expect(::Bovem::Console.parse_style("bg_green")).to eq("\e[42m")
27
+ expect(::Bovem::Console.parse_style("bright")).to eq("\e[1m")
28
+ expect(::Bovem::Console.parse_style("FOO")).to eq("")
29
+ expect(::Bovem::Console.parse_style(nil)).to eq("")
30
+ expect(::Bovem::Console.parse_style(["A"])).to eq("")
31
+ end
32
+ end
33
+
34
+ describe ".replace_markers" do
35
+ it "should correct replace markers" do
36
+ expect(::Bovem::Console.replace_markers("{mark=red}RED{/mark}")).to eq("\e[31mRED\e[0m")
37
+ expect(::Bovem::Console.replace_markers("{mark=red}RED {mark=green}GREEN{/mark}{/mark}")).to eq("\e[31mRED \e[32mGREEN\e[31m\e[0m")
38
+ expect(::Bovem::Console.replace_markers("{mark=red}RED {mark=bright-green}GREEN {mark=blue}BLUE{mark=NONE}RED{/mark}{/mark}{/mark}{/mark}")).to eq("\e[31mRED \e[1m\e[32mGREEN \e[34mBLUERED\e[1m\e[32m\e[31m\e[0m")
39
+ expect(::Bovem::Console.replace_markers("{mark=bg_red}RED{mark=reset}NORMAL{/mark}{/mark}")).to eq("\e[41mRED\e[0mNORMAL\e[41m\e[0m")
40
+ expect(::Bovem::Console.replace_markers("{mark=NONE}RED{/mark}")).to eq("RED")
41
+ end
42
+
43
+ it "should clean up markers if requested" do
44
+ expect(::Bovem::Console.replace_markers("{mark=red}RED{/mark}", true)).to eq("RED")
45
+ end
46
+ end
47
+
48
+ describe ".execute_command" do
49
+ it "should execute a command" do
50
+ expect(::Bovem::Console.execute("echo OK")).to eq("OK\n")
51
+ end
52
+ end
53
+
54
+ describe "#initialize" do
55
+ it "should correctly set defaults" do
56
+ expect(console.indentation).to eq(0)
57
+ expect(console.line_width).to eq(80)
58
+ expect(console.indentation_string).to eq(" ")
59
+ end
60
+ end
61
+
62
+ describe "#get_screen_width" do
63
+ it "should execute tput cols" do
64
+ ::Bovem::Console.should_receive("execute").with("tput cols")
65
+ console.get_screen_width
66
+ end
67
+
68
+ it "should return a number >= 0" do
69
+ expect(console.get_screen_width).to be >= 0
70
+ end
71
+ end
72
+
73
+ describe "#set_indentation" do
74
+ it "should correctly set indentation" do
75
+ expect(console.indentation).to eq(0)
76
+ console.set_indentation(5)
77
+ expect(console.indentation).to eq(5)
78
+ console.set_indentation(-2)
79
+ expect(console.indentation).to eq(3)
80
+ console.set_indentation(10, true)
81
+ expect(console.indentation).to eq(10)
82
+ end
83
+ end
84
+
85
+ describe "#reset_indentation" do
86
+ it "should correctly reset indentation" do
87
+ console.set_indentation(5)
88
+ expect(console.indentation).to eq(5)
89
+ console.reset_indentation
90
+ expect(console.indentation).to eq(0)
91
+ end
92
+ end
93
+
94
+ describe "#with_indentation" do
95
+ it "should correctly wrap indentation" do
96
+ console.set_indentation(5)
97
+ expect(console.indentation).to eq(5)
98
+
99
+ console.with_indentation(7) do
100
+ expect(console.indentation).to eq(12)
101
+ end
102
+ expect(console.indentation).to eq(5)
103
+
104
+ console.with_indentation(3, true) do
105
+ expect(console.indentation).to eq(3)
106
+ end
107
+ expect(console.indentation).to eq(5)
108
+ end
109
+ end
110
+
111
+ describe "#wrap" do
112
+ it "should correct wrap text" do
113
+ message = " ABC__DEF GHI JKL"
114
+ expect(console.wrap(message, 2)).to eq("ABC__DEF\nGHI\nJKL")
115
+ expect(console.wrap(message, 3)).to eq("ABC__DEF\nGHI\nJKL")
116
+ expect(console.wrap(message, 4)).to eq("ABC__DEF\nGHI\nJKL")
117
+ expect(console.wrap(message, 5)).to eq("ABC__DEF\nGHI\nJKL")
118
+ expect(console.wrap(message, 20)).to eq(" ABC__DEF GHI JKL")
119
+
120
+ expect(console.wrap(message, nil)).to eq(message)
121
+ expect(console.wrap(message, -1)).to eq(message)
122
+ end
123
+
124
+ it "should work well with #indent" do
125
+ message = "AB CD"
126
+ console.set_indentation(2)
127
+ expect(console.wrap(console.indent(message), 2)).to eq("AB\nCD")
128
+ end
129
+ end
130
+
131
+ describe "#indent" do
132
+ it "should correctly indent messages" do
133
+ message = "ABC\nCDE"
134
+ console.set_indentation(2)
135
+
136
+ expect(console.indent(message)).to eq(" ABC\n CDE")
137
+ expect(console.indent(message, -1)).to eq(" ABC\n CDE")
138
+ expect(console.indent(message, 1)).to eq(" ABC\n CDE")
139
+ expect(console.indent(message, true, "D")).to eq(" ABC\nCD E")
140
+
141
+ expect(console.indent(message, 0)).to eq(message)
142
+ expect(console.indent(message, nil)).to eq(message)
143
+ expect(console.indent(message, false)).to eq(message)
144
+ expect(console.indent(message, "A")).to eq(message)
145
+ end
146
+ end
147
+
148
+ describe "#format" do
149
+ it "should apply modifications to the message" do
150
+ message = "ABC"
151
+ console.set_indentation(2)
152
+ expect(console.format(message, "\n", false)).to eq("ABC\n")
153
+ expect(console.format(message, "A")).to eq(" ABCA")
154
+ expect(console.format(message, "A", 3)).to eq(" ABCA")
155
+ expect(console.format(message, "A", 3, 4)).to eq(" ABCA")
156
+ expect(console.format("{mark=red}ABC{/mark}", "\n", true, true, true)).to eq(" ABC\n")
157
+ end
158
+ end
159
+
160
+ describe "#replace_markers" do
161
+ it "should just forwards to .replace_markers" do
162
+ ::Bovem::Console.should_receive("replace_markers").with("A", "B")
163
+ console.replace_markers("A", "B")
164
+ end
165
+ end
166
+
167
+ describe "#format_right" do
168
+ it "should correctly align messages" do
169
+ message = "ABCDE"
170
+ extended_message = "ABC\e[AD\e[3mE"
171
+ console.screen_width = 80
172
+
173
+ expect(console.format_right(message)).to eq("\e[A\e[0G\e[#{75}CABCDE")
174
+ expect(console.format_right(message, 10)).to eq("\e[A\e[0G\e[#{5}CABCDE")
175
+ expect(console.format_right(extended_message)).to eq("\e[A\e[0G\e[#{75}CABC\e[AD\e[3mE")
176
+ expect(console.format_right(message, nil, false)).to eq("\e[0G\e[#{75}CABCDE")
177
+ console.screen_width = 10
178
+ expect(console.format_right(message)).to eq("\e[A\e[0G\e[#{5}CABCDE")
179
+ end
180
+ end
181
+
182
+ describe "#write" do
183
+ it "should call #format" do
184
+ console.should_receive("format").with("A", "B", "C", "D", "E")
185
+ console.write("A", "B", "C", "D", "E")
186
+ end
187
+ end
188
+
189
+ describe "#get_banner" do
190
+ it "should correctly format arguments" do
191
+ expect(console.get_banner("LABEL", "red")).to eq("{mark=blue}[{mark=red}LABEL{/mark}]{/mark}")
192
+ expect(console.get_banner("LABEL", "red", true)).to eq("{mark=red}[{mark=red}LABEL{/mark}]{/mark}")
193
+ expect(console.get_banner("LABEL", "red", false, "yellow")).to eq("{mark=yellow}[{mark=red}LABEL{/mark}]{/mark}")
194
+ expect(console.get_banner("LABEL", "red", false, "blue", nil)).to eq("{mark=blue}{mark=red}LABEL{/mark}{/mark}")
195
+ expect(console.get_banner("LABEL", "red", false, "blue", "A")).to eq("{mark=blue}A{mark=red}LABEL{/mark}{/mark}")
196
+ expect(console.get_banner("LABEL", "red", false, "blue", ["A", "B"])).to eq("{mark=blue}A{mark=red}LABEL{/mark}B{/mark}")
197
+ end
198
+ end
199
+
200
+ describe "#info" do
201
+ it "should forward everything to #get_banner" do
202
+ console.should_receive("get_banner").with(" INFO", "bright cyan", false).at_least(1).and_return("")
203
+ console.info("OK", "\n", true, false, false, false, false, false)
204
+ console.should_receive("get_banner").with(" INFO", "bright cyan", true).at_least(1).and_return("")
205
+ console.info("OK", "\n", true, false, false, false, true, false)
206
+ end
207
+
208
+ it "should forward everything to #write" do
209
+ console.should_receive("write").with(/.+/, "B", "C", "D", "E", false)
210
+ console.info("A", "B", "C", "D", "E", "F", "G", false)
211
+ end
212
+ end
213
+
214
+ describe "#begin" do
215
+ it "should forward everything to #get_banner" do
216
+ console.should_receive("get_banner").with("*", "bright green").at_least(1).and_return("")
217
+ console.begin("OK", "\n", true, false, false, false, false, false)
218
+ end
219
+
220
+ it "should forward everything to #write" do
221
+ console.should_receive("write").with(/.+/, "B", "C", "D", "E", false)
222
+ console.begin("A", "B", "C", "D", "E", "F", "G", false)
223
+ end
224
+ end
225
+
226
+ describe "#warn" do
227
+ it "should forward everything to #get_banner" do
228
+ console.should_receive("get_banner").with(" WARN", "bright yellow", false).at_least(1).and_return("")
229
+ console.warn("OK", "\n", true, false, false, false, false, false)
230
+ console.should_receive("get_banner").with(" WARN", "bright yellow", true).at_least(1).and_return("")
231
+ console.warn("OK", "\n", true, false, false, false, true, false)
232
+ end
233
+
234
+ it "should forward everything to #write" do
235
+ console.should_receive("write").with(/.+/, "B", "C", "D", "E", false)
236
+ console.warn("A", "B", "C", "D", "E", "F", "G", false)
237
+ end
238
+ end
239
+
240
+ describe "#error" do
241
+ it "should forward everything to #get_banner" do
242
+ console.should_receive("get_banner").with("ERROR", "bright red", false).at_least(1).and_return("")
243
+ console.error("OK", "\n", true, false, false, false, false, false)
244
+ console.should_receive("get_banner").with("ERROR", "bright red", true).at_least(1).and_return("")
245
+ console.error("OK", "\n", true, false, false, false, true, false)
246
+ end
247
+
248
+ it "should forward everything to #write" do
249
+ console.should_receive("write").with(/.+/, "B", "C", "D", "E", false)
250
+ console.error("A", "B", "C", "D", "E", "F", "G", false)
251
+ end
252
+ end
253
+
254
+ describe "#fatal" do
255
+ it "should forward anything to #error" do
256
+ Kernel.stub(:abort).and_return(true)
257
+ console.should_receive("error").with("A", "B", "C", "D", "E", "F", "G", false)
258
+ console.fatal("A", "B", "C", "D", "E", "F", "G", "H", false)
259
+ end
260
+
261
+ it "should call abort with the right error code" do
262
+ Kernel.stub(:abort).and_return(true)
263
+
264
+ Kernel.should_receive("abort").with(-1).at_least(1)
265
+ console.fatal("A", "B", "C", "D", "E", "F", "G", -1, false)
266
+ Kernel.should_receive("abort").with("H").at_least(1)
267
+ console.fatal("A", "B", "C", "D", "E", "F", "G", "H", false)
268
+ end
269
+ end
270
+
271
+ describe "#debug" do
272
+ it "should forward everything to #get_banner" do
273
+ console.should_receive("get_banner").with("DEBUG", "bright magenta", false).at_least(1).and_return("")
274
+ console.debug("OK", "\n", true, false, false, false, false, false)
275
+ console.should_receive("get_banner").with("DEBUG", "bright magenta", true).at_least(1).and_return("")
276
+ console.debug("OK", "\n", true, false, false, false, true, false)
277
+ end
278
+
279
+ it "should forward everything to #write" do
280
+ console.should_receive("write").with(/.+/, "B", "C", "D", "E", false)
281
+ console.debug("A", "B", "C", "D", "E", "F", "G", false)
282
+ end
283
+ end
284
+
285
+ describe "status" do
286
+ it "should get the right status" do
287
+ expect(console.status(:ok, false, true, false)).to eq({:label => " OK ", :color => "bright green"})
288
+ expect(console.status(:pass, false, true, false)).to eq({:label => "PASS", :color => "bright cyan"})
289
+ expect(console.status(:warn, false, true, false)).to eq({:label => "WARN", :color => "bright yellow"})
290
+ expect(console.status(:fail, false, true, false)).to eq({:label => "FAIL", :color => "bright red"})
291
+ expect(console.status("NO", false, true, false)).to eq({:label => "PASS", :color => "bright cyan"})
292
+ expect(console.status(nil, false, true, false)).to eq({:label => "PASS", :color => "bright cyan"})
293
+ end
294
+
295
+ it "should create the banner" do
296
+ console.should_receive("get_banner").with(" OK ", "bright green").and_return("")
297
+ console.status(:ok)
298
+ end
299
+
300
+ it "should format correctly" do
301
+ console.should_receive("format_right").with(/.+/, true, true, false)
302
+ console.status(:ok, false, true)
303
+ console.should_receive("format").with(/.+/, "\n", true, true, false)
304
+ console.status(:ok, false, true, false)
305
+ end
306
+ end
307
+
308
+ describe "#read" do
309
+ it "should show a prompt" do
310
+ prompt = "PROMPT"
311
+ Kernel.should_receive("print").with("Please insert a value: ")
312
+ console.read(true)
313
+ Kernel.should_receive("print").with(prompt + ": ")
314
+ console.read(prompt)
315
+ Kernel.should_not_receive("print")
316
+ console.read(nil)
317
+ end
318
+
319
+ it "should read a value or a default" do
320
+ Kernel.stub(:gets).and_return("VALUE\n")
321
+ expect(console.read(nil, "DEFAULT")).to eq("VALUE")
322
+ Kernel.stub(:gets).and_return("\n")
323
+ expect(console.read(nil, "DEFAULT")).to eq("DEFAULT")
324
+ end
325
+
326
+ it "should return the default value if the user quits" do
327
+ Kernel.stub(:gets).and_raise(Interrupt)
328
+ expect(console.read(nil, "DEFAULT")).to eq("DEFAULT")
329
+ end
330
+
331
+ it "should validate against an object or array validator" do
332
+ count = 0
333
+
334
+ Kernel.stub(:gets) do
335
+ if count == 0 then
336
+ count += 1
337
+ "2\n"
338
+ else
339
+ raise Interrupt
340
+ end
341
+ end
342
+
343
+ console.should_receive("write").with("Sorry, your reply was not understood. Please try again.", false, false).exactly(4)
344
+ count = 0
345
+ console.read(nil, nil, "A")
346
+ count = 0
347
+ console.read(nil, nil, "1")
348
+ count = 0
349
+ console.read(nil, nil, "nil")
350
+ count = 0
351
+ console.read(nil, nil, ["A", 1])
352
+ end
353
+
354
+ it "should validate against an regexp validator" do
355
+ count = 0
356
+
357
+ Kernel.stub(:gets) do
358
+ if count == 0 then
359
+ count += 1
360
+ "2\n"
361
+ else
362
+ raise Interrupt
363
+ end
364
+ end
365
+
366
+ console.should_receive("write").with("Sorry, your reply was not understood. Please try again.", false, false)
367
+ console.read(nil, nil, /[abc]/)
368
+ end
369
+
370
+ it "should hide echo to the user when the terminal shows echo" do
371
+ stty = %x{which stty}.strip
372
+
373
+ ::Bovem::Console.should_receive("execute").with("which stty").and_return(stty)
374
+ ::Bovem::Console.should_receive("execute").with(stty).and_return("speed 9600 baud;\nlflags: echoe echoke echoctl pendin\niflags: iutf8\noflags: -oxtabs\ncflags: cs8 -parenb")
375
+ ::Bovem::Console.should_receive("execute").with("#{stty} -echo")
376
+ ::Bovem::Console.should_receive("execute").with("#{stty} echo")
377
+ console.read(nil, nil, nil, false)
378
+ end
379
+
380
+ it "shouldn't hide echo again when the terminal already hides it" do
381
+ stty = %x{which stty}.strip
382
+
383
+ ::Bovem::Console.should_receive("execute").with("which stty").and_return(stty)
384
+ ::Bovem::Console.should_receive("execute").with(stty).and_return("speed 9600 baud;\nlflags: -echo echoe echoke echoctl pendin\niflags: iutf8\noflags: -oxtabs\ncflags: cs8 -parenb")
385
+ ::Bovem::Console.should_not_receive("execute").with("#{stty} -echo")
386
+ ::Bovem::Console.should_not_receive("execute").with("#{stty} echo")
387
+ console.read(nil, nil, nil, false)
388
+ end
389
+ end
390
+
391
+ describe "#task" do
392
+ it "should not print the message by default" do
393
+ console.should_not_receive("begin")
394
+ console.task { :ok }
395
+ end
396
+
397
+ it "should print the message and indentate correctly" do
398
+ console.should_receive("begin").with("A", "B", "C", "D", "E", "F", "G")
399
+ console.should_receive("with_indentation").with("H", "I")
400
+ console.task("A", "B", "C", "D", "E", "F", "G", "H", "I") { :ok }
401
+ end
402
+
403
+ it "should execute the given block" do
404
+ ::Bovem::Console.should_receive("foo")
405
+ console.task { ::Bovem::Console.foo }
406
+ end
407
+
408
+ it "should write the correct status" do
409
+ console.should_receive(:status).with(:ok, false)
410
+ console.task { :ok }
411
+ console.should_receive(:status).with(:fail, false)
412
+ expect { console.task { :fatal }}.to raise_error(SystemExit)
413
+ end
414
+
415
+ it "should abort correctly" do
416
+ expect { console.task { [:fatal, -1] }}.to raise_error(SystemExit)
417
+ end
418
+ end
419
+ end
@@ -7,41 +7,37 @@
7
7
  require "spec_helper"
8
8
 
9
9
  describe Bovem::Logger do
10
- before(:each) do
11
- Sickill::Rainbow.enabled = false
12
- end
13
-
14
10
  describe ".create" do
15
11
  it("should create a new default logger") do
16
- logger = Bovem::Logger.create
17
- expect(logger.device).to eq(Bovem::Logger.default_file)
12
+ logger = ::Bovem::Logger.create
13
+ expect(logger.device).to eq(::Bovem::Logger.default_file)
18
14
  expect(logger.level).to eq(::Logger::INFO)
19
- expect(logger.formatter).to eq(Bovem::Logger.default_formatter)
15
+ expect(logger.formatter).to eq(::Bovem::Logger.default_formatter)
20
16
  end
21
17
 
22
18
  it("should create a logger with a custom file and level") do
23
- logger = Bovem::Logger.create("/dev/null", ::Logger::WARN)
19
+ logger = ::Bovem::Logger.create("/dev/null", ::Logger::WARN)
24
20
  expect(logger.device).to eq("/dev/null")
25
21
  expect(logger.level).to eq(::Logger::WARN)
26
- expect(logger.formatter).to eq(Bovem::Logger.default_formatter)
22
+ expect(logger.formatter).to eq(::Bovem::Logger.default_formatter)
27
23
  end
28
24
 
29
25
  it("should create a logger with a custom formatter") do
30
26
  formatter = Proc.new {|severity, datetime, progname, msg| msg }
31
- logger = Bovem::Logger.create("/dev/null", ::Logger::WARN, formatter)
27
+ logger = ::Bovem::Logger.create("/dev/null", ::Logger::WARN, formatter)
32
28
  expect(logger.device).to eq("/dev/null")
33
29
  expect(logger.level).to eq(::Logger::WARN)
34
30
  expect(logger.formatter).to eq(formatter)
35
31
  end
36
32
 
37
33
  it("should raise exceptions for invalid files") do
38
- expect { Bovem::Logger.create("/invalid/file") }.to raise_error(Bovem::Errors::InvalidLogger)
34
+ expect { ::Bovem::Logger.create("/invalid/file") }.to raise_error(::Bovem::Errors::InvalidLogger)
39
35
  end
40
36
  end
41
37
 
42
38
  describe ".default_formatter" do
43
39
  let(:output) { ::StringIO.new }
44
- let(:logger) { Bovem::Logger.create(output, Logger::DEBUG) }
40
+ let(:logger) { ::Bovem::Logger.create(output, Logger::DEBUG) }
45
41
 
46
42
  def get_last_line(buffer)
47
43
  buffer.string.split("\n").last.strip.gsub(/ T\+\d+\.\d+/, "")
@@ -49,52 +45,52 @@ describe Bovem::Logger do
49
45
 
50
46
  it "should correctly format a DEBUG message" do
51
47
  logger.debug("Message.")
52
- expect(get_last_line(output)).to eq("[#{::Time.now.strftime("%Y/%b/%d %H:%M:%S")}] DEBUG: Message.")
48
+ expect(get_last_line(output)).to eq("\e[1m\e[36m[#{::Time.now.strftime("%Y/%b/%d %H:%M:%S")}] DEBUG:\e[0m Message.")
53
49
  end
54
50
 
55
51
  it "should correctly format a INFO message" do
56
52
  logger.info("Message.")
57
- expect(get_last_line(output)).to eq("[#{::Time.now.strftime("%Y/%b/%d %H:%M:%S")}] INFO: Message.")
53
+ expect(get_last_line(output)).to eq("\e[1m\e[32m[#{::Time.now.strftime("%Y/%b/%d %H:%M:%S")}] INFO:\e[0m Message.")
58
54
  end
59
55
 
60
56
  it "should correctly format a WARN message" do
61
57
  logger.warn("Message.")
62
- expect(get_last_line(output)).to eq("[#{::Time.now.strftime("%Y/%b/%d %H:%M:%S")}] WARN: Message.")
58
+ expect(get_last_line(output)).to eq("\e[1m\e[33m[#{::Time.now.strftime("%Y/%b/%d %H:%M:%S")}] WARN:\e[0m Message.")
63
59
  end
64
60
 
65
61
  it "should correctly format a ERROR message" do
66
62
  logger.error("Message.")
67
- expect(get_last_line(output)).to eq("[#{::Time.now.strftime("%Y/%b/%d %H:%M:%S")}] ERROR: Message.")
63
+ expect(get_last_line(output)).to eq("\e[1m\e[31m[#{::Time.now.strftime("%Y/%b/%d %H:%M:%S")}] ERROR:\e[0m Message.")
68
64
  end
69
65
 
70
66
  it "should correctly format a FATAL message" do
71
67
  logger.fatal("Message.")
72
- expect(get_last_line(output)).to eq("[#{::Time.now.strftime("%Y/%b/%d %H:%M:%S")}] FATAL: Message.")
68
+ expect(get_last_line(output)).to eq("\e[1m\e[35m[#{::Time.now.strftime("%Y/%b/%d %H:%M:%S")}] FATAL:\e[0m Message.")
73
69
  end
74
70
 
75
71
  it "should correctly format a INVALID message" do
76
72
  logger.log(::Logger::UNKNOWN, "Message.")
77
- expect(get_last_line(output)).to eq("[#{::Time.now.strftime("%Y/%b/%d %H:%M:%S")}] ANY: Message.")
73
+ expect(get_last_line(output)).to eq("\e[1m\e[37m[#{::Time.now.strftime("%Y/%b/%d %H:%M:%S")}] ANY:\e[0m Message.")
78
74
  end
79
75
  end
80
76
 
81
77
  describe ".get_real_file" do
82
78
  it("should return the standard ouput") do
83
- expect(Bovem::Logger.get_real_file("STDOUT")).to eq($stdout )
79
+ expect(::Bovem::Logger.get_real_file("STDOUT")).to eq($stdout )
84
80
  end
85
81
 
86
82
  it("should return the standard error") do
87
- expect(Bovem::Logger.get_real_file("STDERR")).to eq($stderr )
83
+ expect(::Bovem::Logger.get_real_file("STDERR")).to eq($stderr )
88
84
  end
89
85
 
90
86
  it("should return the file") do
91
- expect(Bovem::Logger.get_real_file("/dev/null")).to eq("/dev/null" )
87
+ expect(::Bovem::Logger.get_real_file("/dev/null")).to eq("/dev/null" )
92
88
  end
93
89
  end
94
90
 
95
91
  describe ".default_file" do
96
92
  it("should return the standard output") do
97
- expect(Bovem::Logger.default_file).to eq($stdout)
93
+ expect(::Bovem::Logger.default_file).to eq($stdout)
98
94
  end
99
95
  end
100
96
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bovem
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.8.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-08-04 00:00:00.000000000 Z
12
+ date: 2012-08-16 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: lazier
@@ -27,22 +27,6 @@ dependencies:
27
27
  - - ~>
28
28
  - !ruby/object:Gem::Version
29
29
  version: '1.0'
30
- - !ruby/object:Gem::Dependency
31
- name: rainbow
32
- requirement: !ruby/object:Gem::Requirement
33
- none: false
34
- requirements:
35
- - - ~>
36
- - !ruby/object:Gem::Version
37
- version: 1.1.0
38
- type: :runtime
39
- prerelease: false
40
- version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
- requirements:
43
- - - ~>
44
- - !ruby/object:Gem::Version
45
- version: 1.1.0
46
30
  - !ruby/object:Gem::Dependency
47
31
  name: rspec
48
32
  requirement: !ruby/object:Gem::Requirement
@@ -164,6 +148,7 @@ extra_rdoc_files: []
164
148
  files:
165
149
  - .gitignore
166
150
  - .travis.yml
151
+ - .yardopts
167
152
  - Gemfile
168
153
  - Gemfile.lock
169
154
  - README.md
@@ -171,10 +156,12 @@ files:
171
156
  - bovem.gemspec
172
157
  - lib/bovem.rb
173
158
  - lib/bovem/configuration.rb
159
+ - lib/bovem/console.rb
174
160
  - lib/bovem/errors.rb
175
161
  - lib/bovem/logger.rb
176
162
  - lib/bovem/version.rb
177
163
  - spec/bovem/configuration_spec.rb
164
+ - spec/bovem/console_spec.rb
178
165
  - spec/bovem/logger_spec.rb
179
166
  - spec/coverage_helper.rb
180
167
  - spec/spec_helper.rb
@@ -192,7 +179,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
192
179
  version: '0'
193
180
  segments:
194
181
  - 0
195
- hash: 2994685413523034481
182
+ hash: 1005901381076848041
196
183
  required_rubygems_version: !ruby/object:Gem::Requirement
197
184
  none: false
198
185
  requirements:
@@ -201,7 +188,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
201
188
  version: '0'
202
189
  segments:
203
190
  - 0
204
- hash: 2994685413523034481
191
+ hash: 1005901381076848041
205
192
  requirements: []
206
193
  rubyforge_project: bovem
207
194
  rubygems_version: 1.8.24
@@ -210,6 +197,7 @@ specification_version: 3
210
197
  summary: A collection of utilities for developers.
211
198
  test_files:
212
199
  - spec/bovem/configuration_spec.rb
200
+ - spec/bovem/console_spec.rb
213
201
  - spec/bovem/logger_spec.rb
214
202
  - spec/coverage_helper.rb
215
203
  - spec/spec_helper.rb