reprise 0.1.0-x64-mingw-ucrt

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,299 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Reprise
4
+ class Error < StandardError; end
5
+ class InvalidRangeError < Error; end
6
+
7
+ # The +Reprise::Schedule+ class is the primary interface of the Reprise gem.
8
+ #
9
+ # It offers methods that enable you to:
10
+ # - Initialize a new schedule.
11
+ # - Add recurring series to the schedule via +#repeat_*+ methods.
12
+ # - Mark specific intervals of time as excluded from the schedule via {Reprise::Schedule#add_exclusion} and {Reprise::Schedule#add_exclusions}.
13
+ # - Query for the presence of occurrences within intervals of time via {Reprise::Schedule#occurs_between?}.
14
+ # - Generate an array of all of the schedule's occurrences via {Reprise::Schedule#occurrences}.
15
+ #
16
+ # @private On the interface of this class: all of the methods on +Reprise::Schedule+ could have been
17
+ # transparently delegated to +Reprise::Core::Schedule+, the internal schedule class that is
18
+ # implemented in Rust; instead, we define explicit proxy methods with obvious kwargs duplication,
19
+ # both to make it easier to generate YARD docs and to offer decent autocomplete support in IDEs.
20
+ # For any changes in the implementation of the interface, prefer DevX over DRY and save our
21
+ # sophistication budget for the underlying Rust extension.
22
+ class Schedule
23
+ # All schedules must be constructed with a valid +starts_at+ and +ends_at+ time.
24
+ # Reprise does not support infinitely-recurring schedules, or the bounding
25
+ # of schedules on the basis of a maximum occurrence count.
26
+ #
27
+ # @param starts_at [Time, ActiveSupport::TimeWithZone]
28
+ # The beginning of the schedule; the earliest possible moment for a valid occurrence.
29
+ # If no +time_zone+ is given, the schedule's time zone will be inferred from +starts_at+,
30
+ # defaulting to UTC if it lacks time zone information (e.g. it is a plain +Time+).
31
+ # @param ends_at [Time, ActiveSupport::TimeWithZone]
32
+ # The end of the schedule; the latest possible moment for a valid occurrence.
33
+ # @param time_zone [String]
34
+ # Must be an unambiguous, valid Rails time zone string or IANA time-zone identifier
35
+ # according to +ActiveSupport::TimeZone::find_tzinfo+.
36
+ # See https://github.com/tzinfo/tzinfo/issues/53
37
+ # @raise [Reprise::InvalidTimeZoneError] if the time zone is ambiguous or invalid.
38
+ def initialize(starts_at:, ends_at:, time_zone: nil)
39
+ raise InvalidRangeError, "The end time cannot precede the start time" if ends_at < starts_at
40
+
41
+ @starts_at = starts_at
42
+ @ends_at = ends_at
43
+ @time_zone = TimeZoneIdentifier.new(time_zone:, datetime_source: starts_at).to_s
44
+ @default_time_of_day = TimeOfDay.new(starts_at)
45
+ end
46
+
47
+ # Returns an array of occurrences sorted in order of ascending occurrence start time.
48
+ # This method is not cached; on every call, it will recompute all of the schedule's occurrences.
49
+ # @return [Array<Reprise::Core::Occurrence>]
50
+ def occurrences
51
+ internal_schedule.occurrences
52
+ end
53
+
54
+ # @!macro [new] weekday
55
+ # @param weekday [Symbol] Accepts +:monday+, +:tuesday+, +:wednesday+, +:thursday+, or +:friday+.
56
+
57
+ # @!macro [new] time_of_day
58
+ # @param time_of_day [Hash,Time,nil]
59
+ # Either a local time value from which the hour, minute, and second
60
+ # should be derived, or a hash containing at least one of +hour+, +minute+,
61
+ # or +second+. If +nil+, the time of day will be inferred from the schedule's
62
+ # +starts_at+ value.
63
+ # @option time_of_day [Integer] :hour, >= 0 && <= 23
64
+ # @option time_of_day [Integer] :minute, >= 0 && <= 59
65
+ # @option time_of_day [Integer] :second, >= 0 && <= 59
66
+ # @raise [UnsupportedTypeError] if +time_of_day+ is neither a +Hash+ nor a +Time+.
67
+ # @raise [InvalidHashError] if the hash representation of the time is invalid.
68
+ # @raise [RangeError] if either the hour, minute, or second is out-of-range.
69
+
70
+ # @!macro [new] interval
71
+ # @param interval [Integer]
72
+ # This determines whether or not occurrences should be skipped.
73
+ # A value of +1+ means that every occurrence for the series should be returned;
74
+ # +2+, every other occurrence should be returned, etc.
75
+
76
+ # @!macro [new] recurring_series_start_and_end_times
77
+ # @param starts_at [Time, nil] The time that the series should begin. If left blank,
78
+ # the series will start at the same time as the parent schedule.
79
+ # @param ends_at [Time, nil] The time that the series should end. If left blank,
80
+ # the series will end at the same time as the parent schedule.
81
+
82
+ # @!macro [new] duration_in_seconds
83
+ # @param duration_in_seconds [Integer]
84
+ # This determines the end time of each occurrence ({Reprise::Core::Occurrence#end_time}), and also
85
+ # influences occurrence queries, and whether any added exclusions conflict with any of the schedule's
86
+ # occurrences.
87
+
88
+ # @!macro [new] label
89
+ # @param label [String, nil] An optional label to apply to all of the occurrences
90
+ # that are generated from the series. See {Reprise::Core::Occurrence#label}.
91
+
92
+ # @!macro time_of_day
93
+ # @!macro duration_in_seconds
94
+ # @!macro interval
95
+ # @!macro recurring_series_start_and_end_times
96
+ # @!macro label
97
+ # @return [void]
98
+ def repeat_minutely(time_of_day: nil, duration_in_seconds:, interval: 1, starts_at: nil, ends_at: nil, label: nil)
99
+ internal_schedule.repeat_minutely(
100
+ time_of_day: TimeOfDay.new(time_of_day || self.starts_at).to_h,
101
+ duration_in_seconds:,
102
+ interval:,
103
+ starts_at_unix_timestamp: starts_at.presence&.to_i,
104
+ ends_at_unix_timestamp: ends_at.presence&.to_i,
105
+ label:
106
+ )
107
+ end
108
+
109
+ # @!macro time_of_day
110
+ # @!macro duration_in_seconds
111
+ # @!macro interval
112
+ # @!macro recurring_series_start_and_end_times
113
+ # @!macro label
114
+ # @return [void]
115
+ def repeat_hourly(time_of_day: nil, duration_in_seconds:, interval: 1, starts_at: nil, ends_at: nil, label: nil)
116
+ internal_schedule.repeat_hourly(
117
+ time_of_day: TimeOfDay.new(time_of_day || self.starts_at).to_h,
118
+ duration_in_seconds:,
119
+ interval:,
120
+ starts_at_unix_timestamp: starts_at.presence&.to_i,
121
+ ends_at_unix_timestamp: ends_at.presence&.to_i,
122
+ label:
123
+ )
124
+ end
125
+
126
+ # @!macro time_of_day
127
+ # @!macro duration_in_seconds
128
+ # @!macro interval
129
+ # @!macro recurring_series_start_and_end_times
130
+ # @!macro label
131
+ # @return [void]
132
+ def repeat_daily(time_of_day: nil, duration_in_seconds:, interval: 1, starts_at: nil, ends_at: nil, label: nil)
133
+ internal_schedule.repeat_daily(
134
+ time_of_day: TimeOfDay.new(time_of_day || self.starts_at).to_h,
135
+ duration_in_seconds:,
136
+ interval:,
137
+ starts_at_unix_timestamp: starts_at.presence&.to_i,
138
+ ends_at_unix_timestamp: ends_at.presence&.to_i,
139
+ label:
140
+ )
141
+ end
142
+
143
+ # @!macro weekday
144
+ # @!macro time_of_day
145
+ # @!macro duration_in_seconds
146
+ # @!macro interval
147
+ # @!macro recurring_series_start_and_end_times
148
+ # @!macro label
149
+ # @return [void]
150
+ # @example with a +time_of_day+ hash
151
+ # schedule.repeat_weekly(:monday, time_of_day: { hour: 6 }, duration_in_seconds: 30)
152
+ # @example with a local time for +time_of_day+
153
+ # local_time = Time.current.in_time_zone(my_current_time_zone)
154
+ # schedule.repeat_weekly(:monday, time_of_day: local_time, duration_in_seconds: 30)
155
+ def repeat_weekly(weekday, time_of_day: nil, duration_in_seconds:, interval: 1, starts_at: nil, ends_at: nil, label: nil)
156
+ internal_schedule.repeat_weekly(
157
+ weekday,
158
+ time_of_day: TimeOfDay.new(time_of_day || self.starts_at).to_h,
159
+ duration_in_seconds:,
160
+ interval:,
161
+ starts_at_unix_timestamp: starts_at.presence&.to_i,
162
+ ends_at_unix_timestamp: ends_at.presence&.to_i,
163
+ label:
164
+ )
165
+ end
166
+
167
+ # @param day_number [Integer] The number of the day in the month; >= 1 && <= 31
168
+ # @!macro time_of_day
169
+ # @!macro duration_in_seconds
170
+ # @!macro interval
171
+ # @!macro recurring_series_start_and_end_times
172
+ # @!macro label
173
+ # @return [void]
174
+ # @example
175
+ # schedule.repeat_monthly_by_day(15, time_of_day: { hour: 9 }, duration_in_seconds: 30)
176
+ def repeat_monthly_by_day(day_number, time_of_day:, duration_in_seconds:, interval: 1, starts_at: nil, ends_at: nil, label: nil)
177
+ internal_schedule.repeat_monthly_by_day(
178
+ day_number,
179
+ time_of_day: TimeOfDay.new(time_of_day || self.starts_at).to_h,
180
+ duration_in_seconds:,
181
+ interval:,
182
+ starts_at_unix_timestamp: starts_at.presence&.to_i,
183
+ ends_at_unix_timestamp: ends_at.presence&.to_i,
184
+ label:
185
+ )
186
+ end
187
+
188
+ # @!macro weekday
189
+ # @param nth_day [Integer] The nth weekday, 0-indexed; e.g. 0 might represent the first wednesday
190
+ # @!macro time_of_day
191
+ # @!macro duration_in_seconds
192
+ # @!macro interval
193
+ # @!macro recurring_series_start_and_end_times
194
+ # @!macro label
195
+ # @return [void]
196
+ def repeat_monthly_by_nth_weekday(weekday, nth_day, time_of_day:, duration_in_seconds:, interval: 1, starts_at: nil, ends_at: nil, label: nil)
197
+ internal_schedule.repeat_monthly_by_nth_weekday(
198
+ weekday,
199
+ nth_day,
200
+ time_of_day: TimeOfDay.new(time_of_day || self.starts_at).to_h,
201
+ duration_in_seconds:,
202
+ interval:,
203
+ starts_at_unix_timestamp: starts_at.presence&.to_i,
204
+ ends_at_unix_timestamp: ends_at.presence&.to_i,
205
+ label:
206
+ )
207
+ end
208
+
209
+ # @param day_number [Integer] The number of the day in the year; >= 1 && <= 366
210
+ # @!macro time_of_day
211
+ # @!macro duration_in_seconds
212
+ # @!macro interval
213
+ # @!macro recurring_series_start_and_end_times
214
+ # @!macro label
215
+ # @return [void]
216
+ # @example
217
+ # schedule.repeat_annually_by_day(200, duration_in_seconds: 30)
218
+ def repeat_annually_by_day(day_number, time_of_day:, duration_in_seconds:, interval: 1, starts_at: nil, ends_at: nil, label: nil)
219
+ internal_schedule.repeat_annually_by_day(
220
+ day_number,
221
+ time_of_day: TimeOfDay.new(time_of_day || self.starts_at).to_h,
222
+ duration_in_seconds:,
223
+ interval:,
224
+ starts_at_unix_timestamp: starts_at.presence&.to_i,
225
+ ends_at_unix_timestamp: ends_at.presence&.to_i,
226
+ label:
227
+ )
228
+ end
229
+
230
+ # Add a time interval between which no occurrences are valid.
231
+ # Any occurrences that overlap with an exclusion are removed from the schedule's occurrences.
232
+ # @param starts_at [Time] The time that the exclusion starts at
233
+ # @param ends_at [Time] The time that the exclusion ends at
234
+ def add_exclusion(starts_at:, ends_at:)
235
+ internal_schedule.add_exclusion(
236
+ starts_at_unix_timestamp: starts_at.to_i,
237
+ ends_at_unix_timestamp: ends_at.to_i
238
+ )
239
+ end
240
+
241
+ # Add time intervals between which no occurrences are valid.
242
+ # Any occurrences that overlap with an exclusion are removed from the schedule's occurrences.
243
+ # @param exclusions [Array<Array<Time,Time>>] An array of exclusion arrays, consisting of start
244
+ # and end +Time+ values.
245
+ # @return [void]
246
+ # @example
247
+ # schedule.add_exclusions([
248
+ # [exclusion_1_starts_at, exclusion_1_ends_at],
249
+ # [exclusion_2_starts_at, exclusion_2_ends_at],
250
+ # ])
251
+ def add_exclusions(exclusions)
252
+ internal_schedule.add_exclusions(
253
+ exclusions.map {|e| e.map(&:to_i) }
254
+ )
255
+ end
256
+
257
+ # @!macro [new] include_overlapping
258
+ # @param include_overlapping [Boolean] when true, the query will also consider
259
+ # occurrences that partially overlap with the given interval, not just the occurrences
260
+ # that are entirely contained within the interval.
261
+
262
+ # Indicates whether one or more of your schedule's occurrences fall within the given interval.
263
+ # @param starts_at [Time] The start of the interval to query
264
+ # @param ends_at [Time] The end of the interval to query
265
+ # @!macro include_overlapping
266
+ # @return [Boolean]
267
+ def occurs_between?(starts_at, ends_at, include_overlapping: false)
268
+ occurrences_between(starts_at, ends_at, include_overlapping:).any?
269
+ end
270
+
271
+ # This method efficiently queries your schedule for occurrences that fall within a given interval.
272
+ # @param starts_at [Time] The start of the interval to query
273
+ # @param ends_at [Time] The end of the interval to query
274
+ # @!macro include_overlapping
275
+ # @return [Array<Reprise::Core::Occurrence>] an array of occurrences that occur between
276
+ # the given +starts_at+ and +ends_at+ bookends.
277
+ def occurrences_between(starts_at, ends_at, include_overlapping: false)
278
+ if include_overlapping
279
+ internal_schedule.occurrences_overlapping_with_interval(starts_at.to_i, ends_at.to_i)
280
+ else
281
+ internal_schedule.occurrences_contained_within_interval(starts_at.to_i, ends_at.to_i)
282
+ end
283
+ end
284
+
285
+ private
286
+
287
+ attr_reader :starts_at, :ends_at, :time_zone, :default_time_of_day
288
+
289
+ def internal_schedule
290
+ return @_internal_schedule if defined?(@_internal_schedule)
291
+
292
+ @_internal_schedule = ::Reprise::Core::Schedule.new(
293
+ starts_at.to_i,
294
+ ends_at.to_i,
295
+ time_zone
296
+ )
297
+ end
298
+ end
299
+ end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support"
4
+ require "active_support/core_ext"
5
+
6
+ module Reprise
7
+ # @api private
8
+ class TimeOfDay
9
+ class UnsupportedTypeError < Reprise::Error; end
10
+ class InvalidHashError < Reprise::Error; end
11
+ class RangeError < Reprise::Error; end
12
+
13
+ DEFAULT_TIME_OF_DAY = { hour: 0, minute: 0, second: 0 }.freeze
14
+ TIME_OF_DAY_ATTRIBUTES = DEFAULT_TIME_OF_DAY.keys.freeze
15
+ attr_accessor(*TIME_OF_DAY_ATTRIBUTES)
16
+
17
+ # @param [Time, Hash] time_of_day
18
+ # Accepts either a local time value from which the hour, minute, and second
19
+ # should be derived, or a hash containing at least one of +hour+, +minute+,
20
+ # or +second+.
21
+ # @option time_of_day [Integer] :hour, >= 0 && <= 23
22
+ # @option time_of_day [Integer] :minute, >= 0 && <= 59
23
+ # @option time_of_day [Integer] :second, >= 0 && <= 59
24
+ # @example
25
+ # { hour: 1, minute: 30, second: 15 }
26
+ # @raise [UnsupportedTypeError] if +time_of_day+ is neither a +Hash+ nor a +Time+.
27
+ # @raise [InvalidHashError] if the hash representation of the time is invalid.
28
+ # @raise [RangeError] if either the hour, minute, or second is out-of-range.
29
+ def initialize(time_of_day)
30
+ return initialize_from_hash(time_of_day) if time_of_day.is_a?(Hash)
31
+ return initialize_from_time(time_of_day) if time_of_day.is_a?(Time)
32
+
33
+ raise UnsupportedTypeError, "#{time_of_day.class} is not a supported type"
34
+ end
35
+
36
+ # @return [Hash]
37
+ # @example
38
+ # { hour: 1, minute: 30, second: 15 }
39
+ def to_h
40
+ {
41
+ hour:,
42
+ minute:,
43
+ second:
44
+ }
45
+ end
46
+
47
+ private
48
+
49
+ # @private
50
+ def initialize_from_time(time)
51
+ self.hour = time.hour
52
+ self.minute = time.min
53
+ self.second = time.sec
54
+ end
55
+
56
+ # @private
57
+ def initialize_from_hash(hms_opts)
58
+ raise InvalidHashError if (hms_opts.keys - TIME_OF_DAY_ATTRIBUTES).any?
59
+
60
+ DEFAULT_TIME_OF_DAY.merge(hms_opts).slice(*TIME_OF_DAY_ATTRIBUTES).each do |key, value|
61
+ public_send("#{key}=", value)
62
+ end
63
+
64
+ validate_time_of_day
65
+ end
66
+
67
+ def validate_time_of_day
68
+ return if (hour >= 0 && hour <= 23) &&
69
+ (minute >= 0 && minute <= 59) &&
70
+ (second >= 0 && second <= 59)
71
+
72
+ raise RangeError, "The time of day is out of range (#{to_h})"
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support"
4
+ require "active_support/core_ext"
5
+
6
+ module Reprise
7
+ class InvalidTimeZoneError < Reprise::Error; end
8
+
9
+ # @api private
10
+ class TimeZoneIdentifier
11
+ # https://github.com/rails/rails/blob/19eebf6d33dd15a0172e3ed2481bec57a89a2404/activesupport/lib/active_support/values/time_zone.rb#L76
12
+ UTC_TIME_ZONE_IDENTIFIER = "Etc/UTC"
13
+
14
+ # @param time_zone [String]
15
+ # Must be an unambiguous, valid Rails time zone string or IANA time-zone identifier
16
+ # according to +ActiveSupport::TimeZone::find_tzinfo+.
17
+ # See https://github.com/tzinfo/tzinfo/issues/53
18
+ # @param datetime_source [Time, ActiveSupport::TimeWithZone]
19
+ # A time value from which the time zone will be inferred.
20
+ # Only considered if no explicit +time_zone+ option is given.
21
+ def initialize(time_zone: nil, datetime_source:)
22
+ @time_zone = time_zone
23
+ @datetime_source = datetime_source
24
+ end
25
+
26
+ # Defaults to UTC if no time zone is passed and the datetime source lacks time zone information.
27
+ # @return [String] IANA Time Zone Database identifier
28
+ # @raise [Reprise::InvalidTimeZoneError] if the time zone is ambiguous or invalid.
29
+ def to_s
30
+ return ActiveSupport::TimeZone.find_tzinfo(time_zone).identifier if time_zone
31
+ return datetime_source.time_zone.tzinfo.identifier if datetime_source.is_a?(ActiveSupport::TimeWithZone)
32
+
33
+ UTC_TIME_ZONE_IDENTIFIER
34
+ rescue TZInfo::InvalidTimezoneIdentifier
35
+ raise InvalidTimeZoneError, invalid_time_zone_identifier_error
36
+ end
37
+
38
+ private
39
+
40
+ attr_reader :time_zone, :datetime_source
41
+
42
+ def invalid_time_zone_identifier_error
43
+ <<~ERROR
44
+ "#{time_zone}" is not a valid, unambiguous IANA Time Zone Database identifier.
45
+ For more information, see:
46
+ - https://github.com/tzinfo/tzinfo/issues/53
47
+ - https://github.com/rails/rails/blob/19eebf6d33dd15a0172e3ed2481bec57a89a2404/activesupport/lib/active_support/values/time_zone.rb#L33-L185
48
+ ERROR
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Reprise
4
+ VERSION = "0.1.0"
5
+ end
data/lib/reprise.rb ADDED
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support"
4
+ require "active_support/core_ext/integer/time"
5
+ require "active_support/core_ext/time"
6
+ require "reprise/reprise"
7
+ require "reprise/schedule"
8
+ require "reprise/time_of_day"
9
+ require "reprise/time_zone_identifier"
10
+ require "reprise/version"
metadata ADDED
@@ -0,0 +1,251 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: reprise
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: x64-mingw-ucrt
6
+ authors:
7
+ - Jordan Hiltunen
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2024-07-20 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: benchmark-ips
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: benchmark-memory
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: ice_cube
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: memory_profiler
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: montrose
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rake
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '13.2'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '13.2'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rake-compiler
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: 1.2.0
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: 1.2.0
125
+ - !ruby/object:Gem::Dependency
126
+ name: redcarpet
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: rspec
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: '3.0'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - "~>"
151
+ - !ruby/object:Gem::Version
152
+ version: '3.0'
153
+ - !ruby/object:Gem::Dependency
154
+ name: rubocop
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ">="
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
167
+ - !ruby/object:Gem::Dependency
168
+ name: yard
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - ">="
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ type: :development
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - ">="
179
+ - !ruby/object:Gem::Version
180
+ version: '0'
181
+ - !ruby/object:Gem::Dependency
182
+ name: activesupport
183
+ requirement: !ruby/object:Gem::Requirement
184
+ requirements:
185
+ - - ">="
186
+ - !ruby/object:Gem::Version
187
+ version: 7.0.0
188
+ type: :runtime
189
+ prerelease: false
190
+ version_requirements: !ruby/object:Gem::Requirement
191
+ requirements:
192
+ - - ">="
193
+ - !ruby/object:Gem::Version
194
+ version: 7.0.0
195
+ force_ruby_platform: false
196
+ description: Generates date & time events from recurrence rules to support various
197
+ calendar and scheduling use cases, with an emphasis on speed; the core of the Reprise
198
+ gem is implemented as a Rust extension to enable its use for performance-sensitive
199
+ workloads.
200
+ email:
201
+ - oss@jordanhiltunen.com
202
+ executables: []
203
+ extensions: []
204
+ extra_rdoc_files: []
205
+ files:
206
+ - Cargo.lock
207
+ - Cargo.toml
208
+ - LICENSE.txt
209
+ - README.md
210
+ - Rakefile
211
+ - lib/reprise.rb
212
+ - lib/reprise/3.1/reprise.so
213
+ - lib/reprise/3.2/reprise.so
214
+ - lib/reprise/3.3/reprise.so
215
+ - lib/reprise/core/occurrence.rb
216
+ - lib/reprise/schedule.rb
217
+ - lib/reprise/time_of_day.rb
218
+ - lib/reprise/time_zone_identifier.rb
219
+ - lib/reprise/version.rb
220
+ homepage: https://github.com/jordanhiltunen/reprise
221
+ licenses:
222
+ - MIT
223
+ metadata:
224
+ allowed_push_host: https://rubygems.org
225
+ homepage_uri: https://github.com/jordanhiltunen/reprise
226
+ source_code_uri: https://github.com/jordanhiltunen/reprise
227
+ changelog_uri: https://github.com/jordanhiltunen/reprise/blob/main/CHANGELOG.md
228
+ rubygems_mfa_required: 'true'
229
+ post_install_message:
230
+ rdoc_options: []
231
+ require_paths:
232
+ - lib
233
+ required_ruby_version: !ruby/object:Gem::Requirement
234
+ requirements:
235
+ - - ">="
236
+ - !ruby/object:Gem::Version
237
+ version: '3.1'
238
+ - - "<"
239
+ - !ruby/object:Gem::Version
240
+ version: 3.4.dev
241
+ required_rubygems_version: !ruby/object:Gem::Requirement
242
+ requirements:
243
+ - - ">="
244
+ - !ruby/object:Gem::Version
245
+ version: '0'
246
+ requirements: []
247
+ rubygems_version: 3.4.4
248
+ signing_key:
249
+ specification_version: 4
250
+ summary: Fast recurring event generation for Ruby.
251
+ test_files: []