File: group.rb

package info (click to toggle)
ruby-timers 4.1.1-2.1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, bullseye, sid, trixie
  • size: 196 kB
  • sloc: ruby: 668; makefile: 7
file content (132 lines) | stat: -rw-r--r-- 3,258 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132

require 'set'
require 'forwardable'
require 'hitimes'

require 'timers/timer'
require 'timers/events'

module Timers
  class Group
    include Enumerable

    extend Forwardable
    def_delegators :@timers, :each, :empty?

    def initialize
      @events = Events.new
      
      @timers = Set.new
      @paused_timers = Set.new
      
      @interval = Hitimes::Interval.new
      @interval.start
    end

    # Scheduled events:
    attr :events
    
    # Active timers:
    attr :timers
    
    # Paused timers:
    attr :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)
      block.call
      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)
      block.call
      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(&block)
      if block_given?
        yield wait_interval
        
        while interval = wait_interval and interval > 0
          yield interval
        end
      else
        while interval = wait_interval and interval > 0
          # We cannot assume that sleep will wait for the specified time, it might be +/- a bit.
          sleep interval
        end
      end

      return fire
    end

    # Interval to wait until when the next timer will fire.
    # - nil: no timers
    # - -ve: timers expired already
    # -   0: timers ready to fire
    # - +ve: timers waiting to fire
    def wait_interval(offset = self.current_offset)
      if handle = @events.first
        return handle.time - Float(offset)
      end
    end

    # Fire all timers that are ready.
    def fire(offset = self.current_offset)
      @events.fire(offset)
    end

    # Pause all timers.
    def pause
      @timers.dup.each do |timer|
        timer.pause
      end
    end

    # Resume all timers.
    def resume
      @paused_timers.dup.each do |timer|
        timer.resume
      end
    end

    alias_method :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 do |timer|
        timer.cancel
      end
    end

    # The group's current time.
    def current_offset
      @interval.to_f
    end
  end
end