ansi 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,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