ice_cube_conrad 0.8.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.
- data/lib/ice_cube.rb +80 -0
- data/lib/ice_cube/builders/hash_builder.rb +27 -0
- data/lib/ice_cube/builders/ical_builder.rb +59 -0
- data/lib/ice_cube/builders/string_builder.rb +74 -0
- data/lib/ice_cube/deprecated.rb +28 -0
- data/lib/ice_cube/errors/count_exceeded.rb +7 -0
- data/lib/ice_cube/errors/until_exceeded.rb +7 -0
- data/lib/ice_cube/errors/zero_interval.rb +7 -0
- data/lib/ice_cube/rule.rb +182 -0
- data/lib/ice_cube/rules/daily_rule.rb +14 -0
- data/lib/ice_cube/rules/hourly_rule.rb +14 -0
- data/lib/ice_cube/rules/minutely_rule.rb +14 -0
- data/lib/ice_cube/rules/monthly_rule.rb +14 -0
- data/lib/ice_cube/rules/secondly_rule.rb +13 -0
- data/lib/ice_cube/rules/weekly_rule.rb +14 -0
- data/lib/ice_cube/rules/yearly_rule.rb +14 -0
- data/lib/ice_cube/schedule.rb +414 -0
- data/lib/ice_cube/single_occurrence_rule.rb +28 -0
- data/lib/ice_cube/time_util.rb +250 -0
- data/lib/ice_cube/validated_rule.rb +108 -0
- data/lib/ice_cube/validations/count.rb +56 -0
- data/lib/ice_cube/validations/daily_interval.rb +55 -0
- data/lib/ice_cube/validations/day.rb +65 -0
- data/lib/ice_cube/validations/day_of_month.rb +52 -0
- data/lib/ice_cube/validations/day_of_week.rb +70 -0
- data/lib/ice_cube/validations/day_of_year.rb +55 -0
- data/lib/ice_cube/validations/hour_of_day.rb +52 -0
- data/lib/ice_cube/validations/hourly_interval.rb +57 -0
- data/lib/ice_cube/validations/lock.rb +47 -0
- data/lib/ice_cube/validations/minute_of_hour.rb +51 -0
- data/lib/ice_cube/validations/minutely_interval.rb +57 -0
- data/lib/ice_cube/validations/month_of_year.rb +49 -0
- data/lib/ice_cube/validations/monthly_interval.rb +51 -0
- data/lib/ice_cube/validations/schedule_lock.rb +41 -0
- data/lib/ice_cube/validations/second_of_minute.rb +49 -0
- data/lib/ice_cube/validations/secondly_interval.rb +54 -0
- data/lib/ice_cube/validations/until.rb +51 -0
- data/lib/ice_cube/validations/weekly_interval.rb +60 -0
- data/lib/ice_cube/validations/yearly_interval.rb +49 -0
- data/lib/ice_cube/version.rb +5 -0
- data/spec/spec_helper.rb +11 -0
- metadata +120 -0
@@ -0,0 +1,57 @@
|
|
1
|
+
module IceCube
|
2
|
+
|
3
|
+
module Validations::MinutelyInterval
|
4
|
+
|
5
|
+
def interval(interval)
|
6
|
+
validations_for(:interval) << Validation.new(interval)
|
7
|
+
clobber_base_validations(:min)
|
8
|
+
self
|
9
|
+
end
|
10
|
+
|
11
|
+
class Validation
|
12
|
+
|
13
|
+
attr_reader :interval
|
14
|
+
|
15
|
+
def type
|
16
|
+
:min
|
17
|
+
end
|
18
|
+
|
19
|
+
def dst_adjust?
|
20
|
+
false
|
21
|
+
end
|
22
|
+
|
23
|
+
def build_s(builder)
|
24
|
+
builder.base = interval == 1 ? 'Minutely' : "Every #{interval} minutes"
|
25
|
+
end
|
26
|
+
|
27
|
+
def build_ical(builder)
|
28
|
+
builder['FREQ'] << 'MINUTELY'
|
29
|
+
unless interval == 1
|
30
|
+
builder['INTERVAL'] << interval
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def build_hash(builder)
|
35
|
+
builder[:interval] = interval
|
36
|
+
end
|
37
|
+
|
38
|
+
def initialize(interval)
|
39
|
+
@interval = interval
|
40
|
+
end
|
41
|
+
|
42
|
+
def validate(time, schedule)
|
43
|
+
raise ZeroInterval if interval == 0
|
44
|
+
start_time = schedule.start_time
|
45
|
+
sec = (time.to_i - time.to_i % ONE_MINUTE) -
|
46
|
+
(start_time.to_i - start_time.to_i % ONE_MINUTE)
|
47
|
+
minutes = sec / ONE_MINUTE
|
48
|
+
unless minutes % interval == 0
|
49
|
+
interval - (minutes % interval)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module IceCube
|
2
|
+
|
3
|
+
module Validations::MonthOfYear
|
4
|
+
|
5
|
+
def month_of_year(*months)
|
6
|
+
months.each do |month|
|
7
|
+
month = TimeUtil.symbol_to_month(month.to_sym) if month.is_a?(Symbol) or month.is_a?(String)
|
8
|
+
validations_for(:month_of_year) << Validation.new(month)
|
9
|
+
end
|
10
|
+
clobber_base_validations :month
|
11
|
+
self
|
12
|
+
end
|
13
|
+
|
14
|
+
class Validation
|
15
|
+
|
16
|
+
include Validations::Lock
|
17
|
+
|
18
|
+
attr_reader :month
|
19
|
+
alias :value :month
|
20
|
+
|
21
|
+
def initialize(month)
|
22
|
+
@month = month
|
23
|
+
end
|
24
|
+
|
25
|
+
def build_s(builder)
|
26
|
+
builder.piece(:month_of_year) << Date::MONTHNAMES[month]
|
27
|
+
end
|
28
|
+
|
29
|
+
def build_hash(builder)
|
30
|
+
builder.validations_array(:month_of_year) << month
|
31
|
+
end
|
32
|
+
|
33
|
+
def build_ical(builder)
|
34
|
+
builder['BYMONTH'] << month
|
35
|
+
end
|
36
|
+
|
37
|
+
def type
|
38
|
+
:month
|
39
|
+
end
|
40
|
+
|
41
|
+
StringBuilder.register_formatter(:month_of_year) do |segments|
|
42
|
+
"in #{StringBuilder.sentence(segments)}"
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module IceCube
|
2
|
+
|
3
|
+
module Validations::MonthlyInterval
|
4
|
+
|
5
|
+
def interval(interval = 1)
|
6
|
+
validations_for(:interval) << Validation.new(interval)
|
7
|
+
clobber_base_validations(:month)
|
8
|
+
self
|
9
|
+
end
|
10
|
+
|
11
|
+
class Validation
|
12
|
+
|
13
|
+
attr_reader :interval
|
14
|
+
|
15
|
+
def type
|
16
|
+
:month
|
17
|
+
end
|
18
|
+
|
19
|
+
def build_s(builder)
|
20
|
+
builder.base = interval == 1 ? 'Monthly' : "Every #{interval} months"
|
21
|
+
end
|
22
|
+
|
23
|
+
def build_ical(builder)
|
24
|
+
builder['FREQ'] << 'MONTHLY'
|
25
|
+
unless interval == 1
|
26
|
+
builder['INTERVAL'] << interval
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def build_hash(builder)
|
31
|
+
builder[:interval] = interval
|
32
|
+
end
|
33
|
+
|
34
|
+
def initialize(interval)
|
35
|
+
@interval = interval
|
36
|
+
end
|
37
|
+
|
38
|
+
def validate(time, schedule)
|
39
|
+
raise ZeroInterval if interval == 0
|
40
|
+
start_time = schedule.start_time
|
41
|
+
months_to_start = (time.month - start_time.month) + (time.year - start_time.year) * 12
|
42
|
+
unless months_to_start % interval == 0
|
43
|
+
interval - (months_to_start % interval)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module IceCube
|
2
|
+
|
3
|
+
module Validations::ScheduleLock
|
4
|
+
|
5
|
+
# Lock the given times down the schedule's start_time for that position
|
6
|
+
# These locks are all clobberable by other rules of the same #type
|
7
|
+
# using clobber_base_validation
|
8
|
+
def schedule_lock(*types)
|
9
|
+
types.each do |type|
|
10
|
+
validations_for(:"base_#{type}") << Validation.new(type)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
# A validation used for locking time into a certain value
|
15
|
+
class Validation
|
16
|
+
|
17
|
+
include Validations::Lock
|
18
|
+
|
19
|
+
attr_reader :type, :value
|
20
|
+
|
21
|
+
def initialize(type)
|
22
|
+
@type = type
|
23
|
+
end
|
24
|
+
|
25
|
+
# no -op
|
26
|
+
def build_s(builder)
|
27
|
+
end
|
28
|
+
|
29
|
+
# no -op
|
30
|
+
def build_ical(builder)
|
31
|
+
end
|
32
|
+
|
33
|
+
# no -op
|
34
|
+
def build_hash(builder)
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module IceCube
|
2
|
+
|
3
|
+
module Validations::SecondOfMinute
|
4
|
+
|
5
|
+
def second_of_minute(*seconds)
|
6
|
+
seconds.each do |second|
|
7
|
+
validations_for(:second_of_minute) << Validation.new(second)
|
8
|
+
end
|
9
|
+
clobber_base_validations :sec
|
10
|
+
self
|
11
|
+
end
|
12
|
+
|
13
|
+
class Validation
|
14
|
+
|
15
|
+
include Validations::Lock
|
16
|
+
|
17
|
+
StringBuilder.register_formatter(:second_of_minute) do |segments|
|
18
|
+
str = "on the #{StringBuilder.sentence(segments)} "
|
19
|
+
str << (segments.size == 1 ? 'second of the minute' : 'seconds of the minute')
|
20
|
+
end
|
21
|
+
|
22
|
+
attr_reader :second
|
23
|
+
alias :value :second
|
24
|
+
|
25
|
+
def initialize(second)
|
26
|
+
@second = second
|
27
|
+
end
|
28
|
+
|
29
|
+
def type
|
30
|
+
:sec
|
31
|
+
end
|
32
|
+
|
33
|
+
def build_s(builder)
|
34
|
+
builder.piece(:second_of_minute) << StringBuilder.nice_number(second)
|
35
|
+
end
|
36
|
+
|
37
|
+
def build_hash(builder)
|
38
|
+
builder.validations_array(:second_of_minute) << second
|
39
|
+
end
|
40
|
+
|
41
|
+
def build_ical(builder)
|
42
|
+
builder['BYSECOND'] << second
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module IceCube
|
2
|
+
|
3
|
+
module Validations::SecondlyInterval
|
4
|
+
|
5
|
+
def interval(interval)
|
6
|
+
validations_for(:interval) << Validation.new(interval)
|
7
|
+
clobber_base_validations(:sec)
|
8
|
+
self
|
9
|
+
end
|
10
|
+
|
11
|
+
class Validation
|
12
|
+
|
13
|
+
attr_reader :interval
|
14
|
+
|
15
|
+
def type
|
16
|
+
:sec
|
17
|
+
end
|
18
|
+
|
19
|
+
def dst_adjust?
|
20
|
+
false
|
21
|
+
end
|
22
|
+
|
23
|
+
def build_s(builder)
|
24
|
+
builder.base = interval == 1 ? 'Secondly' : "Every #{interval} seconds"
|
25
|
+
end
|
26
|
+
|
27
|
+
def build_ical(builder)
|
28
|
+
builder['FREQ'] << 'SECONDLY'
|
29
|
+
unless interval == 1
|
30
|
+
builder['INTERVAL'] << interval
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def build_hash(builder)
|
35
|
+
builder[:interval] = interval
|
36
|
+
end
|
37
|
+
|
38
|
+
def initialize(interval)
|
39
|
+
@interval = interval
|
40
|
+
end
|
41
|
+
|
42
|
+
def validate(time, schedule)
|
43
|
+
raise ZeroInterval if interval == 0
|
44
|
+
seconds = time.to_i - schedule.start_time.to_i
|
45
|
+
unless seconds % interval == 0
|
46
|
+
interval - (seconds % interval)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module IceCube
|
2
|
+
|
3
|
+
module Validations::Until
|
4
|
+
|
5
|
+
extend ::Deprecated
|
6
|
+
|
7
|
+
# accessor
|
8
|
+
def until_time
|
9
|
+
@until
|
10
|
+
end
|
11
|
+
deprecated_alias :until_date, :until_time
|
12
|
+
|
13
|
+
def until(time)
|
14
|
+
@until = time
|
15
|
+
replace_validations_for(:until, [Validation.new(time)])
|
16
|
+
self
|
17
|
+
end
|
18
|
+
|
19
|
+
class Validation
|
20
|
+
|
21
|
+
attr_reader :time
|
22
|
+
|
23
|
+
def type
|
24
|
+
:dealbreaker
|
25
|
+
end
|
26
|
+
|
27
|
+
def initialize(time)
|
28
|
+
@time = time
|
29
|
+
end
|
30
|
+
|
31
|
+
def build_ical(builder)
|
32
|
+
builder['UNTIL'] << IcalBuilder.ical_utc_format(time)
|
33
|
+
end
|
34
|
+
|
35
|
+
def build_hash(builder)
|
36
|
+
builder[:until] = TimeUtil.serialize_time(time)
|
37
|
+
end
|
38
|
+
|
39
|
+
def build_s(builder)
|
40
|
+
builder.piece(:until) << "until #{time.strftime(TO_S_TIME_FORMAT)}"
|
41
|
+
end
|
42
|
+
|
43
|
+
def validate(t, schedule)
|
44
|
+
raise UntilExceeded if t > time
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'date'
|
2
|
+
|
3
|
+
module IceCube
|
4
|
+
|
5
|
+
module Validations::WeeklyInterval
|
6
|
+
|
7
|
+
def interval(interval, week_start = :sunday)
|
8
|
+
validations_for(:interval) << Validation.new(interval, week_start)
|
9
|
+
clobber_base_validations(:day)
|
10
|
+
self
|
11
|
+
end
|
12
|
+
|
13
|
+
class Validation
|
14
|
+
|
15
|
+
attr_reader :interval, :week_start
|
16
|
+
|
17
|
+
def type
|
18
|
+
:day
|
19
|
+
end
|
20
|
+
|
21
|
+
def build_s(builder)
|
22
|
+
builder.base = interval == 1 ? 'Weekly' : "Every #{interval} weeks"
|
23
|
+
end
|
24
|
+
|
25
|
+
def build_ical(builder)
|
26
|
+
builder['FREQ'] << 'WEEKLY'
|
27
|
+
unless interval == 1
|
28
|
+
builder['INTERVAL'] << interval
|
29
|
+
builder['WKST'] << TimeUtil.week_start(week_start)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def build_hash(builder)
|
34
|
+
builder[:interval] = interval
|
35
|
+
end
|
36
|
+
|
37
|
+
def initialize(interval, week_start)
|
38
|
+
@interval = interval
|
39
|
+
@week_start = week_start
|
40
|
+
end
|
41
|
+
|
42
|
+
def validate(time, schedule)
|
43
|
+
raise ZeroInterval if interval == 0
|
44
|
+
date = Date.new(time.year, time.month, time.day)
|
45
|
+
st = schedule.start_time
|
46
|
+
start_date = Date.new(st.year, st.month, st.day)
|
47
|
+
weeks = (
|
48
|
+
(date - TimeUtil.normalize_weekday(date.wday, week_start)) -
|
49
|
+
(start_date - TimeUtil.normalize_weekday(start_date.wday, week_start))
|
50
|
+
) / 7
|
51
|
+
unless weeks % interval == 0
|
52
|
+
(interval - (weeks % interval)) * 7
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module IceCube
|
2
|
+
|
3
|
+
module Validations::YearlyInterval
|
4
|
+
|
5
|
+
def interval(interval = 1)
|
6
|
+
validations_for(:interval) << Validation.new(interval)
|
7
|
+
clobber_base_validations(:year)
|
8
|
+
end
|
9
|
+
|
10
|
+
class Validation
|
11
|
+
|
12
|
+
attr_reader :interval
|
13
|
+
|
14
|
+
def type
|
15
|
+
:year
|
16
|
+
end
|
17
|
+
|
18
|
+
def build_s(builder)
|
19
|
+
builder.base = interval == 1 ? 'Yearly' : "Every #{interval} years"
|
20
|
+
end
|
21
|
+
|
22
|
+
def build_hash(builder)
|
23
|
+
builder[:interval] = interval
|
24
|
+
end
|
25
|
+
|
26
|
+
def build_ical(builder)
|
27
|
+
builder['FREQ'] << 'YEARLY'
|
28
|
+
unless interval == 1
|
29
|
+
builder['INTERVAL'] << interval
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def initialize(interval)
|
34
|
+
@interval = interval
|
35
|
+
end
|
36
|
+
|
37
|
+
def validate(time, schedule)
|
38
|
+
raise ZeroInterval if interval == 0
|
39
|
+
years_to_start = time.year - schedule.start_time.year
|
40
|
+
unless years_to_start % interval == 0
|
41
|
+
interval - (years_to_start % interval)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|