Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package rubygem-timers for openSUSE:Factory checked in at 2021-07-02 13:27:15 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/rubygem-timers (Old) and /work/SRC/openSUSE:Factory/.rubygem-timers.new.2625 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "rubygem-timers" Fri Jul 2 13:27:15 2021 rev:7 rq:902944 version:4.3.3 Changes: -------- --- /work/SRC/openSUSE:Factory/rubygem-timers/rubygem-timers.changes 2020-10-05 19:34:15.297266416 +0200 +++ /work/SRC/openSUSE:Factory/.rubygem-timers.new.2625/rubygem-timers.changes 2021-07-02 13:28:07.264456129 +0200 @@ -1,0 +2,6 @@ +Thu Jun 24 18:04:36 UTC 2021 - Stephan Kulow <[email protected]> + +updated to version 4.3.3 + no changelog found + +------------------------------------------------------------------- Old: ---- timers-4.3.2.gem New: ---- timers-4.3.3.gem ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ rubygem-timers.spec ++++++ --- /var/tmp/diff_new_pack.zpMNxM/_old 2021-07-02 13:28:07.716452622 +0200 +++ /var/tmp/diff_new_pack.zpMNxM/_new 2021-07-02 13:28:07.720452591 +0200 @@ -1,7 +1,7 @@ # # spec file for package rubygem-timers # -# Copyright (c) 2020 SUSE LLC +# Copyright (c) 2021 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -24,7 +24,7 @@ # Name: rubygem-timers -Version: 4.3.2 +Version: 4.3.3 Release: 0 %define mod_name timers %define mod_full_name %{mod_name}-%{version} ++++++ timers-4.3.2.gem -> timers-4.3.3.gem ++++++ Binary files old/checksums.yaml.gz and new/checksums.yaml.gz differ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/timers/events.rb new/lib/timers/events.rb --- old/lib/timers/events.rb 2020-09-04 08:35:48.000000000 +0200 +++ new/lib/timers/events.rb 2021-02-13 07:15:03.000000000 +0100 @@ -21,57 +21,52 @@ # THE SOFTWARE. require_relative "timer" +require_relative "priority_heap" module Timers - # Maintains an ordered list of events, which can be cancelled. + # Maintains a PriorityHeap of events ordered on time, which can be cancelled. class Events # Represents a cancellable handle for a specific timer event. class Handle + include Comparable + def initialize(time, callback) @time = time @callback = callback end - + # The absolute time that the handle should be fired at. attr_reader :time - + # Cancel this timer, O(1). def cancel! # The simplest way to keep track of cancelled status is to nullify the # callback. This should also be optimal for garbage collection. @callback = nil end - + # Has this timer been cancelled? Cancelled timer's don't fire. def cancelled? @callback.nil? end - - def > other - @time > other.to_f - end - - def >= other - @time >= other.to_f - end - - def to_f - @time + + def <=> other + @time <=> other.time end - + # Fire the callback if not cancelled with the given time parameter. def fire(time) @callback.call(time) if @callback end end - + def initialize # A sequence of handles, maintained in sorted order, future to present. # @sequence.last is the next event to be fired. - @sequence = [] + @sequence = PriorityHeap.new @queue = [] end - + # Add an event at the given time. def schedule(time, callback) handle = Handle.new(time.to_f, callback) @@ -80,64 +75,41 @@ return handle end - + # Returns the first non-cancelled handle. def first merge! - while (handle = @sequence.last) + while (handle = @sequence.peek) return handle unless handle.cancelled? @sequence.pop end end - + # Returns the number of pending (possibly cancelled) events. def size @sequence.size + @queue.size end - + # Fire all handles for which Handle#time is less than the given time. def fire(time) merge! - while handle = @sequence.last and handle.time <= time + while handle = @sequence.peek and handle.time <= time @sequence.pop handle.fire(time) end end - + private - + + # Move all non-cancelled timers from the pending queue to the priority heap def merge! while handle = @queue.pop next if handle.cancelled? - index = bisect_right(@sequence, handle) - - if current_handle = @sequence[index] and current_handle.cancelled? - # puts "Replacing handle at index: #{index} due to cancellation in array containing #{@sequence.size} item(s)." - @sequence[index] = handle - else - # puts "Inserting handle at index: #{index} in array containing #{@sequence.size} item(s)." - @sequence.insert(index, handle) - end + @sequence.push(handle) end end - - # Return the right-most index where to insert item e, in a list a, assuming - # a is sorted in descending order. - def bisect_right(a, e, l = 0, u = a.length) - while l < u - m = l + (u - l).div(2) - - if a[m] >= e - l = m + 1 - else - u = m - end - end - - l - end end end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/timers/group.rb new/lib/timers/group.rb --- old/lib/timers/group.rb 2020-09-04 08:35:48.000000000 +0200 +++ new/lib/timers/group.rb 2021-02-13 07:15:03.000000000 +0100 @@ -31,62 +31,62 @@ # A collection of timers which may fire at different times class Group include Enumerable - + extend Forwardable def_delegators :@timers, :each, :empty? - + def initialize @events = Events.new - + @timers = Set.new @paused_timers = Set.new - + @interval = Interval.new @interval.start end - + # Scheduled events: attr_reader :events - + # Active timers: attr_reader :timers - + # Paused timers: attr_reader :paused_timers - + # Call the given block after the given interval. The first argument will be # the time at which the group was asked to fire timers for. def after(interval, &block) Timer.new(self, interval, false, &block) end - + # Call the given block immediately, and then after the given interval. The first # argument will be the time at which the group was asked to fire timers for. def now_and_after(interval, &block) yield after(interval, &block) end - + # Call the given block periodically at the given interval. The first # argument will be the time at which the group was asked to fire timers for. def every(interval, recur = true, &block) Timer.new(self, interval, recur, &block) end - + # Call the given block immediately, and then periodically at the given interval. The first # argument will be the time at which the group was asked to fire timers for. def now_and_every(interval, recur = true, &block) yield every(interval, recur, &block) end - + # Wait for the next timer and fire it. Can take a block, which should behave # like sleep(n), except that n may be nil (sleep forever) or a negative # number (fire immediately after return). def wait if block_given? yield wait_interval - + while (interval = wait_interval) && interval > 0 yield interval end @@ -99,7 +99,7 @@ fire end - + # Interval to wait until when the next timer will fire. # - nil: no timers # - -ve: timers expired already @@ -109,36 +109,36 @@ handle = @events.first handle.time - Float(offset) if handle end - + # Fire all timers that are ready. def fire(offset = current_offset) @events.fire(offset) end - + # Pause all timers. def pause @timers.dup.each(&:pause) end - + # Resume all timers. def resume @paused_timers.dup.each(&:resume) end - + alias continue resume - + # Delay all timers. def delay(seconds) @timers.each do |timer| timer.delay(seconds) end end - + # Cancel all timers. def cancel @timers.dup.each(&:cancel) end - + # The group's current time. def current_offset @interval.to_f diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/timers/priority_heap.rb new/lib/timers/priority_heap.rb --- old/lib/timers/priority_heap.rb 1970-01-01 01:00:00.000000000 +0100 +++ new/lib/timers/priority_heap.rb 2021-02-13 07:15:03.000000000 +0100 @@ -0,0 +1,174 @@ +# frozen_string_literal: true + +# Copyright, 2021, by Wander Hillen. +# Copyright, 2021, by Samuel G. D. Williams. <http://www.codeotaku.com> +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +module Timers + # A priority queue implementation using a standard binary minheap. It uses straight comparison + # of its contents to determine priority. This works because a Handle from Timers::Events implements + # the '<' operation by comparing the expiry time. + # See <https://en.wikipedia.org/wiki/Binary_heap> for explanations of the main methods. + class PriorityHeap + def initialize + # The heap is represented with an array containing a binary tree. See + # https://en.wikipedia.org/wiki/Binary_heap#Heap_implementation for how this array + # is built up. + @contents = [] + end + + # Returns the earliest timer or nil if the heap is empty. + def peek + @contents[0] + end + + # Returns the number of elements in the heap + def size + @contents.size + end + + # Returns the earliest timer if the heap is non-empty and removes it from the heap. + # Returns nil if the heap is empty. (and doesn't change the heap in that case) + def pop + # If the heap is empty: + if @contents.empty? + return nil + end + + # If we have only one item, no swapping is required: + if @contents.size == 1 + return @contents.pop + end + + # Take the root of the tree: + value = @contents[0] + + # Remove the last item in the tree: + last = @contents.pop + + # Overwrite the root of the tree with the item: + @contents[0] = last + + # Bubble it down into place: + bubble_down(0) + + # validate! + + return value + end + + # Inserts a new timer into the heap, then rearranges elements until the heap invariant is true again. + def push(element) + # Insert the item at the end of the heap: + @contents.push(element) + + # Bubble it up into position: + bubble_up(@contents.size - 1) + + # validate! + + return self + end + + private + + # Validate the heap invariant. + def validate!(index = 0) + if value = @contents[index] + left_index = index*2 + 1 + if left_value = @contents[left_index] + unless value < left_value + raise "Invalid left index from #{index}!" + end + + validate!(left_index) + end + + right_index = left_index + 1 + if right_value = @contents[right_index] + unless value < right_value + raise "Invalid right index from #{index}!" + end + + validate!(right_index) + end + end + end + + def swap(i, j) + @contents[i], @contents[j] = @contents[j], @contents[i] + end + + def bubble_up(index) + parent_index = (index - 1) / 2 # watch out, integer division! + + while index > 0 && @contents[index] < @contents[parent_index] + # if the node has a smaller value than its parent, swap these nodes + # to uphold the minheap invariant and update the index of the 'current' + # node. If the node is already at index 0, we can also stop because that + # is the root of the heap. + # swap(index, parent_index) + @contents[index], @contents[parent_index] = @contents[parent_index], @contents[index] + + index = parent_index + parent_index = (index - 1) / 2 # watch out, integer division! + end + end + + def bubble_down(index) + swap_value = 0 + swap_index = nil + + while true + left_index = (2 * index) + 1 + left_value = @contents[left_index] + + if left_value.nil? + # This node has no children so it can't bubble down any further. + # We're done here! + return + end + + # Determine which of the child nodes has the smallest value: + right_index = left_index + 1 + right_value = @contents[right_index] + + if right_value.nil? or right_value > left_value + swap_value = left_value + swap_index = left_index + else + swap_value = right_value + swap_index = right_index + end + + if @contents[index] < swap_value + # No need to swap, the minheap invariant is already satisfied: + return + else + # At least one of the child node has a smaller value than the current node, swap current node with that child and update current node for if it might need to bubble down even further: + # swap(index, swap_index) + @contents[index], @contents[swap_index] = @contents[swap_index], @contents[index] + + index = swap_index + end + end + end + end +end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/timers/timer.rb new/lib/timers/timer.rb --- old/lib/timers/timer.rb 2020-09-04 08:35:48.000000000 +0200 +++ new/lib/timers/timer.rb 2021-02-13 07:15:03.000000000 +0100 @@ -29,66 +29,66 @@ class Timer include Comparable attr_reader :interval, :offset, :recurring - + def initialize(group, interval, recurring = false, offset = nil, &block) @group = group - + @interval = interval @recurring = recurring @block = block @offset = offset - + @handle = nil - + # If a start offset was supplied, use that, otherwise use the current timers offset. reset(@offset || @group.current_offset) end - + def paused? @group.paused_timers.include? self end - + def pause return if paused? - + @group.timers.delete self @group.paused_timers.add self - + @handle.cancel! if @handle @handle = nil end - + def resume return unless paused? - + @group.paused_timers.delete self - + # This will add us back to the group: reset end - + alias continue resume - + # Extend this timer def delay(seconds) @handle.cancel! if @handle - + @offset += seconds - + @handle = @group.events.schedule(@offset, self) end - + # Cancel this timer. Do not call while paused. def cancel return unless @handle - + @handle.cancel! if @handle @handle = nil - + # This timer is no longer valid: @group.timers.delete self if @group end - + # Reset this timer. Do not call while paused. # @param offset [Numeric] the duration to add to the timer. def reset(offset = @group.current_offset) @@ -99,12 +99,12 @@ else @group.timers << self end - + @offset = Float(offset) + @interval - + @handle = @group.events.schedule(@offset, self) end - + # Fire the block. def fire(offset = @group.current_offset) if recurring == :strict @@ -115,36 +115,38 @@ else @offset = offset end - + @block.call(offset, self) - + cancel unless recurring end - + alias call fire - + # Number of seconds until next fire / since last fire def fires_in @offset - @group.current_offset if @offset end - + # Inspect a timer def inspect - str = "#{to_s[0..-2]} ".dup - + buffer = "#{to_s[0..-2]} ".dup + if @offset - str << if fires_in >= 0 - "fires in #{fires_in} seconds" - else - "fired #{fires_in.abs} seconds ago" - end - - str << ", recurs every #{interval}" if recurring + if fires_in >= 0 + buffer << "fires in #{fires_in} seconds" + else + buffer << "fired #{fires_in.abs} seconds ago" + end + + buffer << ", recurs every #{interval}" if recurring else - str << "dead" + buffer << "dead" end - - str << ">" + + buffer << ">" + + return buffer end end end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/timers/version.rb new/lib/timers/version.rb --- old/lib/timers/version.rb 2020-09-04 08:35:48.000000000 +0200 +++ new/lib/timers/version.rb 2021-02-13 07:15:03.000000000 +0100 @@ -21,5 +21,5 @@ # THE SOFTWARE. module Timers - VERSION = "4.3.2" + VERSION = "4.3.3" end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/timers/wait.rb new/lib/timers/wait.rb --- old/lib/timers/wait.rb 2020-09-04 08:35:48.000000000 +0200 +++ new/lib/timers/wait.rb 2021-02-13 07:15:03.000000000 +0100 @@ -28,7 +28,7 @@ def self.for(duration, &block) if duration timeout = new(duration) - + timeout.while_time_remaining(&block) else loop do @@ -36,31 +36,31 @@ end end end - + def initialize(duration) @duration = duration @remaining = true end - + attr_reader :duration attr_reader :remaining - + # Yields while time remains for work to be done: def while_time_remaining @interval = Interval.new @interval.start - + yield @remaining while time_remaining? ensure @interval.stop @interval = nil end - + private - + def time_remaining? @remaining = (@duration - @interval.to_f) - + @remaining > 0 end end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/metadata new/metadata --- old/metadata 2020-09-04 08:35:48.000000000 +0200 +++ new/metadata 2021-02-13 07:15:03.000000000 +0100 @@ -1,7 +1,7 @@ --- !ruby/object:Gem::Specification name: timers version: !ruby/object:Gem::Version - version: 4.3.2 + version: 4.3.3 platform: ruby authors: - Samuel Williams @@ -9,7 +9,7 @@ autorequire: bindir: bin cert_chain: [] -date: 2020-09-04 00:00:00.000000000 Z +date: 2021-02-13 00:00:00.000000000 Z dependencies: - !ruby/object:Gem::Dependency name: bundler @@ -63,6 +63,7 @@ - lib/timers/events.rb - lib/timers/group.rb - lib/timers/interval.rb +- lib/timers/priority_heap.rb - lib/timers/timer.rb - lib/timers/version.rb - lib/timers/wait.rb
