montrose 0.12.0 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.circleci/config.yml +24 -32
- data/.gitignore +0 -3
- data/.rubocop.yml +5 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +24 -0
- data/Gemfile +4 -9
- data/Gemfile.lock +148 -0
- data/README.md +20 -22
- data/bin/bundle-all +5 -0
- data/gemfiles/activesupport_5.2.gemfile +1 -12
- data/gemfiles/activesupport_5.2.gemfile.lock +107 -0
- data/gemfiles/activesupport_6.0.gemfile +1 -12
- data/gemfiles/activesupport_6.0.gemfile.lock +108 -0
- data/gemfiles/activesupport_6.1.gemfile +1 -12
- data/gemfiles/activesupport_6.1.gemfile.lock +108 -0
- data/gemfiles/activesupport_7.0.gemfile +5 -0
- data/gemfiles/activesupport_7.0.gemfile.lock +106 -0
- data/lib/montrose/chainable.rb +0 -1
- data/lib/montrose/clock.rb +54 -9
- data/lib/montrose/day.rb +83 -0
- data/lib/montrose/frequency.rb +60 -27
- data/lib/montrose/hour.rb +22 -0
- data/lib/montrose/ical.rb +128 -0
- data/lib/montrose/minute.rb +22 -0
- data/lib/montrose/month.rb +47 -0
- data/lib/montrose/month_day.rb +25 -0
- data/lib/montrose/options.rb +56 -65
- data/lib/montrose/recurrence.rb +18 -12
- data/lib/montrose/rule/during.rb +7 -15
- data/lib/montrose/rule/minute_of_hour.rb +25 -0
- data/lib/montrose/rule/nth_day_of_month.rb +0 -2
- data/lib/montrose/rule/nth_day_of_year.rb +0 -2
- data/lib/montrose/rule/time_of_day.rb +1 -1
- data/lib/montrose/rule.rb +18 -16
- data/lib/montrose/schedule.rb +7 -7
- data/lib/montrose/stack.rb +1 -2
- data/lib/montrose/time_of_day.rb +48 -0
- data/lib/montrose/utils.rb +0 -38
- data/lib/montrose/version.rb +1 -1
- data/lib/montrose/week.rb +20 -0
- data/lib/montrose/year_day.rb +25 -0
- data/lib/montrose.rb +20 -8
- data/montrose.gemspec +4 -3
- metadata +42 -11
- data/Appraisals +0 -13
- data/bin/appraisal +0 -17
@@ -0,0 +1,47 @@
|
|
1
|
+
module Montrose
|
2
|
+
class Month
|
3
|
+
extend Montrose::Utils
|
4
|
+
|
5
|
+
NAMES = ::Date::MONTHNAMES # starts with nil to match 1-12 numbering
|
6
|
+
NUMBERS = NAMES.map.with_index { |_n, i| i.to_s }.slice(1, 12)
|
7
|
+
|
8
|
+
class << self
|
9
|
+
def parse(value)
|
10
|
+
case value
|
11
|
+
when String
|
12
|
+
parse(value.split(",").compact)
|
13
|
+
when Array
|
14
|
+
value.map { |m|
|
15
|
+
Montrose::Month.number!(m)
|
16
|
+
}.presence
|
17
|
+
else
|
18
|
+
parse(Array(value))
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def names
|
23
|
+
NAMES
|
24
|
+
end
|
25
|
+
|
26
|
+
def numbers
|
27
|
+
NUMBERS
|
28
|
+
end
|
29
|
+
|
30
|
+
def number(name)
|
31
|
+
case name
|
32
|
+
when Symbol, String
|
33
|
+
string = name.to_s
|
34
|
+
NAMES.index(string.titleize) || number(to_index(string))
|
35
|
+
when 1..12
|
36
|
+
name
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def number!(name)
|
41
|
+
numbers = NAMES.map.with_index { |_n, i| i.to_s }.slice(1, 12)
|
42
|
+
number(name) || raise(ConfigurationError,
|
43
|
+
"Did not recognize month #{name}, must be one of #{(NAMES + numbers).inspect}")
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Montrose
|
2
|
+
class MonthDay
|
3
|
+
class << self
|
4
|
+
MDAYS = (-31.upto(-1).to_a + 1.upto(31).to_a)
|
5
|
+
|
6
|
+
def parse(mdays)
|
7
|
+
return nil unless mdays.present?
|
8
|
+
|
9
|
+
case mdays
|
10
|
+
when String
|
11
|
+
parse(mdays.split(","))
|
12
|
+
else
|
13
|
+
Array(mdays).map { |d| assert(d.to_i) }
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def assert(number)
|
18
|
+
test = number.abs
|
19
|
+
raise ConfigurationError, "Out of range: #{MDAYS.inspect} does not include #{test}" unless MDAYS.include?(number.abs)
|
20
|
+
|
21
|
+
number
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/montrose/options.rb
CHANGED
@@ -88,11 +88,13 @@ module Montrose
|
|
88
88
|
def_option :between
|
89
89
|
def_option :covering
|
90
90
|
def_option :during
|
91
|
+
def_option :minute
|
91
92
|
def_option :hour
|
92
93
|
def_option :day
|
93
94
|
def_option :mday
|
94
95
|
def_option :yday
|
95
96
|
def_option :week
|
97
|
+
def_option :week_start
|
96
98
|
def_option :month
|
97
99
|
def_option :interval
|
98
100
|
def_option :total
|
@@ -113,6 +115,7 @@ module Montrose
|
|
113
115
|
week: nil,
|
114
116
|
month: nil,
|
115
117
|
total: nil,
|
118
|
+
week_start: nil,
|
116
119
|
exclude_end: nil
|
117
120
|
}
|
118
121
|
|
@@ -149,7 +152,7 @@ module Montrose
|
|
149
152
|
found = send(key)
|
150
153
|
return found if found
|
151
154
|
return args.first if args.length == 1
|
152
|
-
raise "Key #{key.inspect} not found" unless
|
155
|
+
raise KeyError, "Key #{key.inspect} not found" unless block_given?
|
153
156
|
|
154
157
|
yield
|
155
158
|
end
|
@@ -177,37 +180,46 @@ module Montrose
|
|
177
180
|
@until = normalize_time(as_time(time)) || default_until
|
178
181
|
end
|
179
182
|
|
183
|
+
def minute=(minutes)
|
184
|
+
@minute = Minute.parse(minutes)
|
185
|
+
end
|
186
|
+
|
180
187
|
def hour=(hours)
|
181
188
|
@hour = map_arg(hours) { |h| assert_hour(h) }
|
182
189
|
end
|
183
190
|
|
184
|
-
def during=(
|
185
|
-
@during =
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
+
def during=(during_arg)
|
192
|
+
@during = decompose_during_arg(during_arg)
|
193
|
+
.each_with_object([]) { |(time_of_day_first, time_of_day_last), all|
|
194
|
+
if time_of_day_last < time_of_day_first
|
195
|
+
all.push(
|
196
|
+
[time_of_day_first.parts, end_of_day.parts],
|
197
|
+
[beginning_of_day.parts, time_of_day_last.parts]
|
198
|
+
)
|
199
|
+
else
|
200
|
+
all.push([time_of_day_first.parts, time_of_day_last.parts])
|
201
|
+
end
|
202
|
+
}.presence
|
191
203
|
end
|
192
204
|
|
193
205
|
def day=(days)
|
194
|
-
@day =
|
206
|
+
@day = Day.parse(days)
|
195
207
|
end
|
196
208
|
|
197
209
|
def mday=(mdays)
|
198
|
-
@mday =
|
210
|
+
@mday = MonthDay.parse(mdays)
|
199
211
|
end
|
200
212
|
|
201
213
|
def yday=(ydays)
|
202
|
-
@yday =
|
214
|
+
@yday = YearDay.parse(ydays)
|
203
215
|
end
|
204
216
|
|
205
217
|
def week=(weeks)
|
206
|
-
@week =
|
218
|
+
@week = Week.parse(weeks)
|
207
219
|
end
|
208
220
|
|
209
221
|
def month=(months)
|
210
|
-
@month =
|
222
|
+
@month = Month.parse(months)
|
211
223
|
end
|
212
224
|
|
213
225
|
def between=(range)
|
@@ -219,7 +231,7 @@ module Montrose
|
|
219
231
|
end
|
220
232
|
|
221
233
|
def at=(time)
|
222
|
-
@at = map_arg(time) { |t|
|
234
|
+
@at = map_arg(time) { |t| time_of_day_parse(t).parts }
|
223
235
|
end
|
224
236
|
|
225
237
|
def on=(arg)
|
@@ -260,51 +272,16 @@ module Montrose
|
|
260
272
|
self.class.default_until
|
261
273
|
end
|
262
274
|
|
263
|
-
def nested_map_arg(arg, &block)
|
264
|
-
case arg
|
265
|
-
when Hash
|
266
|
-
arg.each_with_object({}) do |(k, v), hash|
|
267
|
-
hash[yield k] = [*v]
|
268
|
-
end
|
269
|
-
else
|
270
|
-
map_arg(arg, &block)
|
271
|
-
end
|
272
|
-
end
|
273
|
-
|
274
275
|
def map_arg(arg, &block)
|
275
276
|
return nil unless arg
|
276
277
|
|
277
278
|
Array(arg).map(&block)
|
278
279
|
end
|
279
280
|
|
280
|
-
def map_days(arg)
|
281
|
-
map_arg(arg) { |d| day_number!(d) }
|
282
|
-
end
|
283
|
-
|
284
|
-
def map_mdays(arg)
|
285
|
-
map_arg(arg) { |d| assert_mday(d) }
|
286
|
-
end
|
287
|
-
|
288
|
-
def map_ydays(arg)
|
289
|
-
map_arg(arg) { |d| assert_yday(d) }
|
290
|
-
end
|
291
|
-
|
292
281
|
def assert_hour(hour)
|
293
282
|
assert_range_includes(1..::Montrose::Utils::MAX_HOURS_IN_DAY, hour)
|
294
283
|
end
|
295
284
|
|
296
|
-
def assert_mday(mday)
|
297
|
-
assert_range_includes(1..::Montrose::Utils::MAX_DAYS_IN_MONTH, mday, :absolute)
|
298
|
-
end
|
299
|
-
|
300
|
-
def assert_yday(yday)
|
301
|
-
assert_range_includes(1..::Montrose::Utils::MAX_DAYS_IN_YEAR, yday, :absolute)
|
302
|
-
end
|
303
|
-
|
304
|
-
def assert_week(week)
|
305
|
-
assert_range_includes(1..::Montrose::Utils::MAX_WEEKS_IN_YEAR, week, :absolute)
|
306
|
-
end
|
307
|
-
|
308
285
|
def decompose_on_arg(arg)
|
309
286
|
case arg
|
310
287
|
when Hash
|
@@ -312,18 +289,18 @@ module Montrose
|
|
312
289
|
key, val = month_or_day(k)
|
313
290
|
result[key] = val
|
314
291
|
result[:mday] ||= []
|
315
|
-
result[:mday] +=
|
292
|
+
result[:mday] += Montrose::MonthDay.parse(v)
|
316
293
|
end
|
317
294
|
else
|
318
|
-
{day:
|
295
|
+
{day: Montrose::Day.parse(arg)}
|
319
296
|
end
|
320
297
|
end
|
321
298
|
|
322
299
|
def month_or_day(key)
|
323
|
-
month =
|
300
|
+
month = Montrose::Month.number(key)
|
324
301
|
return [:month, month] if month
|
325
302
|
|
326
|
-
day =
|
303
|
+
day = Montrose::Day.number(key)
|
327
304
|
return [:day, day] if day
|
328
305
|
|
329
306
|
raise ConfigurationError, "Did not recognize #{key} as a month or day"
|
@@ -336,13 +313,6 @@ module Montrose
|
|
336
313
|
item
|
337
314
|
end
|
338
315
|
|
339
|
-
def as_time_parts(arg)
|
340
|
-
return arg if arg.is_a?(Array)
|
341
|
-
|
342
|
-
time = as_time(arg)
|
343
|
-
[time.hour, time.min, time.sec]
|
344
|
-
end
|
345
|
-
|
346
316
|
def parse_frequency(input)
|
347
317
|
if input.respond_to?(:parts)
|
348
318
|
frequency, interval = duration_to_frequency_parts(input)
|
@@ -369,15 +339,36 @@ module Montrose
|
|
369
339
|
duration.parts.first
|
370
340
|
end
|
371
341
|
|
372
|
-
def decompose_during_arg(
|
373
|
-
case
|
342
|
+
def decompose_during_arg(during_arg)
|
343
|
+
case during_arg
|
374
344
|
when Range
|
375
|
-
[
|
345
|
+
[decompose_during_parts(during_arg)]
|
346
|
+
else
|
347
|
+
map_arg(during_arg) { |d| decompose_during_parts(d) } || []
|
348
|
+
end
|
349
|
+
end
|
350
|
+
|
351
|
+
def decompose_during_parts(during_parts)
|
352
|
+
case during_parts
|
353
|
+
when Range
|
354
|
+
decompose_during_parts([during_parts.first, during_parts.last])
|
376
355
|
when String
|
377
|
-
|
356
|
+
decompose_during_parts(during_parts.split(/[-—–]/))
|
378
357
|
else
|
379
|
-
|
358
|
+
during_parts.map { |parts| time_of_day_parse(parts) }
|
380
359
|
end
|
381
360
|
end
|
361
|
+
|
362
|
+
def time_of_day_parse(time_parts)
|
363
|
+
::Montrose::TimeOfDay.parse(time_parts)
|
364
|
+
end
|
365
|
+
|
366
|
+
def end_of_day
|
367
|
+
@end_of_day ||= time_of_day_parse(Time.now.end_of_day)
|
368
|
+
end
|
369
|
+
|
370
|
+
def beginning_of_day
|
371
|
+
@beginning_of_day ||= time_of_day_parse(Time.now.beginning_of_day)
|
372
|
+
end
|
382
373
|
end
|
383
374
|
end
|
data/lib/montrose/recurrence.rb
CHANGED
@@ -2,10 +2,6 @@
|
|
2
2
|
|
3
3
|
require "json"
|
4
4
|
require "yaml"
|
5
|
-
require "montrose/chainable"
|
6
|
-
require "montrose/errors"
|
7
|
-
require "montrose/stack"
|
8
|
-
require "montrose/clock"
|
9
5
|
|
10
6
|
module Montrose
|
11
7
|
# Represents the rules for a set of recurring events. Can be instantiated
|
@@ -231,13 +227,13 @@ module Montrose
|
|
231
227
|
return dump(load(obj)) if obj.is_a?(String)
|
232
228
|
|
233
229
|
hash = case obj
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
230
|
+
when Hash
|
231
|
+
obj
|
232
|
+
when self
|
233
|
+
obj.to_hash
|
234
|
+
else
|
235
|
+
fail SerializationError,
|
236
|
+
"Object was supposed to be a #{self}, but was a #{obj.class}. -- #{obj.inspect}"
|
241
237
|
end
|
242
238
|
|
243
239
|
JSON.dump(hash)
|
@@ -250,6 +246,16 @@ module Montrose
|
|
250
246
|
rescue JSON::ParserError => e
|
251
247
|
fail SerializationError, "Could not parse JSON: #{e}"
|
252
248
|
end
|
249
|
+
|
250
|
+
alias_method :from_json, :load
|
251
|
+
|
252
|
+
def from_yaml(yaml)
|
253
|
+
new(YAML.safe_load(yaml))
|
254
|
+
end
|
255
|
+
|
256
|
+
def from_ical(ical)
|
257
|
+
new(Montrose::ICal.parse(ical))
|
258
|
+
end
|
253
259
|
end
|
254
260
|
|
255
261
|
def initialize(opts = {})
|
@@ -331,7 +337,7 @@ module Montrose
|
|
331
337
|
# @return [String] YAML-formatted recurrence options
|
332
338
|
#
|
333
339
|
def to_yaml(*args)
|
334
|
-
YAML.dump(
|
340
|
+
YAML.dump(as_json(*args))
|
335
341
|
end
|
336
342
|
|
337
343
|
def inspect
|
data/lib/montrose/rule/during.rb
CHANGED
@@ -21,22 +21,10 @@ module Montrose
|
|
21
21
|
@during.any? { |range| range.include?(time) }
|
22
22
|
end
|
23
23
|
|
24
|
-
class TimeOfDay
|
25
|
-
def initialize(hour, min, sec)
|
26
|
-
@hour = hour
|
27
|
-
@min = min
|
28
|
-
@sec = sec
|
29
|
-
end
|
30
|
-
|
31
|
-
def seconds_since_midnight
|
32
|
-
@seconds_since_midnight ||= (@hour * 60 * 60) + (@min * 60) + @sec
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
24
|
class TimeOfDayRange
|
37
25
|
def initialize(first, last, exclude_end: false)
|
38
|
-
@first = TimeOfDay.new(
|
39
|
-
@last = TimeOfDay.new(
|
26
|
+
@first = ::Montrose::TimeOfDay.new(first)
|
27
|
+
@last = ::Montrose::TimeOfDay.new(last)
|
40
28
|
@exclude_end = exclude_end
|
41
29
|
end
|
42
30
|
|
@@ -47,7 +35,11 @@ module Montrose
|
|
47
35
|
private
|
48
36
|
|
49
37
|
def range
|
50
|
-
@range ||= Range.new(
|
38
|
+
@range ||= Range.new(
|
39
|
+
@first.seconds_since_midnight,
|
40
|
+
@last.seconds_since_midnight,
|
41
|
+
@exclude_end
|
42
|
+
)
|
51
43
|
end
|
52
44
|
end
|
53
45
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Montrose
|
4
|
+
module Rule
|
5
|
+
class MinuteOfHour
|
6
|
+
include Montrose::Rule
|
7
|
+
|
8
|
+
def self.apply_options(opts)
|
9
|
+
opts[:minute]
|
10
|
+
end
|
11
|
+
|
12
|
+
# Initializes rule
|
13
|
+
#
|
14
|
+
# @param minutes [Array<Fixnum>] valid minutes of hour, e.g. [0, 20, 59]
|
15
|
+
#
|
16
|
+
def initialize(minutes)
|
17
|
+
@minutes = minutes
|
18
|
+
end
|
19
|
+
|
20
|
+
def include?(time)
|
21
|
+
@minutes.include?(time.min)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/montrose/rule.rb
CHANGED
@@ -3,6 +3,24 @@
|
|
3
3
|
module Montrose
|
4
4
|
# Defines the Rule duck type for recurrence rules
|
5
5
|
module Rule
|
6
|
+
autoload :After, "montrose/rule/after"
|
7
|
+
autoload :Covering, "montrose/rule/covering"
|
8
|
+
autoload :DayOfMonth, "montrose/rule/day_of_month"
|
9
|
+
autoload :DayOfWeek, "montrose/rule/day_of_week"
|
10
|
+
autoload :DayOfYear, "montrose/rule/day_of_year"
|
11
|
+
autoload :During, "montrose/rule/during"
|
12
|
+
autoload :Except, "montrose/rule/except"
|
13
|
+
autoload :HourOfDay, "montrose/rule/hour_of_day"
|
14
|
+
autoload :MinuteOfHour, "montrose/rule/minute_of_hour"
|
15
|
+
autoload :MonthOfYear, "montrose/rule/month_of_year"
|
16
|
+
autoload :NthDayMatcher, "montrose/rule/nth_day_matcher"
|
17
|
+
autoload :NthDayOfMonth, "montrose/rule/nth_day_of_month"
|
18
|
+
autoload :NthDayOfYear, "montrose/rule/nth_day_of_year"
|
19
|
+
autoload :TimeOfDay, "montrose/rule/time_of_day"
|
20
|
+
autoload :Total, "montrose/rule/total"
|
21
|
+
autoload :Until, "montrose/rule/until"
|
22
|
+
autoload :WeekOfYear, "montrose/rule/week_of_year"
|
23
|
+
|
6
24
|
def self.included(base)
|
7
25
|
base.extend ClassMethods
|
8
26
|
end
|
@@ -34,19 +52,3 @@ module Montrose
|
|
34
52
|
end
|
35
53
|
end
|
36
54
|
end
|
37
|
-
|
38
|
-
require "montrose/rule/after"
|
39
|
-
require "montrose/rule/covering"
|
40
|
-
require "montrose/rule/day_of_month"
|
41
|
-
require "montrose/rule/day_of_week"
|
42
|
-
require "montrose/rule/day_of_year"
|
43
|
-
require "montrose/rule/during"
|
44
|
-
require "montrose/rule/except"
|
45
|
-
require "montrose/rule/hour_of_day"
|
46
|
-
require "montrose/rule/month_of_year"
|
47
|
-
require "montrose/rule/nth_day_of_month"
|
48
|
-
require "montrose/rule/nth_day_of_year"
|
49
|
-
require "montrose/rule/time_of_day"
|
50
|
-
require "montrose/rule/total"
|
51
|
-
require "montrose/rule/until"
|
52
|
-
require "montrose/rule/week_of_year"
|
data/lib/montrose/schedule.rb
CHANGED
@@ -35,13 +35,13 @@ module Montrose
|
|
35
35
|
return dump(load(obj)) if obj.is_a?(String)
|
36
36
|
|
37
37
|
array = case obj
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
38
|
+
when Array
|
39
|
+
new(obj).to_a
|
40
|
+
when self
|
41
|
+
obj.to_a
|
42
|
+
else
|
43
|
+
fail SerializationError,
|
44
|
+
"Object was supposed to be a #{self}, but was a #{obj.class}. -- #{obj.inspect}"
|
45
45
|
end
|
46
46
|
|
47
47
|
JSON.dump(array)
|
data/lib/montrose/stack.rb
CHANGED
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "montrose/rule"
|
4
|
-
|
5
3
|
module Montrose
|
6
4
|
# Maintains stack of recurrences rules that apply to
|
7
5
|
# an associated recurrence; manages advancing state
|
@@ -18,6 +16,7 @@ module Montrose
|
|
18
16
|
Rule::Except,
|
19
17
|
Rule::Total,
|
20
18
|
Rule::TimeOfDay,
|
19
|
+
Rule::MinuteOfHour,
|
21
20
|
Rule::HourOfDay,
|
22
21
|
Rule::NthDayOfMonth,
|
23
22
|
Rule::NthDayOfYear,
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Montrose
|
2
|
+
class TimeOfDay
|
3
|
+
include Comparable
|
4
|
+
|
5
|
+
attr_reader :parts, :hour, :min, :sec
|
6
|
+
|
7
|
+
def self.parse(arg)
|
8
|
+
return new(arg) if arg.is_a?(Array)
|
9
|
+
|
10
|
+
from_time(::Montrose::Utils.as_time(arg))
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.from_time(time)
|
14
|
+
new(to_parts(time))
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.to_parts(time)
|
18
|
+
[time.hour, time.min, time.sec]
|
19
|
+
end
|
20
|
+
|
21
|
+
def initialize(parts)
|
22
|
+
@parts = parts
|
23
|
+
@hour, @min, @sec = *parts
|
24
|
+
end
|
25
|
+
|
26
|
+
def seconds_since_midnight
|
27
|
+
@seconds_since_midnight ||= (@hour * 60 * 60) + (@min * 60) + @sec
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_a
|
31
|
+
@parts
|
32
|
+
end
|
33
|
+
|
34
|
+
# def inspect
|
35
|
+
# "#<Montrose::TimeOfDay #{format_time(@hour)}:#{format_time(@min)}:#{format_time(@sec)}"
|
36
|
+
# end
|
37
|
+
|
38
|
+
def <=>(other)
|
39
|
+
to_a <=> other.to_a
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def format_time(part)
|
45
|
+
format("%02d", part)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
data/lib/montrose/utils.rb
CHANGED
@@ -4,10 +4,6 @@ module Montrose
|
|
4
4
|
module Utils
|
5
5
|
module_function
|
6
6
|
|
7
|
-
MONTHS = ::Date::MONTHNAMES
|
8
|
-
|
9
|
-
DAYS = ::Date::DAYNAMES
|
10
|
-
|
11
7
|
MAX_HOURS_IN_DAY = 24
|
12
8
|
MAX_DAYS_IN_YEAR = 366
|
13
9
|
MAX_WEEKS_IN_YEAR = 53
|
@@ -44,40 +40,6 @@ module Montrose
|
|
44
40
|
::Time.current
|
45
41
|
end
|
46
42
|
|
47
|
-
def month_number(name)
|
48
|
-
case name
|
49
|
-
when Symbol, String
|
50
|
-
string = name.to_s
|
51
|
-
MONTHS.index(string.titleize) || month_number(to_index(string))
|
52
|
-
when 1..12
|
53
|
-
name
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
def month_number!(name)
|
58
|
-
month_numbers = MONTHS.map.with_index { |_n, i| i.to_s }.slice(1, 12)
|
59
|
-
month_number(name) || raise(ConfigurationError,
|
60
|
-
"Did not recognize month #{name}, must be one of #{(MONTHS + month_numbers).inspect}")
|
61
|
-
end
|
62
|
-
|
63
|
-
def day_number(name)
|
64
|
-
case name
|
65
|
-
when 0..6
|
66
|
-
name
|
67
|
-
when Symbol, String
|
68
|
-
string = name.to_s
|
69
|
-
DAYS.index(string.titleize) || day_number(to_index(string))
|
70
|
-
when Array
|
71
|
-
day_number name.first
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
def day_number!(name)
|
76
|
-
day_numbers = DAYS.map.with_index { |_n, i| i.to_s }
|
77
|
-
day_number(name) || raise(ConfigurationError,
|
78
|
-
"Did not recognize day #{name}, must be one of #{(DAYS + day_numbers).inspect}")
|
79
|
-
end
|
80
|
-
|
81
43
|
def days_in_month(month, year = current_time.year)
|
82
44
|
date = ::Date.new(year, month, 1)
|
83
45
|
((date >> 1) - date).to_i
|
data/lib/montrose/version.rb
CHANGED
@@ -0,0 +1,20 @@
|
|
1
|
+
module Montrose
|
2
|
+
class Week
|
3
|
+
class << self
|
4
|
+
NUMBERS = (-53.upto(-1).to_a + 1.upto(53).to_a)
|
5
|
+
|
6
|
+
def parse(arg)
|
7
|
+
return nil unless arg.present?
|
8
|
+
|
9
|
+
Array(arg).map { |value| assert(value.to_i) }
|
10
|
+
end
|
11
|
+
|
12
|
+
def assert(number)
|
13
|
+
test = number.abs
|
14
|
+
raise ConfigurationError, "Out of range: #{NUMBERS.inspect} does not include #{test}" unless NUMBERS.include?(number.abs)
|
15
|
+
|
16
|
+
number
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Montrose
|
2
|
+
class YearDay
|
3
|
+
class << self
|
4
|
+
YDAYS = 1.upto(366).to_a
|
5
|
+
|
6
|
+
def parse(ydays)
|
7
|
+
return nil unless ydays.present?
|
8
|
+
|
9
|
+
case ydays
|
10
|
+
when String
|
11
|
+
parse(ydays.split(","))
|
12
|
+
else
|
13
|
+
Array(ydays).map { |d| assert(d.to_i) }
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def assert(number)
|
18
|
+
test = number.abs
|
19
|
+
raise ConfigurationError, "Out of range: #{YDAYS.inspect} does not include #{test}" unless YDAYS.include?(number.abs)
|
20
|
+
|
21
|
+
number
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|