ice_cube 0.6.14 → 0.7.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 +63 -37
- 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/errors/count_exceeded.rb +7 -0
- data/lib/ice_cube/errors/until_exceeded.rb +7 -0
- data/lib/ice_cube/rule.rb +85 -147
- data/lib/ice_cube/rules/daily_rule.rb +5 -27
- data/lib/ice_cube/rules/hourly_rule.rb +6 -26
- data/lib/ice_cube/rules/minutely_rule.rb +5 -25
- data/lib/ice_cube/rules/monthly_rule.rb +6 -30
- data/lib/ice_cube/rules/secondly_rule.rb +5 -26
- data/lib/ice_cube/rules/weekly_rule.rb +5 -36
- data/lib/ice_cube/rules/yearly_rule.rb +8 -34
- data/lib/ice_cube/schedule.rb +257 -229
- data/lib/ice_cube/single_occurrence_rule.rb +28 -0
- data/lib/ice_cube/time_util.rb +202 -76
- data/lib/ice_cube/validated_rule.rb +107 -0
- data/lib/ice_cube/validations/count.rb +56 -0
- data/lib/ice_cube/validations/daily_interval.rb +51 -0
- data/lib/ice_cube/validations/day.rb +45 -31
- data/lib/ice_cube/validations/day_of_month.rb +44 -44
- data/lib/ice_cube/validations/day_of_week.rb +60 -47
- data/lib/ice_cube/validations/day_of_year.rb +48 -44
- data/lib/ice_cube/validations/hour_of_day.rb +42 -30
- data/lib/ice_cube/validations/hourly_interval.rb +50 -0
- data/lib/ice_cube/validations/lock.rb +47 -0
- data/lib/ice_cube/validations/minute_of_hour.rb +42 -31
- data/lib/ice_cube/validations/minutely_interval.rb +50 -0
- data/lib/ice_cube/validations/month_of_year.rb +39 -30
- data/lib/ice_cube/validations/monthly_interval.rb +47 -0
- data/lib/ice_cube/validations/schedule_lock.rb +41 -0
- data/lib/ice_cube/validations/second_of_minute.rb +39 -30
- data/lib/ice_cube/validations/secondly_interval.rb +50 -0
- data/lib/ice_cube/validations/until.rb +49 -0
- data/lib/ice_cube/validations/weekly_interval.rb +50 -0
- data/lib/ice_cube/validations/yearly_interval.rb +45 -0
- data/lib/ice_cube/version.rb +2 -2
- data/spec/spec_helper.rb +13 -0
- metadata +50 -9
- data/lib/ice_cube/rule_occurrence.rb +0 -94
- data/lib/ice_cube/validation.rb +0 -44
- data/lib/ice_cube/validation_types.rb +0 -137
@@ -1,40 +1,49 @@
|
|
1
1
|
module IceCube
|
2
2
|
|
3
|
-
|
3
|
+
module Validations::SecondOfMinute
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
@seconds_of_minute = rule.validations[:second_of_minute]
|
9
|
-
end
|
10
|
-
|
11
|
-
def validate(date)
|
12
|
-
return true if !@seconds_of_minute || @seconds_of_minute.empty?
|
13
|
-
@seconds_of_minute.include?(date.sec)
|
14
|
-
end
|
15
|
-
|
16
|
-
def closest(date)
|
17
|
-
return nil if !@seconds_of_minute || @seconds_of_minute.empty?
|
18
|
-
# turn seconds into seconds of minute
|
19
|
-
# second >= 60 should fall into the next minute
|
20
|
-
seconds = @seconds_of_minute.map do |s|
|
21
|
-
s > date.sec ? s - date.sec : 60 - date.sec + s
|
5
|
+
def second_of_minute(*seconds)
|
6
|
+
seconds.each do |second|
|
7
|
+
validations_for(:second_of_minute) << Validation.new(second)
|
22
8
|
end
|
23
|
-
|
24
|
-
|
25
|
-
closest_second = seconds.min
|
26
|
-
goal = date + closest_second
|
27
|
-
self.class.adjust(goal, date)
|
9
|
+
clobber_base_validations :sec
|
10
|
+
self
|
28
11
|
end
|
29
12
|
|
30
|
-
|
31
|
-
|
32
|
-
|
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
|
33
44
|
|
34
|
-
def to_ical
|
35
|
-
'BYSECOND=' << @seconds_of_minute.join(',') unless @seconds_of_minute.empty?
|
36
45
|
end
|
37
|
-
|
46
|
+
|
38
47
|
end
|
39
|
-
|
48
|
+
|
40
49
|
end
|
@@ -0,0 +1,50 @@
|
|
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
|
+
end
|
30
|
+
|
31
|
+
def build_hash(builder)
|
32
|
+
builder.validations[:interval] = interval
|
33
|
+
end
|
34
|
+
|
35
|
+
def initialize(interval)
|
36
|
+
@interval = interval
|
37
|
+
end
|
38
|
+
|
39
|
+
def validate(time, schedule)
|
40
|
+
seconds = time.to_i - schedule.start_time.to_i
|
41
|
+
unless seconds % interval == 0
|
42
|
+
interval - (seconds % interval)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module IceCube
|
2
|
+
|
3
|
+
module Validations::Until
|
4
|
+
|
5
|
+
# accessor
|
6
|
+
def until_time
|
7
|
+
@until
|
8
|
+
end
|
9
|
+
alias :until_date :until_time
|
10
|
+
|
11
|
+
def until(time)
|
12
|
+
@until = time
|
13
|
+
replace_validations_for(:until, [Validation.new(time)])
|
14
|
+
self
|
15
|
+
end
|
16
|
+
|
17
|
+
class Validation
|
18
|
+
|
19
|
+
attr_reader :time
|
20
|
+
|
21
|
+
def type
|
22
|
+
:dealbreaker
|
23
|
+
end
|
24
|
+
|
25
|
+
def initialize(time)
|
26
|
+
@time = time
|
27
|
+
end
|
28
|
+
|
29
|
+
def build_ical(builder)
|
30
|
+
builder['UNTIL'] << IcalBuilder.ical_utc_format(time)
|
31
|
+
end
|
32
|
+
|
33
|
+
def build_hash(builder)
|
34
|
+
builder[:until] = TimeUtil.serialize_time(time)
|
35
|
+
end
|
36
|
+
|
37
|
+
def build_s(builder)
|
38
|
+
builder.piece(:until) << "until #{time.strftime(TO_S_TIME_FORMAT)}"
|
39
|
+
end
|
40
|
+
|
41
|
+
def validate(t, schedule)
|
42
|
+
raise UntilExceeded if t > time
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'date'
|
2
|
+
|
3
|
+
module IceCube
|
4
|
+
|
5
|
+
module Validations::WeeklyInterval
|
6
|
+
|
7
|
+
def interval(interval)
|
8
|
+
validations_for(:interval) << Validation.new(interval)
|
9
|
+
clobber_base_validations(:day)
|
10
|
+
end
|
11
|
+
|
12
|
+
class Validation
|
13
|
+
|
14
|
+
attr_reader :interval
|
15
|
+
|
16
|
+
def type
|
17
|
+
:day
|
18
|
+
end
|
19
|
+
|
20
|
+
def build_s(builder)
|
21
|
+
builder.base = interval == 1 ? 'Weekly' : "Every #{interval} weeks"
|
22
|
+
end
|
23
|
+
|
24
|
+
def build_ical(builder)
|
25
|
+
builder['FREQ'] << 'WEEKLY'
|
26
|
+
end
|
27
|
+
|
28
|
+
def build_hash(builder)
|
29
|
+
builder.validations[:interval] = interval
|
30
|
+
end
|
31
|
+
|
32
|
+
def initialize(interval)
|
33
|
+
@interval = interval
|
34
|
+
end
|
35
|
+
|
36
|
+
def validate(time, schedule)
|
37
|
+
date = Date.new(time.year, time.month, time.day)
|
38
|
+
st = schedule.start_time
|
39
|
+
start_date = Date.new(st.year, st.month, st.day)
|
40
|
+
weeks = ((date - date.wday) - (start_date - start_date.wday)) / 7
|
41
|
+
unless weeks % interval == 0
|
42
|
+
(interval - (weeks % interval)) * 7
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
@@ -0,0 +1,45 @@
|
|
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.validations[:interval] = interval
|
24
|
+
end
|
25
|
+
|
26
|
+
def build_ical(builder)
|
27
|
+
builder['FREQ'] << 'YEARLY'
|
28
|
+
end
|
29
|
+
|
30
|
+
def initialize(interval)
|
31
|
+
@interval = interval
|
32
|
+
end
|
33
|
+
|
34
|
+
def validate(time, schedule)
|
35
|
+
years_to_start = time.year - schedule.start_time.year
|
36
|
+
unless years_to_start % interval == 0
|
37
|
+
interval - (years_to_start % interval)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
data/lib/ice_cube/version.rb
CHANGED
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../lib/ice_cube'
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'cover_me'
|
5
|
+
# https://github.com/markbates/cover_me/issues/50
|
6
|
+
at_exit do
|
7
|
+
CoverMe.complete!
|
8
|
+
end
|
9
|
+
rescue LoadError
|
10
|
+
end
|
11
|
+
|
12
|
+
DAY = Time.utc(2010, 3, 1)
|
13
|
+
WEDNESDAY = Time.utc(2010, 6, 23, 5, 0, 0)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ice_cube
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,12 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2011-
|
12
|
+
date: 2011-12-08 00:00:00.000000000 -05:00
|
13
|
+
default_executable:
|
13
14
|
dependencies:
|
14
15
|
- !ruby/object:Gem::Dependency
|
15
16
|
name: rspec
|
16
|
-
requirement: &
|
17
|
+
requirement: &70154139759660 !ruby/object:Gem::Requirement
|
17
18
|
none: false
|
18
19
|
requirements:
|
19
20
|
- - ! '>='
|
@@ -21,7 +22,29 @@ dependencies:
|
|
21
22
|
version: '0'
|
22
23
|
type: :development
|
23
24
|
prerelease: false
|
24
|
-
version_requirements: *
|
25
|
+
version_requirements: *70154139759660
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: active_support
|
28
|
+
requirement: &70154139758460 !ruby/object:Gem::Requirement
|
29
|
+
none: false
|
30
|
+
requirements:
|
31
|
+
- - ! '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 3.0.0
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: *70154139758460
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: tzinfo
|
39
|
+
requirement: &70154139757400 !ruby/object:Gem::Requirement
|
40
|
+
none: false
|
41
|
+
requirements:
|
42
|
+
- - ! '>='
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: '0'
|
45
|
+
type: :development
|
46
|
+
prerelease: false
|
47
|
+
version_requirements: *70154139757400
|
25
48
|
description: ice_cube is a recurring date library for Ruby. It allows for quick,
|
26
49
|
programatic expansion of recurring date rules.
|
27
50
|
email: john@crepezzi.com
|
@@ -29,8 +52,12 @@ executables: []
|
|
29
52
|
extensions: []
|
30
53
|
extra_rdoc_files: []
|
31
54
|
files:
|
55
|
+
- lib/ice_cube/builders/hash_builder.rb
|
56
|
+
- lib/ice_cube/builders/ical_builder.rb
|
57
|
+
- lib/ice_cube/builders/string_builder.rb
|
58
|
+
- lib/ice_cube/errors/count_exceeded.rb
|
59
|
+
- lib/ice_cube/errors/until_exceeded.rb
|
32
60
|
- lib/ice_cube/rule.rb
|
33
|
-
- lib/ice_cube/rule_occurrence.rb
|
34
61
|
- lib/ice_cube/rules/daily_rule.rb
|
35
62
|
- lib/ice_cube/rules/hourly_rule.rb
|
36
63
|
- lib/ice_cube/rules/minutely_rule.rb
|
@@ -39,19 +66,32 @@ files:
|
|
39
66
|
- lib/ice_cube/rules/weekly_rule.rb
|
40
67
|
- lib/ice_cube/rules/yearly_rule.rb
|
41
68
|
- lib/ice_cube/schedule.rb
|
69
|
+
- lib/ice_cube/single_occurrence_rule.rb
|
42
70
|
- lib/ice_cube/time_util.rb
|
43
|
-
- lib/ice_cube/
|
44
|
-
- lib/ice_cube/
|
71
|
+
- lib/ice_cube/validated_rule.rb
|
72
|
+
- lib/ice_cube/validations/count.rb
|
73
|
+
- lib/ice_cube/validations/daily_interval.rb
|
45
74
|
- lib/ice_cube/validations/day.rb
|
46
75
|
- lib/ice_cube/validations/day_of_month.rb
|
47
76
|
- lib/ice_cube/validations/day_of_week.rb
|
48
77
|
- lib/ice_cube/validations/day_of_year.rb
|
49
78
|
- lib/ice_cube/validations/hour_of_day.rb
|
79
|
+
- lib/ice_cube/validations/hourly_interval.rb
|
80
|
+
- lib/ice_cube/validations/lock.rb
|
50
81
|
- lib/ice_cube/validations/minute_of_hour.rb
|
82
|
+
- lib/ice_cube/validations/minutely_interval.rb
|
51
83
|
- lib/ice_cube/validations/month_of_year.rb
|
84
|
+
- lib/ice_cube/validations/monthly_interval.rb
|
85
|
+
- lib/ice_cube/validations/schedule_lock.rb
|
52
86
|
- lib/ice_cube/validations/second_of_minute.rb
|
87
|
+
- lib/ice_cube/validations/secondly_interval.rb
|
88
|
+
- lib/ice_cube/validations/until.rb
|
89
|
+
- lib/ice_cube/validations/weekly_interval.rb
|
90
|
+
- lib/ice_cube/validations/yearly_interval.rb
|
53
91
|
- lib/ice_cube/version.rb
|
54
92
|
- lib/ice_cube.rb
|
93
|
+
- spec/spec_helper.rb
|
94
|
+
has_rdoc: true
|
55
95
|
homepage: http://seejohnrun.github.com/ice_cube/
|
56
96
|
licenses: []
|
57
97
|
post_install_message:
|
@@ -72,8 +112,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
72
112
|
version: '0'
|
73
113
|
requirements: []
|
74
114
|
rubyforge_project: ice-cube
|
75
|
-
rubygems_version: 1.
|
115
|
+
rubygems_version: 1.6.2
|
76
116
|
signing_key:
|
77
117
|
specification_version: 3
|
78
118
|
summary: Ruby Date Recurrence Library
|
79
|
-
test_files:
|
119
|
+
test_files:
|
120
|
+
- spec/spec_helper.rb
|
@@ -1,94 +0,0 @@
|
|
1
|
-
module IceCube
|
2
|
-
|
3
|
-
class RuleOccurrence
|
4
|
-
|
5
|
-
def to_time
|
6
|
-
@date
|
7
|
-
end
|
8
|
-
|
9
|
-
def all_occurrences
|
10
|
-
raise ArgumentError.new("Rule must specify either an until date or a count to use 'all_occurrences'") unless @rule.occurrence_count || @rule.until_date || @end_time
|
11
|
-
find_occurrences { |roc| false }
|
12
|
-
end
|
13
|
-
|
14
|
-
def between(begin_time, end_time)
|
15
|
-
find_occurrences { |roc| roc > end_time }.select { |d| d >= begin_time }
|
16
|
-
end
|
17
|
-
|
18
|
-
def upto(end_date)
|
19
|
-
find_occurrences { |roc| roc > end_date }
|
20
|
-
end
|
21
|
-
|
22
|
-
# Break after the first occurrence after now
|
23
|
-
def next_occurrence(from)
|
24
|
-
next_occurrences(1, from).first
|
25
|
-
end
|
26
|
-
|
27
|
-
# Break after the first n occurrences after now
|
28
|
-
def next_occurrences(n, from, exclude_dates)
|
29
|
-
found_all = false
|
30
|
-
num_found = 0
|
31
|
-
nexts = find_occurrences do |roc|
|
32
|
-
num_found += 1 if roc > from && !exclude_dates.include?(roc.to_time)
|
33
|
-
success = found_all
|
34
|
-
found_all = num_found == n
|
35
|
-
success
|
36
|
-
end
|
37
|
-
#Since the above returns all up to and including the next N that were requested, we need
|
38
|
-
#to grab the last n, making sure to prune out ones that were actually before the from time
|
39
|
-
nexts.last(n).select{|occurrence| occurrence > from}
|
40
|
-
end
|
41
|
-
|
42
|
-
def first(n)
|
43
|
-
count = 0
|
44
|
-
find_occurrences { |roc| count += 1; count > n }
|
45
|
-
end
|
46
|
-
|
47
|
-
#get the next occurrence of this rule
|
48
|
-
def succ
|
49
|
-
return nil if @rule.occurrence_count && @index >= @rule.occurrence_count # count check
|
50
|
-
# get the next date to walk to
|
51
|
-
if @date.nil?
|
52
|
-
date = @start_date if @rule.validate_single_date(@start_date)
|
53
|
-
date = @rule.next_suggestion(@start_date) unless date
|
54
|
-
else
|
55
|
-
date = @rule.next_suggestion(@date)
|
56
|
-
end
|
57
|
-
# walk through all of the successive dates, looking for the next occurrence (interval-valid), then return it.
|
58
|
-
begin
|
59
|
-
return nil if @end_time && date > @end_time
|
60
|
-
return nil if @rule.until_date && date > @rule.until_date # until check
|
61
|
-
next unless @rule.in_interval?(date, @start_date)
|
62
|
-
return nil if yield(date)
|
63
|
-
return RuleOccurrence.new(@rule, @start_date, @end_time, date, @index + 1)
|
64
|
-
end while date = @rule.next_suggestion(date)
|
65
|
-
end
|
66
|
-
|
67
|
-
attr_reader :rule
|
68
|
-
attr_accessor :start_date
|
69
|
-
|
70
|
-
private
|
71
|
-
|
72
|
-
def find_occurrences(&block)
|
73
|
-
include_dates = []
|
74
|
-
roc = self
|
75
|
-
begin
|
76
|
-
break if roc.nil? #go until we run out of dates
|
77
|
-
next if roc.to_time.nil? #handle the case where start_date is not a valid occurrence
|
78
|
-
include_dates << roc.to_time
|
79
|
-
end while roc = roc.succ(&block)
|
80
|
-
include_dates
|
81
|
-
end
|
82
|
-
|
83
|
-
def initialize(rule, start_date, end_time, date = nil, index = 0)
|
84
|
-
#set some variables
|
85
|
-
@rule = rule
|
86
|
-
@start_date = start_date
|
87
|
-
@end_time = end_time
|
88
|
-
@date = date
|
89
|
-
@index = index
|
90
|
-
end
|
91
|
-
|
92
|
-
end
|
93
|
-
|
94
|
-
end
|