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.
- 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
|