bovem 0.6.0 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.yardopts +1 -0
- data/Gemfile.lock +12 -14
- data/bovem.gemspec +0 -1
- data/lib/bovem.rb +2 -2
- data/lib/bovem/console.rb +527 -0
- data/lib/bovem/logger.rb +1 -2
- data/lib/bovem/version.rb +1 -1
- data/spec/bovem/configuration_spec.rb +3 -3
- data/spec/bovem/console_spec.rb +419 -0
- data/spec/bovem/logger_spec.rb +18 -22
- metadata +8 -20
data/.yardopts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--exclude lib/devdnsd/patches/.+ --exclude utils/ -m markdown
|
data/Gemfile.lock
CHANGED
@@ -1,16 +1,15 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
bovem (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.
|
12
|
-
activemodel (= 3.2.
|
13
|
-
activesupport (= 3.2.
|
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.
|
22
|
-
activesupport (= 3.2.
|
20
|
+
activemodel (3.2.8)
|
21
|
+
activesupport (= 3.2.8)
|
23
22
|
builder (~> 3.0.0)
|
24
|
-
activesupport (3.2.
|
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.
|
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.
|
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.
|
59
|
-
rspec-expectations (2.11.
|
56
|
+
rspec-core (2.11.1)
|
57
|
+
rspec-expectations (2.11.2)
|
60
58
|
diff-lcs (~> 1.1.3)
|
61
|
-
rspec-mocks (2.11.
|
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)
|
data/bovem.gemspec
CHANGED
@@ -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")
|
data/lib/bovem.rb
CHANGED
@@ -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
|
data/lib/bovem/logger.rb
CHANGED
@@ -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)])
|
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
|
data/lib/bovem/version.rb
CHANGED
@@ -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
|
data/spec/bovem/logger_spec.rb
CHANGED
@@ -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
|
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
|
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
|
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
|
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
|
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
|
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.
|
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-
|
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:
|
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:
|
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
|