From 7567c8cf40803457f092f40f0a5cb2fb7054b7fd Mon Sep 17 00:00:00 2001 From: Ivan Kuchin Date: Fri, 2 Apr 2021 12:33:58 +0200 Subject: [PATCH] use Process.clock_gettime instead of Time.now, resolves #13 --- CHANGELOG.markdown | 2 ++ lib/progress/class_methods.rb | 6 ++++-- lib/progress/elapsed_time.rb | 26 ++++++++++++++++++++++++++ lib/progress/eta.rb | 8 +++++--- spec/progress/elapsed_time_spec.rb | 13 +++++++++++++ 5 files changed, 50 insertions(+), 5 deletions(-) create mode 100644 lib/progress/elapsed_time.rb create mode 100644 spec/progress/elapsed_time_spec.rb diff --git a/CHANGELOG.markdown b/CHANGELOG.markdown index 852abe9..cd88e90 100644 --- a/CHANGELOG.markdown +++ b/CHANGELOG.markdown @@ -2,6 +2,8 @@ ## unreleased +* Use `Process.clock_gettime` instead of `Time.now` which is faster and should give proper estimates even if sleeping in the middle [#13](https://github.com/toy/progress/issues/13) [@toy](https://github.com/toy) + ## v3.5.2 (2019-07-14) * Remove deprecated `rubyforge_project` attribute from gemspec [rubygems/rubygems#2436](https://github.com/rubygems/rubygems/pull/2436) [@toy](https://github.com/toy) diff --git a/lib/progress/class_methods.rb b/lib/progress/class_methods.rb index 3338abf..449c2cd 100644 --- a/lib/progress/class_methods.rb +++ b/lib/progress/class_methods.rb @@ -1,6 +1,8 @@ # encoding: UTF-8 # frozen_string_literal: true +require 'progress/elapsed_time' + class Progress # Class methods of Progress module ClassMethods @@ -165,14 +167,14 @@ def restart_beeper end def time_to_print? - !@next_time_to_print || @next_time_to_print <= Time.now + !@next_time_to_print || @next_time_to_print <= ElapsedTime.now end def print_message(options = {}) force = options[:force] lock force do if force || time_to_print? - @next_time_to_print = Time.now + 0.3 + @next_time_to_print = ElapsedTime.now + 0.3 restart_beeper io << message_for_output(options) end diff --git a/lib/progress/elapsed_time.rb b/lib/progress/elapsed_time.rb new file mode 100644 index 0000000..0601c7d --- /dev/null +++ b/lib/progress/elapsed_time.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +class Progress + # Use Process.clock_gettime if available to get time more fitting to calculate elapsed time + module ElapsedTime + CLOCK_NAME = %w[ + CLOCK_UPTIME_RAW + CLOCK_UPTIME + CLOCK_MONOTONIC_RAW + CLOCK_MONOTONIC + CLOCK_REALTIME + ].find{ |name| Process.const_defined?(name) } + + CLOCK_ID = CLOCK_NAME && Process.const_get(CLOCK_NAME) + + module_function + + def now + if CLOCK_ID + Process.clock_gettime(CLOCK_ID) + else + Time.now.to_f + end + end + end +end diff --git a/lib/progress/eta.rb b/lib/progress/eta.rb index ffe6142..0c30e3c 100644 --- a/lib/progress/eta.rb +++ b/lib/progress/eta.rb @@ -1,10 +1,12 @@ # frozen_string_literal: true +require 'progress/elapsed_time' + class Progress # Estimate time of arrival class Eta def initialize - @started_at = Time.now + @started_at = ElapsedTime.now end def left(completed) @@ -15,7 +17,7 @@ def left(completed) end def elapsed - seconds_to_string(Time.now - @started_at) + seconds_to_string(ElapsedTime.now - @started_at) end private @@ -36,7 +38,7 @@ def seconds_to_string(seconds) end def seconds_left(completed) - now = Time.now + now = ElapsedTime.now return unless completed > 0 && now - @started_at >= 1 current_eta = @started_at + (now - @started_at) / completed diff --git a/spec/progress/elapsed_time_spec.rb b/spec/progress/elapsed_time_spec.rb new file mode 100644 index 0000000..f78f4fc --- /dev/null +++ b/spec/progress/elapsed_time_spec.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +require 'progress/elapsed_time' + +describe Progress::ElapsedTime do + let(:timeout){ 0.01 } + + describe '.now' do + it 'returns incrementing value' do + expect{ sleep timeout }.to change{ described_class.now }.by_at_least(timeout) + end + end +end