ice_cube 0.6.14 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|