File: group.rb

package info (click to toggle)
ruby-timers 4.4.0-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 216 kB
  • sloc: ruby: 973; makefile: 6
file content (134 lines) | stat: -rw-r--r-- 3,212 bytes parent folder | download
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
133
134
# frozen_string_literal: true

# Released under the MIT License.
# Copyright, 2014-2025, by Samuel Williams.
# Copyright, 2014-2016, by Tony Arcieri.
# Copyright, 2015, by Donovan Keme.
# Copyright, 2015, by Tommy Ong Gia Phu.

require "set"
require "forwardable"

require_relative "interval"
require_relative "timer"
require_relative "events"

module Timers
	# 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
			else
				while (interval = wait_interval) && interval > 0
					# We cannot assume that sleep will wait for the specified time, it might be +/- a bit.
					sleep interval
				end
			end
			
			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 = current_offset)
			if handle = @events.first
				handle.time - Float(offset)
			end
		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
		end
	end
end