ansi 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,209 @@
1
+ # Ansi::Logger
2
+ # Copyright (c) 2009 Thomas Sawyer
3
+ # Copyright (c) 2005 George Moschovitis
4
+
5
+ require "logger"
6
+ require "time"
7
+ require "ansi/code"
8
+
9
+ # = ANSI::Logger
10
+ #
11
+ # Extended variation of Ruby's standard Logger library.
12
+ # Mainly for compatibility purposes (with what?)
13
+ #
14
+ # log = ANSI::Logger.new
15
+ #
16
+ # log.formatter do |severity, timestamp, progname, msg|
17
+ # ANSI::Logger::SIMPLE_FORMAT % [severity, msg]
18
+ # end
19
+ #
20
+ #--
21
+ # TODO: What's all this about then?
22
+ #
23
+ # When using debug level logger messages always append 'if $DBG'
24
+ # at the end. This hack is needed because Ruby does not support
25
+ # lazy evaluation (lisp macros).
26
+ #++
27
+ class ANSI::Logger < Logger
28
+
29
+ # Some available logging formats.
30
+ SIMPLE_FORMAT = "%5s: %s\n"
31
+ DETAILED_FORMAT = "%s %5s: %s\n"
32
+
33
+ #
34
+ class ::Logger::LogDevice
35
+ attr_writer :ansicolor
36
+
37
+ def ansicolor?
38
+ @ansicolor.nil? ? true : @ansicolor
39
+ end
40
+ end
41
+
42
+ #
43
+ def ansicolor?
44
+ @logdev.ansicolor?
45
+ end
46
+
47
+ #
48
+ def ansicolor=(on)
49
+ @logdev.ansicolor = on
50
+ end
51
+
52
+ # Dictate the way in which this logger should format the
53
+ # messages it displays. This method requires a block. The
54
+ # block should return formatted strings given severity,
55
+ # timestamp, progname and msg.
56
+ #
57
+ # === Example
58
+ #
59
+ # logger = ANSI::Logger.new
60
+ #
61
+ # logger.formatter do |severity, timestamp, progname, msg|
62
+ # "#{progname}@#{timestamp} - #{severity}::#{msg}"
63
+ # end
64
+ #
65
+ def formatter(&block)
66
+ self.formatter = block if block
67
+ super
68
+ end
69
+
70
+ def styles(options=nil)
71
+ @styles ||= {
72
+ :info => [],
73
+ :warn => [:yellow],
74
+ :debug => [:cyan],
75
+ :error => [:red],
76
+ :fatal => [:bold, :red]
77
+ }
78
+ @styles.merge!(options) if options
79
+ @styles
80
+ end
81
+
82
+ #
83
+ def info(progname=nil, &block)
84
+ return unless info?
85
+ @logdev.ansicolor? ? info_with_color{ super } : super
86
+ end
87
+
88
+ #
89
+ def warn(progname=nil, &block)
90
+ return unless warn?
91
+ @logdev.ansicolor? ? warn_with_color{ super } : super
92
+ end
93
+
94
+ #
95
+ def debug(progname=nil, &block)
96
+ return unless debug?
97
+ @logdev.ansicolor? ? debug_with_color{ super } : super
98
+ end
99
+
100
+ #
101
+ def error(progname=nil, &block)
102
+ return unless error?
103
+ @logdev.ansicolor? ? error_with_color{ super } : super
104
+ end
105
+
106
+ #
107
+ def fatal(progname=nil, &block)
108
+ return unless error?
109
+ @logdev.ansicolor? ? fatal_with_color{ super } : super
110
+ end
111
+
112
+ private
113
+
114
+ def info_with_color #:yield:
115
+ styles[:info].each{ |s| self << ANSI::Code.send(s) }
116
+ yield
117
+ self << ANSI::Code.clear
118
+ end
119
+
120
+ def warn_with_color #:yield:
121
+ styles[:warn].each{ |s| self << ANSI::Code.send(s) }
122
+ yield
123
+ self << ANSI::Code.clear
124
+ end
125
+
126
+ def error_with_color #:yield:
127
+ styles[:error].each{ |s| self << ANSI::Code.send(s) }
128
+ yield
129
+ self << ANSI::Code.clear
130
+ end
131
+
132
+ def debug_with_color #:yield:
133
+ styles[:debug].each{ |s| self << ANSI::Code.send(s) }
134
+ yield
135
+ self << ANSI::Code.clear
136
+ end
137
+
138
+ def fatal_with_color #:yield:
139
+ styles[:fatal].each{ |s| self << ANSI::Code.send(s) }
140
+ yield
141
+ self << ANSI::Code.clear
142
+ end
143
+
144
+ end
145
+
146
+
147
+ # NOTE: trace is deprecated b/c binding of caller is no longer possible.
148
+ =begin
149
+ # Prints a trace message to DEBUGLOG (at debug level).
150
+ # Useful for emitting the value of variables, etc. Use
151
+ # like this:
152
+ #
153
+ # x = y = 5
154
+ # trace 'x' # -> 'x = 5'
155
+ # trace 'x ** y' # -> 'x ** y = 3125'
156
+ #
157
+ # If you have a more complicated value, like an array of
158
+ # hashes, then you'll probably want to use an alternative
159
+ # output format. For instance:
160
+ #
161
+ # trace 'value', :yaml
162
+ #
163
+ # Valid output format values (the _style_ parameter) are:
164
+ #
165
+ # :p :inspect
166
+ # :pp (pretty-print, using 'pp' library)
167
+ # :s :to_s
168
+ # :y :yaml :to_yaml (using the 'yaml' library')
169
+ #
170
+ # The default is <tt>:p</tt>.
171
+ #
172
+ # CREDITS:
173
+ #
174
+ # This code comes straight from the dev-utils Gem.
175
+ # Author: Gavin Sinclair <gsinclair@soyabean.com.au>
176
+
177
+ def trace(expr, style=:p)
178
+ unless expr.respond_to? :to_str
179
+ warn "trace: Can't evaluate the given value: #{caller.first}"
180
+ else
181
+ raise "FACETS: binding/or_caller is no longer possible"
182
+ require "facets/core/binding/self/of_caller"
183
+
184
+ Binding.of_caller do |b|
185
+ value = b.eval(expr.to_str)
186
+ formatter = TRACE_STYLES[style] || :inspect
187
+ case formatter
188
+ when :pp then require 'pp'
189
+ when :y, :yaml, :to_yaml then require 'yaml'
190
+ end
191
+ value_s = value.send(formatter)
192
+ message = "#{expr} = #{value_s}"
193
+ lines = message.split(/\n/)
194
+ indent = " "
195
+ debug(lines.shift)
196
+ lines.each do |line|
197
+ debug(indent + line)
198
+ end
199
+ end
200
+ end
201
+ end
202
+
203
+ TRACE_STYLES = {} # :nodoc:
204
+ TRACE_STYLES.update(
205
+ :pp => :pp_s, :s => :to_s, :p => :inspect,
206
+ :y => :to_yaml, :yaml => :to_yaml,
207
+ :inspect => :inspect, :to_yaml => :to_yaml
208
+ )
209
+ =end
@@ -0,0 +1,268 @@
1
+ # Copyright (C) 2009 Thomas Sawyer
2
+ #
3
+ # This library is based on the original ProgressBar
4
+ # by Satoru Takabayashi.
5
+ #
6
+ # ProgressBar Copyright (C) 2001 Satoru Takabayashi
7
+
8
+ require 'ansi/code'
9
+
10
+ # ProgressBar is a text-based progressbar library.
11
+ #
12
+ # pbar = Progressbar.new( "Demo", 100 )
13
+ # 100.times { pbar.inc }
14
+ # pbar.finish
15
+ #
16
+ class ANSI::Progressbar
17
+ #
18
+ def initialize(title, total, out=STDERR)
19
+ @title = title
20
+ @total = total
21
+ @out = out
22
+
23
+ @bar_length = 80
24
+ @bar_mark = "o"
25
+ @total_overflow = true
26
+ @current = 0
27
+ @previous = 0
28
+ @is_finished = false
29
+ @start_time = Time.now
30
+ @format = "%-14s %3d%% %s %s"
31
+ @format_arguments = [:title, :percentage, :bar, :stat]
32
+ @styles = {}
33
+ #
34
+ yield self if block_given?
35
+ #
36
+ show_progress
37
+ end
38
+
39
+ public
40
+
41
+ attr_accessor :format
42
+ attr_accessor :format_arguments
43
+ attr_accessor :styles
44
+
45
+ #
46
+ def title=(str)
47
+ @title = str
48
+ end
49
+ #
50
+ def bar_mark=(mark)
51
+ @bar_mark = String(mark)[0..0]
52
+ end
53
+
54
+ def total_overflow=(boolv)
55
+ @total_overflow = boolv ? true : false
56
+ end
57
+
58
+ # Set format and format arguments.
59
+ def format(format, *arguments)
60
+ @format = format
61
+ @format_arguments = *arguments unless arguments.empty?
62
+ end
63
+
64
+ # Set ANSI styling options.
65
+ def style(options)
66
+ @styles = options
67
+ end
68
+
69
+ #
70
+ def standard_mode
71
+ @format = "%-14s %3d%% %s %s"
72
+ @format_arguments = [:title, :percentage, :bar, :stat]
73
+ end
74
+
75
+ #
76
+ def transfer_mode
77
+ @format = "%-14s %3d%% %s %s"
78
+ @format_arguments = [:title, :percentage, :bar, :stat_for_file_transfer]
79
+ end
80
+
81
+ # For backward compatability
82
+ alias_method :file_transfer_mode, :transfer_mode
83
+
84
+ def finish
85
+ @current = @total
86
+ @is_finished = true
87
+ show_progress
88
+ end
89
+
90
+ def flush
91
+ @out.flush
92
+ end
93
+
94
+ def halt
95
+ @is_finished = true
96
+ show_progress
97
+ end
98
+
99
+ def set(count)
100
+ if count < 0
101
+ raise "invalid count less than zero: #{count}"
102
+ elsif count > @total
103
+ if @total_overflow
104
+ @total = count + 1
105
+ else
106
+ raise "invalid count greater than total: #{count}"
107
+ end
108
+ end
109
+ @current = count
110
+ show_progress
111
+ @previous = @current
112
+ end
113
+
114
+ #
115
+ def reset
116
+ @current = 0
117
+ @is_finished = false
118
+ end
119
+
120
+ def inc(step = 1)
121
+ @current += step
122
+ @current = @total if @current > @total
123
+ show_progress
124
+ @previous = @current
125
+ end
126
+
127
+ def inspect
128
+ "(ProgressBar: #{@current}/#{@total})"
129
+ end
130
+
131
+ private
132
+
133
+ #
134
+ def convert_bytes(bytes)
135
+ if bytes < 1024
136
+ sprintf("%6dB", bytes)
137
+ elsif bytes < 1024 * 1000 # 1000kb
138
+ sprintf("%5.1fKB", bytes.to_f / 1024)
139
+ elsif bytes < 1024 * 1024 * 1000 # 1000mb
140
+ sprintf("%5.1fMB", bytes.to_f / 1024 / 1024)
141
+ else
142
+ sprintf("%5.1fGB", bytes.to_f / 1024 / 1024 / 1024)
143
+ end
144
+ end
145
+ #
146
+ def transfer_rate
147
+ bytes_per_second = @current.to_f / (Time.now - @start_time)
148
+ sprintf("%s/s", convert_bytes(bytes_per_second))
149
+ end
150
+ #
151
+ def bytes
152
+ convert_bytes(@current)
153
+ end
154
+ #
155
+ def format_time(t)
156
+ t = t.to_i
157
+ sec = t % 60
158
+ min = (t / 60) % 60
159
+ hour = t / 3600
160
+ sprintf("%02d:%02d:%02d", hour, min, sec);
161
+ end
162
+ #
163
+ # ETA stands for Estimated Time of Arrival.
164
+ def eta
165
+ if @current == 0
166
+ "ETA: --:--:--"
167
+ else
168
+ elapsed = Time.now - @start_time
169
+ eta = elapsed * @total / @current - elapsed;
170
+ sprintf("ETA: %s", format_time(eta))
171
+ end
172
+ end
173
+ #
174
+ def elapsed
175
+ elapsed = Time.now - @start_time
176
+ sprintf("Time: %s", format_time(elapsed))
177
+ end
178
+ #
179
+ def stat
180
+ if @is_finished then elapsed else eta end
181
+ end
182
+ #
183
+ def stat_for_file_transfer
184
+ if @is_finished then
185
+ sprintf("%s %s %s", bytes, transfer_rate, elapsed)
186
+ else
187
+ sprintf("%s %s %s", bytes, transfer_rate, eta)
188
+ end
189
+ end
190
+ #
191
+ def eol
192
+ if @is_finished then "\n" else "\r" end
193
+ end
194
+ #
195
+ def bar
196
+ len = percentage * @bar_length / 100
197
+ sprintf("|%s%s|", @bar_mark * len, " " * (@bar_length - len))
198
+ end
199
+ #
200
+ def percentage
201
+ if @total.zero?
202
+ 100
203
+ else
204
+ @current * 100 / @total
205
+ end
206
+ end
207
+ #
208
+ def title
209
+ @title[0,13] + ":"
210
+ end
211
+ #
212
+ def get_width
213
+ # FIXME: I don't know how portable it is.
214
+ default_width = 80
215
+ begin
216
+ tiocgwinsz = 0x5413
217
+ data = [0, 0, 0, 0].pack("SSSS")
218
+ if @out.ioctl(tiocgwinsz, data) >= 0 then
219
+ rows, cols, xpixels, ypixels = data.unpack("SSSS")
220
+ if cols >= 0 then cols else default_width end
221
+ else
222
+ default_width
223
+ end
224
+ rescue Exception
225
+ default_width
226
+ end
227
+ end
228
+
229
+ #
230
+ def show
231
+ arguments = @format_arguments.map do |method|
232
+ colorize(send(method), styles[method])
233
+ end
234
+ line = sprintf(@format, *arguments)
235
+ width = get_width
236
+ length = ANSI::Code.uncolored(line).length
237
+ if length == width - 1
238
+ @out.print(line + eol)
239
+ elsif length >= width
240
+ @bar_length = [@bar_length - (length - width + 1), 0].max
241
+ @bar_length == 0 ? @out.print(line + eol) : show
242
+ else #line.length < width - 1
243
+ @bar_length += width - length + 1
244
+ show
245
+ end
246
+ end
247
+
248
+ #
249
+ def show_progress
250
+ if @total.zero?
251
+ cur_percentage = 100
252
+ prev_percentage = 0
253
+ else
254
+ cur_percentage = (@current * 100 / @total).to_i
255
+ prev_percentage = (@previous * 100 / @total).to_i
256
+ end
257
+ if cur_percentage > prev_percentage || @is_finished
258
+ show
259
+ end
260
+ end
261
+
262
+ #
263
+ def colorize(part, style)
264
+ return part unless style
265
+ [style].flatten.inject(part){ |pt, st| ANSI::Code.send(st){ pt } }
266
+ end
267
+
268
+ end