progress 2.4.0 → 3.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.
- checksums.yaml +15 -0
- data/.gitignore +1 -0
- data/.travis.yml +12 -0
- data/Gemfile +3 -0
- data/LICENSE.txt +1 -1
- data/README.markdown +8 -6
- data/lib/progress/active_record.rb +18 -20
- data/lib/progress/beeper.rb +24 -0
- data/lib/progress/eta.rb +48 -0
- data/lib/progress/with_progress.rb +42 -7
- data/lib/progress.rb +163 -151
- data/progress.gemspec +1 -1
- data/spec/progress_spec.rb +281 -240
- metadata +39 -57
- data/spec/spec_helper.rb +0 -3
data/lib/progress.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
1
3
|
require 'singleton'
|
2
4
|
require 'thread'
|
3
5
|
|
@@ -35,51 +37,76 @@ require 'thread'
|
|
35
37
|
class Progress
|
36
38
|
include Singleton
|
37
39
|
|
38
|
-
|
39
|
-
attr_reader :
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
total =
|
40
|
+
attr_reader :total
|
41
|
+
attr_reader :current
|
42
|
+
attr_reader :title
|
43
|
+
attr_accessor :note
|
44
|
+
def initialize(total, title)
|
45
|
+
if !total.kind_of?(Numeric) && (title.nil? || title.kind_of?(Numeric))
|
46
|
+
total, title = title, total
|
45
47
|
end
|
46
|
-
|
48
|
+
total = total && total != 0 ? Float(total) : 1.0
|
49
|
+
|
50
|
+
@total = total
|
47
51
|
@current = 0.0
|
48
|
-
@
|
52
|
+
@title = title
|
49
53
|
end
|
50
54
|
|
51
|
-
def
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
+
def to_f(inner)
|
56
|
+
inner = 1.0 if inner > 1.0
|
57
|
+
inner *= @step if @step
|
58
|
+
(current + inner) / total
|
55
59
|
end
|
56
60
|
|
57
|
-
def
|
58
|
-
|
59
|
-
|
60
|
-
inner *= current_step
|
61
|
+
def step(step, note)
|
62
|
+
if !step.kind_of?(Numeric)
|
63
|
+
step, note = nil, step
|
61
64
|
end
|
62
|
-
|
65
|
+
step = 1 if step.nil?
|
66
|
+
|
67
|
+
@step = step
|
68
|
+
@note = note
|
69
|
+
ret = yield if block_given?
|
70
|
+
Thread.exclusive do
|
71
|
+
@current += step
|
72
|
+
end
|
73
|
+
ret
|
63
74
|
end
|
64
75
|
|
65
|
-
def
|
66
|
-
@
|
67
|
-
|
68
|
-
|
69
|
-
|
76
|
+
def set(new_current, note)
|
77
|
+
@step = new_current - @current
|
78
|
+
@note = note
|
79
|
+
ret = yield if block_given?
|
80
|
+
Thread.exclusive do
|
81
|
+
@current = new_current
|
82
|
+
end
|
83
|
+
ret
|
70
84
|
end
|
71
85
|
|
86
|
+
@lock = Mutex.new
|
72
87
|
class << self
|
88
|
+
|
73
89
|
# start progress indication
|
74
|
-
def start(
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
90
|
+
def start(total = nil, title = nil)
|
91
|
+
lock do
|
92
|
+
if running?
|
93
|
+
unless @started_in == Thread.current
|
94
|
+
warn 'Can\'t start inner progress in different thread'
|
95
|
+
if block_given?
|
96
|
+
return yield
|
97
|
+
else
|
98
|
+
return
|
99
|
+
end
|
100
|
+
end
|
101
|
+
else
|
102
|
+
@started_in = Thread.current
|
103
|
+
@eta = Eta.new
|
104
|
+
start_beeper
|
105
|
+
end
|
106
|
+
@levels ||= []
|
107
|
+
@levels.push new(total, title)
|
80
108
|
end
|
81
|
-
|
82
|
-
print_message true
|
109
|
+
print_message :force => true
|
83
110
|
if block_given?
|
84
111
|
begin
|
85
112
|
yield
|
@@ -89,26 +116,22 @@ class Progress
|
|
89
116
|
end
|
90
117
|
end
|
91
118
|
|
92
|
-
# step current progress
|
93
|
-
def step(
|
94
|
-
if
|
95
|
-
|
119
|
+
# step current progress
|
120
|
+
def step(step = nil, note = nil, &block)
|
121
|
+
if running?
|
122
|
+
ret = @levels.last.step(step, note, &block)
|
123
|
+
print_message
|
124
|
+
ret
|
96
125
|
elsif block
|
97
126
|
block.call
|
98
127
|
end
|
99
128
|
end
|
100
129
|
|
101
|
-
# set current progress
|
102
|
-
def set(
|
103
|
-
if
|
104
|
-
ret =
|
105
|
-
levels.last.step(value - levels.last.current, &block)
|
106
|
-
end
|
107
|
-
if levels.last
|
108
|
-
levels.last.current = Float(value)
|
109
|
-
end
|
130
|
+
# set value of current progress
|
131
|
+
def set(new_current, note = nil, &block)
|
132
|
+
if running?
|
133
|
+
ret = @levels.last.set(new_current, note, &block)
|
110
134
|
print_message
|
111
|
-
self.note = nil
|
112
135
|
ret
|
113
136
|
elsif block
|
114
137
|
block.call
|
@@ -117,176 +140,165 @@ class Progress
|
|
117
140
|
|
118
141
|
# stop progress
|
119
142
|
def stop
|
120
|
-
if
|
121
|
-
if levels.
|
122
|
-
print_message true
|
123
|
-
set_title nil
|
124
|
-
end
|
125
|
-
levels.pop
|
126
|
-
if levels.empty?
|
143
|
+
if running?
|
144
|
+
if @levels.length == 1
|
145
|
+
print_message :force => true, :finish => true
|
127
146
|
stop_beeper
|
128
|
-
io.puts
|
129
147
|
end
|
148
|
+
@levels.pop
|
130
149
|
end
|
131
150
|
end
|
132
151
|
|
133
|
-
# check
|
152
|
+
# check if progress was started
|
134
153
|
def running?
|
135
|
-
|
154
|
+
@levels && !@levels.empty?
|
136
155
|
end
|
137
156
|
|
138
157
|
# set note
|
139
|
-
def note=(
|
140
|
-
if
|
141
|
-
levels.last.note =
|
158
|
+
def note=(note)
|
159
|
+
if running?
|
160
|
+
@levels.last.note = note
|
142
161
|
end
|
143
162
|
end
|
144
163
|
|
145
|
-
#
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
# force highlight
|
150
|
-
# Progress.highlight = true
|
151
|
-
attr_writer :highlight
|
152
|
-
|
153
|
-
private
|
154
|
-
|
155
|
-
def levels
|
156
|
-
@levels ||= []
|
157
|
-
end
|
158
|
-
|
159
|
-
def io
|
160
|
-
@io || $stderr
|
161
|
-
end
|
162
|
-
|
163
|
-
def io_tty?
|
164
|
-
io.tty? || ENV['PROGRESS_TTY']
|
164
|
+
# stay on one line
|
165
|
+
def stay_on_line?
|
166
|
+
@stay_on_line.nil? ? io_tty? : @stay_on_line
|
165
167
|
end
|
166
168
|
|
167
|
-
|
168
|
-
|
169
|
+
# explicitly set staying on one line [true/false/nil]
|
170
|
+
def stay_on_line=(value)
|
171
|
+
@stay_on_line = true && value
|
169
172
|
end
|
170
173
|
|
174
|
+
# highlight output using control characters
|
171
175
|
def highlight?
|
172
176
|
@highlight.nil? ? io_tty? : @highlight
|
173
177
|
end
|
174
178
|
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
true
|
179
|
-
end
|
179
|
+
# explicitly set highlighting [true/false/nil]
|
180
|
+
def highlight=(value)
|
181
|
+
@highlight = true && value
|
180
182
|
end
|
181
183
|
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
current_eta = @started_at + (now - @started_at) / completed
|
186
|
-
@eta = @eta ? @eta + (current_eta - @eta) * (1 + completed) * 0.5 : current_eta
|
187
|
-
seconds = @eta - now
|
188
|
-
if seconds > 0
|
189
|
-
left = case seconds
|
190
|
-
when 0...60
|
191
|
-
'%.0fs' % seconds
|
192
|
-
when 60...3600
|
193
|
-
'%.1fm' % (seconds / 60)
|
194
|
-
when 3600...86400
|
195
|
-
'%.1fh' % (seconds / 3600)
|
196
|
-
else
|
197
|
-
'%.1fd' % (seconds / 86400)
|
198
|
-
end
|
199
|
-
eta_string = " (ETA: #{left})"
|
200
|
-
end
|
201
|
-
end
|
184
|
+
# show progerss in terminal title
|
185
|
+
def set_terminal_title?
|
186
|
+
@set_terminal_title.nil? ? io_tty? : @set_terminal_title
|
202
187
|
end
|
203
188
|
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
end
|
189
|
+
# explicitly set showing progress in terminal title [true/false/nil]
|
190
|
+
def set_terminal_title=(value)
|
191
|
+
@set_terminal_title = true && value
|
208
192
|
end
|
209
193
|
|
210
|
-
|
211
|
-
|
194
|
+
private
|
195
|
+
|
196
|
+
def lock(force = true)
|
197
|
+
if force ? @lock.lock : @lock.try_lock
|
212
198
|
begin
|
213
199
|
yield
|
214
200
|
ensure
|
215
|
-
@
|
201
|
+
@lock.unlock
|
216
202
|
end
|
217
203
|
end
|
218
204
|
end
|
219
205
|
|
206
|
+
def io
|
207
|
+
@io || $stderr
|
208
|
+
end
|
209
|
+
|
210
|
+
def io_tty?
|
211
|
+
io.tty? || ENV['PROGRESS_TTY']
|
212
|
+
end
|
213
|
+
|
220
214
|
def start_beeper
|
221
|
-
@beeper =
|
222
|
-
|
223
|
-
sleep 10
|
224
|
-
print_message unless Thread.current[:skip]
|
225
|
-
end
|
215
|
+
@beeper = Beeper.new(10) do
|
216
|
+
print_message
|
226
217
|
end
|
227
218
|
end
|
228
219
|
|
229
220
|
def stop_beeper
|
230
|
-
@beeper.
|
231
|
-
@beeper = nil
|
221
|
+
@beeper.stop if @beeper
|
232
222
|
end
|
233
223
|
|
234
224
|
def restart_beeper
|
235
|
-
if @beeper
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
225
|
+
@beeper.restart if @beeper
|
226
|
+
end
|
227
|
+
|
228
|
+
def time_to_print?
|
229
|
+
!@next_time_to_print || @next_time_to_print <= Time.now
|
230
|
+
end
|
231
|
+
|
232
|
+
def eta(current)
|
233
|
+
@eta.left(current)
|
240
234
|
end
|
241
235
|
|
242
|
-
def
|
236
|
+
def elapsed
|
237
|
+
@eta.elapsed
|
238
|
+
end
|
239
|
+
|
240
|
+
def print_message(options = {})
|
241
|
+
force = options[:force]
|
243
242
|
lock force do
|
244
|
-
restart_beeper
|
245
243
|
if force || time_to_print?
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
244
|
+
@next_time_to_print = Time.now + 0.3
|
245
|
+
restart_beeper
|
246
|
+
|
247
|
+
current = 0
|
248
|
+
parts = []
|
249
|
+
title_parts = []
|
250
|
+
@levels.reverse.each do |level|
|
251
|
+
current = level.to_f(current)
|
252
|
+
|
253
|
+
percent = current == 0 ? '......' : "#{'%5.1f' % (current * 100.0)}%"
|
254
|
+
title = level.title && "#{level.title}: "
|
255
|
+
if !highlight? || percent == '100.0%'
|
256
|
+
parts << "#{title}#{percent}"
|
255
257
|
else
|
256
|
-
parts << "#{title}\e[1m#{
|
258
|
+
parts << "#{title}\e[1m#{percent}\e[0m"
|
257
259
|
end
|
258
|
-
|
260
|
+
title_parts << "#{title}#{percent}"
|
261
|
+
end
|
262
|
+
|
263
|
+
timing = if options[:finish]
|
264
|
+
" (elapsed: #{elapsed})"
|
265
|
+
elsif eta_ = eta(current)
|
266
|
+
" (ETA: #{eta_})"
|
259
267
|
end
|
260
268
|
|
261
|
-
|
262
|
-
|
263
|
-
message_cl = "#{parts_cl.reverse * ' > '}#{eta_string}"
|
269
|
+
message = "#{parts.reverse * ' > '}#{timing}"
|
270
|
+
text_message = "#{title_parts.reverse * ' > '}#{timing}"
|
264
271
|
|
265
|
-
if note =
|
272
|
+
if note = running? && @levels.last.note
|
266
273
|
message << " - #{note}"
|
267
|
-
|
274
|
+
text_message << " - #{note}"
|
268
275
|
end
|
269
276
|
|
270
|
-
if
|
271
|
-
|
272
|
-
|
273
|
-
io << message << "\e[K\r"
|
274
|
-
end
|
277
|
+
message = "\r#{message}\e[K" if stay_on_line?
|
278
|
+
message << "\n" if !stay_on_line? || options[:finish]
|
279
|
+
io << message
|
275
280
|
|
276
|
-
|
281
|
+
if set_terminal_title?
|
282
|
+
title = options[:finish] ? nil : text_message.to_s.gsub("\a", '␇')
|
283
|
+
io << "\e]0;#{title}\a"
|
284
|
+
end
|
277
285
|
end
|
278
286
|
end
|
279
287
|
end
|
288
|
+
|
280
289
|
end
|
281
290
|
end
|
282
291
|
|
292
|
+
require 'progress/beeper'
|
293
|
+
require 'progress/eta'
|
294
|
+
|
283
295
|
require 'progress/enumerable'
|
284
296
|
require 'progress/integer'
|
285
|
-
require 'progress/active_record'
|
297
|
+
require 'progress/active_record' if defined?(ActiveRecord::Base)
|
286
298
|
|
287
299
|
module Kernel
|
288
|
-
def Progress(
|
289
|
-
Progress.start(
|
300
|
+
def Progress(*args, &block)
|
301
|
+
Progress.start(*args, &block)
|
290
302
|
end
|
291
303
|
private :Progress
|
292
304
|
end
|